From 70422ecaae13f187aa05a23c7819571d9d79360b Mon Sep 17 00:00:00 2001 From: stevenpsmith Date: Thu, 15 Dec 2011 14:32:18 -0500 Subject: [PATCH 01/13] adding collection sort --- js/app.js | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/js/app.js b/js/app.js index d7e098a..3fca4e7 100644 --- a/js/app.js +++ b/js/app.js @@ -10,7 +10,11 @@ var exercise = {}; exercise.Activities = Backbone.Collection.extend({ model: exercise.Activity, - url: "exercise.json" + url: "exercise.json", + comparator: function(activity){ + var date = new Date(activity.get('date')); + return date.getTime(); + } }); exercise.ActivityListView = Backbone.View.extend({ @@ -19,7 +23,7 @@ var exercise = {}; attributes: {"data-role": 'listview'}, initialize: function() { - this.collection.bind('add', this.add, this); + this.collection.bind('add', this.render, this); this.template = _.template($('#activity-list-item-template').html()); }, @@ -36,14 +40,6 @@ var exercise = {}; container.html($(this.el)); container.trigger('create'); return this; - }, - - add: function(item) { - var activitiesList = $('#activities-list'), - template = this.template; - - activitiesList.append(template(item.toJSON())); - activitiesList.listview('refresh'); } }); From 62a5e0b0111e4ab75329c45e438a76ba8b47e94f Mon Sep 17 00:00:00 2001 From: stevenpsmith Date: Mon, 9 Jan 2012 09:13:24 -0500 Subject: [PATCH 02/13] updating readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 13d2632..920bd12 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ This is an example project to support the following blog posts: -* insert intro url here when intro pulished -* insert sort url here +* http://blog.chariotsolutions.com/2011/12/introduction-to-backbonejs-with-jquery.html +* http://blog.chariotsolutions.com/2012/01/sorting-collections-with-backbonejs-and.html This repo has branches that represent the code for various blog posts. Here is a mapping: From 160503205a963385b344541c30e65cb91d6a035a Mon Sep 17 00:00:00 2001 From: stevenpsmith Date: Thu, 19 Jan 2012 14:37:21 -0500 Subject: [PATCH 03/13] adding template and jqm page for activity details --- index.html | 20 ++++++++++++++++++++ js/app.js | 17 +++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/index.html b/index.html index 39e4ee4..b2cf28b 100644 --- a/index.html +++ b/index.html @@ -18,6 +18,16 @@
  • <%= date %> - <%= type %>
  • + + @@ -33,5 +43,15 @@

    Activities

    +
    +
    +

    Activitie Details

    + Edit +
    +
    + +
    +
    + diff --git a/js/app.js b/js/app.js index 3fca4e7..f0f2e21 100644 --- a/js/app.js +++ b/js/app.js @@ -43,6 +43,23 @@ var exercise = {}; } }); + exercise.ActivityDetailsView = Backbone.View.extend({ + //since this template will render inside a div, we don't need to specify a tagname + initialize: function() { + this.template = _.template($('#activity-details-template').html()); + }, + + render: function() { + var container = this.options.viewContainer, + activity = this.model, + renderedContent = this.template(this.model.toJSON()); + + container.html(renderedContent); +// container.trigger('create'); + return this; + } + }); + exercise.initData = function(){ exercise.activities = new exercise.Activities(); exercise.activities.fetch({async: false}); // use async false to have the app wait for data before rendering the list From 40ee60ca6892558c2a70ccd99bfb87d21e26d818 Mon Sep 17 00:00:00 2001 From: stevenpsmith Date: Fri, 20 Jan 2012 11:37:06 -0500 Subject: [PATCH 04/13] updating layouts; passing id to details screen --- index.html | 22 +++++++++++----------- js/app.js | 22 ++++++++++++++++++++-- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/index.html b/index.html index b2cf28b..6a2ec78 100644 --- a/index.html +++ b/index.html @@ -20,12 +20,12 @@ @@ -36,19 +36,19 @@

    <%= type %>

    Activities

    - Add + Add
    -
    +
    -

    Activitie Details

    - Edit + Edit +

    Activities Details

    -
    +
    diff --git a/js/app.js b/js/app.js index f0f2e21..b34eeb2 100644 --- a/js/app.js +++ b/js/app.js @@ -35,7 +35,14 @@ var exercise = {}; $(this.el).empty(); activities.each(function(activity){ - listView.append(template(activity.toJSON())); + var renderedItem = template(activity.toJSON()), + $renderedItem = $(renderedItem); //convert the html into an jQuery object + $renderedItem.jqmData('activityId', activity.get('id')); //set the data on it for use in the click event + $renderedItem.bind('click', function(){ + //set the activity id on the page element for use in the details pagebeforeshow event + $('#activity-details').jqmData('activityId', $(this).jqmData('activityId')); //'this' represents the element being clicked + }); + listView.append($renderedItem); }); container.html($(this.el)); container.trigger('create'); @@ -55,7 +62,7 @@ var exercise = {}; renderedContent = this.template(this.model.toJSON()); container.html(renderedContent); -// container.trigger('create'); + container.trigger('create'); return this; } }); @@ -81,4 +88,15 @@ $('#add-button').live('click', function(){ date = (today.getMonth() + 1) + "/" + today.getDate() + "/" + today.getFullYear(); exercise.activities.add({id: 6, date: date, type: 'Walk', distance: '2 miles', comments: 'Wow...that was easy.'}); +}); + +$('#activity-details').live('pagebeforeshow', function(){ + console.log('activityId: ' + $('#activity-details').jqmData('activityId')); + var activitiesDetailsContainer = $('#activity-details').find(":jqmData(role='content')"), + activityDetailsView, + activityId = $('#activity-details').jqmData('activityId'), + activityModel = exercise.activities.get(activityId); + + activityDetailsView = new exercise.ActivityDetailsView({model: activityModel, viewContainer: activitiesDetailsContainer}); + activityDetailsView.render(); }); \ No newline at end of file From e11762f6e1e91168ff9b042b6b261e009295626f Mon Sep 17 00:00:00 2001 From: stevenpsmith Date: Wed, 25 Jan 2012 13:19:38 -0500 Subject: [PATCH 05/13] fixing spelling error --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 6a2ec78..60d3b3e 100644 --- a/index.html +++ b/index.html @@ -46,7 +46,7 @@

    Activities

    Edit -

    Activities Details

    +

    Activity Details

    From 8a0e931602fc73b7bde148c5870ad596b4a6e90e Mon Sep 17 00:00:00 2001 From: stevenpsmith Date: Mon, 30 Jan 2012 10:15:29 -0500 Subject: [PATCH 06/13] fixing sloppy HTML --- index.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index 60d3b3e..9e7b5b1 100644 --- a/index.html +++ b/index.html @@ -21,10 +21,10 @@ From 0f8cc05a17a1537c3ab38f7d4a836dcabed4f192 Mon Sep 17 00:00:00 2001 From: stevenpsmith Date: Wed, 15 Feb 2012 16:17:00 -0500 Subject: [PATCH 07/13] adding new activity code --- index.html | 39 +++++++++++++++++++++++++++++++++++++-- js/app.js | 34 ++++++++++++++++++++++++++++++---- style/exercise.css | 19 +++++++++++++++++++ 3 files changed, 86 insertions(+), 6 deletions(-) create mode 100644 style/exercise.css diff --git a/index.html b/index.html index 9e7b5b1..a6f4ad1 100644 --- a/index.html +++ b/index.html @@ -4,6 +4,7 @@ Exercise + @@ -18,7 +19,7 @@
  • <%= date %> - <%= type %>
  • - + + @@ -36,7 +60,7 @@

    <%= type %>

    Activities

    - Add + Add
    @@ -53,5 +77,16 @@

    Activity Details

    +
    +
    + Save +

    New Activity

    +
    +
    + +
    +
    +
    + diff --git a/js/app.js b/js/app.js index b34eeb2..a9f31be 100644 --- a/js/app.js +++ b/js/app.js @@ -6,6 +6,13 @@ var exercise = {}; (function($){ exercise.Activity = Backbone.Model.extend({ + defaults: { + date: '', + type: '', + distance: '', + comments: '', + minutes: '' + } }); exercise.Activities = Backbone.Collection.extend({ @@ -67,6 +74,24 @@ var exercise = {}; } }); + exercise.ActivityFormView = Backbone.View.extend({ + //since this template will render inside a div, we don't need to specify a tagname, but we do want the fieldcontain + attributes: {"data-role": 'listview'}, + + initialize: function() { + this.template = _.template($('#activity-form-template').html()); + }, + + render: function() { + var container = this.options.viewContainer, + renderedContent = this.template(this.model.toJSON()); + + container.html(renderedContent); + container.trigger('create'); + return this; + } + }); + exercise.initData = function(){ exercise.activities = new exercise.Activities(); exercise.activities.fetch({async: false}); // use async false to have the app wait for data before rendering the list @@ -83,11 +108,12 @@ $('#activities').live('pageinit', function(event){ }); $('#add-button').live('click', function(){ - var today = new Date(), - date; + var activity = new exercise.Activity(), + activityForm = $('#activity-form-form'), + activityFormView; - date = (today.getMonth() + 1) + "/" + today.getDate() + "/" + today.getFullYear(); - exercise.activities.add({id: 6, date: date, type: 'Walk', distance: '2 miles', comments: 'Wow...that was easy.'}); + activityFormView = new exercise.ActivityFormView({model: activity, viewContainer: activityForm}); + activityFormView.render(); }); $('#activity-details').live('pagebeforeshow', function(){ diff --git a/style/exercise.css b/style/exercise.css new file mode 100644 index 0000000..8404f3e --- /dev/null +++ b/style/exercise.css @@ -0,0 +1,19 @@ +input.ui-input-text { + vertical-align: top; + display: inline-block; + width: 60%; +} + +label.ui-input-text, label.ui-select { + margin: 0; + padding: 0.4em; + vertical-align: middle; + display: inline-block; + width: 25%; + clear:both; +} + +div.ui-select { + width: 60%; + display: inline-block; +} \ No newline at end of file From 78a45c19fea453b7415461128a9b31ee856512a5 Mon Sep 17 00:00:00 2001 From: stevenpsmith Date: Fri, 17 Feb 2012 15:57:19 -0500 Subject: [PATCH 08/13] adding input type date handling --- index.html | 14 +++++++----- js/app.js | 55 ++++++++++++++++++++++++++++++++++++++++++++-- style/exercise.css | 4 ++++ 3 files changed, 66 insertions(+), 7 deletions(-) diff --git a/index.html b/index.html index a6f4ad1..49f13ee 100644 --- a/index.html +++ b/index.html @@ -16,13 +16,13 @@ @@ -69,7 +73,7 @@

    Activities

    - Edit + Edit

    Activity Details

    diff --git a/js/app.js b/js/app.js index a9f31be..456161d 100644 --- a/js/app.js +++ b/js/app.js @@ -4,23 +4,64 @@ var exercise = {}; (function($){ - exercise.Activity = Backbone.Model.extend({ defaults: { - date: '', + date: new Date(), type: '', distance: '', comments: '', minutes: '' + }, + + dateInputType: function(){ + return exercise.formatDate(this.get('date'), "yyyy-mm-dd"); + }, + + displayDate: function(){ + return exercise.formatDate(this.get('date'), "mm/dd/yyyy"); + }, + + toJSON: function(){ + var json = Backbone.Model.prototype.toJSON.call(this); + return _.extend(json, {dateInputType : this.dateInputType(), displayDate: this.displayDate()}); } }); + exercise.formatDate = function(date, formatString){ + var yyyy, month, mm, day, dd, formatedDate; + + if (date instanceof Date){ + yyyy = date.getFullYear(); + month = date.getMonth() + 1; + mm = month < 10 ? "0" + month : month; + day = date.getDate(); + dd = day < 10 ? "0" + day : day; + + formatedDate = formatString.replace(/yyyy/i, yyyy); + formatedDate = formatedDate.replace(/mm/i, mm); + formatedDate = formatedDate.replace(/dd/i, dd); + }else{ + formatedDate = ""; + } + + return formatedDate; + }; + exercise.Activities = Backbone.Collection.extend({ model: exercise.Activity, url: "exercise.json", comparator: function(activity){ var date = new Date(activity.get('date')); return date.getTime(); + }, + + parse: function(response){ + var fixedDate = []; + _.each(response, function(item){ + var stringDate = item.date; + item.date = new Date(stringDate); //https://github.com/jquery/jquery-mobile/issues/2755 + }); + return response; } }); @@ -125,4 +166,14 @@ $('#activity-details').live('pagebeforeshow', function(){ activityDetailsView = new exercise.ActivityDetailsView({model: activityModel, viewContainer: activitiesDetailsContainer}); activityDetailsView.render(); +}); + +$('#edit-activity-button').live('click', function() { + var activityId = $('#activity-details').jqmData('activityId'), + activityModel = exercise.activities.get(activityId), + activityForm = $('#activity-form-form'), + activityFormView; + + activityFormView = new exercise.ActivityFormView({model: activityModel, viewContainer: activityForm}); + activityFormView.render(); }); \ No newline at end of file diff --git a/style/exercise.css b/style/exercise.css index 8404f3e..b12f3b2 100644 --- a/style/exercise.css +++ b/style/exercise.css @@ -4,6 +4,10 @@ input.ui-input-text { width: 60%; } +textarea.ui-input-text { + width: 90% !important; +} + label.ui-input-text, label.ui-select { margin: 0; padding: 0.4em; From b9eb39dbcc4e192b5dd1343839a0832bfc4812dc Mon Sep 17 00:00:00 2001 From: stevenpsmith Date: Mon, 20 Feb 2012 15:51:44 -0500 Subject: [PATCH 09/13] support for save --- index.html | 3 +- js/app.js | 142 +++++++++++++++++++++++++++------------- js/vendor/formparams.js | 111 +++++++++++++++++++++++++++++++ 3 files changed, 210 insertions(+), 46 deletions(-) create mode 100644 js/vendor/formparams.js diff --git a/index.html b/index.html index 49f13ee..47b0bd9 100644 --- a/index.html +++ b/index.html @@ -10,6 +10,7 @@ + @@ -83,7 +84,7 @@

    Activity Details

    - Save + Save

    New Activity

    diff --git a/js/app.js b/js/app.js index 456161d..8e54055 100644 --- a/js/app.js +++ b/js/app.js @@ -13,8 +13,20 @@ var exercise = {}; minutes: '' }, + set: function(attributes, options) { + var aDate; + if (attributes.date){ + //TODO - add validation to model for date strings + aDate = new Date(attributes.date); + if ( Object.prototype.toString.call(aDate) === "[object Date]" ){ + attributes.date = aDate; + } + } + Backbone.Model.prototype.set.call(this, attributes, options); + }, + dateInputType: function(){ - return exercise.formatDate(this.get('date'), "yyyy-mm-dd"); + return exercise.formatDate(this.get('date'), "yyyy-mm-dd");//https://github.com/jquery/jquery-mobile/issues/2755 }, displayDate: function(){ @@ -53,16 +65,15 @@ var exercise = {}; comparator: function(activity){ var date = new Date(activity.get('date')); return date.getTime(); - }, + }//, - parse: function(response){ - var fixedDate = []; - _.each(response, function(item){ - var stringDate = item.date; - item.date = new Date(stringDate); //https://github.com/jquery/jquery-mobile/issues/2755 - }); - return response; - } + // parse: function(response){ + // _.each(response, function(item){ + // var stringDate = item.date; + // item.date = new Date(stringDate); + // }); + // return response; + // } }); exercise.ActivityListView = Backbone.View.extend({ @@ -71,7 +82,7 @@ var exercise = {}; attributes: {"data-role": 'listview'}, initialize: function() { - this.collection.bind('add', this.render, this); + this.collection.bind('add', this.addItem, this); this.template = _.template($('#activity-list-item-template').html()); }, @@ -83,18 +94,33 @@ var exercise = {}; $(this.el).empty(); activities.each(function(activity){ - var renderedItem = template(activity.toJSON()), - $renderedItem = $(renderedItem); //convert the html into an jQuery object - $renderedItem.jqmData('activityId', activity.get('id')); //set the data on it for use in the click event - $renderedItem.bind('click', function(){ - //set the activity id on the page element for use in the details pagebeforeshow event - $('#activity-details').jqmData('activityId', $(this).jqmData('activityId')); //'this' represents the element being clicked - }); - listView.append($renderedItem); - }); + this.renderItem(activity); + }, this); container.html($(this.el)); container.trigger('create'); return this; + }, + + addItem: function(item) { + var listView = $(this.el); + + this.renderItem(item); + listView.listview('refresh'); + }, + + renderItem: function(item) { + var template = this.template, + listView = $(this.el), + renderedItem = template(item.toJSON()), + $renderedItem = $(renderedItem); + + $renderedItem.jqmData('activityId', item.get('id')); + $renderedItem.bind('click', function(){ + //set the activity id on the page element for use in the details pagebeforeshow event + $('#activity-details').jqmData('activityId', $(this).jqmData('activityId')); //'this' represents the element being clicked + }); + + listView.append($renderedItem); } }); @@ -117,7 +143,7 @@ var exercise = {}; exercise.ActivityFormView = Backbone.View.extend({ //since this template will render inside a div, we don't need to specify a tagname, but we do want the fieldcontain - attributes: {"data-role": 'listview'}, + attributes: {"data-role": 'fieldcontain'}, initialize: function() { this.template = _.template($('#activity-form-template').html()); @@ -148,32 +174,58 @@ $('#activities').live('pageinit', function(event){ activitiesListView.render(); }); -$('#add-button').live('click', function(){ - var activity = new exercise.Activity(), - activityForm = $('#activity-form-form'), - activityFormView; +$(document).ready(function(){ - activityFormView = new exercise.ActivityFormView({model: activity, viewContainer: activityForm}); - activityFormView.render(); -}); + $('#add-button').live('click', function(){ + var activity = new exercise.Activity(), + activityForm = $('#activity-form-form'), + activityFormView; + + //clear any existing id attribute from the details page + $('#activity-details').jqmRemoveData('activityId'); + activityFormView = new exercise.ActivityFormView({model: activity, viewContainer: activityForm}); + activityFormView.render(); + }); -$('#activity-details').live('pagebeforeshow', function(){ - console.log('activityId: ' + $('#activity-details').jqmData('activityId')); - var activitiesDetailsContainer = $('#activity-details').find(":jqmData(role='content')"), - activityDetailsView, - activityId = $('#activity-details').jqmData('activityId'), - activityModel = exercise.activities.get(activityId); + $('#activity-details').live('pagebeforeshow', function(){ + console.log('activityId: ' + $('#activity-details').jqmData('activityId')); + var activitiesDetailsContainer = $('#activity-details').find(":jqmData(role='content')"), + activityDetailsView, + activityId = $('#activity-details').jqmData('activityId'), + activityModel = exercise.activities.get(activityId); - activityDetailsView = new exercise.ActivityDetailsView({model: activityModel, viewContainer: activitiesDetailsContainer}); - activityDetailsView.render(); -}); + activityDetailsView = new exercise.ActivityDetailsView({model: activityModel, viewContainer: activitiesDetailsContainer}); + activityDetailsView.render(); + }); -$('#edit-activity-button').live('click', function() { - var activityId = $('#activity-details').jqmData('activityId'), - activityModel = exercise.activities.get(activityId), - activityForm = $('#activity-form-form'), - activityFormView; - - activityFormView = new exercise.ActivityFormView({model: activityModel, viewContainer: activityForm}); - activityFormView.render(); + $('#edit-activity-button').live('click', function() { + var activityId = $('#activity-details').jqmData('activityId'), + activityModel = exercise.activities.get(activityId), + activityForm = $('#activity-form-form'), + activityFormView; + + activityFormView = new exercise.ActivityFormView({model: activityModel, viewContainer: activityForm}); + activityFormView.render(); + }); + + $('#save-activity-button').live('click', function(){ + var activityId = $('#activity-details').jqmData('activityId'), + activity, + formJSON = $('#activity-form-form').formParams(); + + console.log("form: " + JSON.stringify($('#activity-form-form').formParams())); + console.log("id: " + activityId); + + + if (activityId){ + //editing + activity = exercise.activities.get(activityId); + activity.set(formJSON); //not calling save since we have no REST backend...save in memory + }else{ + //new (since we have no REST backend, create a new model and add to collection to prevent Backbone making REST calls) + activity = new exercise.Activity(formJSON); + activity.set({'id': new Date().getTime()}); //create some identifier + exercise.activities.add(activity); + } + }); }); \ No newline at end of file diff --git a/js/vendor/formparams.js b/js/vendor/formparams.js new file mode 100644 index 0000000..eeb7ddc --- /dev/null +++ b/js/vendor/formparams.js @@ -0,0 +1,111 @@ +/*jslint browser: true */ +/*global samapp, _, Backbone, titleCaps, jQuery, console */ +(function( $ ) { + var radioCheck = /radio|checkbox/i, + keyBreaker = /[^\[\]]+/g, + numberMatcher = /^[\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?$/; + + var isNumber = function( value ) { + if ( typeof value === 'number' ) { + return true; + } + + if ( typeof value !== 'string' ) { + return false; + } + + return value.match(numberMatcher); + }; + + $.fn.extend({ + /** + * @parent dom + * @download http://jmvcsite.heroku.com/pluginify?plugins[]=jquery/dom/form_params/form_params.js + * @plugin jquery/dom/form_params + * @test jquery/dom/form_params/qunit.html + *

    Returns an object of name-value pairs that represents values in a form. + * It is able to nest values whose element's name has square brackets.

    + * Example html: + * @codestart html + * <form> + * <input name="foo[bar]" value='2'/> + * <input name="foo[ced]" value='4'/> + * <form/> + * @codeend + * Example code: + * @codestart + * $('form').formParams() //-> { foo:{bar:2, ced: 4} } + * @codeend + * + * @demo jquery/dom/form_params/form_params.html + * + * @param {Boolean} [convert] True if strings that look like numbers and booleans should be converted. Defaults to true. + * @return {Object} An object of name-value pairs. + */ + formParams: function( convert ) { + if ( this[0].nodeName.toLowerCase() === 'form' && this[0].elements ) { + + return jQuery(jQuery.makeArray(this[0].elements)).getParams(convert); + } + return jQuery("input[name], textarea[name], select[name]", this[0]).getParams(convert); + }, + getParams: function( convert ) { + var data = {}, + i, + current; + + convert = convert === undefined ? true : convert; + + this.each(function() { + var el = this, + type = el.type && el.type.toLowerCase(); + //if we are submit, ignore + if ((type === 'submit') || !el.name ) { + return; + } + + var key = el.name, + value = $.data(el, "value") || $.fn.val.call([el]), + isRadioCheck = radioCheck.test(el.type), + parts = key.match(keyBreaker), + write = !isRadioCheck || !! el.checked, + //make an array of values + lastPart; + + if ( convert ) { + if ( isNumber(value) ) { + value = parseFloat(value); + } else if ( value === 'true' || value === 'false' ) { + value = Boolean(value); + } + + } + + // go through and create nested objects + current = data; + for ( i = 0; i < parts.length - 1; i++ ) { + if (!current[parts[i]] ) { + current[parts[i]] = {}; + } + current = current[parts[i]]; + } + lastPart = parts[parts.length - 1]; + + //now we are on the last part, set the value + if ( lastPart in current && type === "checkbox" ) { + if (!$.isArray(current[lastPart]) ) { + current[lastPart] = current[lastPart] === undefined ? [] : [current[lastPart]]; + } + if ( write ) { + current[lastPart].push(value); + } + } else if ( write || !current[lastPart] ) { + current[lastPart] = write ? value : undefined; + } + + }); + return data; + } + }); + +}(jQuery)); \ No newline at end of file From 31917fb25354b9c236f509e2b529ec19d4c16248 Mon Sep 17 00:00:00 2001 From: stevenpsmith Date: Tue, 21 Feb 2012 10:40:17 -0500 Subject: [PATCH 10/13] updating date handling with a little kluge --- js/app.js | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/js/app.js b/js/app.js index 8e54055..969ea8b 100644 --- a/js/app.js +++ b/js/app.js @@ -14,12 +14,14 @@ var exercise = {}; }, set: function(attributes, options) { - var aDate; + var aDate, foo; if (attributes.date){ - //TODO - add validation to model for date strings + //TODO future version - make sure date is valid format during input aDate = new Date(attributes.date); - if ( Object.prototype.toString.call(aDate) === "[object Date]" ){ + if ( Object.prototype.toString.call(aDate) === "[object Date]" && !isNaN(aDate.getTime()) ){ attributes.date = aDate; + }else{ + attributes.date = ''; } } Backbone.Model.prototype.set.call(this, attributes, options); @@ -83,6 +85,7 @@ var exercise = {}; initialize: function() { this.collection.bind('add', this.addItem, this); + this.collection.bind('change', this.changeItem, this); this.template = _.template($('#activity-list-item-template').html()); }, @@ -121,6 +124,10 @@ var exercise = {}; }); listView.append($renderedItem); + }, + + changeItem: function(item){ + console.log("Really"); } }); @@ -211,10 +218,15 @@ $(document).ready(function(){ $('#save-activity-button').live('click', function(){ var activityId = $('#activity-details').jqmData('activityId'), activity, + dateComponents, formJSON = $('#activity-form-form').formParams(); - console.log("form: " + JSON.stringify($('#activity-form-form').formParams())); - console.log("id: " + activityId); + //if we are on iOS and we have a date...convert it from yyyy-mm-dd back to mm/dd/yyyy + //TODO future version - for non-iOS, we would need to validate the date is in the expected format (mm/dd/yyyy) + if (formJSON.date && ((navigator.userAgent.indexOf('iPhone') >= 0 || navigator.userAgent.indexOf('iPad') >= 0)) ){ + dateComponents = formJSON.date.split("-"); + formJSON.date = dateComponents[1] + "/" + dateComponents[2] + "/" + dateComponents[0]; + } if (activityId){ From 498b51214ccc16d55f4f7f8b2bbe7dde791843a0 Mon Sep 17 00:00:00 2001 From: stevenpsmith Date: Tue, 21 Feb 2012 11:43:28 -0500 Subject: [PATCH 11/13] cleaning up event handling --- js/app.js | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/js/app.js b/js/app.js index 969ea8b..a2ff2e1 100644 --- a/js/app.js +++ b/js/app.js @@ -67,15 +67,7 @@ var exercise = {}; comparator: function(activity){ var date = new Date(activity.get('date')); return date.getTime(); - }//, - - // parse: function(response){ - // _.each(response, function(item){ - // var stringDate = item.date; - // item.date = new Date(stringDate); - // }); - // return response; - // } + } }); exercise.ActivityListView = Backbone.View.extend({ @@ -84,8 +76,9 @@ var exercise = {}; attributes: {"data-role": 'listview'}, initialize: function() { - this.collection.bind('add', this.addItem, this); + this.collection.bind('add', this.render, this); this.collection.bind('change', this.changeItem, this); + this.collection.bind('reset', this.render, this); this.template = _.template($('#activity-list-item-template').html()); }, @@ -95,6 +88,7 @@ var exercise = {}; template = this.template, listView = $(this.el); + container.empty(); $(this.el).empty(); activities.each(function(activity){ this.renderItem(activity); @@ -104,13 +98,6 @@ var exercise = {}; return this; }, - addItem: function(item) { - var listView = $(this.el); - - this.renderItem(item); - listView.listview('refresh'); - }, - renderItem: function(item) { var template = this.template, listView = $(this.el), @@ -127,7 +114,7 @@ var exercise = {}; }, changeItem: function(item){ - console.log("Really"); + this.collection.sort(); } }); From 40cd2b308b7ebeaa30c835a33f88460df6abbfc9 Mon Sep 17 00:00:00 2001 From: stevenpsmith Date: Wed, 22 Feb 2012 10:55:02 -0500 Subject: [PATCH 12/13] clean up code --- js/app.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/js/app.js b/js/app.js index a2ff2e1..dc69b36 100644 --- a/js/app.js +++ b/js/app.js @@ -14,14 +14,12 @@ var exercise = {}; }, set: function(attributes, options) { - var aDate, foo; + var aDate; if (attributes.date){ //TODO future version - make sure date is valid format during input aDate = new Date(attributes.date); if ( Object.prototype.toString.call(aDate) === "[object Date]" && !isNaN(aDate.getTime()) ){ attributes.date = aDate; - }else{ - attributes.date = ''; } } Backbone.Model.prototype.set.call(this, attributes, options); @@ -175,7 +173,7 @@ $(document).ready(function(){ activityForm = $('#activity-form-form'), activityFormView; - //clear any existing id attribute from the details page + //clear any existing id attribute from the form page $('#activity-details').jqmRemoveData('activityId'); activityFormView = new exercise.ActivityFormView({model: activity, viewContainer: activityForm}); activityFormView.render(); @@ -215,7 +213,6 @@ $(document).ready(function(){ formJSON.date = dateComponents[1] + "/" + dateComponents[2] + "/" + dateComponents[0]; } - if (activityId){ //editing activity = exercise.activities.get(activityId); From 8866a5b0a859584bf9613688bae08524bb37d1a1 Mon Sep 17 00:00:00 2001 From: windley Date: Fri, 31 Jan 2014 15:34:12 -0700 Subject: [PATCH 13/13] Updated this branch to use jQuery 1.4.0 and Backbone 1.1. Fixed date bug that kept date from displaying and updating properly in Chrome Changed miles and time fields to slides for fun. --- README.md | 3 +- index.html | 47 +- js/app.js | 33 +- js/vendor/backbone-min.js | 2 + js/vendor/backbone.js | 1158 -- js/vendor/jquery-1.11.0.js | 10337 +++++++++++++ js/vendor/jquery-1.11.0.min.js | 15 + js/vendor/jquery-1.6.4.min.js | 4 - js/vendor/jquery.mobile-1.0.min.js | 172 - js/vendor/jquery.mobile-1.4.0.js | 14736 +++++++++++++++++++ js/vendor/jquery.mobile-1.4.0.min.js | 51 + js/vendor/jquery.mobile-1.4.0.min.js.map | 8 + js/vendor/underscore-min.js | 6 + js/vendor/underscore.js | 931 -- style/jquery.mobile-1.0.css | 1847 --- style/jquery.mobile-1.0.min.css | 2 - style/jquery.mobile-1.4.0.css | 5783 ++++++++ style/jquery.mobile-1.4.0.min.css | 11 + style/jquery.mobile.external-png-1.4.0.css | 4392 ++++++ style/jquery.mobile.icons-1.4.0.css | 725 + style/jquery.mobile.icons-1.4.0.min.css | 725 + style/jquery.mobile.inline-png-1.4.0.css | 4392 ++++++ style/jquery.mobile.inline-svg-1.4.0.css | 4392 ++++++ style/jquery.mobile.structure-1.4.0.css | 3472 +++++ style/jquery.mobile.theme-1.4.0.css | 576 + style/jqueryui-flat.css | 5271 +++++++ 26 files changed, 54944 insertions(+), 4147 deletions(-) create mode 100644 js/vendor/backbone-min.js delete mode 100644 js/vendor/backbone.js create mode 100644 js/vendor/jquery-1.11.0.js create mode 100644 js/vendor/jquery-1.11.0.min.js delete mode 100644 js/vendor/jquery-1.6.4.min.js delete mode 100644 js/vendor/jquery.mobile-1.0.min.js create mode 100644 js/vendor/jquery.mobile-1.4.0.js create mode 100644 js/vendor/jquery.mobile-1.4.0.min.js create mode 100644 js/vendor/jquery.mobile-1.4.0.min.js.map create mode 100644 js/vendor/underscore-min.js delete mode 100644 js/vendor/underscore.js delete mode 100644 style/jquery.mobile-1.0.css delete mode 100644 style/jquery.mobile-1.0.min.css create mode 100644 style/jquery.mobile-1.4.0.css create mode 100644 style/jquery.mobile-1.4.0.min.css create mode 100644 style/jquery.mobile.external-png-1.4.0.css create mode 100644 style/jquery.mobile.icons-1.4.0.css create mode 100644 style/jquery.mobile.icons-1.4.0.min.css create mode 100644 style/jquery.mobile.inline-png-1.4.0.css create mode 100644 style/jquery.mobile.inline-svg-1.4.0.css create mode 100644 style/jquery.mobile.structure-1.4.0.css create mode 100644 style/jquery.mobile.theme-1.4.0.css create mode 100644 style/jqueryui-flat.css diff --git a/README.md b/README.md index 87b1ee6..e237637 100644 --- a/README.md +++ b/README.md @@ -10,4 +10,5 @@ This repo has branches that represent the code for various blog posts. Here is * Introduction to Backbone.js with JQuery Mobile => master * Sorting collections with Backbone.js and Jquery Mobile => sort * From List to Details View using jQuery Mobile and Backbone.js => details-display -* Using jQuery Mobile and Backbone.js for handling forms => new-and-edit \ No newline at end of file +* Using jQuery Mobile and Backbone.js for handling forms => new-and-edit +* Using jQuery Mobile 1.4.0 and Backbone 1.1.0 => update-to-jqm14-bb11 diff --git a/index.html b/index.html index 47b0bd9..2d60568 100644 --- a/index.html +++ b/index.html @@ -3,21 +3,13 @@ Exercise - + + - - - - - - - - - + + + + + + + + diff --git a/js/app.js b/js/app.js index dc69b36..246bb46 100644 --- a/js/app.js +++ b/js/app.js @@ -17,6 +17,7 @@ var exercise = {}; var aDate; if (attributes.date){ //TODO future version - make sure date is valid format during input + console.log("attributes.date ", attributes.date); aDate = new Date(attributes.date); if ( Object.prototype.toString.call(aDate) === "[object Date]" && !isNaN(aDate.getTime()) ){ attributes.date = aDate; @@ -26,7 +27,7 @@ var exercise = {}; }, dateInputType: function(){ - return exercise.formatDate(this.get('date'), "yyyy-mm-dd");//https://github.com/jquery/jquery-mobile/issues/2755 + return exercise.formatDate(this.get('date'), "yyyy-mm-dd"); //https://github.com/jquery/jquery-mobile/issues/2755 }, displayDate: function(){ @@ -55,7 +56,7 @@ var exercise = {}; }else{ formatedDate = ""; } - + return formatedDate; }; @@ -73,7 +74,8 @@ var exercise = {}; id: 'activities-list', attributes: {"data-role": 'listview'}, - initialize: function() { + initialize: function(options) { + this.options = options || {}; this.collection.bind('add', this.render, this); this.collection.bind('change', this.changeItem, this); this.collection.bind('reset', this.render, this); @@ -113,12 +115,14 @@ var exercise = {}; changeItem: function(item){ this.collection.sort(); + this.render(); } }); exercise.ActivityDetailsView = Backbone.View.extend({ //since this template will render inside a div, we don't need to specify a tagname - initialize: function() { + initialize: function(options) { + this.options = options || {}; this.template = _.template($('#activity-details-template').html()); }, @@ -137,7 +141,8 @@ var exercise = {}; //since this template will render inside a div, we don't need to specify a tagname, but we do want the fieldcontain attributes: {"data-role": 'fieldcontain'}, - initialize: function() { + initialize: function(options) { + this.options = options || {}; this.template = _.template($('#activity-form-template').html()); }, @@ -158,7 +163,7 @@ var exercise = {}; }(jQuery)); -$('#activities').live('pageinit', function(event){ +$('#activities').on('pageinit', function(event){ var activitiesListContainer = $('#activities').find(":jqmData(role='content')"), activitiesListView; exercise.initData(); @@ -168,7 +173,7 @@ $('#activities').live('pageinit', function(event){ $(document).ready(function(){ - $('#add-button').live('click', function(){ + $('#add-button').on('click', function(){ var activity = new exercise.Activity(), activityForm = $('#activity-form-form'), activityFormView; @@ -179,7 +184,7 @@ $(document).ready(function(){ activityFormView.render(); }); - $('#activity-details').live('pagebeforeshow', function(){ + $('#activity-details').on('pagebeforeshow', function(){ console.log('activityId: ' + $('#activity-details').jqmData('activityId')); var activitiesDetailsContainer = $('#activity-details').find(":jqmData(role='content')"), activityDetailsView, @@ -190,7 +195,7 @@ $(document).ready(function(){ activityDetailsView.render(); }); - $('#edit-activity-button').live('click', function() { + $('#edit-activity-button').on('click', function() { var activityId = $('#activity-details').jqmData('activityId'), activityModel = exercise.activities.get(activityId), activityForm = $('#activity-form-form'), @@ -200,7 +205,7 @@ $(document).ready(function(){ activityFormView.render(); }); - $('#save-activity-button').live('click', function(){ + $('#save-activity-button').on('click', function(){ var activityId = $('#activity-details').jqmData('activityId'), activity, dateComponents, @@ -208,7 +213,11 @@ $(document).ready(function(){ //if we are on iOS and we have a date...convert it from yyyy-mm-dd back to mm/dd/yyyy //TODO future version - for non-iOS, we would need to validate the date is in the expected format (mm/dd/yyyy) - if (formJSON.date && ((navigator.userAgent.indexOf('iPhone') >= 0 || navigator.userAgent.indexOf('iPad') >= 0)) ){ + if (formJSON.date && (navigator.userAgent.indexOf('iPhone') >= 0 || + navigator.userAgent.indexOf('iPad') >= 0 || + navigator.userAgent.indexOf('Chrome') >= 0 + ) + ){ dateComponents = formJSON.date.split("-"); formJSON.date = dateComponents[1] + "/" + dateComponents[2] + "/" + dateComponents[0]; } @@ -224,4 +233,4 @@ $(document).ready(function(){ exercise.activities.add(activity); } }); -}); \ No newline at end of file +}); diff --git a/js/vendor/backbone-min.js b/js/vendor/backbone-min.js new file mode 100644 index 0000000..3b2593d --- /dev/null +++ b/js/vendor/backbone-min.js @@ -0,0 +1,2 @@ +(function(){var t=this;var e=t.Backbone;var i=[];var r=i.push;var s=i.slice;var n=i.splice;var a;if(typeof exports!=="undefined"){a=exports}else{a=t.Backbone={}}a.VERSION="1.1.0";var h=t._;if(!h&&typeof require!=="undefined")h=require("underscore");a.$=t.jQuery||t.Zepto||t.ender||t.$;a.noConflict=function(){t.Backbone=e;return this};a.emulateHTTP=false;a.emulateJSON=false;var o=a.Events={on:function(t,e,i){if(!l(this,"on",t,[e,i])||!e)return this;this._events||(this._events={});var r=this._events[t]||(this._events[t]=[]);r.push({callback:e,context:i,ctx:i||this});return this},once:function(t,e,i){if(!l(this,"once",t,[e,i])||!e)return this;var r=this;var s=h.once(function(){r.off(t,s);e.apply(this,arguments)});s._callback=e;return this.on(t,s,i)},off:function(t,e,i){var r,s,n,a,o,u,c,f;if(!this._events||!l(this,"off",t,[e,i]))return this;if(!t&&!e&&!i){this._events={};return this}a=t?[t]:h.keys(this._events);for(o=0,u=a.length;o").attr(t);this.setElement(e,false)}else{this.setElement(h.result(this,"el"),false)}}});a.sync=function(t,e,i){var r=T[t];h.defaults(i||(i={}),{emulateHTTP:a.emulateHTTP,emulateJSON:a.emulateJSON});var s={type:r,dataType:"json"};if(!i.url){s.url=h.result(e,"url")||U()}if(i.data==null&&e&&(t==="create"||t==="update"||t==="patch")){s.contentType="application/json";s.data=JSON.stringify(i.attrs||e.toJSON(i))}if(i.emulateJSON){s.contentType="application/x-www-form-urlencoded";s.data=s.data?{model:s.data}:{}}if(i.emulateHTTP&&(r==="PUT"||r==="DELETE"||r==="PATCH")){s.type="POST";if(i.emulateJSON)s.data._method=r;var n=i.beforeSend;i.beforeSend=function(t){t.setRequestHeader("X-HTTP-Method-Override",r);if(n)return n.apply(this,arguments)}}if(s.type!=="GET"&&!i.emulateJSON){s.processData=false}if(s.type==="PATCH"&&E){s.xhr=function(){return new ActiveXObject("Microsoft.XMLHTTP")}}var o=i.xhr=a.ajax(h.extend(s,i));e.trigger("request",e,o,i);return o};var E=typeof window!=="undefined"&&!!window.ActiveXObject&&!(window.XMLHttpRequest&&(new XMLHttpRequest).dispatchEvent);var T={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};a.ajax=function(){return a.$.ajax.apply(a.$,arguments)};var k=a.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var S=/\((.*?)\)/g;var $=/(\(\?)?:\w+/g;var H=/\*\w+/g;var A=/[\-{}\[\]+?.,\\\^$|#\s]/g;h.extend(k.prototype,o,{initialize:function(){},route:function(t,e,i){if(!h.isRegExp(t))t=this._routeToRegExp(t);if(h.isFunction(e)){i=e;e=""}if(!i)i=this[e];var r=this;a.history.route(t,function(s){var n=r._extractParameters(t,s);i&&i.apply(r,n);r.trigger.apply(r,["route:"+e].concat(n));r.trigger("route",e,n);a.history.trigger("route",r,e,n)});return this},navigate:function(t,e){a.history.navigate(t,e);return this},_bindRoutes:function(){if(!this.routes)return;this.routes=h.result(this,"routes");var t,e=h.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(A,"\\$&").replace(S,"(?:$1)?").replace($,function(t,e){return e?t:"([^/]+)"}).replace(H,"(.*?)");return new RegExp("^"+t+"$")},_extractParameters:function(t,e){var i=t.exec(e).slice(1);return h.map(i,function(t){return t?decodeURIComponent(t):null})}});var I=a.History=function(){this.handlers=[];h.bindAll(this,"checkUrl");if(typeof window!=="undefined"){this.location=window.location;this.history=window.history}};var N=/^[#\/]|\s+$/g;var O=/^\/+|\/+$/g;var P=/msie [\w.]+/;var C=/\/$/;var j=/[?#].*$/;I.started=false;h.extend(I.prototype,o,{interval:50,getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getFragment:function(t,e){if(t==null){if(this._hasPushState||!this._wantsHashChange||e){t=this.location.pathname;var i=this.root.replace(C,"");if(!t.indexOf(i))t=t.slice(i.length)}else{t=this.getHash()}}return t.replace(N,"")},start:function(t){if(I.started)throw new Error("Backbone.history has already been started");I.started=true;this.options=h.extend({root:"/"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var e=this.getFragment();var i=document.documentMode;var r=P.exec(navigator.userAgent.toLowerCase())&&(!i||i<=7);this.root=("/"+this.root+"/").replace(O,"/");if(r&&this._wantsHashChange){this.iframe=a.$('