Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(219)

Side by Side Diff: chrome/common/extensions/docs/templates/articles/app_codelab8_webresources.html

Issue 13248004: Cleaning up apps codelab (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 <h1 id="lab_8_web_resources">Lab 8 - Web Resources</h1> 1 <h1 id="lab_8_web_resources">Access Web Resources</h1>
2 2
3 <p>Chrome apps have a strict <a href="http://developer.chrome.com/trunk/apps/app _csp.html">Content Security Policy</a> which will not let the user execute code or load resources that are hosted remotely.</p> 3 <p>Chrome packaged apps have a strict
4 <a href="http://developer.chrome.com/trunk/apps/app_csp.html">Content Security P olicy</a>
5 which will not let the user execute code or load resources that are hosted remot ely.</p>
4 6
5 <p>Many applications, however, need to be able to load and display content from a remote location. A News Reader, for example, needs to display remote content i nline or load and show images from a remote URL.</p> 7 <p>Many applications, however, need to be able to load and display content from a remote location. A News Reader, for example, needs to display remote content i nline or load and show images from a remote URL.</p>
6 8
7 <h2 id="you_should_also_read">You should also read</h2> 9 <h2 id="loading_external_web_content_into_an_element">Load external web content< /h2>
10
11 <p>Sites on the internet are inherently a security risk and rendering arbitrary web pages directly into your application with elevated privileges would be a pot ential source of exploits.</p>
12
13 <p>Chrome packaged apps offer developers the ability
14 to securely render third-party content in the <code>&lt;webview&gt;</code> tag.
15 A <a href="http://developer.chrome.com/trunk/apps/webview_tag.html">webview</a>
16 is like an iframe that you can control with greater flexibility and added securi ty.
17 It runs in a separate sandboxed process and can&#39;t communicate directly with the application.</p>
18
19 <p>The <code>webview</code> has a very simple API.
20 From your app you can:</p>
8 21
9 <ul> 22 <ul>
10 <li><a href="http://developer.chrome.com/apps/app_external.html">Embed Content</ a> in Chrome app docs</li> 23 <li> Change the URL of the <code>webview</code>.</li>
24 <li> Navigate forwards and backward, stop loading and reload.</li>
25 <li> Check if the <code>webview</code> has finished loading and if it is possibl e, go back and forward in the history stack.</li>
11 </ul> 26 </ul>
12 27
13 <h2 id="loading_external_web_content_into_an_element">Loading external web conte nt into an element</h2> 28 <p>We will change our code to render the content of URLs dropped
14 29 in the drag-and-drop operations in a <code>webview</code> when the user clicks o n a link.</p>
15 <p>Sites on the internet are inherently a security risk and rendering arbitrary web pages directly into your application with elevated privileges would be a pot ential source of exploits.</p> 30
16 31 <h3 id="manifest">Update manifest</h3>
17 <p>Chrome apps offer developers the ability to securely render third-party conte nt in the <code>&lt;webview&gt;</code> tag. A WebView is like an iframe that you can control with greater flexibility and added security. 32
18 It runs in a separate sandboxed process and can&#39;t communicate directly with the application.</p> 33 <p>Request a new permission, &quot;webview&quot;, in the manifest.
19 34 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_web resources/angularjs/1_webview/manifest.json">Angular JS manifest.json</a> and
20 <p class="note"><b>Tip:</b> The WebView has a very simple API. From your app y ou can:</p> 35 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_web resources/javascript/1_webview/manifest.json">JavaScript manifest.json</a> are t he same:
21 36 </p>
22 <ul> 37
23 <li> Change the URL of the WebView.</li>
24 <li> Navigate forwards and backward, stop loading and reload.</li>
25 <li> Check if the WebView has finished loading and if it is possible, go back an d forward in the history stack.</li>
26 </ul></p>
27
28 <p>We will change our code to render the content of URLs dropped in the drag-and -drop operations in a WebView when the user clicks on a link.</p>
29
30 <ol>
31 <li><p>Request a new permission, &quot;webview&quot;, in <a href="https://github .com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/angularjs/1_w ebview/manifest.json">manifest.json</a>:
32 <pre> 38 <pre>
33 &quot;permissions&quot;: [&quot;storage&quot;, &quot;webview&quot;] 39 &quot;permissions&quot;: [&quot;storage&quot;, &quot;webview&quot;]
34 </pre></p></li> 40 </pre>
35 <li><p>Add a WebView tag and a link to <a href="https://github.com/GoogleChrome/ chrome-app-codelab/blob/master/lab8_webresources/angularjs/1_webview/index.html" >index.html</a>: 41
36 <pre> 42 <h3 id="view">Update view</h3>
43
44 <p>Add a <code>&lt;webview&gt;</code> tag and a link to the view:
45 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_web resources/angularjs/1_webview/index.html">AngularJS index.html</a> or
46 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_web resources/javascript/1_webview/index.html">JavaScript index.html</a>:
47 </p>
48
49 <tabs data-group="source">
50
51 <header tabindex="0" data-value="angular">Angular</header>
52 <header tabindex="0" data-value="js">JavaScript</header>
53
54 <content>
55 <pre>
37 &lt;!-- in TODO item: --&gt; 56 &lt;!-- in TODO item: --&gt;
38 &lt;a ng-show=&quot;todo.uri&quot; href=&quot;&quot; ng-click=&quot;showUri(todo .uri)&quot;&gt;(view url)&lt;/a&gt; 57 &lt;a ng-show=&quot;todo.uri&quot; href=&quot;&quot; ng-click=&quot;showUri(todo .uri)&quot;&gt;(view url)&lt;/a&gt;
39 &lt;!-- at the bottom, below the end of body: --&gt; 58 &lt;!-- at the bottom, below the end of body: --&gt;
40 &lt;webview&gt;&lt;/webview&gt; 59 &lt;webview&gt;&lt;/webview&gt;
41 </pre></p></li> 60 </pre>
42 <li><p>Set an appropriate width and height to the webview tag in <a href="https: //github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/angul arjs/1_webview/todo.css">todo.css</a> (it has zero size by default): 61 </content>
62 <content>
63 <pre>
64 &lt;!-- right after the &quot;dropText&quot; div: --&gt;
65 &lt;webview&gt;&lt;/webview&gt;
66 &lt;!-- in the TODO template, right before the end of the li: --&gt;
67 &lt;a style=&quot;display: none;&quot; href=&quot;&quot;&gt;(view url)&lt;/a&gt;
68 </pre>
69 </content>
70
71 </tabs>
72
73 <h3 id="css">Update stylesheet</h3>
74
75 <p>Set an appropriate width and height to the <code>&lt;webview&gt;</code> tag i n
76 the style sheet.
77 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_web resources/angularjs/1_webview/todo.css">AngularJS todo.css</a> and
78 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_web resources/javascript/1_webview/todo.css">JavaScript todo.css</a> are the same:
79 </p>
80
43 <pre> 81 <pre>
44 webview { 82 webview {
45 width: 100%; 83 width: 100%;
46 height: 200px; 84 height: 200px;
47 } 85 }
48 </pre></p></li> 86 </pre>
49 <li><p>Thanks to AngularJS, we now only need to add the <code>showUri</code> met hod to our <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/mast er/lab8_webresources/angularjs/1_webview/controller.js">controller.js</a> and we &#39;re done: 87
50 <pre> 88 <h3 id="controller">Update controller</h3>
89
90 <p>We now only need to add a method,
91 <code>showUri</code>, to the
92 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_web resources/angularjs/1_webview/controller.js">AngularJS controller.js</a>
93 or an event handler, <code>showUrl</code>, to the
94 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_web resources/javascript/1_webview/controller.js">JavaScript controller.js</a>.
95 </p>
96
97 <tabs data-group="source">
98
99 <header tabindex="0" data-value="angular">Angular</header>
100 <header tabindex="0" data-value="js">JavaScript</header>
101
102 <content>
103 <pre>
51 $scope.showUri = function(uri) { 104 $scope.showUri = function(uri) {
52 var webview=document.querySelector(&quot;webview&quot;); 105 var webview=document.querySelector(&quot;webview&quot;);
53 webview.src=uri; 106 webview.src=uri;
54 }; 107 };
55 </pre></p></li> 108 </pre>
56 </ol> 109 </content>
110 <content>
111 <pre>
112 if(/^http:\/\/|https:\/\//.test(todoObj.text)) {
113 var showUrl = el.querySelector('a');
114 showUrl.addEventListener('click', function(e) {
115 e.preventDefault();
116 var webview=document.querySelector("webview");
117 webview.src=todoObj.text;
118 });
119 showUrl.style.display = 'inline';
120 }
121 </pre>
122 </content>
123
124 </tabs>
125
126 <h3 id="results">Check the results</h3>
57 127
58 <p>To test, open the app, right-click, and select Reload App. 128 <p>To test, open the app, right-click, and select Reload App.
59 You should be able to click on the &quot;view url&quot; link on any dropped URL Todo item, and the corresponding web page will show in the webview. 129 You should be able to click on the &quot;view url&quot; link
60 If it&#39;s not showing, inspect the page and check if you set the webview size appropriately.</p> 130 on any dropped URL Todo item,
61 131 and the corresponding web page will show in the <code>webview</code>.
62 <p class="note"><b>Note:</b> If you get stuck and want to see the app in action , go to <code>chrome://extensions</code>, 132 If it&#39;s not showing,
63 load the unpacked <a href="https://github.com/GoogleChrome/chrome-app-codelab/tr ee/master/lab8_webresources/angularjs/1_webview">1_webview</a>, and launch the a pp from a new tab.</p> 133 inspect the page and check if you set the <code>webview</code> size appropriatel y.</p>
64 134
65 <h2 id="loading_external_images">Loading external images</h2> 135 <p>If you get stuck and want to see the app in action,
136 go to <code>chrome://extensions</code>,
137 load the unpacked
138 <a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab8_web resources/angularjs/1_webview">AngularJS 1_webview</a> or
139 <a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab8_web resources/javascript/1_webview">JavaScript 1_webview</a>,
140 and launch the app from a new tab.</p>
141
142 <h2 id="loading_external_images">Load external images</h2>
66 143
67 <p>If you try to add an <code>&lt;img&gt;</code> tag to your <code>index.html</c ode>, and point its <code>src</code> attribute to any site on the web, the follo wing exception is thrown in the console and the image isn&#39;t loaded:</p> 144 <p>If you try to add an <code>&lt;img&gt;</code> tag to your <code>index.html</c ode>, and point its <code>src</code> attribute to any site on the web, the follo wing exception is thrown in the console and the image isn&#39;t loaded:</p>
68 145
69 <p class="note"><b></b> Refused to load the image &#39;http://angularjs.org/img/ AngularJS-large.png&#39; because it violates the following Content Security Poli cy directive: &quot;img-src &#39;self&#39; data: chrome-extension-resource:&quot ;.</p> 146 <p class="note"><b></b> Refused to load the image &#39;http://angularjs.org/img/ AngularJS-large.png&#39; because it violates the following Content Security Poli cy directive: &quot;img-src &#39;self&#39; data: chrome-extension-resource:&quot ;.</p>
70 147
71 <p>Chrome apps cannot load any external resource directly in the DOM, because of the <a href="http://developer.chrome.com/apps/app_csp.html">CSP restrictions</a >.</p> 148 <p>Chrome packaged apps cannot load any external resource directly in the DOM, b ecause of the <a href="http://developer.chrome.com/apps/app_csp.html">CSP restri ctions</a>.</p>
72 149
73 <p>To avoid this restriction, you can use XHR requests, grab the blob correspond ing to the remote file and use it appropriately. 150 <p>To avoid this restriction, you can use XHR requests, grab the blob correspond ing to the remote file and use it appropriately.
74 For example, <code>&lt;img&gt;</code> tags can use a blob URL. 151 For example, <code>&lt;img&gt;</code> tags can use a blob URL.
75 Let&#39;s change our application to show a small icon in the Todo list if the dr opped URL represents an image:</p> 152 Let&#39;s change our application to show a small icon in the Todo list if the dr opped URL represents an image.</p>
76 153
77 <ol> 154 <h3 id="manifest2">Update manifest</h3>
78 <li><p>Before you start firing XHR requests, you must request permissions. 155
79 Since we want to allow users to drag and drop images from any server, we need to request permission to XHR to any URL. 156 <p>Before you start firing XHR requests, you must request permissions.
80 Change <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/l ab8_webresources/angularjs/2_loading_resources/manifest.json">manifest.json</a>: 157 Since we want to allow users to drag and drop images from any server,
158 we need to request permission to XHR to any URL.
159 Change
160 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_web resources/angularjs/2_loading_resources/manifest.json">AngularJS manifest.json</ a> or
161 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_web resources/javascript/2_loading_resources/manifest.json">JavaScript manifest.json </a>:
162 </p>
163
81 <pre> 164 <pre>
82 &quot;permissions&quot;: [&quot;storage&quot;, &quot;webview&quot;, &quot;&lt;al l_urls&gt;&quot;] 165 &quot;permissions&quot;: [&quot;storage&quot;, &quot;webview&quot;, &quot;&lt;al l_urls&gt;&quot;]
83 </pre></p></li> 166 </pre>
84 <li><p>Add to your project a placeholder image <img src="https://github.com/Goog leChrome/chrome-app-codelab/raw/master/lab8_webresources/angularjs/2_loading_res ources/loading.gif" alt="loading.gif"> that will be shown while we are loading t he proper image.</p></li> 167
85 <li><p>Add the <code>&lt;img&gt;</code> tag to the Todo item on the <a href="htt ps://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/an gularjs/2_loading_resources/index.html">index.html</a>: 168 <h3 id="image">Add image</h3>
86 <pre> 169
87 &lt;img style=&quot;max-height: 48px; max-width: 120px;&quot; ng-show=&quot;todo .validImage&quot; ng-src=&quot;&#123;&#123;todo.imageUrl&#125;&#125;&quot;&gt;&l t;/img&gt; 170 <p>Add to your project a placeholder image
88 </pre> 171 <img src="https://github.com/GoogleChrome/chrome-app-codelab/raw/master/lab8_web resources/angularjs/2_loading_resources/loading.gif" alt="loading.gif">
89 As you will see soon, this element is only shown when the validImage attribute o f the Todo item is true.</p></li> 172 that will be shown while we are loading the proper image.</p>
90 <li><p>Add the method loadImage (either in <a href="https://github.com/GoogleChr ome/chrome-app-codelab/blob/master/lab8_webresources/angularjs/2_loading_resourc es/controller.js">controller.js</a> or in a <a href="https://github.com/GoogleCh rome/chrome-app-codelab/blob/master/lab8_webresources/angularjs/2_loading_resour ces/loader.js">separate script file</a> as we did), that will start a XHR reques t and execute a callback with a Blob URL: 173
174 <p>Then add the <code>&lt;img&gt;</code> tag to the Todo item on the view:
175 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_web resources/angularjs/2_loading_resources/index.html">AngularJS index.html</a> or
176 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_web resources/javascript/2_loading_resources/index.html">JavaScript index_html</a>:
177 </p>
178
179 <tabs data-group="source">
180
181 <header tabindex="0" data-value="angular">Angular</header>
182 <header tabindex="0" data-value="js">JavaScript</header>
183
184 <content>
185 <pre>
186 &lt;img style=&quot;max-height: 48px; max-width: 120px;&quot; ng-show=&quot;todo .validImage&quot;
187 ng-src=&quot;&#123;&#123;todo.imageUrl&#125;&#125;&quot;&gt;&lt;/img&gt;
188 </pre>
189 </content>
190 <content>
191 <pre>
192 &lt;img style=&quot;max-height: 48px; max-width: 120px;&quot;&gt;&lt;/img&gt;
193 </pre>
194 </conteint>
Renato Mangini (chromium) 2013/04/12 20:33:07 typo. should be "content"
mkearney1 2013/04/15 20:48:12 Done.
195
196 </tabs>
197
198 <p>
199 In the
200 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_web resources/javascript/2_loading_resources/controller.js">JavaScript controller.js </a>,
201 add a constant for the placeholder image:
202 </p>
203
204 <pre>
205 const PLACEHOLDER_IMAGE = "loading.gif";
206 </pre>
207
208 <p>
209 As you will see soon,
210 this element is only shown when the <code>validImage</code> attribute of the Tod o item is true.
211 </p>
212
213 <h3 id="controller2">Update controller</h3>
214
215 <p>Add the method <code>loadImage</code> to a new script file
216 that will start a XHR request and execute a callback with a Blob URL.
217 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_web resources/angularjs/2_loading_resources/loader.js">AngularJS loader.js</a> and
218 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_web resources/javascript/2_loading_resources/loader.js">JavaScript loader.js</a> are the same:
219 </p>
220
91 <pre> 221 <pre>
92 var loadImage = function(uri, callback) { 222 var loadImage = function(uri, callback) {
93 var xhr = new XMLHttpRequest(); 223 var xhr = new XMLHttpRequest();
94 xhr.responseType = &#39;blob&#39;; 224 xhr.responseType = &#39;blob&#39;;
95 xhr.onload = function() { 225 xhr.onload = function() {
96 callback(window.webkitURL.createObjectURL(xhr.response), uri); 226 callback(window.webkitURL.createObjectURL(xhr.response), uri);
97 } 227 }
98 xhr.open(&#39;GET&#39;, uri, true); 228 xhr.open(&#39;GET&#39;, uri, true);
99 xhr.send(); 229 xhr.send();
100 } 230 }
101 </pre></p></li> 231 </pre>
102 <li><p>In the <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/m aster/lab8_webresources/angularjs/2_loading_resources/controller.js">controller. js</a>, add a new method that will search the scope.todolist looking for images that are not loaded yet: 232
103 <pre> 233 <p>In the
234 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_web resources/angularjs/2_loading_resources/controller.js">AngularJS controller.js</ a> or
235 <a href="">JavaScript controller.js</a>,
236 add a new method that will search the Todo list looking for images that are not loaded yet:
237 </p>
238
239 <tabs data-group="source">
240
241 <header tabindex="0" data-value="angular">Angular</header>
242 <header tabindex="0" data-value="js">JavaScript</header>
243
244 <content>
245 <pre>
104 // for each image with no imageUrl, start a new loader 246 // for each image with no imageUrl, start a new loader
105 $scope.loadImages = function() { 247 $scope.loadImages = function() {
106 for (var i=0; i&lt;$scope.todos.length; i++) { 248 for (var i=0; i&lt;$scope.todos.length; i++) {
107 var todo=$scope.todos[i]; 249 var todo=$scope.todos[i];
108 if (todo.validImage &amp;&amp; todo.imageUrl===PLACEHOLDER_IMAGE) { 250 if (todo.validImage &amp;&amp; todo.imageUrl===PLACEHOLDER_IMAGE) {
109 loadImage(todo.uri, function(blob_uri, requested_uri) { 251 loadImage(todo.uri, function(blob_uri, requested_uri) {
110 $scope.$apply(function(scope) { 252 $scope.$apply(function(scope) {
111 for (var k=0; k&lt;scope.todos.length; k++) { 253 for (var k=0; k&lt;scope.todos.length; k++) {
112 if (scope.todos[k].uri==requested_uri) { 254 if (scope.todos[k].uri==requested_uri) {
113 scope.todos[k].imageUrl = blob_uri; 255 scope.todos[k].imageUrl = blob_uri;
114 } 256 }
115 } 257 }
116 }); 258 });
117 }); 259 });
118 } 260 }
119 } 261 }
120 }; 262 };
121 </pre></p></li> 263 </pre>
122 <li><p>In the <code>controller.js</code>, <code>drop()</code> method, change the handling of URIs to appropriately detect a valid image. For simplicity sake, we only tested for png and jpg extensions. Feel free to have a better coverage in your code. 264 </content>
265 <content>
266 <pre>
267 var maybeStartImageLoader = function(el, todo) {
268 var img = el.querySelector('img');
269 if (todo['extras'] && todo.extras.validImage && todo.extras.imageUrl) {
270 if (todo.extras.imageUrl===PLACEHOLDER_IMAGE) {
271 img.src = PLACEHOLDER_IMAGE;
272 img.style.display = 'inline';
273 window.loadImage(todo.extras.uri, function(blob_uri, requested_uri) {
274 todo.extras.imageUrl = blob_uri;
275 img.src = blob_uri;
276 });
277 } else {
278 img.src = todo.extras.imageUrl;
279 img.style.display = 'inline';
280 }
281 } else {
282 img.style.display = 'none';
283 }
284 };
285 </pre>
286 </content>
287
288 </tabs>
289
290 <p>
291 If writing your app in JavaScript,
292 you will need to call the <code>maybeStartImageLoader</code> function
293 in the
294 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_web resources/javascript/2_loading_resources/controller.js">JavaScript controller.js </a>
295 to update the Todo list from the model:
296 </p>
297
123 <pre> 298 <pre>
299 var updateTodo = function(model) {
300 var todoElement = list.querySelector('li[data-id="'+model.id+'"]');
301 if (todoElement) {
302 var checkbox = todoElement.querySelector('input[type="checkbox"]');
303 var desc = todoElement.querySelector('span');
304 checkbox.checked = model.isDone;
305 desc.innerText = model.text;
306 desc.className = "done-"+model.isDone;
307
308 // load image, if this ToDo has image data
309 maybeStartImageLoader(todoElement, model);
310 }
311 }
312 </pre>
313
314 <p>Then in the
315 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_web resources/angularjs/2_loading_resources/controller.js">AngularJS controller.js</ a> or
316 <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_web resources/javascript/2_loading_resources/controller.js">JavaScript.controller.js </a>,
317 <code>drop()</code> method,
318 change the handling of URIs to appropriately detect a valid image.
319 For simplicity sake, we only tested for png and jpg extensions.
320 Feel free to have a better coverage in your code.
321 </p>
322
323 <tabs data-group="source">
324
325 <header tabindex="0" data-value="angular">Angular</header>
326 <header tabindex="0" data-value="js">JavaScript</header>
327
328 <content>
329 <pre>
124 var uri=e.dataTransfer.getData(&quot;text/uri-list&quot;); 330 var uri=e.dataTransfer.getData(&quot;text/uri-list&quot;);
125 var todo = {text:uri, done:false, uri: uri}; 331 var todo = {text:uri, done:false, uri: uri};
126 if (/.png$/.test(uri) || /.jpg$/.test(uri)) { 332 if (/.png$/.test(uri) || /.jpg$/.test(uri)) {
127 hasImage = true; 333 hasImage = true;
128 todo.validImage = true; 334 todo.validImage = true;
129 todo.imageUrl = PLACEHOLDER_IMAGE; 335 todo.imageUrl = PLACEHOLDER_IMAGE;
130 } 336 }
131 newTodos.push(todo); 337 newTodos.push(todo);
132 338
133 // [...] inside the $apply method, before save(), call the loadImages method: 339 // [...] inside the $apply method, before save(), call the loadImages method:
134 $scope.loadImages(); 340 $scope.loadImages();
135 </pre></p></li><li><p>And, finally, we will change the load method to reset the Blob URLs, since Blob URLs don&#39;t span through sessions. 341 </pre>
136 Setting Todo&#39;s imageUrls to the PLACEHOLDER_IMAGE will force the loadImages method to request them again: 342 </content>
137 <pre> 343 <content>
344 <pre>
345 var uri = e.dataTransfer.getData("text/uri-list");
346 var extras = { uri: uri };
347 if (/\.png$/.test(uri) || /\.jpg$/.test(uri)) {
348 hasImage = true;
349 extras.validImage = true;
350 extras.imageUrl = PLACEHOLDER_IMAGE;
351 }
352 model.addTodo(uri, false, extras);
353 </pre>
354 </content>
355
356 </tabs>
357
358 <p>And, finally, we will change the load method to reset the Blob URLs,
359 since Blob URLs don&#39;t span through sessions.
360 Setting Todo&#39;s imageUrls to the PLACEHOLDER_IMAGE
361 will force the loadImages method to request them again:
362 </p>
363
364 <tabs data-group="source">
365
366 <header tabindex="0" data-value="angular">Angular</header>
367 <header tabindex="0" data-value="js">JavaScript</header>
368
369 <content>
370 <pre>
138 // If there is saved data in storage, use it. Otherwise, bootstrap with sample t odos 371 // If there is saved data in storage, use it. Otherwise, bootstrap with sample t odos
139 $scope.load = function(value) { 372 $scope.load = function(value) {
140 if (value &amp;&amp; value.todolist) { 373 if (value &amp;&amp; value.todolist) {
141 // ObjectURLs are revoked when the document is removed from memory, 374 // ObjectURLs are revoked when the document is removed from memory,
142 // so we need to reload all images. 375 // so we need to reload all images.
143 for (var i=0; i&lt;value.todolist.length; i++) { 376 for (var i=0; i&lt;value.todolist.length; i++) {
144 value.todolist[i].imageUrl = PLACEHOLDER_IMAGE; 377 value.todolist[i].imageUrl = PLACEHOLDER_IMAGE;
145 } 378 }
146 $scope.todos = value.todolist; 379 $scope.todos = value.todolist;
147 $scope.loadImages(); 380 $scope.loadImages();
148 } else { 381 } else {
149 $scope.todos = [ 382 $scope.todos = [
150 {text:&#39;learn angular&#39;, done:true}, 383 {text:&#39;learn angular&#39;, done:true},
151 {text:&#39;build an angular app&#39;, done:false}]; 384 {text:&#39;build an angular app&#39;, done:false}];
152 } 385 }
153 } 386 }
154 </pre></p></li> 387 </pre>
155 </ol> 388 </content>
389 <content>
390 <pre>
391 /**
392 * Listen to changes in the model and trigger the appropriate changes in the vie w
393 **/
394 model.addListener(function(model, changeType, param) {
395 if ( changeType === 'reset' ) {
396 // let's invalidate all Blob URLs, since their lifetime is tied to the docum ent's lifetime
397 for (var id in model.todos) {
398 if (model.todos[id].extras && model.todos[id].extras.validImage) {
399 model.todos[id].extras.imageUrl = PLACEHOLDER_IMAGE;
400 }
401 }
402 }
403
404 if ( changeType === 'removed' || changeType === 'archived' || changeType === ' reset') {
405 redrawUI(model);
406 } else if ( changeType === 'added' ) {
407 drawTodo(model.todos[param], list);
408 } else if ( changeType === 'stateChanged') {
409 updateTodo(model.todos[param]);
410 }
411 storageSave();
412 updateCounters(model);
413 });
414 </pre>
415 </content>
416
417 </tabs>
418
419 <h3 id="results2">Check the results</h3>
156 420
157 <p>To test, open the app, right-click, and select Reload App. 421 <p>To test, open the app, right-click, and select Reload App.
158 Go to <a href="https://www.google.com/imghp?hl=en&amp;tab=wi&amp;authuser=0">Goo gle images</a>, search for and select an image, 422 Go to
423 <a href="https://www.google.com/imghp?hl=en&amp;tab=wi&amp;authuser=0">Google im ages</a>,
424 search for and select an image,
159 then drag and drop the image into the Todo list app. 425 then drag and drop the image into the Todo list app.
160 Assuming no mistakes were made, you should now have a thumbnail of every image U RL dropped into the Todo list app.</p> 426 Assuming no mistakes were made,
427 you should now have a thumbnail of every image URL dropped into the Todo list ap p.</p>
161 428
162 <p class="note"><b>Note:</b> If you get stuck and want to see the app in action , go to <code>chrome://extensions</code>, 429 <p>
163 load the unpacked <a href="https://github.com/GoogleChrome/chrome-app-codelab/tr ee/master/lab8_webresources/angularjs/2_loading_resources">2_loading_resources</ a>, and launch the app from a new tab.</p> 430 Notice we are not handling local images dropped from the file manager in this ch ange.
431 We leave this as a challenge for you.
432 </p>
433
434 <p>If you get stuck and want to see the app in action,
435 go to <code>chrome://extensions</code>, load the unpacked
436 <a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab8_web resources/angularjs/2_loading_resources">AngularJS 2_loading_resources</a> or,
437 <a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab8_web resources/javascript/2_loading_resources">JavaScript 2_loading_resources</a>
438 and launch the app from a new tab.</p>
164 439
165 <p>The <code>loadImage()</code> method above is not the best solution for this p roblem, because it doesn&#39;t handle errors correctly and it could cache images in a local filesystem. 440 <p>The <code>loadImage()</code> method above is not the best solution for this p roblem, because it doesn&#39;t handle errors correctly and it could cache images in a local filesystem.
166 We are working on a library that will be much more robust and easier to use.</p> 441 We've created the
442 <a href="https://github.com/GoogleChrome/apps-resource-loader">apps-resource-loa der library</a>
443 that's much more robust.</p>
167 444
168 <h1 id="takeaways_">Takeaways:</h1> 445 <h2 id="takeaways_">Takeaways</h2>
169 446
170 <ul> 447 <ul>
171 <li><p>The <code>&lt;webview&gt;</code> tag allows you to have a controlled brow ser inside your app. 448 <li><p>The <code>&lt;webview&gt;</code> tag allows you to have a controlled brow ser inside your app.
172 You can use it if you have part of your application that is not CSP compatible a nd you don&#39;t have resources to migrate it immediately, for example. 449 You can use it if you have part of your application that is not CSP compatible a nd you don&#39;t have resources to migrate it immediately, for example.
173 One feature we didn&#39;t mention here is that WebViews can communicate with you r app and vice-versa using asynchronous <a href="https://developer.chrome.com/tr unk/apps/app_external.html#postMessage">postMessages</a>.</p></li> 450 One feature we didn&#39;t mention here is that webviews can communicate with you r app and vice-versa using asynchronous <a href="https://developer.chrome.com/tr unk/apps/app_external.html#postMessage">postMessages</a>.</p></li>
174 <li><p>Loading resources like images from the web is not straightforward compare d to a standard web page. 451 <li><p>Loading resources like images from the web is not straightforward compare d to a standard web page.
175 But it&#39;s not too different from traditional native platforms, where you need to handle the resource download and, only when it is correctly downloaded, you can render it in the UI. We have also developed <a href="https://github.com/Goog leChrome/apps-resource-loader">a sample library</a> to asynchronously handle res ource loading from XHR calls. Feel free to use it in your projects.</p></li> 452 But it&#39;s not too different from traditional native platforms, where you need to handle the resource download and, only when it is correctly downloaded, you can render it in the UI. We have also developed <a href="https://github.com/Goog leChrome/apps-resource-loader">a sample library</a> to asynchronously handle res ource loading from XHR calls. Feel free to use it in your projects.</p></li>
176 </ul> 453 </ul>
177 454
178 <h1 id="what_39_s_next_">What&#39;s next?</h1> 455 <h2 id="you_should_also_read">You should also read</h2>
179 456
180 <p>In <a href="app_codelab9_multipleviews.html">lab9_multipleviews</a>, 457 <ul>
181 you will see how an app can have multiple windows that talk to each other and th e event page directly.</p> 458 <li><a href="http://developer.chrome.com/trunk/apps/webview_tag.html">Webview Ta g API</a> reference</li>
459 <li><a href="http://developer.chrome.com/apps/app_external.html">Embed Content</ a> tutorial</li>
460 </ul>
461
462 <h2 id="what_39_s_next_">What's next?</h2>
463
464 <p>In <a href="app_codelab_10_publishing.html">8 - Publish App</a>,
465 we finish off with instructions on how to publish your app in the Chrome Web Sto re.</p>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698