mirror of
https://github.com/wassname/HackFlowy.git
synced 2026-06-27 16:00:04 +08:00
Merge branch 'master' into gh-pages
Conflicts: javascripts/vendor/custom.modernizr.js javascripts/vendor/zepto.js mockup.html stylesheets/normalize.css
This commit is contained in:
+44
-51
@@ -3,7 +3,6 @@ define(
|
||||
'backbone',
|
||||
'collections/list',
|
||||
'views/task',
|
||||
'data/demo',
|
||||
'text!../../templates/task.html',
|
||||
'marionette'
|
||||
],
|
||||
@@ -13,7 +12,6 @@ define(
|
||||
Backbone,
|
||||
List,
|
||||
TaskView,
|
||||
demoData,
|
||||
listTemplate,
|
||||
Marionette
|
||||
) {
|
||||
@@ -27,59 +25,53 @@ define(
|
||||
template: _.template(listTemplate),
|
||||
|
||||
events: {
|
||||
'click #add': 'addTask'
|
||||
'click #add': 'addTask',
|
||||
},
|
||||
|
||||
initialize: function () {
|
||||
var self = this;
|
||||
|
||||
// this wholeCollection holds all items
|
||||
this.wholeCollection = Tasks = new List();
|
||||
//this.collection = new List();
|
||||
|
||||
// custom events
|
||||
this.listenTo(this, 'childview:rerender', this.render);
|
||||
// this.listenTo(this.collection, 'add remove', this.render);
|
||||
|
||||
/** Load demo data **/
|
||||
function loadDemoData() {
|
||||
for (var i = 0; i < demoData.length; i++) {
|
||||
var task = Tasks.add(demoData[i]);
|
||||
task.save();
|
||||
}
|
||||
}
|
||||
|
||||
function success(children, data, promise) {
|
||||
// load demo data if the server returns nothing
|
||||
var directChildren = children.filter(this.filterDirectChildren);
|
||||
if (directChildren.length === 0)
|
||||
loadDemoData();
|
||||
this.collection = new List(Tasks.filter(this.filterDirectChildren));
|
||||
this.render();
|
||||
}
|
||||
|
||||
Tasks.fetch({
|
||||
success: success,
|
||||
error: function () {
|
||||
|
||||
// switch to localforage database if server isn't present and fetch again
|
||||
// from there
|
||||
window.hackflowyOffline = true;
|
||||
$('#header').append('<div class="alert-box secondary round">Running in offline mode, data may be lost </div>');
|
||||
Tasks.fetch({
|
||||
success: success,
|
||||
context: this
|
||||
});
|
||||
},
|
||||
context: this
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
|
||||
/** Get root id for the displayed list from the url hash or 0 **/
|
||||
// getRootId: function(){
|
||||
// var hash = window.location.hash.slice(1);
|
||||
// return hash ? hash: 0;
|
||||
//
|
||||
// },
|
||||
|
||||
// /** Called when window location hash changes **/
|
||||
// changeRootId: function(){
|
||||
// this.collection.remove(this.collection.models);
|
||||
// this.collection.add(pageView.collection.filter(this.filterDirectChildren,this));
|
||||
// this.updateBreadCrumbs();
|
||||
// },
|
||||
|
||||
// updateBreadCrumbs: function(){
|
||||
// var rootId = this.getRootId();
|
||||
// if (rootId){
|
||||
// var current = Tasks.get(rootId);
|
||||
// var breadCrumbs = _.template('<a href="#<%= id %>"><%= content %></a>')(current.attributes);
|
||||
// var depth=0;
|
||||
// while (current.get('parentId') && depth<100){
|
||||
// depth++;
|
||||
// current = Tasks.get(current.get('parentId'));
|
||||
// breadCrumbs=_.template('<a href="#<%= id %>"><%= content %></a> > ')(current.attributes)+breadCrumbs;
|
||||
// }
|
||||
// if (depth>=100) console.error('Max depth exceeded while making breadCrumbs');
|
||||
// breadCrumbs='<a href="#">Home</a> > '+breadCrumbs;
|
||||
// $('#task-breadcrumbs').append(breadCrumbs);
|
||||
//
|
||||
// }
|
||||
// },
|
||||
|
||||
// Only show direct children
|
||||
filterDirectChildren: function (child, index, collection) {
|
||||
return child.get('parentId') === 0;
|
||||
},
|
||||
// filterDirectChildren: function (child, index, collection) {
|
||||
// var rootId = this.getRootId();
|
||||
// if (rootId)
|
||||
// return child.get('id') == rootId;
|
||||
// else
|
||||
// return child.get('parentId') == rootId;
|
||||
// },
|
||||
|
||||
/** This is the root view in the tree **/
|
||||
getParentView: function () {
|
||||
@@ -88,8 +80,9 @@ define(
|
||||
|
||||
/** Update parentId when added to collection **/
|
||||
onAddChild: function(childView){
|
||||
if (childView.model.get('parentId')!==0)
|
||||
childView.model.save({parentId: 0});
|
||||
var rootId = pageView.getRootId();
|
||||
if (childView.model.get('parentId')!=rootId && childView.model==rootId)
|
||||
childView.model.save({parentId: rootId});
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
+104
-15
@@ -1,41 +1,130 @@
|
||||
define(
|
||||
['jquery',
|
||||
'backbone',
|
||||
'marionette',
|
||||
'views/list',
|
||||
'models/task'
|
||||
'data/demo',
|
||||
'models/task',
|
||||
'collections/list'
|
||||
],
|
||||
|
||||
function(
|
||||
$,
|
||||
Backbone,
|
||||
Marionette,
|
||||
ListView,
|
||||
Task
|
||||
demoData,
|
||||
Task,
|
||||
List
|
||||
) {
|
||||
|
||||
var PageView = Backbone.View.extend({
|
||||
var PageView = Marionette.View.extend({
|
||||
|
||||
el: $("#main"),
|
||||
el: $("#hackflowy"),
|
||||
|
||||
events: {
|
||||
'keypress #newTask': 'createNewTask',
|
||||
'blur #newTask': 'createNewTask'
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
listView = this.listView = new ListView();
|
||||
this.input = $('#newTask');
|
||||
|
||||
// this wholeCollection holds all items
|
||||
this.collection = new List();
|
||||
|
||||
|
||||
function success(children, data, promise) {
|
||||
// load demo data if the server returns nothing
|
||||
var directChildren = children.filter(this.filterDirectChildren,this);
|
||||
if (directChildren.length === 0){
|
||||
for (var i = 0; i < demoData.length; i++) {
|
||||
var task = this.collection.add(demoData[i]);
|
||||
task.save();
|
||||
}
|
||||
}
|
||||
this.listView.collection.add(children.filter(this.filterDirectChildren,this));
|
||||
this.listView.render();
|
||||
this.updateBreadCrumbs();
|
||||
}
|
||||
|
||||
this.collection.fetch({
|
||||
success: success,
|
||||
error: function () {
|
||||
// switch to localforage database if server isn't present and fetch again
|
||||
// from there
|
||||
window.hackflowyOffline = true;
|
||||
this.$('#header-alerts').append('<div class="alert-box secondary round">Running in offline mode, data may be lost </div>');
|
||||
this.collection.fetch({
|
||||
success: success,
|
||||
context: this
|
||||
});
|
||||
},
|
||||
context: this
|
||||
});
|
||||
|
||||
var rootItems = new List(this.collection.filter(this.filterDirectChildren,this));
|
||||
this.listView = new ListView({collection: rootItems});
|
||||
|
||||
|
||||
// change root item when the url hash changes
|
||||
// HACK should ideally use http://stackoverflow.com/a/19114496/221742
|
||||
$(window).on("hashchange", this.changeRootId.bind(this));
|
||||
|
||||
// stop browser going back a page when jamming backspace
|
||||
window.addEventListener('keydown',function(e){if(e.keyIdentifier=='U+0008'||e.keyIdentifier=='Backspace'){if(e.target==document.body){e.preventDefault();}}},true);
|
||||
$(window).on('keydown',function(e){if(e.keyIdentifier=='U+0008'||e.keyIdentifier=='Backspace'){if(e.target==document.body){e.preventDefault();}}});
|
||||
|
||||
|
||||
},
|
||||
|
||||
createNewTask: function(e) {
|
||||
if (e.keyCode != 13) return;
|
||||
if (!this.input.val().trim()) return;
|
||||
this.listView.collection.add(new Task({content: this.input.val().trim() }));
|
||||
this.input.val('');
|
||||
}
|
||||
/** remove non backbone listener on delete **/
|
||||
onDestroy: function() {
|
||||
$(window).off("haschange",this.changeRootId);
|
||||
$(window).off('keydown',function(e){if(e.keyIdentifier=='U+0008'||e.keyIdentifier=='Backspace'){if(e.target==document.body){e.preventDefault();}}});
|
||||
},
|
||||
|
||||
/** Get root id for the displayed list from the url hash or 0 **/
|
||||
getRootId: function(){
|
||||
var hash = window.location.hash.slice(1);
|
||||
if (hash && pageView.collection.get(hash))
|
||||
return hash;
|
||||
else if (hash)
|
||||
window.location.hash='';
|
||||
return 0;
|
||||
},
|
||||
|
||||
/** Called when window location hash changes **/
|
||||
changeRootId: function(){
|
||||
// change the listview children
|
||||
this.listView.collection.remove(this.collection.models);
|
||||
this.listView.collection.add(this.collection.filter(this.filterDirectChildren,this));
|
||||
this.updateBreadCrumbs();
|
||||
},
|
||||
|
||||
// Only show direct children
|
||||
filterDirectChildren: function (child, index, collection) {
|
||||
var rootId = this.getRootId();
|
||||
if (rootId)
|
||||
return child.get('id') == rootId;
|
||||
else
|
||||
return child.get('parentId') == rootId;
|
||||
},
|
||||
|
||||
updateBreadCrumbs: function(){
|
||||
var rootId = this.getRootId();
|
||||
this.$('#task-breadcrumbs').empty();
|
||||
if (rootId){
|
||||
var current = this.collection.get(rootId);
|
||||
var breadCrumbs = '';//_.template('<a href="#<%= id %>"><%= content %></a>')(current.attributes);
|
||||
var depth=0;
|
||||
while (current.get('parentId') && depth<100){
|
||||
depth++;
|
||||
current = this.collection.get(current.get('parentId'));
|
||||
breadCrumbs=_.template('<a href="#<%= id %>"><%= content %></a> > ')(current.attributes)+breadCrumbs;
|
||||
}
|
||||
if (depth>=100) console.error('Max depth exceeded while making breadCrumbs');
|
||||
breadCrumbs='<a href="#">Home</a> > '+breadCrumbs;
|
||||
this.$('#task-breadcrumbs').append(breadCrumbs);
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
|
||||
+23
-20
@@ -20,9 +20,10 @@ define(
|
||||
// The recursive tree view. Ref:http://jsfiddle.net/wassname/zf61mLvh/2/
|
||||
var TaskView = Backbone.Marionette.CompositeView.extend({
|
||||
|
||||
template: _.template(taskTemplate), //'#task-view-template',
|
||||
template: _.template(taskTemplate),
|
||||
tagName: 'ul',
|
||||
className: "shift",
|
||||
className: "task-view",
|
||||
viewComparator: List.prototype.comporator,
|
||||
childView: TaskView,
|
||||
childViewContainer: '.children',
|
||||
childViewOptions: {
|
||||
@@ -50,38 +51,42 @@ define(
|
||||
'click .complete:first': 'markComplete',
|
||||
'click .uncomplete:first': 'unmarkComlete',
|
||||
'click .note:first': 'addNote',
|
||||
'click .mouse-tip:first': 'foldChildren',
|
||||
'click .fold-button:first': 'foldChildren',
|
||||
'click .fold:first': 'foldChildren',
|
||||
'click .destroy:first': 'destroy',
|
||||
// custom events
|
||||
'focus': 'this.model.focusOnView',
|
||||
|
||||
},
|
||||
|
||||
collectionEvents: {},
|
||||
collectionEvents: {
|
||||
},
|
||||
|
||||
childEvents: {},
|
||||
|
||||
initialize: function (options) {
|
||||
var task = this;
|
||||
|
||||
// options
|
||||
if (!('reorderOnSort' in options)) {
|
||||
options.reorderOnSort = true;
|
||||
}
|
||||
|
||||
// backlink
|
||||
this.model.view = this;
|
||||
|
||||
var children = Tasks.filter(
|
||||
var children = pageView.collection.filter(
|
||||
function (child, index, collection) {
|
||||
return child.get('parentId') === this.model.id;
|
||||
}, this);
|
||||
this.collection = new List(children);
|
||||
|
||||
// there is probobly a better way to do this
|
||||
if (this.isEmpty()){
|
||||
this.$el.addClass('empty');
|
||||
}
|
||||
|
||||
// events
|
||||
this.listenTo(this.model, 'change', this.render);
|
||||
this.listenTo(this.model, 'destroy', this.remove);
|
||||
// refresh ui hashes after children are rendered
|
||||
this.listenTo(this, 'render:collection', this.bindUIElements);
|
||||
// custom event
|
||||
this.listenTo(this, 'childview:rerender', this.render);
|
||||
this.listenTo(this, 'focus', this.model.focusOnView);
|
||||
|
||||
// updates from server
|
||||
@@ -113,9 +118,9 @@ define(
|
||||
|
||||
/** Get the parent view or root view **/
|
||||
getParentView: function () {
|
||||
var parent = Tasks.get(this.model.get('parentId'));
|
||||
var parent = pageView.collection.get(this.model.get('parentId'));
|
||||
if (parent) return parent.view;
|
||||
else return listView;
|
||||
else return pageView.listView;
|
||||
},
|
||||
|
||||
/** Update parentId when added to collection **/
|
||||
@@ -126,7 +131,7 @@ define(
|
||||
|
||||
/** Focus on the next visible element down despite list level **/
|
||||
focusOnPrev: function () {
|
||||
var all = listView.$el.find('ul:visible');
|
||||
var all = pageView.listView.$el.find('ul:visible');
|
||||
var prev = $(all[all.index(this.$el) - 1]);
|
||||
if (prev.length){
|
||||
prev.find('input:first').focus();
|
||||
@@ -135,7 +140,7 @@ define(
|
||||
},
|
||||
|
||||
focusOnNext: function () {
|
||||
var all = listView.$el.find('ul:visible');
|
||||
var all = pageView.listView.$el.find('ul:visible');
|
||||
var next = $(all[all.index(this.$el) + 1]);
|
||||
if (next)
|
||||
next.find('input:first').focus();
|
||||
@@ -169,13 +174,11 @@ define(
|
||||
// move down list by swapping priority with next sibling
|
||||
e.preventDefault();
|
||||
this.getParentView().collection.moveDown(this.model);
|
||||
this.trigger('rerender');
|
||||
this.model.focusOnView();
|
||||
} else if (e.ctrlKey && e.keyCode == constants.UP_ARROW) {
|
||||
// move up the list
|
||||
e.preventDefault();
|
||||
this.getParentView().collection.moveUp(this.model);
|
||||
this.trigger('rerender');
|
||||
this.model.focusOnView();
|
||||
} else if (e.keyCode == constants.DOWN_ARROW) {
|
||||
this.focusOnNext();
|
||||
@@ -188,7 +191,7 @@ define(
|
||||
if (parentId===0){
|
||||
|
||||
} else if (parentId){
|
||||
parentModel = Tasks.get(parentId);
|
||||
parentModel = pageView.collection.get(parentId);
|
||||
this.getParentView().collection.remove(this.model);
|
||||
var index = parentModel.view.getParentView().collection.indexOf(parentModel);
|
||||
if (index<0) index=this.getParentView().collection.length-1;
|
||||
@@ -203,7 +206,7 @@ define(
|
||||
var prevSibling = this.$el.prev('ul');
|
||||
if (prevSibling.length) {
|
||||
var prevSibId = prevSibling.find('input:first').data('id');
|
||||
var prevSibView =Tasks.get(prevSibId).view;
|
||||
var prevSibView =pageView.collection.get(prevSibId).view;
|
||||
this.getParentView().collection.remove(this.model);
|
||||
prevSibView.collection.add(this.model);
|
||||
this.model.focusOnView();
|
||||
@@ -269,7 +272,7 @@ define(
|
||||
|
||||
var index= this.getParentView().collection.indexOf(this.model);
|
||||
|
||||
var task = Tasks.add({parentId: this.model.get('parentId')});
|
||||
var task = pageView.collection.add({parentId: this.model.get('parentId')});
|
||||
task.save();
|
||||
if (index>=0)
|
||||
this.getParentView().collection.add(task, {at:index+1});
|
||||
|
||||
Reference in New Issue
Block a user