| 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 00212c923ddef04c1619e8df9690a1e6c12b8d90..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
|
| --- a/chrome/common/extensions/docs/templates/articles/app_codelab3_mvc.html
|
| +++ b/chrome/common/extensions/docs/templates/articles/app_codelab3_mvc.html
|
| @@ -1,428 +0,0 @@
|
| -<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>There are several frameworks to help apply
|
| -<a href="app_frameworks">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.
|
| -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>
|
| -
|
| -<p class="note"><b>Note:</b>
|
| -Chrome Apps don't enforce any specific framework or programming style.
|
| -</p>
|
| -
|
| -<h2 id="simple">Create a simple view</h2>
|
| -
|
| -<h3 id="basic-mvc">Add MVC basics</h3>
|
| -
|
| -<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>
|
| -
|
| -<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>
|
| -
|
| -<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="angular">Angular</header>
|
| - <header tabindex="0" data-value="js">JavaScript</header>
|
| -
|
| - <content>
|
| - <pre data-filename="index.html">
|
| -<!doctype html>
|
| -<html ng-app ng-csp>
|
| - <head>
|
| - <script src="angular.min.js"></script>
|
| - <link rel="stylesheet" href="todo.css">
|
| - </head>
|
| - <body>
|
| - <h2>Todo</h2>
|
| - <div>
|
| - <ul>
|
| - <li>
|
| - {{todoText}}
|
| - </li>
|
| - </ul>
|
| - <input type="text" ng-model="todoText" size="30"
|
| - placeholder="type your todo here">
|
| - </div>
|
| - </body>
|
| -</html>
|
| - </pre>
|
| - </content>
|
| - <content>
|
| - <pre data-filename="index.html">
|
| -<!doctype html>
|
| -<html>
|
| - <head>
|
| - <link rel="stylesheet" href="todo.css">
|
| - </head>
|
| - <body>
|
| - <h2>Todo</h2>
|
| - <div>
|
| - <ul>
|
| - <li id="todoText">
|
| - </li>
|
| - </ul>
|
| - <input type="text" id="newTodo" size="30"
|
| - placeholder="type your todo here">
|
| - </div>
|
| - <script src="controller.js"></script>
|
| - </body>
|
| -</html>
|
| - </pre>
|
| - </content>
|
| -</tabs>
|
| -
|
| -<p class="note"><b>Note:</b> The <code>ng-csp</code> directive tells Angular to run in a "content security mode". You don't need this directive when using Angular v1.1.0+. We'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 data-filename="todo.css">
|
| -body {
|
| - font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
|
| -}
|
| -
|
| -ul {
|
| - list-style: none;
|
| -}
|
| -
|
| -button, input[type=submit] {
|
| - background-color: #0074CC;
|
| - background-image: linear-gradient(top, #08C, #05C);
|
| - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
| - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
| - color: white;
|
| -}
|
| -
|
| -.done-true {
|
| - text-decoration: line-through;
|
| - color: grey;
|
| -}
|
| -</pre>
|
| -
|
| -<h3 id="check1">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="real-todo">Create real Todo list</h2>
|
| -
|
| -<p>
|
| -The previous sample, although interesting, is not exactly useful.
|
| -Let'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 data-filename="controller.js">
|
| -function TodoCtrl($scope) {
|
| - $scope.todos = [
|
| - {text:'learn angular', done:true},
|
| - {text:'build an angular Chrome packaged app', done:false}];
|
| -
|
| -$scope.addTodo = function() {
|
| - $scope.todos.push({text:$scope.todoText, done:false});
|
| - $scope.todoText = '';
|
| - };
|
| -
|
| -$scope.remaining = function() {
|
| - var count = 0;
|
| - angular.forEach($scope.todos, function(todo) {
|
| - count += todo.done ? 0 : 1;
|
| - });
|
| - return count;
|
| - };
|
| -
|
| -$scope.archive = function() {
|
| - var oldTodos = $scope.todos;
|
| - $scope.todos = [];
|
| - angular.forEach(oldTodos, function(todo) {
|
| - if (!todo.done) $scope.todos.push(todo);
|
| - });
|
| - };
|
| -}
|
| - </pre>
|
| - </content>
|
| - <content>
|
| - <pre data-filename="controller.js">
|
| -(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 > [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 data-filename="index.html">
|
| -<html ng-app ng-csp>
|
| - <head>
|
| - <script src="angular.min.js"></script>
|
| - <script src="controller.js"></script>
|
| - <link rel="stylesheet" href="todo.css">
|
| - </head>
|
| - <body>
|
| - <h2>Todo</h2>
|
| - <div ng-controller="TodoCtrl">
|
| - <span>{{remaining()}} of {{todos.length}} remaining</span>
|
| - [ <a href="" ng-click="archive()">archive</a> ]
|
| - <ul>
|
| - <li ng-repeat="todo in todos">
|
| - <input type="checkbox" ng-model="todo.done">
|
| - <span class="done-{{todo.done}}">{{todo.text}}</span>
|
| - </li>
|
| - </ul>
|
| - <form ng-submit="addTodo()">
|
| - <input type="text" ng-model="todoText" size="30"
|
| - placeholder="add new todo here">
|
| - <input class="btn-primary" type="submit" value="add">
|
| - </form>
|
| - </div>
|
| - </body>
|
| -</html>
|
| - </pre>
|
| - </content>
|
| - <content>
|
| - <pre data-filename="index.html">
|
| -<!doctype html>
|
| -<html>
|
| - <head>
|
| - <link rel="stylesheet" href="todo.css">
|
| - </head>
|
| - <body>
|
| - <h2>Todo</h2>
|
| - <div>
|
| - <span><span id="remaining"></span> of <span id="length"></span> remaining</span>
|
| - [ <a href="" id="archive">archive</a> ]
|
| - <ul class="unstyled" id="list">
|
| - </ul>
|
| - <form>
|
| - <input type="text" size="30"
|
| - placeholder="add new todo here">
|
| - <input class="btn-primary" type="submit" value="add">
|
| - </form>
|
| - </div>
|
| -
|
| - <!-- poor man's template -->
|
| - <div id="templates" style="display: none;">
|
| - <li data-name="list">
|
| - <input type="checkbox">
|
| - <span></span>
|
| - </li>
|
| - </div>
|
| -
|
| - <script src="controller.js"></script>
|
| - </body>
|
| -</html>
|
| - </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>
|
| -
|
| -<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="offline_apps">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>
|
| -</ul>
|
| -
|
| -<h2 id="you_should_also_read">You should also read</h2>
|
| -
|
| -<ul>
|
| -<li><p><a href="angular_framework">Build Apps with AngularJS</a> tutorial</p></li>
|
| -<li><p><a href="http://angularjs.org/">AngularJS Todo</a> tutorial</p></li>
|
| -</ul>
|
| -
|
| -<h2 id="what_39_s_next_">What's next?</h2>
|
| -
|
| -<p>In <a href="app_codelab5_data">4 - Save and Fetch Data</a>,
|
| -you will modify your Todo list app so that Todo items are saved.</p>
|
|
|