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

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

Issue 645693006: Updated Chrome Apps codelab (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 2 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
OLDNEW
(Empty)
1 <h1 id="add-images">
2 <span class="h1-step">Step 5:</span>
3 Add Images From the Web
4 </h1>
5
6 <p class="note">
7 <strong>Want to start fresh from here?</strong>
8 Find the previous step's code in the <a href="https://github.com/mangini/io13- codelab/archive/master.zip">reference code zip</a> under <strong><em>cheat_code > solution_for_step4</strong></em>.
9 </p>
10
11 <p>In this step, you will learn:</p>
12
13 <ul>
14 <li>How to load resources from outside your app and add them to the DOM throug h XHR and ObjectURLs.</li>
15 </ul>
16
17 <p>
18 <em>Estimated time to complete this step: 20 minutes.</em>
19 <br>
20 To preview what you will complete in this step, <a href="#launch">jump down to the bottom of this page &#8595;</a>.
21 </p>
22
23 <h2 id="csp-compliance">Learn how CSP affects the use of external web resources< /h2>
24
25 <p>The Chrome Apps platform forces your app to be fully compliant with Content
26 Security Policies (CSP). This includes not being able to directly load DOM
27 resources like images, fonts, and CSS from outside of your packaged app.</p>
28
29 <p>If you want to show an external image in your app, you need to request it via <a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest">XMLHt tpRequest</a>,
30 transform it into a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Bl ob">Blob</a>, and create an <a href="https://developer.mozilla.org/en-US/docs/We b/API/URL.createObjectURL">ObjectURL</a>. This ObjectURL can then be
31 added to the DOM because it refers to an in-memory item in the context of the
32 app.</p>
33
34 <h2 id="show-images">Show thumbnail images for todo items</h2>
35
36 <p>Let's change our app to look for image URLs in a todo item. If the URL
37 looks like an image (e.g. ends with .png, .jpg, .svg, or .gif), we will apply th e
38 process mentioned above in order to show an image thumbnail next to the URL.</p>
39
40 <h3 id="update-permissions">Update permissions</h3>
41
42 <p>In a Chrome App you can make XMLHttpRequest calls to any URL as long as you
43 whitelist its domain in the manifest. Since we won't know
44 beforehand what image URL the user will type,
45 we will ask permission to make requests to <code>"&lt;all_urls&gt;"</code>.</p>
46
47 <p>In <strong><em>manifest.json</em></strong>, request the "&lt;all_urls&gt;" pe rmission:</p>
48
49 <pre data-filename="manifest.json">
50 "permissions": ["storage", "alarms", "notifications",
51 "webview"<b>, "&lt;all_urls&gt;"</b>],
52 </pre>
53
54 <h3 id="object-urls">Create and clear ObjectURLs</h3>
55
56 In <strong><em>controller.js</em></strong>, add a <code>_createObjectURL()</code > method to create ObjectURLs from a Blob:
57
58 <pre data-filename="controller.js">
59 Controller.prototype._createObjectURL = function(blob) {
60 var objURL = URL.createObjectURL(blob);
61 this.objectURLs = this.objectURLs || [];
62 this.objectURLs.push(objURL);
63 return objURL;
64 };
65 </pre>
66
67 <p>ObjectURLs hold memory so, when you no longer need the ObjectURL, you
68 should revoke them. Add this
69 <code>_clearObjectURL()</code> method to <em>controller.js</em> to handle that:< /p>
70
71 <pre data-filename="controller.js">
72 Controller.prototype._clearObjectURL = function() {
73 if (this.objectURLs) {
74 this.objectURLs.forEach(function(objURL) {
75 URL.revokeObjectURL(objURL);
76 });
77 this.objectURLs = null;
78 }
79 };
80 </pre>
81
82 <h3 id="xhr">Make a XHR request</h3>
83
84 <p>Add a <code>_requestRemoteImageAndAppend()</code> method to execute a XMLHttp Request
85 on a given image URL:</p>
86
87 <pre data-filename="controller.js">
88 Controller.prototype._requestRemoteImageAndAppend = function(imageUrl, element) {
89 var xhr = new XMLHttpRequest();
90 xhr.open('GET', imageUrl);
91 xhr.responseType = 'blob';
92 xhr.onload = function() {
93 var img = document.createElement('img');
94 img.setAttribute('data-src', imageUrl);
95 img.className = 'icon';
96 var objURL = this._createObjectURL(xhr.response);
97 img.setAttribute('src', objURL);
98 element.appendChild(img);
99 }.bind(this);
100 xhr.send();
101 };
102 </pre>
103
104 <p>On XHR load, this method will create an ObjectURL from the XHR's response,
105 and add an <code>&lt;img&gt;</code> element with this ObjectURL to the DOM.</p>
106
107 <h3 id="parse-urls">Parse for image URLs in todo items</h3>
108
109 <p>Now add a <code>_parseForImageURLs()</code> method that finds all links not y et processed and checks them
110 for images. For each URL that looks like an image, execute <code>_requestRemoteI mageAndAppend()</code>:
111
112 <pre data-filename="controller.js">
113 Controller.prototype._parseForImageURLs = function () {
114 // remove old blobs to avoid memory leak:
115 this._clearObjectURL();
116 var links = this.$todoList.querySelectorAll('a[data-src]:not(.thumbnail)');
117 var re = /\.(png|jpg|jpeg|svg|gif)$/;
118 for (var i = 0; i&lt;links.length; i++) {
119 var url = links[i].getAttribute('data-src');
120 if (re.test(url)) {
121 links[i].classList.add('thumbnail');
122 this._requestRemoteImageAndAppend(url, links[i]);
123 }
124 }
125 };
126 </pre>
127
128 <h3 id="render-thumbnails">Render thumbnails in the todo list</h3>
129
130 <p>Now call <code>_parseForImageURLs()</code> from <code>showAll()</code>, <code >showActive()</code>, and
131 <code>showCompleted()</code>:</p>
132
133 <pre data-filename="controller.js">
134 /**
135 * An event to fire on load. Will get all items and display them in the
136 * todo-list
137 */
138 Controller.prototype.showAll = function () {
139 this.model.read(function (data) {
140 this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));
141 <b>this._parseForImageURLs();</b>
142 }.bind(this));
143 };
144
145 /**
146 * Renders all active tasks
147 */
148 Controller.prototype.showActive = function () {
149 this.model.read({ completed: 0 }, function (data) {
150 this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));
151 <b>this._parseForImageURLs();</b>
152 }.bind(this));
153 };
154
155 /**
156 * Renders all completed tasks
157 */
158 Controller.prototype.showCompleted = function () {
159 this.model.read({ completed: 1 }, function (data) {
160 this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));
161 <b>this._parseForImageURLs();</b>
162 }.bind(this));
163 };
164 </pre>
165
166 <p>Do the same for <code>editItem()</code>:</p>
167
168 <pre data-filename="controller.js">
169 Controller.prototype.editItem = function (id, label) {
170 ...
171 var onSaveHandler = function () {
172 ...
173 if (value.length &amp;&amp; !discarding) {
174 ...
175 label.innerHTML = this._parseForURLs(value);
176 <b>this._parseForImageURLs();</b>
177 } else if (value.length === 0) {
178 ...
179 }
180 </pre>
181
182 <h3 id="css">Constrain the displayed image dimensions</h3>
183
184 <p>Finally, in <strong></em>bower_components/todomvc-common/base.css</strong></e m>, add a CSS rule to limit
185 the size of the image:</p>
186
187 <pre data-filename="base.css">
188 .thumbnail img[data-src] {
189 max-width: 100px;
190 max-height: 28px;
191 }
192 </pre>
193
194 <h2 id="launch">Launch your finished Todo app</h2>
195
196 <p>You are done Step 5! Reload your app and add a todo item with a URL
197 to an image hosted online. Some URLs you could use: <strong>http://goo.gl/nqHMF# .jpg</strong> or <strong>http://goo.gl/HPBGR#.png</strong>.</p>
198
199 <p>The result should be something like this:</p>
200
201 <figure>
202 <img src="{{static}}/images/app_codelab/step5-completed.gif" alt="The Todo app with image thumbnails"/>
203 </figure>
204
205 <p class="note"><strong>Tip</strong>: For real-world situations, when you need t o control
206 offline cache and dozens of simultaneous resource downloads, we have created
207 <a href="https://github.com/GoogleChrome/apps-resource-loader#readme">a helper l ibrary</a>
208 to handle some common use cases.</p>
209
210 <h2 id="recap">Recap APIs referenced in this step</h2>
211
212 <p>For more detailed information about some of the APIs introduced in this step, refer to:</p>
213
214 <ul>
215 <li>
216 <a href="/apps/contentSecurityPolicy" title="Read 'Content Security Policy' in the Chrome developer docs">Content Security Policy</a>
217 <a href="#csp-compliance" class="anchor-link-icon" title="This feature menti oned in 'Learn how CSP affects the use of external web resources'">&#8593;</a>
218 </li>
219 <li>
220 <a href="/apps/declare_permissions" title="Read 'Declare Permissions' in the Chrome developer docs">Declare Permissions</a>
221 <a href="#update-permissions" class="anchor-link-icon" title="This feature m entioned in 'Update permissions'">&#8593;</a>
222 </li>
223 </ul>
224
225 <p>Ready to continue onto the next step? Go to <a href="app_codelab_filesystem.h tml">Step 6 - Export todos to the filesystem &raquo;</a></p>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698