summaryrefslogtreecommitdiffstats
path: root/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js')
-rw-r--r--third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/app.js16
-rw-r--r--third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/backbone.sync.js118
-rw-r--r--third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/collections/todos.js39
-rw-r--r--third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/models/todo.js26
-rw-r--r--third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/routers/router.js26
-rw-r--r--third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/views/app-view.js131
-rw-r--r--third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/views/todo-view.js123
7 files changed, 479 insertions, 0 deletions
diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/app.js b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/app.js
new file mode 100644
index 0000000000..4c4bde363a
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/app.js
@@ -0,0 +1,16 @@
+/*global $ */
+/*jshint unused:false */
+var app = app || {};
+var ENTER_KEY = 13;
+var ESC_KEY = 27;
+
+$(function () {
+ 'use strict';
+
+ // kick things off by creating the `App`
+ window.appView = new app.AppView();
+
+ var dummyNodeToNotifyAppIsReady = document.createElement('div');
+ dummyNodeToNotifyAppIsReady.id = 'appIsReady';
+ document.body.appendChild(dummyNodeToNotifyAppIsReady);
+});
diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/backbone.sync.js b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/backbone.sync.js
new file mode 100644
index 0000000000..f8e3c67edd
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/backbone.sync.js
@@ -0,0 +1,118 @@
+Backbone.sync = function(method, model, options) {
+
+ // we need to make sure we initialize a store, in this case
+ // we will just use a JS object.
+ var cache = {};
+
+ // The size will be primarily used to assign ids to newly
+ // created models. Each time a new model is created, the size
+ // will be incremented.
+ var size = 0;
+
+ // since we need to create a store for the models/collections
+ // we are actually going to invoke the outer function which will
+ // return this function below as the Backbone.sync that will
+ // actually be used.
+ return function(method, model, options) {
+
+ // create a new deferred object. standard sync returns the $.ajax
+ // request, which internally returns a deferred. It's important to
+ // do this so that people can chain on fetch using the standard .then/.fail
+ // syntax, rather than just the success/error callbacks.
+ var deferred = $.Deferred();
+
+ // when creating a new model...
+ if (method === "create") {
+
+ // first assign it an id. The server would traditionally do this.
+ model.id = size;
+ // store it in our cache
+ cache[model.id] = model;
+ // make sure we increment the number of models we now have.
+ size += 1;
+
+ // if a success callback was provided, execute it.
+ if (options.success) {
+ options.success(model, model.toJSON(), options);
+ }
+
+ // resolve the deferred.
+ deferred.resolve(model);
+
+ // we are updating a model
+ } else if (method === "update") {
+
+ // as long as the model actually exists in our store
+ if (cache[model.id]) {
+
+ // overwrite what is currently in the store with this model.
+ cache[model.id] = model;
+
+ // if a success callback was provided, execute it.
+ if (options.success) {
+ options.success(model, model.toJSON(), options);
+ }
+
+ deferred.resolve(model);
+
+ // if this model doesn't exist yet, we can't update it
+ } else {
+
+ if (options.error) {
+ options.error(model, "Model not found");
+ }
+ deferred.reject(model);
+ }
+
+ // if we're trying to read a model...
+ } else if (method === "read") {
+
+ // as long as it exists
+ if (cache[model.id]) {
+
+ // if a success callback was provided, execute it.
+ if (options.success) {
+ options.success(model, cache[model.id].toJSON(), options);
+ }
+
+ // resolve
+ deferred.resolve(model);
+ } else {
+ if (options.error) {
+ options.error(model, "Model not found");
+ }
+ deferred.reject(model);
+ }
+
+ // if we're deleting a model...
+ } else if (method === "delete") {
+
+ // first make sure it exists in the cache
+ if (cache[model.id]) {
+
+ // then remove it from the cache
+ delete cache[model.id];
+
+ // and trigger the success callback. Note we're passing an
+ // empty object as the second argument, because a deletion
+ // would result in an empty return from the server.
+ if (options.success) {
+ options.success(model, {}, options);
+ }
+
+ // resolve the deferred
+ deferred.resolve(model);
+
+ // otherwise, error that the model doesn't exist.
+ } else {
+ if (options.error) {
+ options.error(model, "Model not found");
+ }
+ deferred.reject(model);
+ }
+ }
+
+ return deferred.promise();
+ }
+
+}(); \ No newline at end of file
diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/collections/todos.js b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/collections/todos.js
new file mode 100644
index 0000000000..f8f5d31113
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/collections/todos.js
@@ -0,0 +1,39 @@
+/*global Backbone */
+var app = app || {};
+
+(function () {
+ 'use strict';
+
+ // Todo Collection
+ // ---------------
+
+
+ var Todos = Backbone.Collection.extend({
+ // Reference to this collection's model.
+ model: app.Todo,
+
+ // Save all of the todo items under this example's namespace.
+
+ // Filter down the list of all todo items that are finished.
+ completed: function () {
+ return this.where({completed: true});
+ },
+
+ // Filter down the list to only todo items that are still not finished.
+ remaining: function () {
+ return this.where({completed: false});
+ },
+
+ // We keep the Todos in sequential order, despite being saved by unordered
+ // GUID in the database. This generates the next order number for new items.
+ nextOrder: function () {
+ return this.length ? this.last().get('order') + 1 : 1;
+ },
+
+ // Todos are sorted by their original insertion order.
+ comparator: 'order'
+ });
+
+ // Create our global collection of **Todos**.
+ app.todos = new Todos();
+})();
diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/models/todo.js b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/models/todo.js
new file mode 100644
index 0000000000..4f3fde3e26
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/models/todo.js
@@ -0,0 +1,26 @@
+/*global Backbone */
+var app = app || {};
+
+(function () {
+ 'use strict';
+
+ // Todo Model
+ // ----------
+
+ // Our basic **Todo** model has `title`, `order`, and `completed` attributes.
+ app.Todo = Backbone.Model.extend({
+ // Default attributes for the todo
+ // and ensure that each todo created has `title` and `completed` keys.
+ defaults: {
+ title: '',
+ completed: false
+ },
+
+ // Toggle the `completed` state of this todo item.
+ toggle: function () {
+ this.save({
+ completed: !this.get('completed')
+ });
+ }
+ });
+})();
diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/routers/router.js b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/routers/router.js
new file mode 100644
index 0000000000..5937e9ff03
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/routers/router.js
@@ -0,0 +1,26 @@
+/*global Backbone */
+var app = app || {};
+
+(function () {
+ 'use strict';
+
+ // Todo Router
+ // ----------
+ var TodoRouter = Backbone.Router.extend({
+ routes: {
+ '*filter': 'setFilter'
+ },
+
+ setFilter: function (param) {
+ // Set the current filter to be used
+ app.TodoFilter = param || '';
+
+ // Trigger a collection filter event, causing hiding/unhiding
+ // of Todo view items
+ app.todos.trigger('filter');
+ }
+ });
+
+ app.TodoRouter = new TodoRouter();
+ Backbone.history.start();
+})();
diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/views/app-view.js b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/views/app-view.js
new file mode 100644
index 0000000000..34252fc9cb
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/views/app-view.js
@@ -0,0 +1,131 @@
+/*global Backbone, jQuery, _, ENTER_KEY */
+var app = app || {};
+
+(function ($) {
+ 'use strict';
+
+ // The Application
+ // ---------------
+
+ // Our overall **AppView** is the top-level piece of UI.
+ app.AppView = Backbone.View.extend({
+
+ // Instead of generating a new element, bind to the existing skeleton of
+ // the App already present in the HTML.
+ el: '.todoapp',
+
+ // Our template for the line of statistics at the bottom of the app.
+ statsTemplate: _.template($('#stats-template').html()),
+
+ // Delegated events for creating new items, and clearing completed ones.
+ events: {
+ 'keypress .new-todo': 'createOnEnter',
+ 'click .clear-completed': 'clearCompleted',
+ 'click .toggle-all': 'toggleAllComplete'
+ },
+
+ // At initialization we bind to the relevant events on the `Todos`
+ // collection, when items are added or changed. Kick things off by
+ // loading any preexisting todos that might be saved in *localStorage*.
+ initialize: function () {
+ this.allCheckbox = this.$('.toggle-all')[0];
+ this.$input = this.$('.new-todo');
+ this.$footer = this.$('.footer');
+ this.$main = this.$('.main');
+ this.$list = $('.todo-list');
+
+ this.listenTo(app.todos, 'add', this.addOne);
+ this.listenTo(app.todos, 'reset', this.addAll);
+ this.listenTo(app.todos, 'change:completed', this.filterOne);
+ this.listenTo(app.todos, 'filter', this.filterAll);
+ this.listenTo(app.todos, 'all', _.debounce(this.render, 0));
+
+ // Suppresses 'add' events with {reset: true} and prevents the app view
+ // from being re-rendered for every model. Only renders when the 'reset'
+ // event is triggered at the end of the fetch.
+ app.todos.fetch({reset: true});
+ },
+
+ // Re-rendering the App just means refreshing the statistics -- the rest
+ // of the app doesn't change.
+ render: function () {
+ var completed = app.todos.completed().length;
+ var remaining = app.todos.remaining().length;
+
+ if (app.todos.length) {
+ this.$main.show();
+ this.$footer.show();
+
+ this.$footer.html(this.statsTemplate({
+ completed: completed,
+ remaining: remaining
+ }));
+
+ this.$('.filters li a')
+ .removeClass('selected')
+ .filter('[href="#/' + (app.TodoFilter || '') + '"]')
+ .addClass('selected');
+ } else {
+ this.$main.hide();
+ this.$footer.hide();
+ }
+
+ this.allCheckbox.checked = !remaining;
+ },
+
+ // Add a single todo item to the list by creating a view for it, and
+ // appending its element to the `<ul>`.
+ addOne: function (todo) {
+ var view = new app.TodoView({ model: todo });
+ this.$list.append(view.render().el);
+ },
+
+ // Add all items in the **Todos** collection at once.
+ addAll: function () {
+ this.$list.html('');
+ app.todos.each(this.addOne, this);
+ },
+
+ filterOne: function (todo) {
+ todo.trigger('visible');
+ },
+
+ filterAll: function () {
+ app.todos.each(this.filterOne, this);
+ },
+
+ // Generate the attributes for a new Todo item.
+ newAttributes: function () {
+ return {
+ title: this.$input.val().trim(),
+ order: app.todos.nextOrder(),
+ completed: false
+ };
+ },
+
+ // If you hit return in the main input field, create new **Todo** model,
+ // persisting it to *memory*.
+ createOnEnter: function (e) {
+ if (e.which === ENTER_KEY && this.$input.val().trim()) {
+ app.todos.create(this.newAttributes());
+ this.$input.val('');
+ }
+ },
+
+ // Clear all completed todo items, destroying their models.
+ clearCompleted: function () {
+ _.invoke(app.todos.completed(), 'destroy');
+ return false;
+ },
+
+ toggleAllComplete: function () {
+ var completed = this.allCheckbox.checked;
+
+ app.todos.each(function (todo) {
+ todo.save({
+ completed: completed
+ });
+ });
+ }
+ });
+})(jQuery);
diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/views/todo-view.js b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/views/todo-view.js
new file mode 100644
index 0000000000..bb3b4043ff
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/backbone/js/views/todo-view.js
@@ -0,0 +1,123 @@
+/*global Backbone, jQuery, _, ENTER_KEY, ESC_KEY */
+var app = app || {};
+
+(function ($) {
+ 'use strict';
+
+ // Todo Item View
+ // --------------
+
+ // The DOM element for a todo item...
+ app.TodoView = Backbone.View.extend({
+ //... is a list tag.
+ tagName: 'li',
+
+ // Cache the template function for a single item.
+ template: _.template($('#item-template').html()),
+
+ // The DOM events specific to an item.
+ events: {
+ 'click .toggle': 'toggleCompleted',
+ 'dblclick label': 'edit',
+ 'click .destroy': 'clear',
+ 'keypress .edit': 'updateOnEnter',
+ 'keydown .edit': 'revertOnEscape',
+ 'blur .edit': 'close'
+ },
+
+ // The TodoView listens for changes to its model, re-rendering. Since
+ // there's a one-to-one correspondence between a **Todo** and a
+ // **TodoView** in this app, we set a direct reference on the model for
+ // convenience.
+ initialize: function () {
+ this.listenTo(this.model, 'change', this.render);
+ this.listenTo(this.model, 'destroy', this.remove);
+ this.listenTo(this.model, 'visible', this.toggleVisible);
+ },
+
+ // Re-render the titles of the todo item.
+ render: function () {
+ // Backbone LocalStorage is adding `id` attribute instantly after
+ // creating a model. This causes our TodoView to render twice. Once
+ // after creating a model and once on `id` change. We want to
+ // filter out the second redundant render, which is caused by this
+ // `id` change. It's known Backbone LocalStorage bug, therefore
+ // we've to create a workaround.
+ // https://github.com/tastejs/todomvc/issues/469
+ if (this.model.changed.id !== undefined) {
+ return;
+ }
+
+ this.$el.html(this.template(this.model.toJSON()));
+ this.$el.toggleClass('completed', this.model.get('completed'));
+ this.toggleVisible();
+ this.$input = this.$('.edit');
+ return this;
+ },
+
+ toggleVisible: function () {
+ this.$el.toggleClass('hidden', this.isHidden());
+ },
+
+ isHidden: function () {
+ return this.model.get('completed') ?
+ app.TodoFilter === 'active' :
+ app.TodoFilter === 'completed';
+ },
+
+ // Toggle the `"completed"` state of the model.
+ toggleCompleted: function () {
+ this.model.toggle();
+ },
+
+ // Switch this view into `"editing"` mode, displaying the input field.
+ edit: function () {
+ this.$el.addClass('editing');
+ this.$input.focus();
+ },
+
+ // Close the `"editing"` mode, saving changes to the todo.
+ close: function () {
+ var value = this.$input.val();
+ var trimmedValue = value.trim();
+
+ // We don't want to handle blur events from an item that is no
+ // longer being edited. Relying on the CSS class here has the
+ // benefit of us not having to maintain state in the DOM and the
+ // JavaScript logic.
+ if (!this.$el.hasClass('editing')) {
+ return;
+ }
+
+ if (trimmedValue) {
+ this.model.save({ title: trimmedValue });
+ } else {
+ this.clear();
+ }
+
+ this.$el.removeClass('editing');
+ },
+
+ // If you hit `enter`, we're through editing the item.
+ updateOnEnter: function (e) {
+ if (e.which === ENTER_KEY) {
+ this.close();
+ }
+ },
+
+ // If you're pressing `escape` we revert your change by simply leaving
+ // the `editing` state.
+ revertOnEscape: function (e) {
+ if (e.which === ESC_KEY) {
+ this.$el.removeClass('editing');
+ // Also reset the hidden input back to the original value.
+ this.$input.val(this.model.get('title'));
+ }
+ },
+
+ // Remove the item, destroy the model from *localStorage* and delete its view.
+ clear: function () {
+ this.model.destroy();
+ }
+ });
+})(jQuery);