diff --git a/app/controllers/tasks_controller.rb b/app/controllers/tasks_controller.rb index 840474e..0189f84 100644 --- a/app/controllers/tasks_controller.rb +++ b/app/controllers/tasks_controller.rb @@ -43,10 +43,10 @@ def destroy task = Task.find(params[:id]) if (task.board == params[:board]) - task.destroy - Pusher[params[:board]].trigger('task-destroy', task.as_json, params[:socket_id]) + task.destroy + render :json => task end end diff --git a/app/views/common/application_board_selected.jst b/app/views/common/application_board_selected.jst index 12c3249..5d600f8 100644 --- a/app/views/common/application_board_selected.jst +++ b/app/views/common/application_board_selected.jst @@ -9,7 +9,7 @@

Clear Tasks?

-

Edit

+
diff --git a/config/assets.yml b/config/assets.yml index a2efbce..b0f6cac 100644 --- a/config/assets.yml +++ b/config/assets.yml @@ -1,5 +1,6 @@ javascripts: core: + - public/javascripts/vendor/modernizr.js - public/javascripts/vendor/jquery.js - public/javascripts/vendor/underscore.js - public/javascripts/vendor/backbone.js diff --git a/public/javascripts/models/task_store.js b/public/javascripts/models/task_store.js index 20cc06b..3f2694c 100644 --- a/public/javascripts/models/task_store.js +++ b/public/javascripts/models/task_store.js @@ -48,12 +48,13 @@ var TaskStore = Backbone.Collection.extend(function(){ updateTask: function(task) { this.findById(task._id).set(task); + this.trigger('taskToggled'); }, removeTask: function(task) { var task = this.findById(task._id); - this.remove(task); + this.trigger('taskToggled'); }, //internal get function doesn't work on tasks which @@ -63,10 +64,6 @@ var TaskStore = Backbone.Collection.extend(function(){ return this.find(function(task) { return task.id == id; }); - }, - - toggleEditMode: function() { - this.trigger('editableChange'); } }; }()); \ No newline at end of file diff --git a/public/javascripts/vendor/modernizr.js b/public/javascripts/vendor/modernizr.js new file mode 100644 index 0000000..c6a800a --- /dev/null +++ b/public/javascripts/vendor/modernizr.js @@ -0,0 +1,30 @@ +/* + * Modernizr v1.6 + * http://www.modernizr.com + * + * Developed by: + * - Faruk Ates http://farukat.es/ + * - Paul Irish http://paulirish.com/ + * + * Copyright (c) 2009-2010 + * Dual-licensed under the BSD or MIT licenses. + * http://www.modernizr.com/license/ + */ +window.Modernizr=function(i,e,u){function s(a,b){return(""+a).indexOf(b)!==-1}function D(a,b){for(var c in a)if(j[a[c]]!==u&&(!b||b(a[c],E)))return true}function n(a,b){var c=a.charAt(0).toUpperCase()+a.substr(1);c=(a+" "+F.join(c+" ")+c).split(" ");return!!D(c,b)}function S(){f.input=function(a){for(var b=0,c=a.length;b7)};d.history=function(){return!!(i.history&&history.pushState)};d.draganddrop=function(){return o("drag")&& +o("dragstart")&&o("dragenter")&&o("dragover")&&o("dragleave")&&o("dragend")&&o("drop")};d.websockets=function(){return"WebSocket"in i};d.rgba=function(){j.cssText="background-color:rgba(150,255,150,.5)";return s(j.backgroundColor,"rgba")};d.hsla=function(){j.cssText="background-color:hsla(120,40%,100%,.5)";return s(j.backgroundColor,"rgba")||s(j.backgroundColor,"hsla")};d.multiplebgs=function(){j.cssText="background:url(//:),url(//:),red url(//:)";return/(url\s*\(.*?){3}/.test(j.background)};d.backgroundsize= +function(){return n("backgroundSize")};d.borderimage=function(){return n("borderImage")};d.borderradius=function(){return n("borderRadius","",function(a){return s(a,"orderRadius")})};d.boxshadow=function(){return n("boxShadow")};d.textshadow=function(){return e.createElement("div").style.textShadow===""};d.opacity=function(){var a=q.join("opacity:.5;")+"";j.cssText=a;return s(j.opacity,"0.5")};d.cssanimations=function(){return n("animationName")};d.csscolumns=function(){return n("columnCount")};d.cssgradients= +function(){var a=("background-image:"+q.join("gradient(linear,left top,right bottom,from(#9f9),to(white));background-image:")+q.join("linear-gradient(left top,#9f9, white);background-image:")).slice(0,-17);j.cssText=a;return s(j.backgroundImage,"gradient")};d.cssreflections=function(){return n("boxReflect")};d.csstransforms=function(){return!!D(["transformProperty","WebkitTransform","MozTransform","OTransform","msTransform"])};d.csstransforms3d=function(){var a=!!D(["perspectiveProperty","WebkitPerspective", +"MozPerspective","OPerspective","msPerspective"]);if(a)a=Q("@media ("+q.join("transform-3d),(")+"modernizr)");return a};d.csstransitions=function(){return n("transitionProperty")};d.fontface=function(){var a,b=e.head||e.getElementsByTagName("head")[0]||l,c=e.createElement("style"),k=e.implementation||{hasFeature:function(){return false}};c.type="text/css";b.insertBefore(c,b.firstChild);a=c.sheet||c.styleSheet;b=k.hasFeature("CSS2","")?function(g){if(!(a&&g))return false;var r=false;try{a.insertRule(g, +0);r=!/unknown/i.test(a.cssRules[0].cssText);a.deleteRule(a.cssRules.length-1)}catch(x){}return r}:function(g){if(!(a&&g))return false;a.cssText=g;return a.cssText.length!==0&&!/unknown/i.test(a.cssText)&&a.cssText.replace(/\r+|\n+/g,"").indexOf(g.split(" ")[0])===0};f._fontfaceready=function(g){g(f.fontface)};return b('@font-face { font-family: "font"; src: "font.ttf"; }')};d.video=function(){var a=e.createElement("video"),b=!!a.canPlayType;if(b){b=new Boolean(b);b.ogg=a.canPlayType('video/ogg; codecs="theora"'); +b.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"')||a.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"');b.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"')}return b};d.audio=function(){var a=e.createElement("audio"),b=!!a.canPlayType;if(b){b=new Boolean(b);b.ogg=a.canPlayType('audio/ogg; codecs="vorbis"');b.mp3=a.canPlayType("audio/mpeg;");b.wav=a.canPlayType('audio/wav; codecs="1"');b.m4a=a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")}return b};d.localstorage=function(){try{return"localStorage"in +i&&i.localStorage!==null}catch(a){return false}};d.sessionstorage=function(){try{return"sessionStorage"in i&&i.sessionStorage!==null}catch(a){return false}};d.webWorkers=function(){return!!i.Worker};d.applicationcache=function(){return!!i.applicationCache};d.svg=function(){return!!e.createElementNS&&!!e.createElementNS(v.svg,"svg").createSVGRect};d.inlinesvg=function(){var a=document.createElement("div");a.innerHTML="";return(a.firstChild&&a.firstChild.namespaceURI)==v.svg};d.smil=function(){return!!e.createElementNS&& +/SVG/.test(O.call(e.createElementNS(v.svg,"animate")))};d.svgclippaths=function(){return!!e.createElementNS&&/SVG/.test(O.call(e.createElementNS(v.svg,"clipPath")))};for(var H in d)if(R(d,H)){w=H.toLowerCase();f[w]=d[H]();P.push((f[w]?"":"no-")+w)}f.input||S();f.crosswindowmessaging=f.postmessage;f.historymanagement=f.history;f.addTest=function(a,b){a=a.toLowerCase();if(!f[a]){b=!!b();l.className+=" "+(b?"":"no-")+a;f[a]=b;return f}};j.cssText="";E=h=null;i.attachEvent&&function(){var a=e.createElement("div"); +a.innerHTML="";return a.childNodes.length!==1}()&&function(a,b){function c(p){for(var m=-1;++m (defaults.threshold.y*-1)) { + changeX = originalCoord.x - finalCoord.x + + if(changeX > defaults.threshold.x) { + defaults.swipeLeft() + } + if(changeX < (defaults.threshold.x*-1)) { + defaults.swipeRight() + } + } + } + + // Swipe was started + function touchStart(event) { + //console.log('Starting swipe gesture...') + originalCoord.x = event.targetTouches[0].pageX + originalCoord.y = event.targetTouches[0].pageY + + finalCoord.x = originalCoord.x + finalCoord.y = originalCoord.y + } + + // Swipe was canceled + function touchCancel(event) { + //console.log('Canceling swipe gesture...') + } + + // Add gestures to all swipable areas + this.addEventListener("touchstart", touchStart, false); + this.addEventListener("touchmove", touchMove, false); + this.addEventListener("touchend", touchEnd, false); + this.addEventListener("touchcancel", touchCancel, false); + + }); + }; +})(jQuery); \ No newline at end of file diff --git a/public/javascripts/vendor/plugins/toggleDoneButton.js b/public/javascripts/vendor/plugins/toggleDoneButton.js deleted file mode 100644 index 4508319..0000000 --- a/public/javascripts/vendor/plugins/toggleDoneButton.js +++ /dev/null @@ -1,19 +0,0 @@ -(function( $ ){ - $.fn.toggleDoneButton = function() { - this.each(function() { - var done = false; - var originalLabel = $(this).html(); - - $(this).click(function() { - - if (done) { - $(this).html(originalLabel); - done = false; - } else { - $(this).html("Done"); - done = true; - } - }); - }); - } -})( jQuery ); \ No newline at end of file diff --git a/public/javascripts/views/big_board_view.js b/public/javascripts/views/big_board_view.js index 81961a8..32c39b0 100644 --- a/public/javascripts/views/big_board_view.js +++ b/public/javascripts/views/big_board_view.js @@ -64,7 +64,6 @@ var BigBoardView = Backbone.View.extend(Stately).extend(function() { }, taskDestroyedEventListener: function(task) { - console.log("SOMEONE DESTROYED!"); taskStore.removeTask(task); }, @@ -84,8 +83,7 @@ var BigBoardView = Backbone.View.extend(Stately).extend(function() { "keypress .board_selected input[type=text]" : "keyPressListener", "click .clearCompleted" : "clearCompletedListener", "confirm .clearCompleted" : "clearCompletedConfirmListener", - "cancelConfirm .clearCompleted" : "clearCompletedCancelListener", - "click #editTasks" : "editTasksClickListener" + "cancelConfirm .clearCompleted" : "clearCompletedCancelListener" }, initialize: function() { @@ -110,8 +108,6 @@ var BigBoardView = Backbone.View.extend(Stately).extend(function() { showEffect: 'slideDown', hideEffect: 'slideUp' }); - - this.$('.toggleDoneButton').toggleDoneButton(); }, getState: function() { @@ -183,10 +179,6 @@ var BigBoardView = Backbone.View.extend(Stately).extend(function() { taskStore.clearCompleted(); }, - editTasksClickListener: function() { - taskStore.toggleEditMode(); - }, - log: function(str) { if (window['console']) console.log(str); diff --git a/public/javascripts/views/task_store_view.js b/public/javascripts/views/task_store_view.js index 62379ae..164f575 100644 --- a/public/javascripts/views/task_store_view.js +++ b/public/javascripts/views/task_store_view.js @@ -27,8 +27,7 @@ var TaskStoreView = Backbone.View.extend(Stately).extend(function() { states: { NO_ITEMS: "no_items", LOADING: "loading", - NORMAL: "normal", - EDITABLE: "editable" + NORMAL: "normal" }, initialize: function() { @@ -37,7 +36,6 @@ var TaskStoreView = Backbone.View.extend(Stately).extend(function() { this.model.bind('refresh', _.bind(this.render, this)); this.model.bind('loadingChange', _.bind(this.render, this)); this.model.bind('taskToggled', _.bind(this.updateTasksRemaining, this)); - this.model.bind('editableChange', _.bind(this.editableChangeListener, this)); }, render: function() { @@ -103,10 +101,6 @@ var TaskStoreView = Backbone.View.extend(Stately).extend(function() { $('.numTasks').html(numTasks); $('.tasksNoun').html(tasksNoun); - }, - - editableChangeListener: function() { - $(this.el).toggleClass(this.states.EDITABLE); } }; }()); \ No newline at end of file diff --git a/public/javascripts/views/task_view.js b/public/javascripts/views/task_view.js index b9ee38c..7b14b59 100644 --- a/public/javascripts/views/task_view.js +++ b/public/javascripts/views/task_view.js @@ -1,6 +1,8 @@ var TaskView = Backbone.View.extend(Stately).extend(function() { return { + controlsVisible: false, + tagName: "li", states: { @@ -28,6 +30,8 @@ var TaskView = Backbone.View.extend(Stately).extend(function() { this.processComponents(); this.delegateEvents(); + $(this.el).swipe({ swipeRight: _.bind(this.swipedTaskListener, this) }); + return this; }, @@ -51,7 +55,26 @@ var TaskView = Backbone.View.extend(Stately).extend(function() { }, deleteTaskListener: function() { - this.model.destroy(); - } + this.model.destroy(); + this.model.collection.remove(this.model); + }, + + swipedTaskListener: function() { + if (!this.controlsVisible) { + $(this.el).addClass('editable'); + this.controlsVisible = true; + $(document).bind('touchstart', _.bind(this.swipedTaskCancelListener, this)); + } else { + $(this.el).removeClass('editable'); + this.controlsVisible = false; + $(document).unbind('touchstart'); + } + }, + + swipedTaskCancelListener: function(event) { + if ($(event.target).parent('.controls').length == 0) { + this.swipedTaskListener(); + } + } }; }()); \ No newline at end of file diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css index 02abced..a7b2892 100644 --- a/public/stylesheets/application.css +++ b/public/stylesheets/application.css @@ -114,17 +114,22 @@ footer .app_name { display:block; } -.controls { - display:none; +/* show controls on hover for browsers with drag and drop AKA mouse */ +.no-touch #taskStoreView li:hover .controls { + visibility:visible; } -.editable .controls { - display:inline; +.controls { + visibility:hidden; position:absolute; right:10px; top:10px; } +.editable .controls { + visibility:visible; +} + .addTask { position:absolute; left:5px; diff --git a/spec/javascripts/views/task_store_view_spec.js b/spec/javascripts/views/task_store_view_spec.js index d189478..ad78c92 100644 --- a/spec/javascripts/views/task_store_view_spec.js +++ b/spec/javascripts/views/task_store_view_spec.js @@ -24,13 +24,4 @@ describe("Task Store View", function() { expect(sut.getState()).toBe(sut.states.NORMAL); }); - it("should render the editable class when the model dispatches the editableChange event", function() { - expect( $(sut.el).hasClass(sut.states.EDITABLE)).toBe(false); - - model.trigger('editableChange'); - - expect( $(sut.el).hasClass(sut.states.EDITABLE)).toBeTruthy(); - }); - - }); \ No newline at end of file