Uses localstorage db in offline mode

This commit is contained in:
2016-01-29 22:51:59 +08:00
parent 39d4284de3
commit f0cf9e6d7b
6 changed files with 180 additions and 33 deletions
+2 -1
View File
@@ -5,7 +5,8 @@ require.config({
jquery: '../bower_components/jquery/dist/jquery', jquery: '../bower_components/jquery/dist/jquery',
lodash: "../bower_components/lodash/dist/lodash.min", lodash: "../bower_components/lodash/dist/lodash.min",
backbone: '../bower_components/backbone/backbone', backbone: '../bower_components/backbone/backbone',
localstorage: '../bower_components/backbone.localStorage/backbone.localStorage', localforage: '../bower_components/localforage/dist/localforage',
localforagebackbone: '../bower_components/localforage-backbone/dist/localforage.backbone',
modernizr: "vendor/custom.modernizr", modernizr: "vendor/custom.modernizr",
socket: "../bower_components/socket.io-client/socket.io", socket: "../bower_components/socket.io-client/socket.io",
text: '../bower_components/text/text', text: '../bower_components/text/text',
+14 -3
View File
@@ -2,19 +2,30 @@ define(
[ [
'backbone', 'backbone',
'models/task', 'models/task',
'localstorage', 'localforage',
'localforagebackbone'
], ],
function( function(
Backbone, Backbone,
Task, Task,
LocalStorage localforage,
localforageBackbone
) { ) {
var List = Backbone.Collection.extend({ var List = Backbone.Collection.extend({
localStorage: new Backbone.LocalStorage("tasks"),
model: Task, model: Task,
offlineSync: Backbone.localforage.sync("tasks"),
/** switches sync between server and local databases **/
sync: function(){
if (window.hackflowyOffline)
return this.offlineSync.apply(this, arguments);
else
return Backbone.sync.apply(this, arguments);
},
url: '/tasks' url: '/tasks'
}); });
+115
View File
@@ -0,0 +1,115 @@
define(function (require) {
return [{
"id": 80,
"content": "Welcome to HackFlowy!",
"parentId": 0,
"isCompleted": false,
"priority": 0,
"createdAt": "2016-01-29T05:44:30.858Z",
"updatedAt": "2016-01-29T05:44:30.858Z"
}, {
"id": 81,
"content": "An open-source WorkFlowy clone",
"parentId": 0,
"isCompleted": false,
"priority": 0,
"createdAt": "2016-01-29T05:44:30.858Z",
"updatedAt": "2016-01-29T05:44:30.858Z"
}, {
"id": 82,
"content": "Built using Backbone + Socket.IO",
"parentId": 0,
"isCompleted": false,
"priority": 0,
"createdAt": "2016-01-29T05:44:30.858Z",
"updatedAt": "2016-01-29T05:44:30.858Z"
}, {
"id": 83,
"content": "Desyncr pulled this together in a few hours to learn Backbone",
"parentId": 0,
"isCompleted": false,
"priority": 0,
"createdAt": "2016-01-29T05:44:30.858Z",
"updatedAt": "2016-01-29T05:44:30.858Z"
}, {
"id": 84,
"content": "Feel free to try it out and hack on it",
"parentId": 0,
"isCompleted": false,
"priority": 0,
"createdAt": "2016-01-29T05:44:30.858Z",
"updatedAt": "2016-01-29T05:44:30.858Z"
}, {
"id": 85,
"content": "Good Luck!",
"parentId": 0,
"isCompleted": false,
"priority": 0,
"createdAt": "2016-01-29T05:44:30.858Z",
"updatedAt": "2016-01-29T05:44:30.858Z"
}, {
"id": 86,
"content": "P.S",
"parentId": 0,
"isCompleted": false,
"priority": 0,
"createdAt": "2016-01-29T05:44:40.978Z",
"updatedAt": "2016-01-29T05:44:40.978Z"
}, {
"id": 88,
"content": "It makes sense if you don't think about it; I haven't",
"parentId": 0,
"isCompleted": false,
"priority": 0,
"createdAt": "2016-01-29T05:44:58.737Z",
"updatedAt": "2016-01-29T05:45:50.939Z"
}, {
"id": 89,
"content": "Make love not war",
"parentId": 88,
"isCompleted": false,
"priority": 0,
"createdAt": "2016-01-29T05:45:03.048Z",
"updatedAt": "2016-01-29T05:45:57.481Z"
}, {
"id": 91,
"content": "Love can be brought not sold",
"parentId": 88,
"isCompleted": false,
"priority": 0,
"createdAt": "2016-01-29T05:45:32.331Z",
"updatedAt": "2016-01-29T05:46:10.478Z"
}, {
"id": 93,
"content": "How do I love thee? Let me count the ways - Shakespeare",
"parentId": 88,
"isCompleted": false,
"priority": 0,
"createdAt": "2016-01-29T05:46:25.119Z",
"updatedAt": "2016-01-29T05:48:00.604Z"
}, {
"id": 95,
"content": "Therefore: love can be listed and lists can be loved",
"parentId": 88,
"isCompleted": false,
"priority": 0,
"createdAt": "2016-01-29T05:46:38.998Z",
"updatedAt": "2016-01-29T05:48:22.937Z"
}, {
"id": 96,
"content": "Conclusion: lists and love should be free",
"parentId": 88,
"isCompleted": false,
"priority": 0,
"createdAt": "2016-01-29T05:47:26.684Z",
"updatedAt": "2016-01-29T05:48:29.796Z"
}, {
"id": 97,
"content": "But how can our lists be real if our love isnt? - Jaden Smith",
"parentId": 88,
"isCompleted": false,
"priority": 0,
"createdAt": "2016-01-29T05:47:46.930Z",
"updatedAt": "2016-01-29T05:47:46.930Z"
}];
});
+16 -3
View File
@@ -1,13 +1,26 @@
define( define(
['backbone' ['backbone',
'localforage',
'localforagebackbone'
], ],
function( function(
Backbone Backbone,
localforage,
localforageBackbone
) { ) {
var TaskModel = Backbone.Model.extend({ var TaskModel = Backbone.Model.extend({
offlineSync: Backbone.localforage.sync('TaskModel'),
/** switches sync between server and local databases **/
sync: function(){
if (window.hackflowyOffline)
return this.offlineSync.apply(this,arguments);
else
return Backbone.sync.apply(this, arguments);
},
defaults: { defaults: {
parentId: 0, parentId: 0,
content: '', content: '',
@@ -25,7 +38,7 @@ Backbone
//REVERT BACK ON ERROR //REVERT BACK ON ERROR
self.set({'isCompleted':prev_isCompleted}); self.set({'isCompleted':prev_isCompleted});
} }
}) });
} }
}); });
+32 -26
View File
@@ -27,32 +27,35 @@ define(
this.listenTo(this.collection, 'add', this.renderTask); this.listenTo(this.collection, 'add', this.renderTask);
this.collection.fetch() /** Load demo data and warn users **/
.fail(function (e) { function loadDemoData() {
// if the server isn't running so load some demo data and a demo warning for (var i = 0; i < demoData.length; i++) {
$('#header').append('<div class="alert-box secondary round">Warning: Running in demo mode, all work will be lost</div>'); var task = Tasks.add(demoData[i]);
for (var i = 0; i < demoData.length; i++) { task.save();
Tasks.add(demoData[i]); }
} }
})
.always(function(data){ function success(data) {
console.log({data:data}); // load demo data if the server returns nothing
if (data.length===0){ if (data.length === 0)
// if the server isn't running so load some demo data and a demo warning loadDemoData();
$('#header').append('<div class="alert-box secondary round">Warning: Running in demo mode, work will be lost</div>'); }
for (var i = 0; i < demoData.length; i++) {
var task = Tasks.add(demoData[i]); this.collection.fetch({
task.save(); success: success,
} error: function () {
} // switch to localforage database if server isn't present
}); window.hackflowyOffline=true;
$('#header').append('<div class="alert-box secondary round">Running in offline mode, data may be lost </div>');
Tasks.fetch({
success: success
});
}
});
}, },
render: function (data) { render: function () {
for (var i = 0; i < data.length; i++) {
Tasks.add(data[i]);
}
this.collection.each(function (task) { this.collection.each(function (task) {
this.renderTask(task); this.renderTask(task);
}, this); }, this);
@@ -66,10 +69,13 @@ define(
if (a.model.get('parentId') === 0) { if (a.model.get('parentId') === 0) {
this.$el.append(a.el); this.$el.append(a.el);
} else { } else {
var parent = $('*[data-id="' + a.model.get('parentId')+ '"]'); var parent = $('*[data-id="' + a.model.get('parentId') + '"]');
if (parent.length===0) { if (parent.length === 0) {
// TODO deal with loading order // TODO deal with loading order
console.error("Parent not rendered yet: ", {selector: parent.selector, task: task}); console.error("Parent not rendered yet: ", {
selector: parent.selector,
task: task
});
this.$el.append(a.el); this.$el.append(a.el);
} else { } else {
a.$el.insertBefore(parent.parents('li:first')); a.$el.insertBefore(parent.parents('li:first'));
+1
View File
@@ -127,6 +127,7 @@ define(
var value = this.$input.val().trim(); var value = this.$input.val().trim();
if (value === '') { if (value === '') {
this.model.destroy(); this.model.destroy();
// collection.at(this.model.get('id')).destroy();
} else { } else {
this.model.save({ this.model.save({
content: value, content: value,