summaryrefslogtreecommitdiffstats
path: root/chrome/common
diff options
context:
space:
mode:
authormkearney@google.com <mkearney@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-15 22:56:14 +0000
committermkearney@google.com <mkearney@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-15 22:56:14 +0000
commitd4635d2a46787ba65694f667e4255ebcaed1206d (patch)
tree300f80908ef933a672bc6f44cb47ca4c6f43b8cc /chrome/common
parent52be60f65a1c003543fabaf490c2b6a5b411462d (diff)
downloadchromium_src-d4635d2a46787ba65694f667e4255ebcaed1206d.zip
chromium_src-d4635d2a46787ba65694f667e4255ebcaed1206d.tar.gz
chromium_src-d4635d2a46787ba65694f667e4255ebcaed1206d.tar.bz2
Cleaning up apps codelab
Adding proper navigation, rewriting introductions to flow better, covering JavaScript and AngularJS samples, and including new tabs for code snippets. BUG=162992 Review URL: https://codereview.chromium.org/13248004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@194252 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/common')
-rw-r--r--chrome/common/extensions/docs/templates/articles/app_codelab.html95
-rw-r--r--chrome/common/extensions/docs/templates/articles/app_codelab1_setup.html12
-rw-r--r--chrome/common/extensions/docs/templates/articles/app_codelab2_basic.html121
-rw-r--r--chrome/common/extensions/docs/templates/articles/app_codelab3_mvc.html358
-rw-r--r--chrome/common/extensions/docs/templates/articles/app_codelab4_testing.html8
-rw-r--r--chrome/common/extensions/docs/templates/articles/app_codelab5_data.html352
-rw-r--r--chrome/common/extensions/docs/templates/articles/app_codelab6_lifecycle.html153
-rw-r--r--chrome/common/extensions/docs/templates/articles/app_codelab7_useridentification.html124
-rw-r--r--chrome/common/extensions/docs/templates/articles/app_codelab8_webresources.html412
-rw-r--r--chrome/common/extensions/docs/templates/articles/app_codelab9_multipleviews.html57
-rw-r--r--chrome/common/extensions/docs/templates/articles/app_codelab_10_publishing.html5
-rw-r--r--chrome/common/extensions/docs/templates/articles/develop_apps.html57
-rw-r--r--chrome/common/extensions/docs/templates/json/apps_sidenav.json53
-rw-r--r--chrome/common/extensions/docs/templates/public/apps/app_codelab4_testing.html1
-rw-r--r--chrome/common/extensions/docs/templates/public/apps/app_codelab9_multipleviews.html1
15 files changed, 1409 insertions, 400 deletions
diff --git a/chrome/common/extensions/docs/templates/articles/app_codelab.html b/chrome/common/extensions/docs/templates/articles/app_codelab.html
index 141461d..ce298d8 100644
--- a/chrome/common/extensions/docs/templates/articles/app_codelab.html
+++ b/chrome/common/extensions/docs/templates/articles/app_codelab.html
@@ -1,48 +1,67 @@
-<h1 id="get_ready_to_build_chrome_apps_">Get Ready to Build Chrome Apps!</h1>
+<h1 id="get_ready_to_build_chrome_apps_">About this Codelab</h1>
-<p>Chrome apps are written in HTML5, JavaScript, and CSS, just like web apps.
-But they look and behave more like native apps, and they have super-powerful capabilities,
-like the ability to interact with network and hardware devices, media tools, and much more.</p>
+<p>The goal of this codelab is to
+get you building Chrome packaged apps fast.
+We&#39;ve done our best to capture some of the trickier parts
+to the development process
+keeping the samples simple and straightforward.
+Once you&#39;ve completed this codelab,
+you will have a simple Todo app.
+</p>
-<h2 id="help_us_make_chrome_apps_better_">Help us make Chrome Apps better!</h2>
-
-<p>Chrome apps are still in developer preview-- we know they aren&#39;t perfect. But we&#39;re trying to do something new here, bridging together the native and web experience, giving developers choice and users the best experience possible.</p>
+<p>
+All sample code can be downloaded from the
+<a href="https://github.com/GoogleChrome/chrome-app-codelab">chrome-app-codelab repository</a>.
+Each lab builds upon the previous lab's sample code.
+To see how the Todo app changes as you work through the lab,
+upload the code from the extensions management page
+and launch the app
+(see <a href="first_app.html#five">Create Your First App tutorial</a>).
+</p>
-<p>For Chrome apps to succeed, we need and want your feedback and we don&#39;t want you to have to go in circles to provide it.
-We appreciate your feedback either at the <a href="http://groups.google.com/a/chromium.org/group/chromium-apps">chromium-apps group</a> or, if appropriate, as a bug filled at the <a href="http://crbug.com/new">official issue tracker</a></a>.</p>
+<p class="note">
+<strong>Note: </strong>
+After the first launch,
+ChromeOS and Windows users can see their apps in the
+<a href="http://blog.chromium.org/2013/02/chrome-app-launcher-developer-preview.html">Chrome app launcher</a>.
+Other platforms can see installed apps on a new Chrome tab
+or by navigating to <code>chrome://extensions</code>.
+</p>
-<h2 id="learn_more_about_chrome_apps">Learn more about Chrome Apps</h2>
+<h2 id="options">Choose your framework</h2>
-<ul>
-<li>Read the <a href="http://developer.chrome.com/apps/">docs</a>.</li>
-<li>Check out the <a href="http://developer.chrome.com/apps/api_index.html">Chrome Apps APIs</a>.</li>
-<li>Fork any and all <a href="https://github.com/GoogleChrome/chrome-app-samples">chrome-app-samples</a> and make something of your own.</li>
-<li>Watch the <a href="https://developers.google.com/live/chrome/">Chrome Apps GDL sessions</a>.</li>
-<li>Follow the Chrome Apps Todo tutorial here.</li>
-</ul>
+<p>
+You can choose to write your sample Todo app
+using a preferred
+<a href="app_frameworks.html">MVC framework</a>.
+Starting in
+<a href="app_codelab3_mvc.html">3 - Create MVC</a>,
+we've provided sample code in pure JavaScript
+and using
+<a href="http://angularjs.org">AngularJS</a>.
+We've also included code snippets for both versions
+throughout the codelab docs.
+As you continue through the codelab,
+make sure your sample code builds from the same version.
+</p>
-<h2 id="about_this_tutorial">About this Tutorial</h2>
-
-<p>The goal of this tutorial is to get you building Chrome apps fast.
-We&#39;ve done our best to capture some of the trickier parts to the development process
-keeping the sample simple and straightforward.</p>
-
-<p>Once you&#39;ve completed the tutorial,
-you will have a simple Todo app. The sample code in each lab builds upon the previous.
-To see how the Todo app changes as you work through the lab,
-you can upload the code in each lab and launch the app from a new tab.</p>
+<p class="note">
+<strong>Want to add a framework?</strong><br>
+You can always create your own Todo app
+in a different preferred framework.
+And we would be very happy to include it
+in the sample code repository.
+</p>
-<h2 id="tutorial_structure">Tutorial structure</h2>
+<h2 id="tutorial_structure">Codelab structure</h2>
<ul>
-<li>Set up development environment: <a href="app_codelab1_setup.html">lab1_setup</a></li>
-<li>Create basic app: <a href="app_codelab2_basic.html">lab2_basic</a></li>
-<li>Create model-view-controller: <a href="app_codelab3_mvc.html">lab3_mvc</a></li>
-<li>Test app **Work-in-progress**: <a href="app_codelab4_testing.html">lab4_testing</a></li>
-<li>Save and fetch data: <a href="app_codelab5_data.html">lab5_data</a></li>
-<li>Manage app lifecycle: <a href="app_codelab6_lifecycle.html">lab6_lifecycle</a></li>
-<li>Access user&#39;s data: <a href="app_codelab7_useridentification.html">lab7_useridentification</a></li>
-<li>Access resources from the web: <a href="app_codelab8_webresources.html">lab8_webresources</a></li>
-<li>Create multiple views: <a href="app_codelab9_multipleviews.html">lab9_multipleviews</a></li>
-<li>Publish app in Chrome Web Store: <a href="app_codelab_10_publishing.html">lab_10_publishing</a></li>
+<li><a href="app_codelab1_setup.html">1 - Set Up Development Environment</a></li>
+<li><a href="app_codelab2_basic.html">2 - Create Basic App</a></li>
+<li><a href="app_codelab3_mvc.html">3 - Create MVC</a></li>
+<li><a href="app_codelab5_data.html">4 - Save and Feth Data</a></li>
+<li><a href="app_codelab6_lifecycle.html">5 - Manage App Lifecycle</a></li>
+<li><a href="app_codelab7_useridentification.html">6 - Access User's Data</a></li>
+<li><a href="app_codelab8_webresources.html">7 - Access Web Resources</a></li>
+<li><a href="app_codelab_10_publishing.html">8 - Publish App</a></li>
</ul>
diff --git a/chrome/common/extensions/docs/templates/articles/app_codelab1_setup.html b/chrome/common/extensions/docs/templates/articles/app_codelab1_setup.html
index 032a42f..140fd22 100644
--- a/chrome/common/extensions/docs/templates/articles/app_codelab1_setup.html
+++ b/chrome/common/extensions/docs/templates/articles/app_codelab1_setup.html
@@ -1,10 +1,10 @@
-<h1 id="lab_1_set_up_development_environment">Lab 1 - Set up development environment</h1>
+<h1 id="lab_1_set_up_development_environment">Set Up Development Environment</h1>
<h2 id="dependencies_and_prerequisites">Dependencies and prerequisites</h2>
<ul>
<li><p><a href="https://tools.google.com/dlpage/chromesxs">Chrome Canary on Mac and Windows</a> and <a href="http://www.chromium.org/getting-involved/dev-channel#TOC-Linux">Chromium Dev on Linux</a></p></li>
-<li><p>Open your preferred text editor. We have an under-development <a href="http://chrome-api.storage.googleapis.com/index.html">Chrome apps plugin</a> for <a href="http://www.sublimetext.com">Sublime</a>.</p></li>
+<li><p>Open your preferred text editor. We have an under-development <a href="http://www.youtube.com/watch?v=x_FTILqlbsg&hd=1">Chrome apps plugin</a> for <a href="http://www.sublimetext.com">Sublime</a>.</p></li>
</ul>
<h2 id="set_up_chrome">Set up Chrome</h2>
@@ -27,14 +27,12 @@ You will use this page quite a bit to load and reload the Todo app.</p>
<h2 id="set_up_workspace">Set up workspace</h2>
-<p>If you don&#39;t have it yet, <a href="https://help.github.com/articles/set-up-git">install git</a> and run </p>
+<p>If you don&#39;t have it yet, <a href="https://help.github.com/articles/set-up-git">install git</a> and run:</p>
<p><pre>
git clone git://github.com/GoogleChrome/chrome-app-codelab.git
</pre></p>
-<p>Note: for the rest of this tutorial, we&#39;ll refer to the directory for the cloned git repository as &lt;tutorial&gt;.</p>
+<h2 id="what_39_s_next_">What's next?</h2>
-<h1 id="what_39_s_next_">What&#39;s next?</h1>
-
-<p>In <a href="app_codelab2_basic.html">lab2_basic</a>, you will create your first Chrome app!</p>
+<p>In <a href="app_codelab2_basic.html">2 - Create Basic App</a>, you will create your first Chrome packaged app!</p>
diff --git a/chrome/common/extensions/docs/templates/articles/app_codelab2_basic.html b/chrome/common/extensions/docs/templates/articles/app_codelab2_basic.html
index d56c941..6778556 100644
--- a/chrome/common/extensions/docs/templates/articles/app_codelab2_basic.html
+++ b/chrome/common/extensions/docs/templates/articles/app_codelab2_basic.html
@@ -1,22 +1,31 @@
-<h1 id="lab_2_work_with_code">Lab 2 - Work with code</h1>
+<h1 id="lab_2_work_with_code">Create Basic App</h1>
-<h2 id="create_your_first_chrome_app">Create your first Chrome app</h2>
-
-<p>There are three core pieces to any Chrome app:</p>
+<p>There are three core pieces to any Chrome packaged app:</p>
<ul>
-<li>The manifest that descibes meta-information about your applicaiton: name, description, version number and how to launch your application</li>
-<li>The background script, which sets up how your application responds to system events such as the user installing and launching the app and the system suspending it</li>
-<li>The view (which is optional, but you normally need to show the user something)</li>
+<li>The manifest that describes meta-information about your application:
+name, description, version number and how to launch your application</li>
+<li>The background script,
+which sets up how your application responds to system events
+such as the user installing and launching the app and the system suspending it</li>
+<li>The view
+(which is optional, but you normally need to show the user something)</li>
</ul>
-<p>Let&#39;s look at each of these components at their simplest level. </p>
+<p>Let&#39;s look at each of these components at their simplest level.</p>
-<ol>
-<li><p>In an empty directory (let&#39;s call it <code>&lt;myappdir&gt;</code>), create three files:</p>
+<p class="note"><b>Tip:</b>
+If you use the Sublime Text editor with
+<a href="http://www.youtube.com/watch?v=x_FTILqlbsg&hd=1">our plugin</a>,
+you can create these three files with a click (Chrome -&gt; New App -&gt; Hello World).
+</p>
+
+<h2 id="manifest">Create manifest</h2>
+
+<p>In an empty directory (let&#39;s call it <code>&lt;myappdir&gt;</code>),
+create the manifest file: <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab2_basic/manifest.json">manifest.json</a>
+</p>
-<ul>
-<li>Manifest: <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab2_basic/manifest.json">manifest.json</a>
<pre>
{
&quot;manifest_version&quot;: 2,
@@ -28,8 +37,13 @@
}
}
}
-</pre></li>
-<li>Background script: <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab2_basic/main.js">main.js</a>
+</pre>
+
+<h2 id="background">Create background script</h2>
+
+<p>In the same directory,
+create the background script: <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab2_basic/main.js">main.js</a>
+
<pre>
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create(&#39;index.html&#39;, {
@@ -39,8 +53,12 @@ chrome.app.runtime.onLaunched.addListener(function() {
}
});
});
-</pre></li>
-<li>User interface: <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab2_basic/index.html">index.html</a>
+</pre>
+
+<h2 id="view">Create view</h2>
+
+<p>Create the user interface: <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab2_basic/index.html">index.html</a>
+
<pre>
&lt;html&gt;
&lt;head&gt;
@@ -51,9 +69,9 @@ chrome.app.runtime.onLaunched.addListener(function() {
&lt;h1&gt;Hello, World!&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;
-</pre></li>
-</ul></li>
-<li><p>Install and execute your sample app: </p>
+</pre>
+
+<h2 id="install">Install and execute sample app</h2>
<ul>
<li>Go to <code>chrome://extensions</code>.</li>
@@ -61,36 +79,59 @@ chrome.app.runtime.onLaunched.addListener(function() {
<li>Select the <code>&lt;myappdir&gt;</code> directory.</li>
<li>Open a new Chrome tab.</li>
<li>Click on the &quot;My First App&quot; icon.</li>
-</ul></li>
-</ol>
-
-<h2 id="you_should_also_read">You should also read</h2>
-
-<ul>
-<li><a href="http://developer.chrome.com/trunk/apps/first_app.html">Create Your First App</a></li>
-<li><a href="http://developer.chrome.com/trunk/apps/app.runtime.html">chrome.app.runtime</a></li>
-<li><a href="http://developer.chrome.com/trunk/apps/app.window.html">chrome.app.window</a></li>
</ul>
-<h2 id="debug_fix_and_reload_app">Debug, fix, and reload app</h2>
+<h2 id="debug_fix_and_reload_app">Debug, fix, and reload</h2>
-<p class="note"><b>Tip:</b> If you have enabled Developer mode in <code>chrome://extensions</code>, your apps can be inspected and debugged using the Chrome Developer Tools just like any standard web page: right-click on page, select Inspect Element. For the background page, which doesn&#39;t have UI, you can either right-click on any app window and select <code>Inspect Background Page</code> or go to <code>chrome://extensions</code> and click on Inspect Views...</p>
+<p class="note"><b>Tip:</b>
+If you have enabled Developer mode in <code>chrome://extensions</code>,
+your apps can be inspected and debugged using the Chrome Developer Tools.
+Just like any standard web page, right-click on page and select Inspect Element.
+For the background page which doesn&#39;t have UI,
+you can either right-click on any app window and
+select <code>Inspect Background Page</code> or
+go to <code>chrome://extensions</code> and click on Inspect Views...</p>
<ol>
-<li><p>Change the text &quot;Hello world&quot; to &quot;My first app&quot; in index.html.</p></li>
-<li><p>Change the <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab2_basic/main.js">main.js</a> background script to create two windows instead of one. Don&#39;t bother to create another html. For now, you can open index.html on both.</p></li>
-<li><p>After changing code, right-click on your app and select Reload App to reload the changed files. All Developer Tools windows will be reopened when you reload your app.</p></li>
-<li><p>Launch the app in a new tab page. Move the top window and you will see the second window behind it. </p></li>
+<li><p>Change the text &quot;Hello world&quot;
+to &quot;My first app&quot; in index.html.</p></li>
+<li><p>Change the
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab2_basic/main.js">main.js</a> background script to create two windows instead of one.
+Don&#39;t bother to create another html.
+For now, you can open index.html on both.</p></li>
+<li><p>After changing code,
+right-click on your app and select Reload App to reload the changed files.
+All Developer Tools windows will be reopened when you reload your app.</p></li>
+<li><p>Launch the app in a new tab page.
+Move the top window and you will see the second window behind it.</p></li>
</ol>
-<h1 id="takeaways">Takeaways</h1>
+<h2 id="takeaways">Takeaways</h2>
+
+<ul>
+<li>Chrome packaged apps have three basic pieces.
+The first and foremost is the manifest, which describes your app,
+requests special permissions, defines important meta information and much more.
+The second part is the background script,
+which contains all logic not tied to a specific user interface.
+The last part is the user interface: HTML, CSS, JavaScripts related to the interface, images, etc.</li>
+<li>Chrome packaged apps can be debugged just like standard web pages
+using the Chrome Developer Tools.
+But since an app doesn&#39;t have the Reload control of a browser,
+a Reload App option has been added when you run in Developer mode.</li>
+</ul>
+
+<h2 id="you_should_also_read">You should also read</h2>
<ul>
-<li>Chrome apps have three basic pieces. The first and foremost is the manifest.json, which describes your app, requests special permissions, defines important meta information and much more. The second part is the background script, which contains all logic not tied to a specific user interface. The last part is the user interface: HTML, CSS, JavaScripts related to the interface, images, etc.</li>
-<li>Chrome apps can be debugged just like standard web pages using the Chrome Developer Tools. But since an app doesn&#39;t have the Reload control of a browser, a Reload App option has been added when you run in Developer mode.</li>
+<li><a href="http://developer.chrome.com/trunk/apps/first_app.html">Create Your First App</a> tutorial</li>
+<li><a href="http://developer.chrome.com/trunk/apps/app.runtime.html">chrome.app.runtime</a> reference</li>
+<li><a href="http://developer.chrome.com/trunk/apps/app.window.html">chrome.app.window</a> reference</li>
</ul>
-<h1 id="what_39_s_next_">What&#39;s next?</h1>
+<h2 id="what_39_s_next_">What's next?</h2>
-<p>In <a href="app_codelab3_mvc.html">lab3_mvc</a>,
-you will use the <a href="http://angularjs.org/">AngluarJS framework</a> to build your app.</p>
+<p>In <a href="app_codelab3_mvc.html">3 - Create MVC</a>,
+you will use either pure JavaScript or
+<a href="http://angularjs.org/">AngluarJS</a>
+to build your app's model, view, and controller.</p>
diff --git a/chrome/common/extensions/docs/templates/articles/app_codelab3_mvc.html b/chrome/common/extensions/docs/templates/articles/app_codelab3_mvc.html
index 941f54f..4df297c 100644
--- a/chrome/common/extensions/docs/templates/articles/app_codelab3_mvc.html
+++ b/chrome/common/extensions/docs/templates/articles/app_codelab3_mvc.html
@@ -1,68 +1,109 @@
-<h1 id="lab_3_model_view_controller">Lab 3 - Model-View-Controller</h1>
+<h1 id="lab_3_model_view_controller">Create MVC</h1>
-<p>Whenever your application grows beyond a single script with a few dozen lines, it gets
-harder and harder to manage without a good separation of roles among app components. One of the most common
-models for structuring a complex application, no matter what language, is the Model-View-Controller (MVC) and
-its variants, like Model-View-Presentation (MVP).</p>
+<p>Whenever your application grows beyond a single script with a few dozen lines,
+it gets harder and harder to manage without a good separation
+of roles among app components.
+One of the most common models for structuring a complex application,
+no matter what language,
+is the Model-View-Controller (MVC) and its variants,
+like Model-View-Presentation (MVP).</p>
-<p>There are several frameworks to help apply <a href="http://developer.chrome.com/trunk/apps/app_frameworks.html">MVC concepts</a> to a Javascript application, and most of them,
-as long as they are CSP compliant, can be used in a Chrome App. We will use the <a href="http://angularjs.org/">AngularJS</a> framework in parts of this tutorial, with a special focus on the framework in this section.</p>
+<p>There are several frameworks to help apply
+<a href="http://developer.chrome.com/trunk/apps/app_frameworks.html">MVC concepts</a>
+to a Javascript application, and most of them,
+as long as they are CSP compliant, can be used in a Chrome packaged app.
+In this lab,
+we'll add an MVC model using both pure JavaScript and
+the <a href="http://angularjs.org/">AngularJS</a> framework.
+Most of the AngularJS code from this section was copied,
+with small changes, from the AngularJS Todo tutorial.</p>
-<h2 id="you_should_also_read">You should also read</h2>
+<p class="note"><b>Note:</b>
+Chrome packaged apps don&#39;t enforce any specific framework or programming style.
+</p>
-<ul>
-<li><p><a href="http://developer.chrome.com/trunk/apps/angular_framework.html">Build Apps with AngularJS</a> tutorial</p></li>
-<li><p><a href="http://angularjs.org/">AngularJS Todo</a> tutorial</p></li>
-</ul>
+<h2 id="simple">Create a simple view</h2>
+
+<h3 id="basic-mvc">Add MVC basics</h3>
-<p class="note"><b>Note:</b> Chrome apps don&#39;t enforce any specific framework or programming style. This section and additional parts of this tutorial use the AngularJS framework. Most of the code from this section was copied, with small changes, from the AngularJS Todo tutorial. </p>
+<p>If using AngularJS, download the
+<a href="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js">Angular script</a>
+and save it as
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab3_mvc/angularjs/simpleview/angular.min.js">angular.min.js</a>.</p>
-<h2 id="create_a_simple_view_using_angularjs">Create a simple view using AngularJS</h2>
+<p>If using JavaScript,
+you will need to add a very simple controller with basic MVC functionalities:
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab3_mvc/javascript/simpleview/controller.js">JavaScript controller.js</a></p>
-<ol>
-<li><p>Download the <a href="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js">Angular script</a> and save it as <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab3_mvc/angularjs/simpleview/angular.min.js">angular.min.js</a>.</p></li>
-<li><p>Change your <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab3_mvc/angularjs/simpleview/index.html">index.html</a> to use a simple Angular sample:</p>
+<h3 id="update-view">Update view</h3>
+
+<p>Change the <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab3_mvc/angularjs/simpleview/index.html">AngularJS index.html</a> or
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab3_mvc/javascript/simpleview/index.html">JavaScript index.html</a> to use a simple sample:
+</p>
<tabs data-group="source">
- <header tabindex="0" data-value="js">JavaScript</header>
<header tabindex="0" data-value="angular">Angular</header>
+ <header tabindex="0" data-value="js">JavaScript</header>
<content>
<pre>
- This is where the pure javascript code comes in
+&lt;!doctype html&gt;
+&lt;html ng-app ng-csp&gt;
+ &lt;head&gt;
+ &lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
+ &lt;link rel="stylesheet" href="todo.css"&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+ &lt;h2&gt;Todo&lt;/h2&gt;
+ &lt;div&gt;
+ &lt;ul&gt;
+ &lt;li&gt;
+ &#123;&#123;todoText&#125;&#125;
+ &lt;/li&gt;
+ &lt;/ul&gt;
+ &lt;input type=&quot;text&quot; ng-model=&quot;todoText&quot; size="30"
+ placeholder=&quot;type your todo here&quot;&gt;
+ &lt;/div&gt;
+ &lt;/body&gt;
+&lt;/html&gt;
</pre>
</content>
<content>
<pre>
-&lt;html ng-app ng-csp&gt;
+&lt;!doctype html&gt;
+&lt;html&gt;
&lt;head&gt;
- &lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;todo.css&quot;&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h2&gt;Todo&lt;/h2&gt;
&lt;div&gt;
&lt;ul&gt;
- &lt;li&gt;
- &#123;&#123;todoText&#125;&#125;
+ &lt;li id=&quot;todoText&quot;&gt;
&lt;/li&gt;
&lt;/ul&gt;
- &lt;input type=&quot;text&quot; ng-model=&quot;todoText&quot; size=&quot;30&quot;
+ &lt;input type=&quot;text&quot; id=&quot;newTodo&quot; size=&quot;30&quot;
placeholder=&quot;type your todo here&quot;&gt;
&lt;/div&gt;
+ &lt;script src=&quot;controller.js&quot;&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
</content>
-
</tabs>
-</li>
-<li><p>Add a simple stylesheet: <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab3_mvc/angularjs/simpleview/todo.css">todo.css</a>
+<p class="note"><b>Note:</b> The <code>ng-csp</code> directive tells Angular to run in a &quot;content security mode&quot;. You don&#39;t need this directive when using Angular v1.1.0+. We&#39;ve included it here so that the sample works regardless of the Angular version in use.</p>
+
+<h3 id="stylesheet">Add stylesheet</h3>
+
+<p><a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab3_mvc/angularjs/simpleview/todo.css">AngularJS todo.css</a> and
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab3_mvc/javascript/simpleview/todo.css">JavaScript todo.css</a> are the same:
+</p>
+
<pre>
body {
- font-family: &quot;Helvetica Neue&quot;,Helvetica,Arial,sans-serif;
+ font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
}
ul {
@@ -81,18 +122,37 @@ button, input[type=submit] {
text-decoration: line-through;
color: grey;
}
-</pre></li><li>Check the results by reloading the app: open the app, right-click and select Reload App.</li>
-</ol>
+</pre>
-<p class="note"><b>Note:</b> The ng-csp directive tells Angular to run in a &quot;content security mode&quot;. You don&#39;t need this directive when using Angular v1.1.0+. We&#39;ve included it here so that the sample works regardless of the Angular version in use.</p>
+<h3 id="check1">Check the results</h3>
-<h2 id="add_a_controller">Add a Controller</h2>
+<p>
+Check the results by reloading the app: open the app, right-click and select Reload App.</li>
+</p>
-The previous sample, although interesting, is not exactly useful. Let&#39;s transform it into a real Todo list, instead of a simple Todo item. We will create a controller (controller.js) and make some small changes in the index.html:
+<h2 id="real-todo">Create real Todo list</h2>
-<ol>
-<li>Add the <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab3_mvc/angularjs/withcontroller/controller.js">controller.js</a> file:
-<pre>
+<p>
+The previous sample, although interesting, is not exactly useful.
+Let&#39;s transform it into a real Todo list, instead of a simple Todo item.
+</p>
+
+<h3 id="controller">Add controller</h3>
+
+<p>
+Whether using pure JavaScript or AngularJS,
+the controller manages the Todo list:
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab3_mvc/angularjs/withcontroller/controller.js">AngularJS controller.js</a> or
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab3_mvc/javascript/withcontroller/controller.js">JavaScript controller.js</a>.
+</p>
+
+<tabs data-group="source">
+
+ <header tabindex="0" data-value="angular">Angular</header>
+ <header tabindex="0" data-value="js">JavaScript</header>
+
+ <content>
+ <pre>
function TodoCtrl($scope) {
$scope.todos = [
{text:&#39;learn angular&#39;, done:true},
@@ -119,8 +179,157 @@ $scope.archive = function() {
});
};
}
-</pre></p></li><li><p>Change <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab3_mvc/angularjs/withcontroller/index.html">index.html</a> file:
-<pre>
+ </pre>
+ </content>
+ <content>
+ <pre>
+(function(exports) {
+
+ var nextId = 1;
+
+ var TodoModel = function() {
+ this.todos = {};
+ this.listeners = [];
+ }
+
+ TodoModel.prototype.clearTodos = function() {
+ this.todos = {};
+ this.notifyListeners('removed');
+ }
+
+ TodoModel.prototype.archiveDone = function() {
+ var oldTodos = this.todos;
+ this.todos={};
+ for (var id in oldTodos) {
+ if ( ! oldTodos[id].isDone ) {
+ this.todos[id] = oldTodos[id];
+ }
+ }
+ this.notifyListeners('archived');
+ }
+
+ TodoModel.prototype.setTodoState = function(id, isDone) {
+ if ( this.todos[id].isDone != isDone ) {
+ this.todos[id].isDone = isDone;
+ this.notifyListeners('stateChanged', id);
+ }
+ }
+
+ TodoModel.prototype.addTodo = function(text, isDone) {
+ var id = nextId++;
+ this.todos[id]={'id': id, 'text': text, 'isDone': isDone};
+ this.notifyListeners('added', id);
+ }
+
+ TodoModel.prototype.addListener = function(listener) {
+ this.listeners.push(listener);
+ }
+
+ TodoModel.prototype.notifyListeners = function(change, param) {
+ var this_ = this;
+ this.listeners.forEach(function(listener) {
+ listener(this_, change, param);
+ });
+ }
+
+ exports.TodoModel = TodoModel;
+
+})(window);
+
+
+window.addEventListener('DOMContentLoaded', function() {
+
+ var model = new TodoModel();
+ var form = document.querySelector('form');
+ var archive = document.getElementById('archive');
+ var list = document.getElementById('list');
+ var todoTemplate = document.querySelector('#templates &gt; [data-name="list"]');
+
+ form.addEventListener('submit', function(e) {
+ var textEl = e.target.querySelector('input[type="text"]');
+ model.addTodo(textEl.value, false);
+ textEl.value=null;
+ e.preventDefault();
+ });
+
+ archive.addEventListener('click', function(e) {
+ model.archiveDone();
+ e.preventDefault();
+ });
+
+ model.addListener(function(model, changeType, param) {
+ if ( changeType === 'removed' || changeType === 'archived') {
+ redrawUI(model);
+ } else if ( changeType === 'added' ) {
+ drawTodo(model.todos[param], list);
+ } else if ( changeType === 'stateChanged') {
+ updateTodo(model.todos[param]);
+ }
+ updateCounters(model);
+ });
+
+ var redrawUI = function(model) {
+ list.innerHTML='';
+ for (var id in model.todos) {
+ drawTodo(model.todos[id], list);
+ }
+ };
+
+ var drawTodo = function(todoObj, container) {
+ var el = todoTemplate.cloneNode(true);
+ el.setAttribute('data-id', todoObj.id);
+ container.appendChild(el);
+ updateTodo(todoObj);
+ var checkbox = el.querySelector('input[type="checkbox"]');
+ checkbox.addEventListener('change', function(e) {
+ model.setTodoState(todoObj.id, e.target.checked);
+ });
+ }
+
+ var updateTodo = function(model) {
+ var todoElement = list.querySelector('li[data-id="'+model.id+'"]');
+ if (todoElement) {
+ var checkbox = todoElement.querySelector('input[type="checkbox"]');
+ var desc = todoElement.querySelector('span');
+ checkbox.checked = model.isDone;
+ desc.innerText = model.text;
+ desc.className = "done-"+model.isDone;
+ }
+ }
+
+ var updateCounters = function(model) {
+ var count = 0;
+ var notDone = 0;
+ for (var id in model.todos) {
+ count++;
+ if ( ! model.todos[id].isDone ) {
+ notDone ++;
+ }
+ }
+ document.getElementById('remaining').innerText = notDone;
+ document.getElementById('length').innerText = count;
+ }
+
+ updateCounters(model);
+
+});
+ </pre>
+ </content>
+</tabs>
+
+<h3 id="index">Update view</h3>
+
+<p>Change the <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab3_mvc/angularjs/withcontroller/index.html">AngularJS index.html</a> or
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab3_mvc/javascript/withcontroller/index.html">JavaScript index.html</a>:
+</p>
+
+<tabs data-group="source">
+
+ <header tabindex="0" data-value="angular">Angular</header>
+ <header tabindex="0" data-value="js">JavaScript</header>
+
+ <content>
+ <pre>
&lt;html ng-app ng-csp&gt;
&lt;head&gt;
&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
@@ -146,21 +355,74 @@ $scope.archive = function() {
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
-</pre></p></li>
-<li><p>Check the results by reloading the app: open the app, right-click and select Reload App.</p></li>
-</ol>
+ </pre>
+ </content>
+ <content>
+ <pre>
+&lt;!doctype html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;link rel=&quot;stylesheet&quot; href=&quot;todo.css&quot;&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+ &lt;h2&gt;Todo&lt;/h2&gt;
+ &lt;div&gt;
+ &lt;span&gt;&lt;span id=&quot;remaining&quot;&gt;&lt;/span&gt; of &lt;span id=&quot;length&quot;&gt;&lt;/span&gt; remaining&lt;/span&gt;
+ [ &lt;a href=&quot;&quot; id=&quot;archive&quot;&gt;archive&lt;/a&gt; ]
+ &lt;ul class=&quot;unstyled&quot; id=&quot;list&quot;&gt;
+ &lt;/ul&gt;
+ &lt;form&gt;
+ &lt;input type=&quot;text&quot; size=&quot;30&quot;
+ placeholder=&quot;add new todo here&quot;&gt;
+ &lt;input class=&quot;btn-primary&quot; type=&quot;submit&quot; value=&quot;add&quot;&gt;
+ &lt;/form&gt;
+ &lt;/div&gt;
+
+ &lt;!-- poor man's template --&gt;
+ &lt;div id=&quot;templates&quot; style=&quot;display: none;&quot;&gt;
+ &lt;li data-name=&quot;list&quot;&gt;
+ &lt;input type=&quot;checkbox&quot;&gt;
+ &lt;span&gt;&lt;/span&gt;
+ &lt;/li&gt;
+ &lt;/div&gt;
+
+ &lt;script src=&quot;controller.js&quot;&gt;&lt;/script&gt;
+ &lt;/body&gt;
+&lt;/html&gt;
+ </pre>
+ </content>
+</tabs>
<p>Note how the data, stored in an array inside the controller, binds to the view and is automatically updated when it is changed by the controller.</p>
-<h1 id="takeaways_">Takeaways:</h1>
+<h3 id="check2">Check the results</h3>
+
+<p>
+Check the results by reloading the app: open the app, right-click and select Reload App.</li>
+</p>
+
+<h2 id="takeaways_">Takeaways</h2>
<ul>
-<li><p>Chrome apps are <a href="http://developer.chrome.com/apps/offline_apps.html">offline first</a>, so the recommended way to include third-party scripts is to download and package them inside your app.</p></li>
-<li><p>You can use any framework you want, as long as it complies with Content Security Policies and other restrictions that Chrome apps are enforced to follow.</p></li>
-<li><p>MVC frameworks make your life easier. Use them, specially if you want to build a non-trivial application.</p></li>
+<li><p>Chrome packaged apps are
+<a href="http://developer.chrome.com/apps/offline_apps.html">offline first</a>,
+so the recommended way to include third-party scripts is to download
+and package them inside your app.</p></li>
+<li><p>You can use any framework you want,
+as long as it complies with Content Security Policies
+and other restrictions that Chrome packaged apps are enforced to follow.</p></li>
+<li><p>MVC frameworks make your life easier.
+Use them, specially if you want to build a non-trivial application.</p></li>
+</ul>
+
+<h2 id="you_should_also_read">You should also read</h2>
+
+<ul>
+<li><p><a href="http://developer.chrome.com/trunk/apps/angular_framework.html">Build Apps with AngularJS</a> tutorial</p></li>
+<li><p><a href="http://angularjs.org/">AngularJS Todo</a> tutorial</p></li>
</ul>
-<h1 id="what_39_s_next_">What&#39;s next?</h1>
+<h2 id="what_39_s_next_">What's next?</h2>
-<p>Eventually in <a href="app_codelab4_testing.html">lab4_testing</a>, you will test your app.
-Right now this lab is a work-in-progress. You can skip ahead to <a href="app_codelab5_data.html">lab5_data</a>.</p>
+<p>In <a href="app_codelab5_data.html">4 - Save and Fetch Data</a>,
+you will modify your Todo list app so that Todo items are saved.</p>
diff --git a/chrome/common/extensions/docs/templates/articles/app_codelab4_testing.html b/chrome/common/extensions/docs/templates/articles/app_codelab4_testing.html
deleted file mode 100644
index ad13d85..0000000
--- a/chrome/common/extensions/docs/templates/articles/app_codelab4_testing.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<h1 id="lab_4_testing">Lab 4 - Testing</h1>
-
-<p>We are working on guidelines and best practices for testing Chrome apps... stay tuned.</p>
-
-<h1 id="what_39_s_next_">What&#39;s next?</h1>
-
-<p>In <a href="app_codelab5_data.html">lab5_data</a>, you will modify your Todo list app
-so that Todo items are saved.</p>
diff --git a/chrome/common/extensions/docs/templates/articles/app_codelab5_data.html b/chrome/common/extensions/docs/templates/articles/app_codelab5_data.html
index bf2f26a8..d8f4fc6 100644
--- a/chrome/common/extensions/docs/templates/articles/app_codelab5_data.html
+++ b/chrome/common/extensions/docs/templates/articles/app_codelab5_data.html
@@ -1,25 +1,57 @@
-<h1 id="lab_5_manage_data">Lab 5 - Manage Data</h1>
+<h1 id="lab_5_manage_data">Save and Fetch Data</h1>
-<p>The <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab3_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&#39;ve changed is lost. In this section, we will save every change using <a href="http://developer.chrome.com/trunk/apps/storage.html">chrome.storage.sync</a>. This lets you store <em>small things</em> that automatically sync to the cloud if you are online and logged in to Chrome. If you are offline or unlogged, it saves locally and transparently: you don&#39;t have to handle online check and offline fallback in your application.</p>
+<p>The <a href="http://developer.chrome.com/trunk/apps/app_codelab3_mvc.html">sample from Lab 3</a>
+uses a static array of Todos.
+Every time your app restarts,
+whatever you&#39;ve changed is lost.
+In this section, we will save every change using
+<a href="http://developer.chrome.com/trunk/apps/storage.html">chrome.storage.sync</a>.
+</p>
-<h2 id="you_should_also_read">You should also read</h2>
-
-<p><a href="http://developer.chrome.com/apps/app_storage.html">Manage Data</a> in Chrome app docs</p>
+<p>
+This lets you store <em>small things</em> that automatically sync to the cloud
+if you are online and logged in to Chrome.
+If you are offline or unlogged, it saves locally and transparently:
+you don&#39;t have to handle online check and offline fallback in your application.
+</p>
<h2 id="save_your_todos_in_the_cloud">Save your Todos in the cloud</h2>
-<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>
+<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>
+
+<h3 id="manifest">Update manifest</h3>
+
+<p>Request permission to use storage in your manifest.
+Permissions are the same in the
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_data/angularjs/1_storage_sync/manifest.json">AngularJS manifest.json</a> and
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_data/javascript/1_storage_sync/manifest.json">JavaScript manifest.json</a>:
+</p>
-<ol>
-<li><p>Request permission to use storage in your <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_data/angularjs/1_storage_sync/manifest.json">manifest.json</a>:
<pre>
{
... ,
&quot;permissions&quot;: [&quot;storage&quot;]
}
-</pre></p></li>
-<li><p>Change your <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_data/angularjs/1_storage_sync/controller.js">controller.js</a> and, instead of a static list, get the Todo list from the syncable storage:
-<pre>
+</pre>
+
+<h3 id="simple-controller">Update controller</h3>
+
+<p>Change your controller to get the Todo list
+from syncable storage instead of a static list:
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_data/angularjs/1_storage_sync/controller.js">AngularJS controller.js</a> or
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_data/javascript/1_storage_sync/controller.js">JavaScript controller.js</a>.
+</p>
+
+<tabs data-group="source">
+
+ <header tabindex="0" data-value="angular">Angular</header>
+ <header tabindex="0" data-value="js">JavaScript</header>
+
+ <content>
+ <pre>
// Notice that chrome.storage.sync.get is asynchronous
chrome.storage.sync.get(&#39;todolist&#39;, function(value) {
// The $apply is only necessary to execute the function inside Angular scope
@@ -37,13 +69,69 @@ $scope.load = function(value) {
{text:&#39;learn angular&#39;, done:true},
{text:&#39;build an angular app&#39;, done:false}];
}
-}
+}
$scope.save = function() {
chrome.storage.sync.set({&#39;todolist&#39;: $scope.todos});
};
-</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 explicit.
-<pre>
+ </pre>
+ </content>
+ <content>
+ <pre>
+ /**
+ * Listen to changes in the model and trigger the appropriate changes in the view
+ **/
+ model.addListener(function(model, changeType, param) {
+ if ( changeType === 'removed' || changeType === 'archived' || changeType === 'reset') {
+ redrawUI(model);
+ } else if ( changeType === 'added' ) {
+ drawTodo(model.todos[param], list);
+ } else if ( changeType === 'stateChanged') {
+ updateTodo(model.todos[param]);
+ }
+ storageSave();
+ updateCounters(model);
+ });
+
+// If there is saved data in storage, use it. Otherwise, bootstrap with sample todos
+ var storageLoad = function() {
+ chrome.storage.sync.get('todolist', function(value) {
+ if (value && value.todolist) {
+ model.setTodos(value.todolist);
+ } else {
+ model.addTodo('learn Chrome Apps', true);
+ model.addTodo('build a Chrome App', false);
+ }
+ });
+ }
+
+ var storageSave = function() {
+ chrome.storage.sync.set({'todolist': model.todos});
+ };
+ </pre>
+ </content>
+</tabs>
+
+<h3 id="simple-view">Update view</h3>
+
+<p>In the view,
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_data/angularjs/1_storage_sync/index.html">AngularJs index.hmtl</a> or
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_data/javascript/1_storage_sync/index.html">JavaScript index.html</a>,
+save the data whenever it changes.
+In AngularJS,
+we call <code>save()</code> explicitedly
+but there are many ways of doing this.
+For example,
+you could also use <code>$watchers</code> on the scope.
+</p>
+
+<tabs data-group="source">
+
+ <header tabindex="0" data-value="angular">Angular</header>
+ <header tabindex="0" data-value="js">JavaScript</header>
+
+ <content>
+ <pre>
...
[ &lt;a href=&quot;&quot; ng-click=&quot;archive() || save()&quot;&gt;archive&lt;/a&gt; ]
...
@@ -51,32 +139,70 @@ $scope.save = function() {
...
&lt;form ng-submit=&quot;addTodo() || save()&quot;&gt;
...
-</pre></li>
-<li>Check the results by reloading the app: open the app, right-click and select Reload App.
-You can now add Todo items, close the app, and the new items will still be there when you reopen the app.</li>
-</ol>
+ </pre>
+ </content>
+ <content>
+ <pre>
+&lt;form&gt;
+ &lt;input type="text" size="30"
+ placeholder="add new todo here"&gt;
+ &lt;input class="btn-primary" type="submit" value="add"&gt;
+&lt;/form&gt;
+ </pre>
+ </content>
+
+</tabs>
+
+<h3 id="results1">Check the results</h3>
-<p class="note"><b>Note:</b> If you get stuck and want to see the app in action,
-go to <code>chrome://extensions</code>, load the unpacked <a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab5_data/angularjs/1_storage_sync">1_storage_sync</a> app,
-and launch the app from a new tab.</p>
+<p>Check the results by reloading the app:
+open the app, right-click and select Reload App.
+You can now add Todo items, close the app,
+and the new items will still be there when you reopen the app.
+</p>
+
+<p>
+If you get stuck and want to see the app in action,
+go to <code>chrome://extensions</code>,
+load the unpacked app, and launch the app from a new tab:
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab5_data/angularjs/1_storage_sync">Angular JS 1_storage_sync</a> or
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab5_data/javascript/1_storage_sync">JavaScript 1_storage_sync</a>.
+</p>
<h2 id="handle_drag_and_dropped_files_and_urls">Handle drag-and-dropped files and URLs</h2>
-Suppose you want to create Todos associated with local files and/or URLs. The natural way of doing this is to accept dropped items. It&#39;s simple enough to add drag-and-drop support in a Chrome app using the standard HTML5 Drag-and-Drop API.
+<p>Suppose you want to create Todos associated with local files and/or URLs.
+The natural way of doing this is to accept dropped items.
+It&#39;s simple enough to add drag-and-drop support
+in a Chrome packaged app using the standard
+<a href="http://www.html5rocks.com/en/tutorials/dnd/basics/">HTML5 Drag-and-Drop API</a>.
+</p>
-<ol>
-<li>In <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_data/angularjs/2_drop_files/controller.js">controller.js</a>, add code to handle the events of dragover, dragleave and drop:
-<pre>
+<h3 id="dd-controller">Update controller</h3>
+
+<p>In the controller,
+add code to handle the events of dragover, dragleave, and drop:
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_data/angularjs/2_drop_files/controller.js">AngularJS controller.js</a> or
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_data/javascript/2_drop_files/controller.js">JavaScript controller.js</a>.
+</p>
+
+<tabs data-group="source">
+
+ <header tabindex="0" data-value="angular">Angular</header>
+ <header tabindex="0" data-value="js">JavaScript</header>
+
+ <content>
+ <pre>
var defaultDropText = &quot;Or drop files here...&quot;;
$scope.dropText = defaultDropText;
-// on dragOver, we will change the style and text accordingly, depending on
+// on dragOver, we will change the style and text accordingly, depending on
// the data being transferred
var dragOver = function(e) {
e.stopPropagation();
e.preventDefault();
- var valid = e.dataTransfer &amp;&amp; e.dataTransfer.types
- &amp;&amp; ( e.dataTransfer.types.indexOf(&#39;Files&#39;) &gt;= 0
+ var valid = e.dataTransfer &amp;&amp; e.dataTransfer.types
+ &amp;&amp; ( e.dataTransfer.types.indexOf(&#39;Files&#39;) &gt;= 0
|| e.dataTransfer.types.indexOf(&#39;text/uri-list&#39;) &gt;=0 )
$scope.$apply(function() {
$scope.dropText = valid ? &quot;Drop files and remote images and they will become Todos&quot;
@@ -123,19 +249,132 @@ $scope.$apply(function() {
document.body.addEventListener(&quot;dragover&quot;, dragOver, false);
document.body.addEventListener(&quot;dragleave&quot;, dragLeave, false);
document.body.addEventListener(&quot;drop&quot;, drop, false);
-</pre></li><li>To make all the area of the window accept the drop event and still work on the same scope, let&#39;s move the Angular scope definition from the div to the body in the <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_data/angularjs/2_drop_files/index.html">index.html</a> file.
-Also, let&#39;s associate the body&#39;s CSS class with the Angular controller&#39;s class, so we can change the class directly in the scope and have it automatically changed in the DOM:
-<pre>
+ </pre>
+ </content>
+ <content>
+ <pre>
+var defaultDropText = "Or drop files here...";
+
+var dropText = document.getElementById('dropText');
+dropText.innerText = defaultDropText;
+
+// on dragOver, we will change the style and text accordingly, depending on
+// the data being transfered
+var dragOver = function(e) {
+ e.stopPropagation();
+ e.preventDefault();
+ var valid = isValid(e.dataTransfer);
+ if (valid) {
+ dropText.innerText="Drop files and remote images and they will become Todos";
+ document.body.classList.add("dragging");
+ } else {
+ dropText.innerText="Can only drop files and remote images here";
+ document.body.classList.add("invalid-dragging");
+ }
+}
+
+var isValid = function(dataTransfer) {
+ return dataTransfer && dataTransfer.types
+ && ( dataTransfer.types.indexOf('Files') >= 0
+ || dataTransfer.types.indexOf('text/uri-list') >=0 )
+}
+
+// reset style and text to the default
+var dragLeave = function(e) {
+ dropText.innerText=defaultDropText;
+ document.body.classList.remove('dragging');
+ document.body.classList.remove('invalid-dragging');
+}
+
+// on drop, we create the appropriate TODOs using dropped data
+var drop = function(e, model) {
+ e.preventDefault();
+ e.stopPropagation();
+ if (isValid(e.dataTransfer)) {
+ if (e.dataTransfer.types.indexOf('Files') >= 0) {
+ var files = e.dataTransfer.files;
+ for (var i = 0; i &lt; files.length; i++) {
+ var text = files[i].name+', '+files[i].size+' bytes';
+ model.addTodo(text, false, {file: files[i]});
+ }
+ } else { // uris
+ var uri=e.dataTransfer.getData("text/uri-list");
+ model.addTodo(uri, false, {uri: uri});
+ }
+ }
+
+ dragLeave();
+}
+
+exports.setDragHandlers = function(model) {
+ document.body.addEventListener("dragover", dragOver, false);
+ document.body.addEventListener("dragleave", dragLeave, false);
+ document.body.addEventListener("drop", function(e) {
+ drop(e, model);
+ }, false);
+}
+ </pre>
+ </content>
+
+</tabs>
+
+<h3 id="dd-view">Update view</h3>
+
+<p>If using AngularJS,
+let&#39;s move the Angular scope definition from the div to the body in the
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_data/angularjs/2_drop_files/index.html">AngularJS index.html</a> file to make all the area of the window accept the drop event and still work on the same scope.
+Also, let&#39;s associate the body&#39;s CSS class with the Angular controller&#39;s class,
+so we can change the class directly in the scope and have it automatically changed in the DOM:
+</p>
+
+<tabs data-group="source">
+
+ <header tabindex="0" data-value="angular">Angular</header>
+
+ <content>
+ <pre>
&lt;body ng-controller=&quot;TodoCtrl&quot; ng-class=&quot;dropClass&quot;&gt;
&lt;!-- remember to remove the ng-controller attribute from the div where it was before --&gt;
-</pre></li>
-<li>Add a message placeholder (in <code>index.html</code>) to warn the user that some types of dragging are not allowed:
-<pre>
+ </pre>
+ </content>
+
+</tabs>
+
+<p>Add a message placeholder
+(in <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_data/angularjs/2_drop_files/index.html">AngularJS index.html</a> or
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_data/javascript/2_drop_files/index.html">JavaScript index.html</a>) to warn the user that some types of dragging are not allowed:
+</p>
+
+<tabs data-group="source">
+
+ <header tabindex="0" data-value="angular">Angular</header>
+ <header tabindex="0" data-value="js">JavaScript</header>
+
+ <content>
+ <pre>
&lt;div&gt;
&#123;&#123;dropText&#125;&#125;
&lt;/div&gt;
-</pre></li>
-<li>Add appropriate styling for the <code>dragging</code> and <code>invalid-dragging</code> CSS classes in <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_data/angularjs/2_drop_files/todo.css">todo.css</a>. Here we used a green or red background color animation:
+ </pre>
+ </content>
+ <content>
+ <pre>
+&lt;div id=&quot;dropText&quot;&gt;
+&lt;/div&gt;
+ </pre>
+ </content>
+
+</tabs>
+
+<h3 id="dd-css">Update stylesheet</h3>
+
+<p>Add appropriate styling for the <code>dragging</code> and
+<code>invalid-dragging</code> CSS classes in the css.
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_data/angularjs/2_drop_files/todo.css">AngularJS todo.css</a> and
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab5_data/javascript/2_drop_files/todo.css">JavaScript todo.css</a> are the same.
+Here we used a green or red background color animation:
+</p>
+
<pre>
@-webkit-keyframes switch-green {
from { background-color: white;} to {background-color: rgb(163, 255, 163);}
@@ -150,27 +389,44 @@ Also, let&#39;s associate the body&#39;s CSS class with the Angular controller&#
.invalid-dragging {
-webkit-animation: switch-red 0.5s ease-in-out 0 infinite alternate;
}
-</pre></p></li><li><p>Check the results by reloading the app: open the app, right-click and select Reload App.
-You can now drag files into the Todo list.</p></li>
-</ol>
+</pre>
+
+<h3 id="results2">Check the results</h3>
-<p class="note"><b>Note:</b> If you get stuck and want to see the app in action,
-go to <code>chrome://extensions</code>, load the unpacked <a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab5_data/angularjs/2_drop_files">2_drop_files</a> app,
-and launch the app from a new tab.</p>
+<p>Check the results by reloading the app:
+open the app, right-click and select Reload App.
+You can now drag files into the Todo list.</p>
-<h1 id="challenge_">Challenge:</h1>
+<p>
+If you get stuck and want to see the app in action,
+go to <code>chrome://extensions</code>, load the unpacked app,
+and launch the app from a new tab:
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab5_data/angularjs/2_drop_files">AngularJS 2_drop_files</a>
+or <a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab5_data/javascript/2_drop_files">JavaScript 2_drop_files</a>.
+</p>
-<p>The current code only saves the file reference, but it doesn&#39;t open the file. Using the <a href="http://www.html5rocks.com/en/tutorials/file/filesystem/">HTML5 Filesystem API</a>, save the file contents in a sandboxed filesystem. When the Todo item is archived, remove the corresponding file from the sandboxed filesystem. Add an &quot;open&quot; link on each Todo that has an associated file. When the item is clicked and the file exists in the sandboxed filesystem, use the Chrome app <a href="http://developer.chrome.com/apps/fileSystem.html">Filesystem extension</a> to request a writable FileEntry from the user. Save the file data from the sandboxed filesystem into that entry.</p>
+<h2 id="challenge_">Challenge</h2>
+
+<p>The current code only saves the file reference, but it doesn&#39;t open the file. Using the <a href="http://www.html5rocks.com/en/tutorials/file/filesystem/">HTML5 Filesystem API</a>, save the file contents in a sandboxed filesystem. When the Todo item is archived, remove the corresponding file from the sandboxed filesystem. Add an &quot;open&quot; link on each Todo that has an associated file. When the item is clicked and the file exists in the sandboxed filesystem, use the 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 file data from the sandboxed filesystem into that entry.</p>
<p class="note"><b>Tip:</b> managing file entries using the raw HTML5 Filesystem API is not trivial. You might want to use a wrapper library, like Eric Bidelman&#39;s <a href="https://github.com/ebidel/filer.js">filer.js</a>.</p>
-<h1 id="takeaways_">Takeaways:</h1>
+<h2 id="takeaways_">Takeaways</h2>
<ul>
<li><p>Use <a href="http://developer.chrome.com/apps/storage.html">chrome.storage.sync</a> to save small data that you need to be sync&#39;ed among devices, like configuration options, application state, etc. The sync is automatic, as long as the same user is logged into Chrome on all devices.</p></li>
-<li><p>Chrome apps support almost all HTML5 APIs, such as drag and drop. HTML Filesystem API is also supported, with extra features from the Chrome app&#39;s <a href="http://developer.chrome.com/apps/fileSystem.html">Filesystem API extension</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>
+<li><p>Chrome packaged apps support almost all HTML5 APIs, such as drag and drop.
+HTML Filesystem API is also supported, with extra features from the Chrome packaged app&#39;s
+<a href="http://developer.chrome.com/apps/fileSystem.html">Filesystem API</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>
</ul>
-<h1 id="what_39_s_next_">What&#39;s next?</h1>
+<h2 id="you_should_also_read">You should also read</h2>
+
+<p><a href="http://developer.chrome.com/apps/app_storage.html">Manage Data</a> tutorial</p>
+
+<h2 id="what_39_s_next_">What's next?</h2>
-<p>In <a href="app_codelab6_lifecycle.html">lab6_lifecycle</a>, you will learn the basics of the Chrome app lifecycle. </p>
+<p>In <a href="app_codelab6_lifecycle.html">5 - Manage App Lifecycle</a>,
+you will learn the basics of the Chrome packaged app lifecycle. </p>
diff --git a/chrome/common/extensions/docs/templates/articles/app_codelab6_lifecycle.html b/chrome/common/extensions/docs/templates/articles/app_codelab6_lifecycle.html
index 8450926..df2eed9 100644
--- a/chrome/common/extensions/docs/templates/articles/app_codelab6_lifecycle.html
+++ b/chrome/common/extensions/docs/templates/articles/app_codelab6_lifecycle.html
@@ -1,11 +1,7 @@
-<h1 id="lab_6_lifecycle">Lab 6 - Lifecycle</h1>
+<h1 id="lab_6_lifecycle">Manage App Lifecycle</h1>
<p>Like everything in this world, apps have a lifecycle. They are installed, launched, restarted, suspended when the system needs to free up resources and uninstalled. This lab will show you the basics of the Chrome app lifecycle and how its heart, the event page (aka background script), is used.</p>
-<h2 id="you_should_also_read">You should also read</h2>
-
-<p><a href="http://developer.chrome.com/apps/app_lifecycle.html">Manage App Lifecycle</a> in Chrome app docs</p>
-
<h2 id="the_event_page">The event page</h2>
<p>The event page is one of the most important pieces of a Chrome app. It&#39;s responsible for what gets launched, when, and how.
@@ -14,42 +10,72 @@ For example, if your app is an instant messenger, you might want your event page
<p>For simpler apps, the event page listens to the app lifecycle events and reacts appropriately.
There are two important lifecycle events, $ref:app.runtime.onLaunched and $ref:app.runtime.onRestarted.</p>
-<h2 id="the_onlaunched_event_and_the_chrome_app_window_create_method">The onLaunched event and the chrome.app.window.create method</h2>
+<h2 id="the_onlaunched">The onLaunched event</h2>
-<p>$ref:app.runtime.onLaunched is the most important event. It fires when the user clicks on your app&#39;s icon with the intent of launching it. For most simpler apps, the event page will listen for this event and open a window when it fires. See our <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab6_lifecycle/angularjs/main.js">main.js</a> for the most common usage.</p>
+<p>The $ref:app.runtime.onLaunched event is the most important event.
+It fires when the user clicks on your app&#39;s icon with the intent of launching it.
+For most simpler apps,
+the event page will listen for this event and open a window when it fires.
+See
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab6_lifecycle/angularjs/main.js">AngularJS main.js</a> or
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab6_lifecycle/javascript/main.js">JavaScript main.js</a>
+for the most common usage.</p>
<h3 id="windows_with_ids">Windows with IDs</h3>
<p>The $ref:app.window.create method can associate an ID to the window being opened. Currently, the most interesting use for this is to restore a window&#39;s width, height and location and its associated Developer Tools window, if opened, when the app is launched. </p>
-<p>Execute your app as it is now, move and resize the window, close and restart it. The app will reopen in the original location, right? Now add a property <code>id</code> to the <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab6_lifecycle/angularjs/main.js">main.js</a>, reload the app and test again:</p>
+<p>Execute your app as it is now, move and resize the window,
+close and restart it.
+The app will reopen in the original location, right?
+Now add a property <code>id</code> to the event page,
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab6_lifecycle/angularjs/main.js">Angular main.js</a> or
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab6_lifecycle/javascript/main.js">JavaScript main.js</a>,
+reload the app and test again:</p>
-<pre><code><pre>
+<pre>
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create(&#39;index.html&#39;,
{id: &#39;mainwindow&#39;, bounds: {width: 500, height: 309} });
});
-</pre></code></pre>
+</pre>
<p>If your application requires, you can open more than one window.</p>
<h2 id="the_onrestarted_event">The onRestarted event</h2>
-<p>The $ref:app.runtime.onRestarted event is not as essential as <code>onLaunched</code>, but it might be relevant to certain types of apps.
-This event is executed when the app is restarted, for example, when Chrome quits, restarts, and the app is launched again.
-You can use this event to restore a transient state. </p>
+<p>The $ref:app.runtime.onRestarted event is not as essential as <code>onLaunched</code>,
+but it might be relevant to certain types of apps.
+This event is executed when the app is restarted, for example,
+when Chrome quits, restarts, and the app is launched again.
+You can use this event to restore a transient state.</p>
-<p>For example, if your app has a form with several fields, you won&#39;t always want to save the partial form while the user is typing.
+<p>For example, if your app has a form with several fields,
+you won&#39;t always want to save the partial form while the user is typing.
If the user quits the app on purpose, she might not be interested keeping the partial data.
-If the Chrome runtime restarted for some reason other than by a user&#39;s intention, the user will want that data when the app is restarted.</p>
+If the Chrome runtime restarted for some reason other than by a user&#39;s intention,
+the user will want that data when the app is restarted.</p>
+
+<p>Let&#39;s change our code to save the Todo input field in $ref:storage as the user types,
+only restoring it if the <code>onRestarted</code> event is triggered.</p>
+
+<p class="note"><b>Note:</b>
+We learned about <code>chrome.storage.sync</code> before, but
+<a href="http://developer.chrome.com/trunk/apps/storage.html#using-sync">chrome.storage.local</a>
+wasn&#39;t mentioned until now.
+Both have exactly the same syntax,
+but the semantics of <code>chrome.storage.local</code> is, as the name says, completely local.
+There&#39;s no attempt to synchronize or to save the data in the cloud.</p>
-<p>Let&#39;s change our code to save the Todo input field in $ref:storage as the user types, only restoring it if the <code>onRestarted</code> event is triggered.</p>
+<h3 id="event-page">Update event page</h3>
-<p class="note"><b>Note:</b> We learned about <code>chrome.storage.sync</code> before, but <a href="http://developer.chrome.com/trunk/apps/storage.html#using-sync">chrome.storage.local</a> wasn&#39;t mentioned until now. Both have exactly the same syntax, but the semantics of <code>chrome.storage.local</code> is, as the name says, completely local.
-There&#39;s no attempt to synchronize or to save the data in the cloud.</p>
+<p>Update the event page to include the
+<code>onLaunched</code> and <code>onRestarted</code> events.
+Events are handled the same in
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab6_lifecycle/angularjs/main.js">AngularJS main.js</a> and
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab6_lifecycle/javascript/main.js">JavaScript main.js</a>:
+</p>
-<ul>
-<li>Event page: <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab6_lifecycle/angularjs/main.js">main.js</a>
<pre>
chrome.app.runtime.onLaunched.addListener(function() {
// normal launch initiated by the user, let&#39;s start clean.
@@ -79,8 +105,22 @@ function runApp(readInitialState) {
});
});
}
-</pre></li><li>Controller: add to existing <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab6_lifecycle/angularjs/controller.js">controller.js</a>
-<pre>
+</pre>
+
+<h3 id="controller">Update controller</h3>
+
+<p>Add to existing
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab6_lifecycle/angularjs/controller.js">AngularJS controller.js</a> or
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab6_lifecycle/javascript/controller.js">JavaScript controller.js</a>:
+</p>
+
+<tabs data-group="source">
+
+ <header tabindex="0" data-value="angular">Angular</header>
+ <header tabindex="0" data-value="js">JavaScript</header>
+
+ <content>
+ <pre>
var newTodoInput = null;
var clearInitialState = function() {
@@ -105,24 +145,71 @@ window.addEventListener(&#39;load&#39;, function() {
saveTransientState();<br>
})
})
-</pre></p></li><li><p>Save the changes by reloading the app: open the app, right-click and select Reload.</p></li>
-</ul>
+ </pre>
+ </content>
+ <content>
+ <pre>
+ var newTodoInput = document.querySelector('input[type="text"]');
+
+ window.clearInitialState = function() {
+ chrome.storage.local.set({'newtodo': null});
+ }
+
+ window.setInitialState = function() {
+ chrome.storage.local.get('newtodo', function(data) {
+ if (newTodoInput && data && data.newtodo) {
+ newTodoInput.value = data.newtodo;
+ newTodoInput.focus();
+ }
+ });
+ };
+
+ var saveTransientState = function() {
+ chrome.storage.local.set({'newtodo': newTodoInput.value});
+ };
+
+ newTodoInput.addEventListener('keypress' , function() {
+ saveTransientState();
+ })
+ </pre>
-<p>If Chrome and the app shuts down for any reason (other than a user-gesture), the <code>onRestarted</code> event is fired.
-Any text entered in the input field (but not yet saved as a Todo item) will reappear when Chrome and the app are reopened.</p>
+</tabs>
-<p class="note"><b>Note:</b> If you get stuck and want to see the app in action, go to <code>chrome://extensions</code>,
-load the unpacked <a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab6_lifecycle">lab6 app</a>, and launch the app from a new tab.</p>
+<h3 id="results">Check the results</h3>
-<h1 id="takeaways_">Takeaways:</h1>
+<p>Save the changes by reloading the app:
+open the app, right-click and select Reload.</p>
+
+<p>If Chrome and the app shuts down for any reason (other than a user-gesture),
+the <code>onRestarted</code> event is fired.
+Any text entered in the input field (but not yet saved as a Todo item)
+will reappear when Chrome and the app are reopened.</p>
+
+<p>If you get stuck and want to see the app in action,
+go to <code>chrome://extensions</code>,
+load the unpacked
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab6_lifecycle/angularjs">AngularJS app</a> or
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab6_lifecycle/javascript">JavaScript app</a>,
+and launch the app from a new tab.</p>
+
+<h2 id="takeaways_">Takeaways</h2>
<ul>
-<li>The event page may continue to run even when your windows are closed. You can move logic that is shared among windows to the event page, as we will see in <a href="app_codelab9_multipleviews.html">lab9</a>.</li>
+<li>The event page may continue to run even when your windows are closed;
+you can move logic that is shared amoung windows to the event page.</li>
</ul>
-<h1 id="what_39_s_next_">What&#39;s next?</h1>
+<h2 id="you_should_also_read">You should also read</h2>
+
+<p><a href="http://developer.chrome.com/apps/app_lifecycle.html">Manage App Lifecycle</a> tutorial</p>
+
+<h2 id="what_39_s_next_">What's next?</h2>
-<p>In <a href="app_codelab7_useridentification.html">lab7_useridentification</a>,
+<p>In <a href="app_codelab7_useridentification.html">6 - Access User's Data</a>,
you will learn how to identify users and use OAuth2.0 to access Google and other third party services.</p>
-<p class="note"><b>Note:</b> The <a href="http://developer.chrome.com/trunk/apps/app_identity.html">identify API</a> covered in lab 7 is still experimental.</p>
+<p class="note"><b>Note:</b>
+The next chapter covers a still experimental API.
+If you don't want to play with experimental APIs, feel free to skip it - the
+rest of the codelab is independent from it.
+</p>
diff --git a/chrome/common/extensions/docs/templates/articles/app_codelab7_useridentification.html b/chrome/common/extensions/docs/templates/articles/app_codelab7_useridentification.html
index 02b5868..94f7ddd 100644
--- a/chrome/common/extensions/docs/templates/articles/app_codelab7_useridentification.html
+++ b/chrome/common/extensions/docs/templates/articles/app_codelab7_useridentification.html
@@ -1,18 +1,17 @@
-<h1 id="lab_7_user_identity">Lab 7 - User Identity</h1>
+<h1 id="lab_7_user_identity">Access User's Data</h1>
<p>Most modern applications are attached to the web to synchronize data. When synchronizing data, you need to identify who the user is.
-Chrome apps come with an <a href="http://developer.chrome.com/trunk/apps/experimental.identity.html">identity API</a> that makes it easy to integrate either with Google accounts or with any other service that supports OAuth.</p>
+Chrome packaged apps come with an <a href="http://developer.chrome.com/trunk/apps/experimental.identity.html">identity API</a> that makes it easy to integrate either with Google accounts or with any other service that supports OAuth.</p>
<ol>
<li> Built in - Google Authenticiation</li>
<li> Third Party Authentication (Twitter, Foursquare, etc.)</li>
</ol>
-<h2 id="you_should_also_read">You should also read</h2>
-
-<p><a href="http://developer.chrome.com/trunk/apps/app_identity.html">Identify User</a> in Chrome app docs</p>
-
-<p class="note"><b>Note:</b> Apps with authentication require the experimental permission in the <code>manifest.json</code> and, until they came out of experimental state, they cannot be uploaded to the Chrome Web Store.
+<p class="warning"><b>Warning:</b>
+Apps with authentication require the experimental permission in the
+<code>manifest.json</code> and, until they came out of experimental state,
+they cannot be uploaded to the Chrome Web Store.
If you prefer, you can choose to skip this lab.</p>
<h2 id="authenticating_with_google">Authenticating with Google</h2>
@@ -21,7 +20,7 @@ If you prefer, you can choose to skip this lab.</p>
<h2 id="integrating_with_a_third_party_service">Integrating with a third-party service</h2>
-<p>Chrome apps have a dedicated API for lauching the authentication flow to any third-party OAuth2 service, called $ref:experimental.identity.launchWebAuthFlow.
+<p>Chrome packaged apps have a dedicated API for lauching the authentication flow to any third-party OAuth2 service, called $ref:experimental.identity.launchWebAuthFlow.
To show how this flow works, we&#39;re going to update our sample to import <a href="https://developers.google.com/google-apps/tasks/">Google Tasks</a> into the Todo list.</p>
<h3 id="register_with_the_provider">Register with the provider</h3>
@@ -41,13 +40,21 @@ replacing &lt;YOURAPP_ID&gt; with your app ID (this is the app&#39;s long alphan
<h3 id="add_permissions">Add permissions</h3>
-<p>Update the <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab7_useridentification/angularjs/manifest.json">manifest.json</a> to use &quot;experimental&quot; features. Note that we&#39;ve also requested permission to make XHR requests to the Tasks service URL - for security reasons, you need to request explicit permission in the manifest for every URL you will call via XHR.
+<p>Update the
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab7_useridentification/angularjs/manifest.json">AngularJS manifest.json</a> or
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab7_useridentification/javascript/manifest.json">JavaScript manifest.json</a>
+to use &quot;experimental&quot; features.
+Note that we&#39;ve also requested permission
+to make XHR requests to the Tasks service URL - for security reasons,
+you need to request explicit permission in the manifest for every URL you will call via XHR.
+</p>
+
<pre>
{
... ,
&quot;permissions&quot;: [&quot;storage&quot;, &quot;experimental&quot;, &quot;https://www.googleapis.com/tasks/*&quot;]
}
-</pre></p>
+</pre>
<h3 id="add_google_tasks_to_the_todo_list">Add Google tasks to the Todo list</h3>
@@ -55,12 +62,28 @@ replacing &lt;YOURAPP_ID&gt; with your app ID (this is the app&#39;s long alphan
Once we have this token, we are able to call the Google Tasks API directly.</p>
<ol>
-<li><p>Since this is time consuming and error prone, you can cheat and copy our JavaScript that handles the authentication to the Google Tasks API from here: <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab7_useridentification/angularjs/gapi_tasks.js">gapi_tasks.js</a>.
-This script calls <code>launchWebFlow</code> and gets a valid access token for the specified client ID. It also has simple JavaScript methods that, after authenticated, goes to the Tasks API and gets the user&#39;s task lists and the corresponding tasks. </p>
-
-<p class="note"><b>Note:</b> this script is NOT intented to be used in production - it is just a very simple, limited and definitely not robust piece of code intented to highlight the basic authentication and API calls.</p></li>
-<li><p>Add a new method to the existing <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab7_useridentification/angularjs/controller.js">controller.js</a> that, using the methods from the script of the previous step, authenticates the user and imports his Google tasks into the Todo list:
-<pre>
+<li><p>Since this is time consuming and error prone, you can cheat and copy our JavaScript that handles the authentication to the Google Tasks API from here: <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab7_useridentification/angularjs/gapi_tasks.js">Angular gapi_tasks.js</a>
+and <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab7_useridentification/javascript/gapi_tasks.js">JavaScript gapi_tasks.js</a> are the same.
+This script calls <code>launchWebFlow</code> and
+gets a valid access token for the specified client ID.
+It also has simple JavaScript methods that, after authenticated,
+goes to the Tasks API and gets the user&#39;s task lists and the corresponding tasks. </p>
+
+<p class="note"><b>Note:</b> This script is NOT intented to be used in production - it is just a very simple, limited and definitely not robust piece of code intented to highlight the basic authentication and API calls.</p></li>
+<li><p>Add a new method to the existing
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab7_useridentification/angularjs/controller.js">AngularJS controller.js</a> or
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab7_useridentification/javascript/controller.js">JavaScript controller.js</a> that,
+using the methods from the script of the previous step,
+authenticates the user and imports his Google tasks into the Todo list:
+</p>
+
+<tabs data-group="source">
+
+ <header tabindex="0" data-value="angular">Angular</header>
+ <header tabindex="0" data-value="js">JavaScript</header>
+
+ <content>
+ <pre>
$scope.importFromGTasks = function() {
var api = new TasksAPI();
var clientId = &quot;&lt;GET_YOURS_AT_https://code.google.com/apis/console&gt;&quot;;
@@ -82,31 +105,84 @@ $scope.importFromGTasks = function() {
});
});
}
-</pre> </p>
+ </pre>
+ </content>
+ <content>
+ <pre>
+ document.getElementById('importGTasks').addEventListener('click', function() {
+ var api = new TasksAPI();
+ var clientId = &quot;&lt;GET_YOURS_AT_https://code.google.com/apis/console&gt;&quot;;
+ api.authenticate(clientId, function() {
+ api.getLists(function(result) {
+ console.log(result);
+ if (!result || !result.items || result.items.length==0) {
+ throw "No task lists available";
+ }
+ var listId=result.items[0].id;
+ api.getTasks(listId, function(tasks) {
+ console.log(tasks);
+ for (var j=0; j&lt;tasks.items.length; j++) {
+ model.addTodo(tasks.items[j].title, tasks.items[j].status!='needsAction');
+ }
+ });
+ });
+ });
+ });
+ </pre>
+
+</tabs>
<p>Replace the following line in the code above:
<pre>
var clientId = &quot;&lt;GET_YOURS_AT_https://code.google.com/apis/console&gt;&quot;;
</pre>
-with your own project&#39;s Client ID that you got from the Google API Console. Should look like this:
+with your own project&#39;s Client ID that you got from the Google API Console.
+Should look like this:
<pre>
var clientId = &quot;xxxxxxxxxxxxxx.apps.googleusercontent.com&quot;;
</pre></p></li>
<li><p>Now we just need a button that starts the import process. Update the <code>index.html</code> to include <code>gapi_tasks.js</code> and add a new button to call <code>importFromGTasks</code>:
-<pre>
+</p>
+
+<tabs data-group="source">
+
+ <header tabindex="0" data-value="angular">Angular</header>
+ <header tabindex="0" data-value="js">JavaScript</header>
+
+ <content>
+ <pre>
&lt;script src=&quot;gapi_tasks.js&quot;&gt;&lt;/script&gt;
...
&lt;button ng-click=&quot;importFromGTasks()&quot;&gt;import tasks from GTasks&lt;/button&gt;
-</pre></p></li>
+ </pre>
+ </content>
+ <content>
+ <pre>
+&lt;button id="importGTasks"&gt;import tasks from GTasks&lt;/button&gt;
+...
+&lt;script src="gapi_tasks.js"&gt;&lt;/script&gt;
+ </pre>
+ </content>
+
+</tabs></li>
</ol>
-<p class="note"><b>Note:</b> If you get stuck and want to see the app in action,
-go to <code>chrome://extensions</code>, load the unpacked <a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab7_useridentification">lab7 app</a>,
+<h3 id="results">Check the results</h3>
+
+<p>If you get stuck and want to see the app in action,
+go to <code>chrome://extensions</code>,
+load the unpacked
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab7_useridentification/angularjs">AngularJS app</a> or
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab7_useridentification/javascript">JavaScript app</a>,
and launch the app from a new tab.</p>
-<h1 id="what_39_s_next_">What&#39;s next?</h1>
+<h2 id="you_should_also_read">You should also read</h2>
+
+<p><a href="http://developer.chrome.com/trunk/apps/app_identity.html">Identify User</a> tutorial</p>
+
+<h2 id="what_39_s_next_">What's next?</h2>
-<p>In <a href="app_codelab8_webresources.html">lab8_webresources</a>,
+<p>In <a href="app_codelab8_webresources.html">7 - Access Web Resources</a>,
you will learn how to load and show images from a remote URL.</p>
<p class="note"><b>Note:</b> Up until now, the code in each lab builds upon the previous lab code sample.
diff --git a/chrome/common/extensions/docs/templates/articles/app_codelab8_webresources.html b/chrome/common/extensions/docs/templates/articles/app_codelab8_webresources.html
index 1670990..d766706 100644
--- a/chrome/common/extensions/docs/templates/articles/app_codelab8_webresources.html
+++ b/chrome/common/extensions/docs/templates/articles/app_codelab8_webresources.html
@@ -1,93 +1,223 @@
-<h1 id="lab_8_web_resources">Lab 8 - Web Resources</h1>
+<h1 id="lab_8_web_resources">Access Web Resources</h1>
-<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>
+<p>Chrome packaged 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>
<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 inline or load and show images from a remote URL.</p>
-<h2 id="you_should_also_read">You should also read</h2>
-
-<ul>
-<li><a href="http://developer.chrome.com/apps/app_external.html">Embed Content</a> in Chrome app docs</li>
-</ul>
-
-<h2 id="loading_external_web_content_into_an_element">Loading external web content into an element</h2>
+<h2 id="loading_external_web_content_into_an_element">Load external web content</h2>
<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 potential source of exploits.</p>
-<p>Chrome apps offer developers the ability to securely render third-party content in the <code>&lt;webview&gt;</code> tag. A WebView is like an iframe that you can control with greater flexibility and added security.
+<p>Chrome packaged apps offer developers the ability
+to securely render third-party content in the <code>&lt;webview&gt;</code> tag.
+A <a href="http://developer.chrome.com/trunk/apps/webview_tag.html">webview</a>
+is like an iframe that you can control with greater flexibility and added security.
It runs in a separate sandboxed process and can&#39;t communicate directly with the application.</p>
-<p class="note"><b>Tip:</b> The WebView has a very simple API. From your app you can:</p>
+<p>The <code>webview</code> has a very simple API.
+From your app you can:</p>
<ul>
-<li> Change the URL of the WebView.</li>
+<li> Change the URL of the <code>webview</code>.</li>
<li> Navigate forwards and backward, stop loading and reload.</li>
-<li> Check if the WebView has finished loading and if it is possible, go back and forward in the history stack.</li>
-</ul></p>
+<li> Check if the <code>webview</code> has finished loading and if it is possible, go back and forward in the history stack.</li>
+</ul>
-<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>
+<p>We will change our code to render the content of URLs dropped
+in the drag-and-drop operations in a <code>webview</code> when the user clicks on a link.</p>
+
+<h3 id="manifest">Update manifest</h3>
+
+<p>Request a new permission, &quot;webview&quot;, in the manifest.
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/angularjs/1_webview/manifest.json">Angular JS manifest.json</a> and
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/javascript/1_webview/manifest.json">JavaScript manifest.json</a> are the same:
+</p>
-<ol>
-<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_webview/manifest.json">manifest.json</a>:
<pre>
&quot;permissions&quot;: [&quot;storage&quot;, &quot;webview&quot;]
-</pre></p></li>
-<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>:
-<pre>
+</pre>
+
+<h3 id="view">Update view</h3>
+
+<p>Add a <code>&lt;webview&gt;</code> tag and a link to the view:
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/angularjs/1_webview/index.html">AngularJS index.html</a> or
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/javascript/1_webview/index.html">JavaScript index.html</a>:
+</p>
+
+<tabs data-group="source">
+
+ <header tabindex="0" data-value="angular">Angular</header>
+ <header tabindex="0" data-value="js">JavaScript</header>
+
+ <content>
+ <pre>
&lt;!-- in TODO item: --&gt;
&lt;a ng-show=&quot;todo.uri&quot; href=&quot;&quot; ng-click=&quot;showUri(todo.uri)&quot;&gt;(view url)&lt;/a&gt;
&lt;!-- at the bottom, below the end of body: --&gt;
&lt;webview&gt;&lt;/webview&gt;
-</pre></p></li>
-<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/angularjs/1_webview/todo.css">todo.css</a> (it has zero size by default):
+ </pre>
+ </content>
+ <content>
+ <pre>
+&lt;!-- right after the &quot;dropText&quot; div: --&gt;
+&lt;webview&gt;&lt;/webview&gt;
+&lt;!-- in the TODO template, right before the end of the li: --&gt;
+&lt;a style=&quot;display: none;&quot; href=&quot;&quot;&gt;(view url)&lt;/a&gt;
+ </pre>
+ </content>
+
+</tabs>
+
+<h3 id="css">Update stylesheet</h3>
+
+<p>Set an appropriate width and height to the <code>&lt;webview&gt;</code> tag in
+the style sheet.
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/angularjs/1_webview/todo.css">AngularJS todo.css</a> and
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/javascript/1_webview/todo.css">JavaScript todo.css</a> are the same:
+</p>
+
<pre>
webview {
width: 100%;
height: 200px;
}
-</pre></p></li>
-<li><p>Thanks to AngularJS, we now only need to add the <code>showUri</code> method to our <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/angularjs/1_webview/controller.js">controller.js</a> and we&#39;re done:
-<pre>
+</pre>
+
+<h3 id="controller">Update controller</h3>
+
+<p>We now only need to add a method,
+<code>showUri</code>, to the
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/angularjs/1_webview/controller.js">AngularJS controller.js</a>
+or an event handler, <code>showUrl</code>, to the
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/javascript/1_webview/controller.js">JavaScript controller.js</a>.
+</p>
+
+<tabs data-group="source">
+
+ <header tabindex="0" data-value="angular">Angular</header>
+ <header tabindex="0" data-value="js">JavaScript</header>
+
+ <content>
+ <pre>
$scope.showUri = function(uri) {
var webview=document.querySelector(&quot;webview&quot;);
webview.src=uri;
};
-</pre></p></li>
-</ol>
+ </pre>
+ </content>
+ <content>
+ <pre>
+if(/^http:\/\/|https:\/\//.test(todoObj.text)) {
+ var showUrl = el.querySelector('a');
+ showUrl.addEventListener('click', function(e) {
+ e.preventDefault();
+ var webview=document.querySelector("webview");
+ webview.src=todoObj.text;
+ });
+ showUrl.style.display = 'inline';
+}
+ </pre>
+ </content>
+
+</tabs>
+
+<h3 id="results">Check the results</h3>
<p>To test, open the app, right-click, and select Reload App.
-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.
-If it&#39;s not showing, inspect the page and check if you set the webview size appropriately.</p>
+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 <code>webview</code>.
+If it&#39;s not showing,
+inspect the page and check if you set the <code>webview</code> size appropriately.</p>
-<p class="note"><b>Note:</b> If you get stuck and want to see the app in action, go to <code>chrome://extensions</code>,
-load the unpacked <a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab8_webresources/angularjs/1_webview">1_webview</a>, and launch the app from a new tab.</p>
+<p>If you get stuck and want to see the app in action,
+go to <code>chrome://extensions</code>,
+load the unpacked
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab8_webresources/angularjs/1_webview">AngularJS 1_webview</a> or
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab8_webresources/javascript/1_webview">JavaScript 1_webview</a>,
+and launch the app from a new tab.</p>
-<h2 id="loading_external_images">Loading external images</h2>
+<h2 id="loading_external_images">Load external images</h2>
<p>If you try to add an <code>&lt;img&gt;</code> tag to your <code>index.html</code>, and point its <code>src</code> attribute to any site on the web, the following exception is thrown in the console and the image isn&#39;t loaded:</p>
<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 Policy directive: &quot;img-src &#39;self&#39; data: chrome-extension-resource:&quot;.</p>
-<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>
+<p>Chrome packaged 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>
<p>To avoid this restriction, you can use XHR requests, grab the blob corresponding to the remote file and use it appropriately.
For example, <code>&lt;img&gt;</code> tags can use a blob URL.
-Let&#39;s change our application to show a small icon in the Todo list if the dropped URL represents an image:</p>
+Let&#39;s change our application to show a small icon in the Todo list if the dropped URL represents an image.</p>
+
+<h3 id="manifest2">Update manifest</h3>
+
+<p>Before you start firing XHR requests, you must request permissions.
+Since we want to allow users to drag and drop images from any server,
+we need to request permission to XHR to any URL.
+Change
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/angularjs/2_loading_resources/manifest.json">AngularJS manifest.json</a> or
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/javascript/2_loading_resources/manifest.json">JavaScript manifest.json</a>:
+</p>
-<ol>
-<li><p>Before you start firing XHR requests, you must request permissions.
-Since we want to allow users to drag and drop images from any server, we need to request permission to XHR to any URL.
-Change <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/angularjs/2_loading_resources/manifest.json">manifest.json</a>:
<pre>
&quot;permissions&quot;: [&quot;storage&quot;, &quot;webview&quot;, &quot;&lt;all_urls&gt;&quot;]
-</pre></p></li>
-<li><p>Add to your project a placeholder image <img src="https://github.com/GoogleChrome/chrome-app-codelab/raw/master/lab8_webresources/angularjs/2_loading_resources/loading.gif" alt="loading.gif"> that will be shown while we are loading the proper image.</p></li>
-<li><p>Add the <code>&lt;img&gt;</code> tag to the Todo item on the <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/angularjs/2_loading_resources/index.html">index.html</a>:
+</pre>
+
+<h3 id="image">Add image</h3>
+
+<p>Add to your project a placeholder image
+<img src="https://github.com/GoogleChrome/chrome-app-codelab/raw/master/lab8_webresources/angularjs/2_loading_resources/loading.gif" alt="loading.gif">
+that will be shown while we are loading the proper image.</p>
+
+<p>Then add the <code>&lt;img&gt;</code> tag to the Todo item on the view:
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/angularjs/2_loading_resources/index.html">AngularJS index.html</a> or
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/javascript/2_loading_resources/index.html">JavaScript index_html</a>:
+</p>
+
+<tabs data-group="source">
+
+ <header tabindex="0" data-value="angular">Angular</header>
+ <header tabindex="0" data-value="js">JavaScript</header>
+
+ <content>
+ <pre>
+&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;&lt;/img&gt;
+ </pre>
+ </content>
+ <content>
+ <pre>
+&lt;img style=&quot;max-height: 48px; max-width: 120px;&quot;&gt;&lt;/img&gt;
+ </pre>
+ </content>
+
+</tabs>
+
+<p>
+In the
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/javascript/2_loading_resources/controller.js">JavaScript controller.js</a>,
+add a constant for the placeholder image:
+</p>
+
<pre>
-&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;&lt;/img&gt;
+const PLACEHOLDER_IMAGE = "loading.gif";
</pre>
-As you will see soon, this element is only shown when the validImage attribute of the Todo item is true.</p></li>
-<li><p>Add the method loadImage (either in <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/angularjs/2_loading_resources/controller.js">controller.js</a> or in a <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/angularjs/2_loading_resources/loader.js">separate script file</a> as we did), that will start a XHR request and execute a callback with a Blob URL:
+
+<p>
+As you will see soon,
+this element is only shown when the <code>validImage</code> attribute of the Todo item is true.
+</p>
+
+<h3 id="controller2">Update controller</h3>
+
+<p>Add the method <code>loadImage</code> to a new script file
+that will start a XHR request and execute a callback with a Blob URL.
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/angularjs/2_loading_resources/loader.js">AngularJS loader.js</a> and
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/javascript/2_loading_resources/loader.js">JavaScript loader.js</a> are the same:
+</p>
+
<pre>
var loadImage = function(uri, callback) {
var xhr = new XMLHttpRequest();
@@ -98,9 +228,21 @@ var loadImage = function(uri, callback) {
xhr.open(&#39;GET&#39;, uri, true);
xhr.send();
}
-</pre></p></li>
-<li><p>In the <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/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:
-<pre>
+</pre>
+
+<p>In the
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/angularjs/2_loading_resources/controller.js">AngularJS controller.js</a> or
+<a href="">JavaScript controller.js</a>,
+add a new method that will search the Todo list looking for images that are not loaded yet:
+</p>
+
+<tabs data-group="source">
+
+ <header tabindex="0" data-value="angular">Angular</header>
+ <header tabindex="0" data-value="js">JavaScript</header>
+
+ <content>
+ <pre>
// for each image with no imageUrl, start a new loader
$scope.loadImages = function() {
for (var i=0; i&lt;$scope.todos.length; i++) {
@@ -118,9 +260,73 @@ $scope.loadImages = function() {
}
}
};
-</pre></p></li>
-<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.
+ </pre>
+ </content>
+ <content>
+ <pre>
+ var maybeStartImageLoader = function(el, todo) {
+ var img = el.querySelector('img');
+ if (todo['extras'] && todo.extras.validImage && todo.extras.imageUrl) {
+ if (todo.extras.imageUrl===PLACEHOLDER_IMAGE) {
+ img.src = PLACEHOLDER_IMAGE;
+ img.style.display = 'inline';
+ window.loadImage(todo.extras.uri, function(blob_uri, requested_uri) {
+ todo.extras.imageUrl = blob_uri;
+ img.src = blob_uri;
+ });
+ } else {
+ img.src = todo.extras.imageUrl;
+ img.style.display = 'inline';
+ }
+ } else {
+ img.style.display = 'none';
+ }
+ };
+ </pre>
+ </content>
+
+</tabs>
+
+<p>
+If writing your app in JavaScript,
+you will need to call the <code>maybeStartImageLoader</code> function
+in the
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/javascript/2_loading_resources/controller.js">JavaScript controller.js</a>
+to update the Todo list from the model:
+</p>
+
<pre>
+var updateTodo = function(model) {
+ var todoElement = list.querySelector('li[data-id="'+model.id+'"]');
+ if (todoElement) {
+ var checkbox = todoElement.querySelector('input[type="checkbox"]');
+ var desc = todoElement.querySelector('span');
+ checkbox.checked = model.isDone;
+ desc.innerText = model.text;
+ desc.className = "done-"+model.isDone;
+
+ // load image, if this ToDo has image data
+ maybeStartImageLoader(todoElement, model);
+ }
+}
+</pre>
+
+<p>Then in the
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/angularjs/2_loading_resources/controller.js">AngularJS controller.js</a> or
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab8_webresources/javascript/2_loading_resources/controller.js">JavaScript.controller.js</a>,
+<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.
+</p>
+
+<tabs data-group="source">
+
+ <header tabindex="0" data-value="angular">Angular</header>
+ <header tabindex="0" data-value="js">JavaScript</header>
+
+ <content>
+ <pre>
var uri=e.dataTransfer.getData(&quot;text/uri-list&quot;);
var todo = {text:uri, done:false, uri: uri};
if (/.png$/.test(uri) || /.jpg$/.test(uri)) {
@@ -132,9 +338,36 @@ newTodos.push(todo);
// [...] inside the $apply method, before save(), call the loadImages method:
$scope.loadImages();
-</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.
-Setting Todo&#39;s imageUrls to the PLACEHOLDER_IMAGE will force the loadImages method to request them again:
-<pre>
+ </pre>
+ </content>
+ <content>
+ <pre>
+var uri = e.dataTransfer.getData("text/uri-list");
+var extras = { uri: uri };
+if (/\.png$/.test(uri) || /\.jpg$/.test(uri)) {
+ hasImage = true;
+ extras.validImage = true;
+ extras.imageUrl = PLACEHOLDER_IMAGE;
+}
+model.addTodo(uri, false, extras);
+ </pre>
+ </content>
+
+</tabs>
+
+<p>And, finally, we will change the load method to reset the Blob URLs,
+since Blob URLs don&#39;t span through sessions.
+Setting Todo&#39;s imageUrls to the PLACEHOLDER_IMAGE
+will force the loadImages method to request them again:
+</p>
+
+<tabs data-group="source">
+
+ <header tabindex="0" data-value="angular">Angular</header>
+ <header tabindex="0" data-value="js">JavaScript</header>
+
+ <content>
+ <pre>
// If there is saved data in storage, use it. Otherwise, bootstrap with sample todos
$scope.load = function(value) {
if (value &amp;&amp; value.todolist) {
@@ -151,31 +384,82 @@ $scope.load = function(value) {
{text:&#39;build an angular app&#39;, done:false}];
}
}
-</pre></p></li>
-</ol>
+ </pre>
+ </content>
+ <content>
+ <pre>
+/**
+ * Listen to changes in the model and trigger the appropriate changes in the view
+ **/
+model.addListener(function(model, changeType, param) {
+ if ( changeType === 'reset' ) {
+ // let's invalidate all Blob URLs, since their lifetime is tied to the document's lifetime
+ for (var id in model.todos) {
+ if (model.todos[id].extras && model.todos[id].extras.validImage) {
+ model.todos[id].extras.imageUrl = PLACEHOLDER_IMAGE;
+ }
+ }
+ }
+
+ if ( changeType === 'removed' || changeType === 'archived' || changeType === 'reset') {
+ redrawUI(model);
+ } else if ( changeType === 'added' ) {
+ drawTodo(model.todos[param], list);
+ } else if ( changeType === 'stateChanged') {
+ updateTodo(model.todos[param]);
+ }
+ storageSave();
+ updateCounters(model);
+});
+ </pre>
+ </content>
+
+</tabs>
+
+<h3 id="results2">Check the results</h3>
<p>To test, open the app, right-click, and select Reload App.
-Go to <a href="https://www.google.com/imghp?hl=en&amp;tab=wi&amp;authuser=0">Google images</a>, search for and select an image,
+Go to
+<a href="https://www.google.com/imghp?hl=en&amp;tab=wi&amp;authuser=0">Google images</a>,
+search for and select an image,
then drag and drop the image into the Todo list app.
-Assuming no mistakes were made, you should now have a thumbnail of every image URL dropped into the Todo list app.</p>
+Assuming no mistakes were made,
+you should now have a thumbnail of every image URL dropped into the Todo list app.</p>
+
+<p>
+Notice we are not handling local images dropped from the file manager in this change.
+We leave this as a challenge for you.
+</p>
-<p class="note"><b>Note:</b> If you get stuck and want to see the app in action, go to <code>chrome://extensions</code>,
-load the unpacked <a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab8_webresources/angularjs/2_loading_resources">2_loading_resources</a>, and launch the app from a new tab.</p>
+<p>If you get stuck and want to see the app in action,
+go to <code>chrome://extensions</code>, load the unpacked
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab8_webresources/angularjs/2_loading_resources">AngularJS 2_loading_resources</a> or,
+<a href="https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab8_webresources/javascript/2_loading_resources">JavaScript 2_loading_resources</a>
+and launch the app from a new tab.</p>
<p>The <code>loadImage()</code> method above is not the best solution for this problem, because it doesn&#39;t handle errors correctly and it could cache images in a local filesystem.
-We are working on a library that will be much more robust and easier to use.</p>
+We've created the
+<a href="https://github.com/GoogleChrome/apps-resource-loader">apps-resource-loader library</a>
+that's much more robust.</p>
-<h1 id="takeaways_">Takeaways:</h1>
+<h2 id="takeaways_">Takeaways</h2>
<ul>
<li><p>The <code>&lt;webview&gt;</code> tag allows you to have a controlled browser inside your app.
You can use it if you have part of your application that is not CSP compatible and you don&#39;t have resources to migrate it immediately, for example.
-One feature we didn&#39;t mention here is that WebViews can communicate with your app and vice-versa using asynchronous <a href="https://developer.chrome.com/trunk/apps/app_external.html#postMessage">postMessages</a>.</p></li>
+One feature we didn&#39;t mention here is that webviews can communicate with your app and vice-versa using asynchronous <a href="https://developer.chrome.com/trunk/apps/app_external.html#postMessage">postMessages</a>.</p></li>
<li><p>Loading resources like images from the web is not straightforward compared to a standard web page.
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/GoogleChrome/apps-resource-loader">a sample library</a> to asynchronously handle resource loading from XHR calls. Feel free to use it in your projects.</p></li>
</ul>
-<h1 id="what_39_s_next_">What&#39;s next?</h1>
+<h2 id="you_should_also_read">You should also read</h2>
+
+<ul>
+<li><a href="http://developer.chrome.com/trunk/apps/webview_tag.html">Webview Tag API</a> reference</li>
+<li><a href="http://developer.chrome.com/apps/app_external.html">Embed Content</a> tutorial</li>
+</ul>
+
+<h2 id="what_39_s_next_">What's next?</h2>
-<p>In <a href="app_codelab9_multipleviews.html">lab9_multipleviews</a>,
-you will see how an app can have multiple windows that talk to each other and the event page directly.</p>
+<p>In <a href="app_codelab_10_publishing.html">8 - Publish App</a>,
+we finish off with instructions on how to publish your app in the Chrome Web Store.</p>
diff --git a/chrome/common/extensions/docs/templates/articles/app_codelab9_multipleviews.html b/chrome/common/extensions/docs/templates/articles/app_codelab9_multipleviews.html
deleted file mode 100644
index 2e19cb0..0000000
--- a/chrome/common/extensions/docs/templates/articles/app_codelab9_multipleviews.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<h1 id="lab_9_multiple_views">Lab 9 - Multiple Views</h1>
-
-<p>Unlike standard web apps, a Chrome app has complete control of its windows. It can create any number of windows at arbitrary screen locations, control the window&#39;s look and feel, minimize, maximize and much more.</p>
-
-<p>In this lab, we will move the Drop area of our current application to another window. Here you can see how windows talk to each other and to the event page directly, synchronously, because they are all in the same thread.</p>
-
-<ol>
-<li><p>Let&#39;s adapt our code then. Start by removing the droptext <code>&lt;div&gt;</code> from <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab9_multipleviews/angularjs/index.html">index.html</a>.</p></li>
-<li><p>Create a new HTML with the drop area: <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab9_multipleviews/angularjs/droparea.html">droparea.html</a>
-<pre>
-&lt;html ng-app ng-csp&gt;
- &lt;head&gt;
- &lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
- &lt;script src=&quot;droparea.js&quot;&gt;&lt;/script&gt;
- &lt;link rel=&quot;stylesheet&quot; href=&quot;todo.css&quot;&gt;
- &lt;title&gt;File Drop&lt;/title&gt;
- &lt;/head&gt;
- &lt;body ng-controller=&quot;DropCtrl&quot; ng-class=&quot;dropClass&quot;&gt;
- &lt;h2&gt;Drop Area&lt;/h2&gt;
- &lt;div&gt;&#123;&#123;dropText&#125;&#125;&lt;/div&gt;
- &lt;/body&gt;
-&lt;/html&gt;
-</pre></p></li>
-<li><p>Move all drop-related functionality from <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab9_multipleviews/angularjs/controller.js">controller.js</a> to a new file, <a href="https://github.com/GoogleChrome/chrome-app-codelab/blob/master/lab9_multipleviews/angularjs/droparea.js">droparea.js</a>:
-<pre>
-function DropCtrl($scope) {
- // move here the variable initializations for defaultDropText and $scope.dropText
- // move here the methods dragOver, dragLeave and drop
-}
-</pre></p></li>
-<li><p>In the existing <code>controller.js</code>, add the call to create a new window:
-<pre>
-chrome.app.window.create(&#39;droparea.html&#39;,
- {id: &#39;dropArea&#39;, bounds: {width: 200, height: 200} },
- function(dropWin) {
- dropWin.contentWindow.$parentScope = $scope;
- });
-</pre></p></li>
-</ol>
-
-<p>And that&#39;s all. Thanks to the hierarchical scope support on Angular, the <code>DropCtrl</code> controller is a child of the <code>TodoCtrl</code> and inherits all the context of its parent.</p>
-
-<p>To test, open the app, right-click, and select Reload App. Move the top view to the right, and you can see the additional view.</p>
-
-<p class="note"><b>Note:</b> If you get stuck and want to see the app in action, go to <code>chrome://extensions</code>, load the unpacked <a href="app_codelab9_multipleviews.html">lab9_multipleviews</a>, and launch the app from a new tab.</p>
-
-<h1 id="takeaway_">Takeaway:</h1>
-
-<ul>
-<li>Web developers usually have a mindset of one-window-per-webapp.
-The Chrome app platform opens more possibilities for your creativity.
-A document editor, for example, can have one window per opened document, a more natural metaphor for native-like apps.</li>
-</ul>
-
-<h1 id="what_39_s_next_">What&#39;s next?</h1>
-
-<p>In <a href="app_codelab_10_publishing.html">lab_10_publishing</a>, we finish off with instructions on how to publish your app in the Chrome Web Store.</p>
diff --git a/chrome/common/extensions/docs/templates/articles/app_codelab_10_publishing.html b/chrome/common/extensions/docs/templates/articles/app_codelab_10_publishing.html
index ae35486..d9e4984 100644
--- a/chrome/common/extensions/docs/templates/articles/app_codelab_10_publishing.html
+++ b/chrome/common/extensions/docs/templates/articles/app_codelab_10_publishing.html
@@ -1,7 +1,7 @@
-<h1 id="lab_10_publishing">Lab 10 - Publishing</h1>
+<h1 id="lab_10_publishing">Publish App</h1>
<p>An app without users is just a piece of code. To get users, you need to distribute your application.
-All Chrome applications are distributed through the <a href="https://chrome.google.com/webstore">Chrome Web Store</a>.
+All Chrome packaged apps are distributed through the <a href="https://chrome.google.com/webstore">Chrome Web Store</a>.
For those not familiar with the store, it provides several benefits to users and developers.</p>
<p>For users:</p>
@@ -59,4 +59,3 @@ Just make sure it contains the <code>manifest.json</code>.</p>
<p><img src="{{static}}/images/codelab/publish.jpg" alt="Developer Dashboard Publish"></p>
-<p>Hint: if anyone wants to create a tool that lets users quickly create all the required assets, developers would sincerely appreciate.</p>
diff --git a/chrome/common/extensions/docs/templates/articles/develop_apps.html b/chrome/common/extensions/docs/templates/articles/develop_apps.html
index 44541d9..1afc18e 100644
--- a/chrome/common/extensions/docs/templates/articles/develop_apps.html
+++ b/chrome/common/extensions/docs/templates/articles/develop_apps.html
@@ -1,6 +1,5 @@
<h1>Before You Start</h1>
-
<p>
This documentation tells you how to write packaged apps.
All developers, however, should know that the new APIs
@@ -8,9 +7,6 @@ for packaged apps are being released as a developer preview.
This means that they are evolving daily,
and anything you read now might be different in the near future.
Please keep up to date with the API reference and documentation.
-If you hit any stumbling blocks,
-feedback is welcome at
-<a href="http://groups.google.com/a/chromium.org/group/chromium-apps">#chromium-apps</a>
</p>
<p class="caution">
@@ -21,29 +17,44 @@ will still work the way they always have,
but they won't have access to the new APIs.
</p>
-<h2 id="start">Where to start</h2>
+<h2 id="common">Common platform</h2>
<p>
-The <a href="about_apps.html">Getting Started</a> guide is a great place to start.
-It's fast reading; shouldn't take more than 10 minutes to read all three docs.
-After the Getting Started guide,
-decide what's most relevant to you.
-The <a href="app_lifecycle.html">Fundamentals</a> guide covers
-the details of the app and data lifecycle,
-or learn more about good app design
-by reading <a href="app_frameworks.html">MVC Architecture</a>.
-We've also got lots of sample code in our repository
-that is linked to directly from the documentation.
-</p>
-
-<p>
-If you're familiar with the Chrome extension docs,
-then the Reference docs should seem familiar.
Packaged apps and extensions share a common platform.
-They can access many of the same APIs,
+They can access many of the same APIs and
they have the same manifest and permissions format.
+If you're familiar with the
+<a href="http://developer.chrome.com/extensions/">Chrome Extension docs</a>,
+then the Reference docs should seem familiar.
Many of the reference docs are shared;
-we've filtered accessibility to docs that aren't shared.
+we've filtered accessibility to docs that aren't.
+</p>
+
+<h2 id="start">Where to start</h2>
+
+<ul>
+ <li>Read the
+ <a href="about_apps.html">Getting Started</a> guide.</li>
+ <li>Follow the
+ <a href="app_codelab.html">Todo App Codelab</a>.</li>
+ <li>Check out the
+ <a href="api_index.html">Chrome JavaScript APIs</a>.</li>
+ <li>Fork any and all
+ <a href="https://github.com/GoogleChrome/chrome-app-samples">chrome-app-samples</a> and make something of your own.</li>
+ <li>Watch the
+<a href="https://developers.google.com/live/chrome/">Chrome Apps GDL sessions</a>.</li>
+</ul>
+
+<h2 id="help">Send feedback!</h2>
+
+<p>
+For Chrome packaged apps to succeed,
+we need and want your feedback.
+You can enter feedback at the
+<a href="https://groups.google.com/a/chromium.org/group/chromium-apps">chromium-apps group</a>,
+file a bug at the
+<a href="http://crbug.com/new">official issue tracker</a>,
+or press "Send Feedback" at the bottom of every doc page.
</p>
-<p class="backtotop"><a href="#top">Back to top</a></p> \ No newline at end of file
+<p class="backtotop"><a href="#top">Back to top</a></p>
diff --git a/chrome/common/extensions/docs/templates/json/apps_sidenav.json b/chrome/common/extensions/docs/templates/json/apps_sidenav.json
index 67ffbfa..831d423 100644
--- a/chrome/common/extensions/docs/templates/json/apps_sidenav.json
+++ b/chrome/common/extensions/docs/templates/json/apps_sidenav.json
@@ -46,6 +46,49 @@
]
},
{
+ "title": "Learn with a Codelab",
+ "toggleable": true,
+ "items": [
+ {
+ "title": "About this Codelab",
+ "fileName": "app_codelab.html"
+ },
+ {
+ "title": "1 - Set Up Development Environment",
+ "fileName": "app_codelab1_setup.html"
+ },
+ {
+ "title": "2 - Create Basic App",
+ "fileName": "app_codelab2_basic.html"
+ },
+ {
+ "title": "3 - Create MVC",
+ "fileName": "app_codelab3_mvc.html"
+ },
+ {
+ "title": "4 - Save and Fetch Data",
+ "fileName": "app_codelab5_data.html"
+ },
+ {
+ "title": "5 - Manage App Lifecycle",
+ "fileName": "app_codelab6_lifecycle.html"
+ },
+
+ {
+ "title": "6 - Access User's Data",
+ "fileName": "app_codelab7_useridentification.html"
+ },
+ {
+ "title": "7 - Access Web Resources",
+ "fileName": "app_codelab8_webresources.html"
+ },
+ {
+ "title": "8 - Publish App",
+ "fileName": "app_codelab_10_publishing.html"
+ }
+ ]
+ },
+ {
"title": "Security & Privacy",
"toggleable": true,
"items": [
@@ -109,11 +152,11 @@
"title": "MVC Architecture",
"toggleable": true,
"items": [
- {
- "title": "About MVC Architecture",
- "fileName": "app_frameworks.html"
- },
- {
+ {
+ "title": "About MVC Architecture",
+ "fileName": "app_frameworks.html"
+ },
+ {
"title": "Build Apps with AngularJS",
"fileName": "angular_framework.html"
},
diff --git a/chrome/common/extensions/docs/templates/public/apps/app_codelab4_testing.html b/chrome/common/extensions/docs/templates/public/apps/app_codelab4_testing.html
deleted file mode 100644
index 0e27c17..0000000
--- a/chrome/common/extensions/docs/templates/public/apps/app_codelab4_testing.html
+++ /dev/null
@@ -1 +0,0 @@
-{{+partials.standard_apps_article article:intros.app_codelab4_testing}}
diff --git a/chrome/common/extensions/docs/templates/public/apps/app_codelab9_multipleviews.html b/chrome/common/extensions/docs/templates/public/apps/app_codelab9_multipleviews.html
deleted file mode 100644
index b535c32..0000000
--- a/chrome/common/extensions/docs/templates/public/apps/app_codelab9_multipleviews.html
+++ /dev/null
@@ -1 +0,0 @@
-{{+partials.standard_apps_article article:intros.app_codelab9_multipleviews}}