Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 <h1 id="lab_5_manage_data">Lab 5 - Manage Data</h1> | 1 <h1 id="lab_5_manage_data">Save and Fetch Data</h1> |
| 2 | 2 |
| 3 <p>The <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/l ab3_mvc/angularjs/withcontroller/controller.js#L2-L4">sample from Lab 3</a> uses a static array of Todos. Every time your app restarts, whatever you've chan ged is lost. In this section, we will save every change using <a href="http://de veloper.chrome.com/trunk/apps/storage.html">chrome.storage.sync</a>. This lets y ou store <em>small things</em> that automatically sync to the cloud if you are o nline and logged in to Chrome. If you are offline or unlogged, it saves locally and transparently: you don't have to handle online check and offline fallbac k in your application.</p> | 3 <p>The <a href="http://developer.chrome.com/trunk/apps/app_codelab3_mvc.html">sa mple from Lab 3</a> |
| 4 uses a static array of Todos. | |
| 5 Every time your app restarts, | |
| 6 whatever you've changed is lost. | |
| 7 In this section, we will save every change using | |
| 8 <a href="http://developer.chrome.com/trunk/apps/storage.html">chrome.storage.syn c</a>. | |
| 9 </p> | |
| 4 | 10 |
| 5 <h2 id="you_should_also_read">You should also read</h2> | 11 <p> |
| 6 | 12 This lets you store <em>small things</em> that automatically sync to the cloud |
| 7 <p><a href="http://developer.chrome.com/apps/app_storage.html">Manage Data</a> i n Chrome app docs</p> | 13 if you are online and logged in to Chrome. |
| 14 If you are offline or unlogged, it saves locally and transparently: | |
| 15 you don't have to handle online check and offline fallback in your applicati on. | |
| 16 </p> | |
| 8 | 17 |
| 9 <h2 id="save_your_todos_in_the_cloud">Save your Todos in the cloud</h2> | 18 <h2 id="save_your_todos_in_the_cloud">Save your Todos in the cloud</h2> |
| 10 | 19 |
| 11 <p class="note"><b>Note:</b> Chrome Sync Storage is not intended to be used as a generic database. There are several restrictions on the amount of information you can save, so it is more appropriate to save settings and other small chunks of data. </p> | 20 <p class="note"><b>Note:</b> |
| 21 Chrome Sync Storage is not intended to be used as a generic database. | |
| 22 There are several restrictions on the amount of information you can save, | |
| 23 so it is more appropriate to save settings and other small chunks of data. </p> | |
| 12 | 24 |
| 13 <ol> | 25 <h3 id="manifest">Update manifest</h3> |
| 14 <li><p>Request permission to use storage in your <a href="https://github.com/Goo gleChrome/chrome-app-codelab/blob/master/lab5_data/angularjs/1_storage_sync/mani fest.json">manifest.json</a>: | 26 |
| 27 <p>Request permission to use storage in your manifest. | |
| 28 Permissions are the same in the | |
| 29 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_dat a/angularjs/1_storage_sync/manifest.json">AngularJS manifest.json</a> and | |
| 30 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_dat a/javascript/1_storage_sync/manifest.json">JavaScript manifest.json</a>: | |
| 31 </p> | |
| 32 | |
| 15 <pre> | 33 <pre> |
| 16 { | 34 { |
| 17 ... , | 35 ... , |
| 18 "permissions": ["storage"] | 36 "permissions": ["storage"] |
| 19 } | 37 } |
| 20 </pre></p></li> | 38 </pre> |
| 21 <li><p>Change your <a href="https://github.com/GoogleChrome/chrome-app-codelab/b lob/master/lab5_data/angularjs/1_storage_sync/controller.js">controller.js</a> a nd, instead of a static list, get the Todo list from the syncable storage: | 39 |
| 22 <pre> | 40 <h3 id="simple-controller">Update controller</h3> |
| 41 | |
| 42 <p>Change your controller to get the Todo list | |
| 43 from syncable storage instead of a static list: | |
| 44 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_dat a/angularjs/1_storage_sync/controller.js">AngularJS controller.js</a> or | |
| 45 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_dat a/javascript/1_storage_sync/controller.js">JavaScript controller.js</a>. | |
| 46 </p> | |
| 47 | |
| 48 <tabs data-group="source"> | |
| 49 | |
| 50 <header tabindex="0" data-value="angular">Angular</header> | |
| 51 <header tabindex="0" data-value="js">JavaScript</header> | |
| 52 | |
| 53 <content> | |
| 54 <pre> | |
| 23 // Notice that chrome.storage.sync.get is asynchronous | 55 // Notice that chrome.storage.sync.get is asynchronous |
| 24 chrome.storage.sync.get('todolist', function(value) { | 56 chrome.storage.sync.get('todolist', function(value) { |
| 25 // The $apply is only necessary to execute the function inside Angular scope | 57 // The $apply is only necessary to execute the function inside Angular scope |
| 26 $scope.$apply(function() { | 58 $scope.$apply(function() { |
| 27 $scope.load(value); | 59 $scope.load(value); |
| 28 }); | 60 }); |
| 29 }); | 61 }); |
| 30 | 62 |
| 31 // If there is saved data in storage, use it. Otherwise, bootstrap with sample t odos | 63 // If there is saved data in storage, use it. Otherwise, bootstrap with sample t odos |
| 32 $scope.load = function(value) { | 64 $scope.load = function(value) { |
| 33 if (value && value.todolist) { | 65 if (value && value.todolist) { |
| 34 $scope.todos = value.todolist; | 66 $scope.todos = value.todolist; |
| 35 } else { | 67 } else { |
| 36 $scope.todos = [ | 68 $scope.todos = [ |
| 37 {text:'learn angular', done:true}, | 69 {text:'learn angular', done:true}, |
| 38 {text:'build an angular app', done:false}]; | 70 {text:'build an angular app', done:false}]; |
| 39 } | 71 } |
| 40 } | 72 } |
| 41 | 73 |
| 42 $scope.save = function() { | 74 $scope.save = function() { |
| 43 chrome.storage.sync.set({'todolist': $scope.todos}); | 75 chrome.storage.sync.set({'todolist': $scope.todos}); |
| 44 }; | 76 }; |
| 45 </pre></li><li>In the HTML, call <code>save()</code> whenever the data changes. There are many other ways of doing this in Angular, like using <code>$watchers</ code> on the scope. The one used here makes the <code>save()</code> calls explic it. | 77 </pre> |
| 46 <pre> | 78 </content> |
| 79 <content> | |
| 80 <pre> | |
| 81 /** | |
| 82 * Listen to changes in the model and trigger the appropriate changes in the v iew | |
| 83 **/ | |
| 84 model.addListener(function(model, changeType, param) { | |
| 85 if ( changeType === 'removed' || changeType === 'archived' || changeType === 'reset') { | |
| 86 redrawUI(model); | |
| 87 } else if ( changeType === 'added' ) { | |
| 88 drawTodo(model.todos[param], list); | |
| 89 } else if ( changeType === 'stateChanged') { | |
| 90 updateTodo(model.todos[param]); | |
| 91 } | |
| 92 storageSave(); | |
| 93 updateCounters(model); | |
| 94 }); | |
| 95 | |
| 96 | |
| 97 // If there is saved data in storage, use it. Otherwise, bootstrap with sample todos | |
| 98 var storageLoad = function() { | |
| 99 chrome.storage.sync.get('todolist', function(value) { | |
| 100 if (value && value.todolist) { | |
| 101 model.setTodos(value.todolist); | |
| 102 } else { | |
| 103 model.addTodo('learn Chrome Apps', true); | |
| 104 model.addTodo('build a Chrome App', false); | |
| 105 } | |
| 106 }); | |
| 107 } | |
| 108 | |
| 109 var storageSave = function() { | |
| 110 chrome.storage.sync.set({'todolist': model.todos}); | |
| 111 }; | |
| 112 </pre> | |
| 113 </content> | |
| 114 </tabs> | |
| 115 | |
| 116 <h3 id="simple-view">Update view</h3> | |
| 117 | |
| 118 <p>In the view, | |
| 119 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_dat a/angularjs/1_storage_sync/index.html">AngularJs index.hmtl</a> or | |
| 120 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_dat a/javascript/1_storage_sync/index.html">JavaScript index.html</a>, | |
| 121 save the data whenever it changes. | |
| 122 In AngularJS, | |
| 123 we call <code>save()</code> explicitedly | |
| 124 but there are many ways of doing this. | |
| 125 For example, | |
| 126 you could also use <code>$watchers</code> on the scope. | |
| 127 </p> | |
| 128 | |
| 129 <tabs data-group="source"> | |
| 130 | |
| 131 <header tabindex="0" data-value="angular">Angular</header> | |
| 132 <header tabindex="0" data-value="js">JavaScript</header> | |
| 133 | |
| 134 <content> | |
| 135 <pre> | |
| 47 ... | 136 ... |
| 48 [ <a href="" ng-click="archive() || save()">arc hive</a> ] | 137 [ <a href="" ng-click="archive() || save()">arc hive</a> ] |
| 49 ... | 138 ... |
| 50 <input type="checkbox" ng-model="todo.done" n g-change="save()"> | 139 <input type="checkbox" ng-model="todo.done" n g-change="save()"> |
| 51 ... | 140 ... |
| 52 <form ng-submit="addTodo() || save()"> | 141 <form ng-submit="addTodo() || save()"> |
| 53 ... | 142 ... |
| 54 </pre></li> | 143 </pre> |
| 55 <li>Check the results by reloading the app: open the app, right-click and select Reload App. | 144 </content> |
| 56 You can now add Todo items, close the app, and the new items will still be there when you reopen the app.</li> | 145 <content> |
| 57 </ol> | 146 <pre> |
| 147 <form> | |
| 148 <input type="text" size="30" | |
| 149 placeholder="add new todo here"> | |
| 150 <input class="btn-primary" type="submit" value="add"> | |
| 151 </form> | |
| 152 </pre> | |
| 153 </content> | |
| 58 | 154 |
| 59 <p class="note"><b>Note:</b> If you get stuck and want to see the app in action , | 155 </tabs> |
| 60 go to <code>chrome://extensions</code>, load the unpacked <a href="https://githu b.com/GoogleChrome/chrome-app-codelab/tree/master/lab5_data/angularjs/1_storage_ sync">1_storage_sync</a> app, | 156 |
| 61 and launch the app from a new tab.</p> | 157 <h3 id="results1">Check the results</h3> |
| 158 | |
| 159 <p>Check the results by reloading the app: | |
| 160 open the app, right-click and select Reload App. | |
| 161 You can now add Todo items, close the app, | |
| 162 and the new items will still be there when you reopen the app. | |
| 163 </p> | |
| 164 | |
| 165 <p> | |
| 166 If you get stuck and want to see the app in action, | |
| 167 go to <code>chrome://extensions</code>, | |
| 168 load the unpacked app, and launch the app from a new tab: | |
| 169 <a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab5_dat a/angularjs/1_storage_sync">Angular JS 1_storage_sync</a> or | |
| 170 <a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab5_dat a/javascript/1_storage_sync">JavaScript 1_storage_sync</a>. | |
| 171 </p> | |
| 62 | 172 |
| 63 <h2 id="handle_drag_and_dropped_files_and_urls">Handle drag-and-dropped files an d URLs</h2> | 173 <h2 id="handle_drag_and_dropped_files_and_urls">Handle drag-and-dropped files an d URLs</h2> |
| 64 | 174 |
| 65 Suppose you want to create Todos associated with local files and/or URLs. The na tural way of doing this is to accept dropped items. It's simple enough to ad d drag-and-drop support in a Chrome app using the standard HTML5 Drag-and-Drop A PI. | 175 <p>Suppose you want to create Todos associated with local files and/or URLs. |
| 176 The natural way of doing this is to accept dropped items. | |
| 177 It's simple enough to add drag-and-drop support | |
| 178 in a Chrome packaged app using the standard | |
| 179 <a href="http://www.html5rocks.com/en/tutorials/file/filesystem/">HTML5 Drag-and -Drop API</a>. | |
|
Renato Mangini (chromium)
2013/04/09 17:32:32
http://www.html5rocks.com/en/tutorials/dnd/basics/
mkearney1
2013/04/10 17:59:58
Done.
| |
| 66 | 180 |
| 67 <ol> | 181 <h3 id="dd-controller">Update controller</h3> |
| 68 <li>In <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/l ab5_data/angularjs/2_drop_files/controller.js">controller.js</a>, add code to ha ndle the events of dragover, dragleave and drop: | 182 |
| 69 <pre> | 183 <p>In the controller, |
| 184 add code to handle the events of dragover, dragleave, and drop: | |
| 185 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_dat a/angularjs/2_drop_files/controller.js">AngularJS controller.js</a> or | |
| 186 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_dat a/javascript/2_drop_files/controller.js">JavaScript controller.js</a>. | |
| 187 </p> | |
| 188 | |
| 189 <tabs data-group="source"> | |
| 190 | |
| 191 <header tabindex="0" data-value="angular">Angular</header> | |
| 192 <header tabindex="0" data-value="js">JavaScript</header> | |
| 193 | |
| 194 <content> | |
| 195 <pre> | |
| 70 var defaultDropText = "Or drop files here..."; | 196 var defaultDropText = "Or drop files here..."; |
| 71 $scope.dropText = defaultDropText; | 197 $scope.dropText = defaultDropText; |
| 72 | 198 |
| 73 // on dragOver, we will change the style and text accordingly, depending on | 199 // on dragOver, we will change the style and text accordingly, depending on |
| 74 // the data being transferred | 200 // the data being transferred |
| 75 var dragOver = function(e) { | 201 var dragOver = function(e) { |
| 76 e.stopPropagation(); | 202 e.stopPropagation(); |
| 77 e.preventDefault(); | 203 e.preventDefault(); |
| 78 var valid = e.dataTransfer && e.dataTransfer.types | 204 var valid = e.dataTransfer && e.dataTransfer.types |
| 79 && ( e.dataTransfer.types.indexOf('Files') >= 0 | 205 && ( e.dataTransfer.types.indexOf('Files') >= 0 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 116 for (var i = 0; i < newTodos.length; i++) { | 242 for (var i = 0; i < newTodos.length; i++) { |
| 117 $scope.todos.push(newTodos[i]); | 243 $scope.todos.push(newTodos[i]); |
| 118 } | 244 } |
| 119 $scope.save(); | 245 $scope.save(); |
| 120 }); | 246 }); |
| 121 } | 247 } |
| 122 | 248 |
| 123 document.body.addEventListener("dragover", dragOver, false); | 249 document.body.addEventListener("dragover", dragOver, false); |
| 124 document.body.addEventListener("dragleave", dragLeave, false); | 250 document.body.addEventListener("dragleave", dragLeave, false); |
| 125 document.body.addEventListener("drop", drop, false); | 251 document.body.addEventListener("drop", drop, false); |
| 126 </pre></li><li>To make all the area of the window accept the drop event and stil l work on the same scope, let's move the Angular scope definition from the d iv to the body in the <a href="https://github.com/GoogleChrome/chrome-app-codela b/blob/master/lab5_data/angularjs/2_drop_files/index.html">index.html</a> file. | 252 </pre> |
| 127 Also, let's associate the body's CSS class with the Angular controller&# 39;s class, so we can change the class directly in the scope and have it automat ically changed in the DOM: | 253 </content> |
| 254 <content> | |
| 255 <pre> | |
| 256 var defaultDropText = "Or drop files here..."; | |
| 257 | |
| 258 var dropText = document.getElementById('dropText'); | |
| 259 dropText.innerText = defaultDropText; | |
| 260 | |
| 261 // on dragOver, we will change the style and text accordingly, depending on | |
| 262 // the data being transfered | |
| 263 var dragOver = function(e) { | |
| 264 e.stopPropagation(); | |
| 265 e.preventDefault(); | |
| 266 var valid = isValid(e.dataTransfer); | |
| 267 if (valid) { | |
| 268 dropText.innerText="Drop files and remote images and they will become Todos" ; | |
| 269 document.body.classList.add("dragging"); | |
| 270 } else { | |
| 271 dropText.innerText="Can only drop files and remote images here"; | |
| 272 document.body.classList.add("invalid-dragging"); | |
| 273 } | |
| 274 } | |
| 275 | |
| 276 var isValid = function(dataTransfer) { | |
| 277 return dataTransfer && dataTransfer.types | |
| 278 && ( dataTransfer.types.indexOf('Files') >= 0 | |
| 279 || dataTransfer.types.indexOf('text/uri-list') >=0 ) | |
| 280 } | |
| 281 | |
| 282 // reset style and text to the default | |
| 283 var dragLeave = function(e) { | |
| 284 dropText.innerText=defaultDropText; | |
| 285 document.body.classList.remove('dragging'); | |
| 286 document.body.classList.remove('invalid-dragging'); | |
| 287 } | |
| 288 | |
| 289 // on drop, we create the appropriate TODOs using dropped data | |
| 290 var drop = function(e, model) { | |
| 291 e.preventDefault(); | |
| 292 e.stopPropagation(); | |
| 293 if (isValid(e.dataTransfer)) { | |
| 294 if (e.dataTransfer.types.indexOf('Files') >= 0) { | |
| 295 var files = e.dataTransfer.files; | |
| 296 for (var i = 0; i < files.length; i++) { | |
| 297 var text = files[i].name+', '+files[i].size+' bytes'; | |
| 298 model.addTodo(text, false, {file: files[i]}); | |
| 299 } | |
| 300 } else { // uris | |
| 301 var uri=e.dataTransfer.getData("text/uri-list"); | |
| 302 model.addTodo(uri, false, {uri: uri}); | |
| 303 } | |
| 304 } | |
| 305 | |
| 306 dragLeave(); | |
| 307 } | |
| 308 | |
| 309 exports.setDragHandlers = function(model) { | |
| 310 document.body.addEventListener("dragover", dragOver, false); | |
| 311 document.body.addEventListener("dragleave", dragLeave, false); | |
| 312 document.body.addEventListener("drop", function(e) { | |
| 313 drop(e, model); | |
| 314 }, false); | |
| 315 } | |
| 316 </pre> | |
| 317 </content> | |
| 318 | |
| 319 </tabs> | |
| 320 | |
| 321 <h3 id="dd-view">Update view</h3> | |
| 322 | |
| 323 <p>If using AngularJS, | |
| 324 let's move the Angular scope definition from the div to the body in the | |
| 325 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_dat a/angularjs/2_drop_files/index.html">AngularJS index.html</a> file to make all t he area of the window accept the drop event and still work on the same scope. | |
| 326 Also, let's associate the body's CSS class with the Angular controller&# 39;s class, | |
| 327 so we can change the class directly in the scope and have it automatically chang ed in the DOM: | |
| 328 </p> | |
| 329 | |
| 128 <pre> | 330 <pre> |
|
Renato Mangini (chromium)
2013/04/09 17:32:32
maybe add a Angular tab (no JavaScript) to be clea
mkearney1
2013/04/10 17:59:58
Done.
| |
| 129 <body ng-controller="TodoCtrl" ng-class="dropClass"> | 331 <body ng-controller="TodoCtrl" ng-class="dropClass"> |
| 130 <!-- remember to remove the ng-controller attribute from the div where it was before --> | 332 <!-- remember to remove the ng-controller attribute from the div where it was before --> |
| 131 </pre></li> | 333 </pre> |
| 132 <li>Add a message placeholder (in <code>index.html</code>) to warn the user that some types of dragging are not allowed: | 334 |
| 335 <p>Add a message placeholder (in both the AngularJS and | |
| 336 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_dat a/javascript/2_drop_files/index.html">JavaScript index.html</a>) to warn the use r that some types of dragging are not allowed: | |
| 337 </p> | |
| 338 | |
| 133 <pre> | 339 <pre> |
| 134 <div> | 340 <div> |
| 135 {{dropText}} | 341 {{dropText}} |
|
Renato Mangini (chromium)
2013/04/09 17:32:32
Needs tabs. The JavaScript version should be:
<d
mkearney1
2013/04/10 17:59:58
Done.
| |
| 136 </div> | 342 </div> |
| 137 </pre></li> | 343 </pre> |
| 138 <li>Add appropriate styling for the <code>dragging</code> and <code>invalid-drag ging</code> CSS classes in <a href="https://github.com/GoogleChrome/chrome-app-c odelab/blob/master/lab5_data/angularjs/2_drop_files/todo.css">todo.css</a>. Here we used a green or red background color animation: | 344 |
| 345 <h3 id="dd-css">Update stylesheet</h3> | |
| 346 | |
| 347 <p>Add appropriate styling for the <code>dragging</code> and | |
| 348 <code>invalid-dragging</code> CSS classes in the css. | |
| 349 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_dat a/angularjs/2_drop_files/todo.css">AngularJS todo.css</a> and | |
| 350 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_dat a/javascript/2_drop_files/todo.css">JavaScript todo.css</a> are the same. | |
| 351 Here we used a green or red background color animation: | |
| 352 </p> | |
| 353 | |
| 139 <pre> | 354 <pre> |
| 140 @-webkit-keyframes switch-green { | 355 @-webkit-keyframes switch-green { |
| 141 from { background-color: white;} to {background-color: rgb(163, 255, 163);} | 356 from { background-color: white;} to {background-color: rgb(163, 255, 163);} |
| 142 } | 357 } |
| 143 @-webkit-keyframes switch-red { | 358 @-webkit-keyframes switch-red { |
| 144 from { background-color: white;} to {background-color: rgb(255, 203, 203);} | 359 from { background-color: white;} to {background-color: rgb(255, 203, 203);} |
| 145 } | 360 } |
| 146 .dragging { | 361 .dragging { |
| 147 -webkit-animation: switch-green 0.5s ease-in-out 0 infinite alternate; | 362 -webkit-animation: switch-green 0.5s ease-in-out 0 infinite alternate; |
| 148 } | 363 } |
| 149 | 364 |
| 150 .invalid-dragging { | 365 .invalid-dragging { |
| 151 -webkit-animation: switch-red 0.5s ease-in-out 0 infinite alternate; | 366 -webkit-animation: switch-red 0.5s ease-in-out 0 infinite alternate; |
| 152 } | 367 } |
| 153 </pre></p></li><li><p>Check the results by reloading the app: open the app, righ t-click and select Reload App. | 368 </pre> |
| 154 You can now drag files into the Todo list.</p></li> | |
| 155 </ol> | |
| 156 | 369 |
| 157 <p class="note"><b>Note:</b> If you get stuck and want to see the app in action , | 370 <h3 id="results2">Check the results</h3> |
| 158 go to <code>chrome://extensions</code>, load the unpacked <a href="https://githu b.com/GoogleChrome/chrome-app-codelab/tree/master/lab5_data/angularjs/2_drop_fil es">2_drop_files</a> app, | |
| 159 and launch the app from a new tab.</p> | |
| 160 | 371 |
| 161 <h1 id="challenge_">Challenge:</h1> | 372 <p>Check the results by reloading the app: |
| 373 open the app, right-click and select Reload App. | |
| 374 You can now drag files into the Todo list.</p> | |
| 162 | 375 |
| 163 <p>The current code only saves the file reference, but it doesn't open the f ile. Using the <a href="http://www.html5rocks.com/en/tutorials/file/filesystem/" >HTML5 Filesystem API</a>, save the file contents in a sandboxed filesystem. Whe n the Todo item is archived, remove the corresponding file from the sandboxed fi lesystem. Add an "open" link on each Todo that has an associated file. When the item is clicked and the file exists in the sandboxed filesystem, use t he Chrome app <a href="http://developer.chrome.com/apps/fileSystem.html">Filesys tem extension</a> to request a writable FileEntry from the user. Save the file d ata from the sandboxed filesystem into that entry.</p> | 376 <p> |
| 377 If you get stuck and want to see the app in action, | |
| 378 go to <code>chrome://extensions</code>, load the unpacked app, | |
| 379 and launch the app from a new tab: | |
| 380 <a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab5_dat a/angularjs/2_drop_files">AngularJS 2_drop_files</a> | |
| 381 or <a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab5_ data/javascript/2_drop_files">JavaScript 2_drop_files</a>. | |
| 382 </p> | |
| 383 | |
| 384 <h2 id="challenge_">Challenge</h2> | |
| 385 | |
| 386 <p>The current code only saves the file reference, but it doesn't open the f ile. Using the <a href="http://www.html5rocks.com/en/tutorials/file/filesystem/" >HTML5 Filesystem API</a>, save the file contents in a sandboxed filesystem. Whe n the Todo item is archived, remove the corresponding file from the sandboxed fi lesystem. Add an "open" link on each Todo that has an associated file. When the item is clicked and the file exists in the sandboxed filesystem, use t he Chrome packaged app <a href="http://developer.chrome.com/apps/fileSystem.html ">Filesystem API</a> to request a writable FileEntry from the user. Save the fil e data from the sandboxed filesystem into that entry.</p> | |
| 164 | 387 |
| 165 <p class="note"><b>Tip:</b> managing file entries using the raw HTML5 Filesyste m API is not trivial. You might want to use a wrapper library, like Eric Bidelma n's <a href="https://github.com/ebidel/filer.js">filer.js</a>.</p> | 388 <p class="note"><b>Tip:</b> managing file entries using the raw HTML5 Filesyste m API is not trivial. You might want to use a wrapper library, like Eric Bidelma n's <a href="https://github.com/ebidel/filer.js">filer.js</a>.</p> |
| 166 | 389 |
| 167 <h1 id="takeaways_">Takeaways:</h1> | 390 <h2 id="takeaways_">Takeaways</h2> |
| 168 | 391 |
| 169 <ul> | 392 <ul> |
| 170 <li><p>Use <a href="http://developer.chrome.com/apps/storage.html">chrome.storag e.sync</a> to save small data that you need to be sync'ed among devices, lik e configuration options, application state, etc. The sync is automatic, as long as the same user is logged into Chrome on all devices.</p></li> | 393 <li><p>Use <a href="http://developer.chrome.com/apps/storage.html">chrome.storag e.sync</a> to save small data that you need to be sync'ed among devices, lik e configuration options, application state, etc. The sync is automatic, as long as the same user is logged into Chrome on all devices.</p></li> |
| 171 <li><p>Chrome apps support almost all HTML5 APIs, such as drag and drop. HTML Fi lesystem API is also supported, with extra features from the Chrome app's <a href="http://developer.chrome.com/apps/fileSystem.html">Filesystem API extensio n</a>, like asking the user to pick files on her local disk for read and write. The vanilla HTML5 Filesystem API only allows access to a sandboxed filesystem.</ p></li> | 394 <li><p>Chrome packaged apps support almost all HTML5 APIs, such as drag and drop . |
| 395 HTML Filesystem API is also supported, with extra features from the Chrome packa ged app's | |
| 396 <a href="http://developer.chrome.com/apps/fileSystem.html">Filesystem API</a>, | |
| 397 like asking the user to pick files on her local disk for read and write. | |
| 398 The vanilla HTML5 Filesystem API only allows access to a sandboxed filesystem.</ p></li> | |
| 172 </ul> | 399 </ul> |
| 173 | 400 |
| 174 <h1 id="what_39_s_next_">What's next?</h1> | 401 <h2 id="you_should_also_read">You should also read</h2> |
| 175 | 402 |
| 176 <p>In <a href="app_codelab6_lifecycle.html">lab6_lifecycle</a>, you will learn t he basics of the Chrome app lifecycle. </p> | 403 <p><a href="http://developer.chrome.com/apps/app_storage.html">Manage Data</a> t utorial</p> |
| 404 | |
| 405 <h2 id="what_39_s_next_">What's next?</h2> | |
| 406 | |
| 407 <p>In <a href="app_codelab6_lifecycle.html">5 - Manage App Lifecycle</a>, | |
| 408 you will learn the basics of the Chrome packaged app lifecycle. </p> | |
| OLD | NEW |