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

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

Issue 219213007: Remove .html extension from links (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 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
OLDNEW
1 <meta name="doc-family" content="apps"> 1 <meta name="doc-family" content="apps">
2 <h1>Build Apps with AngularJS</h1> 2 <h1>Build Apps with AngularJS</h1>
3 <!--Article written by Eric Bidelman--> 3 <!--Article written by Eric Bidelman-->
4 <p> 4 <p>
5 This guide gets you started building Chrome Apps 5 This guide gets you started building Chrome Apps
6 with the <a href="http://angularjs.org/">AngularJS</a> MVC framework. 6 with the <a href="http://angularjs.org/">AngularJS</a> MVC framework.
7 To illustrate Angular in action, 7 To illustrate Angular in action,
8 we'll be referencing an actual app built using the framework, 8 we'll be referencing an actual app built using the framework,
9 the Google Drive Uploader. 9 the Google Drive Uploader.
10 The <a href="https://github.com/GoogleChrome/chrome-app-samples/tree/master/gdri ve">source code</a> 10 The <a href="https://github.com/GoogleChrome/chrome-app-samples/tree/master/gdri ve">source code</a>
(...skipping 15 matching lines...) Expand all
26 <a href="http://www.html5rocks.com/en/tutorials/dnd/basics/">HTML Drag and Drop APIs</a>. 26 <a href="http://www.html5rocks.com/en/tutorials/dnd/basics/">HTML Drag and Drop APIs</a>.
27 It's a great example of building an app which talks 27 It's a great example of building an app which talks
28 to one of <a href="https://developers.google.com/apis-explorer/#p/">Google's API s</a>; 28 to one of <a href="https://developers.google.com/apis-explorer/#p/">Google's API s</a>;
29 in this case, the Google Drive API. 29 in this case, the Google Drive API.
30 </p> 30 </p>
31 31
32 <p class="note"> 32 <p class="note">
33 <strong>Note: </strong> 33 <strong>Note: </strong>
34 You can also build apps which talk to 3rd party APIs/services 34 You can also build apps which talk to 3rd party APIs/services
35 that are OAuth2-enabled. 35 that are OAuth2-enabled.
36 See <a href="app_identity.html#non">non-Google Account authentication</a>. 36 See <a href="app_identity#non">non-Google Account authentication</a>.
37 </p> 37 </p>
38 38
39 <p> 39 <p>
40 The Uploader uses OAuth2 to access the user's data. The 40 The Uploader uses OAuth2 to access the user's data. The
41 <a href="identity.html">chrome.identity API</a> 41 <a href="identity">chrome.identity API</a>
42 handles fetching an OAuth token for the logged-in user, 42 handles fetching an OAuth token for the logged-in user,
43 so the hard work is done for us! 43 so the hard work is done for us!
44 Once we have a long-lived access token, 44 Once we have a long-lived access token,
45 the apps uses the 45 the apps uses the
46 <a href="https://developers.google.com/drive/get-started">Google Drive API</a> 46 <a href="https://developers.google.com/drive/get-started">Google Drive API</a>
47 to access the user's data. 47 to access the user's data.
48 </p> 48 </p>
49 49
50 <p> 50 <p>
51 Key features this app uses: 51 Key features this app uses:
52 </p> 52 </p>
53 53
54 <ul> 54 <ul>
55 <li>AngularJS's autodetection for 55 <li>AngularJS's autodetection for
56 <a href="contentSecurityPolicy.html">CSP</a></li> 56 <a href="contentSecurityPolicy">CSP</a></li>
57 <li>Render a list of files fetched from the 57 <li>Render a list of files fetched from the
58 <a href="https://developers.google.com/drive/get-started">Google Drive A PI</a></li> 58 <a href="https://developers.google.com/drive/get-started">Google Drive A PI</a></li>
59 <li><a href="http://www.html5rocks.com/en/tutorials/file/filesystem/">HTML5 Filesystem API</a> 59 <li><a href="http://www.html5rocks.com/en/tutorials/file/filesystem/">HTML5 Filesystem API</a>
60 to store file icons offline</li> 60 to store file icons offline</li>
61 <li><a href="http://www.html5rocks.com/en/tutorials/dnd/basics/">HTML5 Drag and Drop</a> 61 <li><a href="http://www.html5rocks.com/en/tutorials/dnd/basics/">HTML5 Drag and Drop</a>
62 for importing/uploading new files from the desktop</li> 62 for importing/uploading new files from the desktop</li>
63 <li>XHR2 to load images, cross-domain</li> 63 <li>XHR2 to load images, cross-domain</li>
64 <li><a href="app_identity.html">chrome.identity API</a> 64 <li><a href="app_identity">chrome.identity API</a>
65 for OAuth authorization</li> 65 for OAuth authorization</li>
66 <li>Chromeless frames to define the app's own navbar look and feel</li> 66 <li>Chromeless frames to define the app's own navbar look and feel</li>
67 </ul> 67 </ul>
68 68
69 <h2 id="second">Creating the manifest</h2> 69 <h2 id="second">Creating the manifest</h2>
70 70
71 <p> 71 <p>
72 All Chrome Apps require a <code>manifest.json</code> file 72 All Chrome Apps require a <code>manifest.json</code> file
73 which contains the information Chrome needs to launch the app. 73 which contains the information Chrome needs to launch the app.
74 The manifest contains relevant metadata and 74 The manifest contains relevant metadata and
(...skipping 26 matching lines...) Expand all
101 } 101 }
102 </pre> 102 </pre>
103 103
104 <p> 104 <p>
105 The most important parts of this manifest are the "oauth2" and "permissions" sec tions. 105 The most important parts of this manifest are the "oauth2" and "permissions" sec tions.
106 </p> 106 </p>
107 107
108 <p> 108 <p>
109 The "oauth2" section defines the required parameters by OAuth2 to do its magic. 109 The "oauth2" section defines the required parameters by OAuth2 to do its magic.
110 To create a "client_id", follow the instructions in 110 To create a "client_id", follow the instructions in
111 <a href="app_identity.html#client_id">Get your client id</a>. 111 <a href="app_identity#client_id">Get your client id</a>.
112 The "scopes" list the authorization scopes 112 The "scopes" list the authorization scopes
113 that the OAuth token will be valid for (for example, the APIs the app wants to a ccess). 113 that the OAuth token will be valid for (for example, the APIs the app wants to a ccess).
114 </p> 114 </p>
115 115
116 <p> 116 <p>
117 The "permissions" section includes URLs that the app will access via XHR2. 117 The "permissions" section includes URLs that the app will access via XHR2.
118 The URL prefixes are required in order for Chrome 118 The URL prefixes are required in order for Chrome
119 to know which cross-domain requests to allow. 119 to know which cross-domain requests to allow.
120 </p> 120 </p>
121 121
122 <h2 id="three">Creating the event page</h2> 122 <h2 id="three">Creating the event page</h2>
123 123
124 <p> 124 <p>
125 All Chrome Apps require a background script/page 125 All Chrome Apps require a background script/page
126 to launch the app and respond to system events. 126 to launch the app and respond to system events.
127 </p> 127 </p>
128 128
129 <p> 129 <p>
130 In its 130 In its
131 <a href="https://github.com/GoogleChrome/chrome-app-samples/blob/master/gdrive/j s/background.js">background.js</a> 131 <a href="https://github.com/GoogleChrome/chrome-app-samples/blob/master/gdrive/j s/background.js">background.js</a>
132 script, 132 script,
133 Drive Uploader opens a 500x600px window to the main page. 133 Drive Uploader opens a 500x600px window to the main page.
134 It also specifies a minimum height and width for the window 134 It also specifies a minimum height and width for the window
135 so the content doesn't become too crunched: 135 so the content doesn't become too crunched:
136 </p> 136 </p>
137 137
138 <pre data-filename="background.js"> 138 <pre data-filename="background.js">
139 chrome.app.runtime.onLaunched.addListener(function(launchData) { 139 chrome.app.runtime.onLaunched.addListener(function(launchData) {
140 chrome.app.window.create('../main.html', { 140 chrome.app.window.create('../main', {
141 id: "GDriveExample", 141 id: "GDriveExample",
142 bounds: { 142 bounds: {
143 width: 500, 143 width: 500,
144 height: 600 144 height: 600
145 }, 145 },
146 minWidth: 500, 146 minWidth: 500,
147 minHeight: 600, 147 minHeight: 600,
148 frame: 'none' 148 frame: 'none'
149 }); 149 });
150 }); 150 });
151 </pre> 151 </pre>
152 152
153 <p> 153 <p>
154 The window is created as a chromeless window (frame: 'none'). 154 The window is created as a chromeless window (frame: 'none').
155 By default, windows render with the OS's default close/expand/minimize bar: 155 By default, windows render with the OS's default close/expand/minimize bar:
156 </p> 156 </p>
157 157
158 <img src="{{static}}/images/noframe.png" 158 <img src="{{static}}/images/noframe.png"
159 width="508" 159 width="508"
160 height="75" 160 height="75"
161 alt="Google Drive Uploader with no frame"> 161 alt="Google Drive Uploader with no frame">
162 162
163 <p> 163 <p>
164 The Uploader uses <code>frame: 'none'</code> to render the window as a "blank sl ate" 164 The Uploader uses <code>frame: 'none'</code> to render the window as a "blank sl ate"
165 and creates a custom close button in <code>main.html</code>: 165 and creates a custom close button in <code>main</code>:
166 </p> 166 </p>
167 167
168 <img src="{{static}}/images/customframe.png" 168 <img src="{{static}}/images/customframe.png"
169 width="504" 169 width="504"
170 height="50" 170 height="50"
171 alt="Google Drive Uploader with custom frame"> 171 alt="Google Drive Uploader with custom frame">
172 172
173 <p> 173 <p>
174 The entire navigational area is wrapped in a &lt;nav> (see next section). 174 The entire navigational area is wrapped in a &lt;nav> (see next section).
175 To declutter the app a bit, 175 To declutter the app a bit,
176 the custom close button is hidden until the user interacts with this the area: 176 the custom close button is hidden until the user interacts with this the area:
177 </p> 177 </p>
178 178
179 <pre data-filename="main.css"> 179 <pre data-filename="main.css">
180 &lt;style> 180 &lt;style>
181 nav:hover #close-button { 181 nav:hover #close-button {
182 opacity: 1; 182 opacity: 1;
183 } 183 }
184 184
185 #close-button { 185 #close-button {
186 float: right; 186 float: right;
187 padding: 0 5px 2px 5px; 187 padding: 0 5px 2px 5px;
188 font-weight: bold; 188 font-weight: bold;
189 opacity: 0; 189 opacity: 0;
190 -webkit-transition: all 0.3s ease-in-out; 190 -webkit-transition: all 0.3s ease-in-out;
191 } 191 }
192 &lt;/style> 192 &lt;/style>
193 </pre> 193 </pre>
194 <pre data-filename="main.html"> 194 <pre data-filename="main">
195 &lt;button class="btn" id="close-button" title="Close">x&lt;/button> 195 &lt;button class="btn" id="close-button" title="Close">x&lt;/button>
196 </pre> 196 </pre>
197 197
198 <p> 198 <p>
199 In 199 In
200 <a href="https://github.com/GoogleChrome/chrome-app-samples/blob/master/gdrive/j s/app.js">app.js</a>, 200 <a href="https://github.com/GoogleChrome/chrome-app-samples/blob/master/gdrive/j s/app.js">app.js</a>,
201 this button is hooked up to <code>window.close()</code>. 201 this button is hooked up to <code>window.close()</code>.
202 </p> 202 </p>
203 203
204 <h2 id="four">Designing the app the Angular way</h2> 204 <h2 id="four">Designing the app the Angular way</h2>
205 205
206 <p> 206 <p>
207 Angular is an MVC framework, so we need to define the app in such a way that a 207 Angular is an MVC framework, so we need to define the app in such a way that a
208 model, view, and controller logically fall out of it. Luckily, this is trivial w hen using Angular. 208 model, view, and controller logically fall out of it. Luckily, this is trivial w hen using Angular.
209 </p> 209 </p>
210 210
211 <p> 211 <p>
212 The View is the easiest, so let's start there. 212 The View is the easiest, so let's start there.
213 </p> 213 </p>
214 214
215 <h3 id="view">Creating the view</h3> 215 <h3 id="view">Creating the view</h3>
216 216
217 <p> 217 <p>
218 <a href="https://github.com/GoogleChrome/chrome-app-samples/blob/master/gdrive/m ain.html">main.html</a> 218 <a href="https://github.com/GoogleChrome/chrome-app-samples/blob/master/gdrive/m ain">main</a>
219 is the "V" in MVC; where we define HTML templates to render data into. 219 is the "V" in MVC; where we define HTML templates to render data into.
220 In Angular, templates are simple blocks of HTML with some special sauce. 220 In Angular, templates are simple blocks of HTML with some special sauce.
221 </p> 221 </p>
222 222
223 <p> 223 <p>
224 Ultimately we want to display the user's list of files. 224 Ultimately we want to display the user's list of files.
225 For that, a simple &lt;ul> list makes sense. 225 For that, a simple &lt;ul> list makes sense.
226 The Angular bits are highlighted in bold: 226 The Angular bits are highlighted in bold:
227 </p> 227 </p>
228 228
229 <pre data-filename="main.html"> 229 <pre data-filename="main">
230 &lt;ul> 230 &lt;ul>
231 &lt;li <strong>data-ng-repeat="doc in docs"</strong>> 231 &lt;li <strong>data-ng-repeat="doc in docs"</strong>>
232 &lt;img data-ng-src=<strong>"&#123;{doc.icon}&#125;"</strong>> &lt;a href=<s trong>"&#123;{doc.alternateLink}&#125;"</strong>><strong>&#123;{doc.title}&#125; </strong>&lt;/a> 232 &lt;img data-ng-src=<strong>"&#123;{doc.icon}&#125;"</strong>> &lt;a href=<s trong>"&#123;{doc.alternateLink}&#125;"</strong>><strong>&#123;{doc.title}&#125; </strong>&lt;/a>
233 <strong>&#123;{doc.size}&#125;</strong> 233 <strong>&#123;{doc.size}&#125;</strong>
234 &lt;span class="date"><strong>&#123;{doc.updatedDate}&#125;</strong>&lt;/spa n> 234 &lt;span class="date"><strong>&#123;{doc.updatedDate}&#125;</strong>&lt;/spa n>
235 &lt;/li> 235 &lt;/li>
236 &lt;/ul> 236 &lt;/ul>
237 </pre> 237 </pre>
238 238
239 <p> 239 <p>
(...skipping 12 matching lines...) Expand all
252 You could easily write the repeater as <code>&lt;li ng-repeat="doc in docs"></co de>. 252 You could easily write the repeater as <code>&lt;li ng-repeat="doc in docs"></co de>.
253 </p> 253 </p>
254 254
255 <p> 255 <p>
256 Next, we need to tell Angular which controller will oversee this template's rend ering. 256 Next, we need to tell Angular which controller will oversee this template's rend ering.
257 For that, we use the 257 For that, we use the
258 <a href="http://docs.angularjs.org/api/ng.directive:ngController">ngController</ a> 258 <a href="http://docs.angularjs.org/api/ng.directive:ngController">ngController</ a>
259 directive to tell the <code>DocsController</code> to have reign over the templat e &lt;body&gt;: 259 directive to tell the <code>DocsController</code> to have reign over the templat e &lt;body&gt;:
260 </p> 260 </p>
261 261
262 <pre data-filename="main.html"> 262 <pre data-filename="main">
263 &lt;body <strong>data-ng-controller="DocsController"</strong>> 263 &lt;body <strong>data-ng-controller="DocsController"</strong>>
264 &lt;section id="main"> 264 &lt;section id="main">
265 &lt;ul> 265 &lt;ul>
266 &lt;li data-ng-repeat="doc in docs"> 266 &lt;li data-ng-repeat="doc in docs">
267 &lt;img data-ng-src="&#123;{doc.icon}&#125;"> &lt;a href="&#123;{doc.alter nateLink}&#125;">&#123;{doc.title}&#125;&lt;/a> &#123;{doc.size}&#125; 267 &lt;img data-ng-src="&#123;{doc.icon}&#125;"> &lt;a href="&#123;{doc.alter nateLink}&#125;">&#123;{doc.title}&#125;&lt;/a> &#123;{doc.size}&#125;
268 &lt;span class="date">&#123;{doc.updatedDate}&#125;&lt;/span> 268 &lt;span class="date">&#123;{doc.updatedDate}&#125;&lt;/span>
269 &lt;/li> 269 &lt;/li>
270 &lt;/ul> 270 &lt;/ul>
271 &lt;/section> 271 &lt;/section>
272 &lt;/body> 272 &lt;/body>
273 </pre> 273 </pre>
274 274
275 <p> 275 <p>
276 Keep in mind, 276 Keep in mind,
277 what you don't see here is us hooking up event listeners or properties for data binding. 277 what you don't see here is us hooking up event listeners or properties for data binding.
278 Angular is doing that heavy lifting for us! 278 Angular is doing that heavy lifting for us!
279 </p> 279 </p>
280 280
281 <p> 281 <p>
282 The last step is to make Angular light up our templates. 282 The last step is to make Angular light up our templates.
283 The typical way to do that is include the 283 The typical way to do that is include the
284 <a href="http://docs.angularjs.org/api/ng.directive:ngApp">ngApp</a> 284 <a href="http://docs.angularjs.org/api/ng.directive:ngApp">ngApp</a>
285 directive all the way up on &lt;html>: 285 directive all the way up on &lt;html>:
286 </p> 286 </p>
287 287
288 <pre data-filename="main.html"> 288 <pre data-filename="main">
289 &lt;html <strong>data-ng-app="gDriveApp"</strong>> 289 &lt;html <strong>data-ng-app="gDriveApp"</strong>>
290 </pre> 290 </pre>
291 291
292 <p> 292 <p>
293 You could also scope the app down 293 You could also scope the app down
294 to a smaller portion of the page if you wanted to. 294 to a smaller portion of the page if you wanted to.
295 We only have one controller in this app, 295 We only have one controller in this app,
296 but if we were to add more later, 296 but if we were to add more later,
297 putting <a href="http://docs.angularjs.org/api/ng.directive:ngApp">ngApp</a> 297 putting <a href="http://docs.angularjs.org/api/ng.directive:ngApp">ngApp</a>
298 on the topmost element makes the entire page Angular-ready. 298 on the topmost element makes the entire page Angular-ready.
299 </p> 299 </p>
300 300
301 <p> 301 <p>
302 The final product for <code>main.html</code> looks something like this: 302 The final product for <code>main</code> looks something like this:
303 </p> 303 </p>
304 304
305 <pre data-filename="main.html"> 305 <pre data-filename="main">
306 &lt;html <strong>data-ng-app="gDriveApp"</strong>> 306 &lt;html <strong>data-ng-app="gDriveApp"</strong>>
307 &lt;head> 307 &lt;head>
308 … 308 …
309 <!-- crbug.com/120693: so we don't need target="_blank" on every anchor. --> 309 <!-- crbug.com/120693: so we don't need target="_blank" on every anchor. -->
310 &lt;base target="_blank"> 310 &lt;base target="_blank">
311 &lt;/head> 311 &lt;/head>
312 &lt;body <strong>data-ng-controller="DocsController"</strong>> 312 &lt;body <strong>data-ng-controller="DocsController"</strong>>
313 &lt;section id="main"> 313 &lt;section id="main">
314 &lt;nav> 314 &lt;nav>
315 &lt;h2>Google Drive Uploader&lt;/h2> 315 &lt;h2>Google Drive Uploader&lt;/h2>
316 &lt;button class="btn" <strong>data-ng-click="fetchDocs()"</strong>>Refresh& lt;/button> 316 &lt;button class="btn" <strong>data-ng-click="fetchDocs()"</strong>>Refresh& lt;/button>
317 &lt;button class="btn" id="close-button" title="Close">&lt;/button> 317 &lt;button class="btn" id="close-button" title="Close">&lt;/button>
318 &lt;/nav> 318 &lt;/nav>
319 &lt;ul> 319 &lt;ul>
320 &lt;li <strong>data-ng-repeat="doc in docs"</strong>> 320 &lt;li <strong>data-ng-repeat="doc in docs"</strong>>
321 &lt;img data-ng-src=<strong>"&#123;{doc.icon}&#125;"</strong>> &lt;a href= <strong>"&#123;{doc.alternateLink}&#125;"</strong>><strong>&#123;{doc.title}&#12 5;</strong>&lt;/a> <strong>&#123;{doc.size}&#125;</strong> 321 &lt;img data-ng-src=<strong>"&#123;{doc.icon}&#125;"</strong>> &lt;a href= <strong>"&#123;{doc.alternateLink}&#125;"</strong>><strong>&#123;{doc.title}&#12 5;</strong>&lt;/a> <strong>&#123;{doc.size}&#125;</strong>
322 &lt;span class="date"><strong>&#123;{doc.updatedDate}&#125;</strong>&lt;/s pan> 322 &lt;span class="date"><strong>&#123;{doc.updatedDate}&#125;</strong>&lt;/s pan>
323 &lt;/li> 323 &lt;/li>
324 &lt;/ul> 324 &lt;/ul>
325 &lt;/section> 325 &lt;/section>
326 </pre> 326 </pre>
327 327
328 <h3 id="csp">A word on Content Security Policy</h3> 328 <h3 id="csp">A word on Content Security Policy</h3>
329 329
330 <p> 330 <p>
331 Unlike many other JS MVC frameworks, 331 Unlike many other JS MVC frameworks,
332 Angular v1.1.0+ requires no tweaks to work within a strict 332 Angular v1.1.0+ requires no tweaks to work within a strict
333 <a href="contentSecurityPolicy.html">CSP</a>. 333 <a href="contentSecurityPolicy">CSP</a>.
334 It just works, out of the box! 334 It just works, out of the box!
335 </p> 335 </p>
336 336
337 <p> 337 <p>
338 However, if you're using an older version 338 However, if you're using an older version
339 of Angular between v1.0.1 and v1.1.0, 339 of Angular between v1.0.1 and v1.1.0,
340 you'll need tell Angular to run in a "content security mode". 340 you'll need tell Angular to run in a "content security mode".
341 This is done by including the 341 This is done by including the
342 <a href="http://docs.angularjs.org/api/ng.directive:ngCsp">ngCsp</a> 342 <a href="http://docs.angularjs.org/api/ng.directive:ngCsp">ngCsp</a>
343 directive alongside <a href="http://docs.angularjs.org/api/ng.directive:ngApp">n gApp</a>: 343 directive alongside <a href="http://docs.angularjs.org/api/ng.directive:ngApp">n gApp</a>:
344 </p> 344 </p>
345 345
346 <pre data-filename="main.html"> 346 <pre data-filename="main">
347 &lt;html data-ng-app data-ng-csp> 347 &lt;html data-ng-app data-ng-csp>
348 </pre> 348 </pre>
349 349
350 <h3 id="authorization">Handling authorization</h3> 350 <h3 id="authorization">Handling authorization</h3>
351 351
352 <p> 352 <p>
353 The data model isn't generated by the app itself. 353 The data model isn't generated by the app itself.
354 Instead, it's populated from an external API (the Google Drive API). 354 Instead, it's populated from an external API (the Google Drive API).
355 Thus, there's a bit of work necessary in order to populate the app's data. 355 Thus, there's a bit of work necessary in order to populate the app's data.
356 </p> 356 </p>
(...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after
750 $scope.fetchDocs(); 750 $scope.fetchDocs();
751 }); 751 });
752 }); 752 });
753 }); 753 });
754 754
755 return gdocs; 755 return gdocs;
756 }); 756 });
757 </pre> 757 </pre>
758 758
759 <p class="backtotop"><a href="#top">Back to top</a></p> 759 <p class="backtotop"><a href="#top">Back to top</a></p>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698