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

Unified Diff: chrome/common/extensions/docs/templates/articles/app_codelab3_mvc.html

Issue 13248004: Cleaning up apps codelab (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/common/extensions/docs/templates/articles/app_codelab3_mvc.html
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 941f54ff0e6422968348a924a73373f71e4b347b..4df297c8a448313cf756d5f4ba12dedda8ac1cd3 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>

Powered by Google App Engine
This is Rietveld 408576698