所以,我正在开发一个 javascript + api 论坛软件。我的观点是,您可以在离线时阅读论坛——这涉及 HTML5 的离线存储。特别是,我想使用 IndexedDB,因为它似乎是未来最有前途的。我已经获得了一个很好的服务/工厂来获取/临时存储数据,但是 IDDB 被严重破坏了。有人对如何解决这个问题有建议吗?
编辑此外,对于任何想要托管版本的人,它位于cloud9上。
var angular = angular || {};
(function(w){
w.localStorage = w.localStorage||{};
w.indexedDB = w.indexedDB || w.mozIndexedDB || w.webkitIndexedDB || w.msIndexedDB || null;
w.IDBTransaction = w.IDBTransaction || w.webkitIDBTransaction || w.msIDBTransaction || null;
w.IDBKeyRange = w.IDBKeyRange || w.webkitIDBKeyRange || w.msIDBKeyRange || null;
})(this);
angular.module("JSForumServices",[],function($provide){
$provide.factory('ForumStorage',(function(){
var service = {
post:null,
thread:null,
board:null,
cache:{},
pending:{}
};
var fetch = (function(baseFunction,path,callback){
if(path in service.pending)
return service.pending[path];
var r=baseFunction();
service.pending[path] = r;
var ajaxRequest = new XMLHttpRequest();
var cancelled = false;
var dateRegex =
/^(?:(Sun|Mon|Tue|Wed|Thu|Fri|Sat),\s+)?(0[1-9]|[1-2]?[0-9]|3[01])\s+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+(19[0-9]{2}|[2-9][0-9]{3})\s+(2[0-3]|[0-1][0-9]):([0-5][0-9])(?::(60|[0-5][0-9]))?\s+([-\+][0-9]{2}[0-5][0-9]|(?:UT|GMT|(?:E|C|M|P)(?:ST|DT)|[A-IK-Z]))(\s+|\(([^\(\)]+|\\\(|\\\))*\))*$/;
ajaxRequest.onreadystatechange = (function(){
var readyState = ajaxRequest.readyState;
if(readyState==4&&(!cancelled)){
// Store the copy locally!
// Also, initiate the callback.
// This way if the storage fails,
// The application continues to work
// As expected.
var data = JSON.parse(ajaxRequest.responseText);
for(var k in data)
r[k] = data[k];
service.cache[path]={obj:r,modified:new Date()};
delete service.pending[path];
callback(r);
}
else if((path in service.cache)&&readyState>=2){
var oldDate = service.cache[path].modified;
console.log("Cache'd copy for",path,"exists.",oldDate.toString());
var isMoreRecent = false;//Is the server-copy more recent?
var serverModifiedString = ajaxRequest.getResponseHeader("Last-Modified");
console.log(serverModifiedString);
var match = dateRegex.exec(serverModifiedString);
var serverModified = new Date();
serverModified.setDate(parseInt(match[2],10));
serverModified.setMonth({
"jan":0,
"feb":1,
"mar":2,
"apr":3,
"may":4,
"jun":5,
"jul":6,
"aug":7,
"sep":8,
"oct":9,
"nov":10,
"dec":11
}[match[3].toLowerCase()]);
serverModified.setYear(parseInt(match[4],10));
serverModified.setHours(parseInt(match[5],10));
serverModified.setMinutes(parseInt(match[6],10));
serverModified.setMilliseconds(parseInt(match[7],10));
isMoreRecent = serverModified > oldDate;
if(!isMoreRecent&&(path in service.pending)){//sometimes this code may be slower than network speeds? Just to be safe, I guess.
cancelled=true;
var oldObject = service.cache[path].obj;
for(var key in oldObject)
r[key]=oldObject[key];
console.log("using a cache'd value.",r);
callback(r);
delete service.pending[path];
ajaxRequest.abort();//No need to waste more bandwidth!
}
}
});
ajaxRequest.open("GET",path,true);
ajaxRequest.send();
return r;
});
var ObjectFetch = (function(base,constr){
var ret = (function(id,cb){
cb = cb||(function(){});
return fetch(constr,base+id+".json",cb);
});
return ret;
});
service.post = ObjectFetch("./post/",(function(){
return {
id:"???",
author:"???",
content:"",
date:""
};
}));
service.thread = ObjectFetch("./thread/",(function(){
return {
id:"???",
title:"???",
posts:[],
tags:""
};
}));
service.board = ObjectFetch("./board/",(function(){
return {
id:"???",
title:"???",
threads:[],
tags:""
};
}));
service.forum = ObjectFetch("./",(function(){
return {
name:"Javascript Forum Software.",
boards:[]
};
}));
if(window.indexedDB!==null){
var postFetch = service.post;
var threadFetch = service.thread;
var boardFetch = service.board;
(function(dbengine){
var boardsLoaded = false;
var threadsLoaded = false;
var postsLoaded = false;
var req = dbengine.open("forum",1);
req.onupgradeneeded = (function(e){
var db = e.target.result;
db.createObjectStore("post",{
keyPath:"id"
});
db.createObjectStore("thread",{
keyPath:"id"
});
db.createObjectStore("board",{
keyPath:"id"
});
});
req.onsuccess = (function(e){
service.database = e.target.result;
var loadData = service.database.transaction([
'board',
'thread',
'post'],'readwrite');
loadData.onsuccess = (function(ee){
var transaction = ee.target.result;
transaction.objectStore("board").openCursor().onsuccess=(function(e){
var cursor = e.target.result;
if(cursor===null){
boardsLoaded = true;
return;
}
var id = cursor.key;
var obj = cursor.value;
var lastModified = new Date();
if("lastModified" in obj){
lastModified = obj.lastModified;
}
service.cache["./board/"+id.toString().toLowerCase()+".json"]={
obj:obj,
modified:lastModified
};
});
transaction.objectStore("thread").openCursor().onsuccess=(function(e){
var cursor = e.target.result;
if(cursor===null){
threadsLoaded = true;
return;
}
var id = cursor.key;
var obj = cursor.value;
var lastModified = new Date();
if("lastModified" in obj){
lastModified = obj.lastModified;
}
service.cache["./thread/"+id.toString().toLowerCase()+".json"]={
obj:obj,
modified:lastModified
};
});
transaction.objectStore("post").openCursor().onsuccess=(function(e){
var cursor = e.target.result;
if(cursor===null){
postsLoaded = true;
return;
}
var id = cursor.key;
var obj = cursor.value;
var lastModified = new Date();
if("lastModified" in obj){
lastModified = obj.lastModified;
}
service.cache["./post/"+id.toString().toLowerCase()+".json"]={
obj:obj,
modified:lastModified
};
});
service.post = (function(id,cb){
console.log("DDDDDAFF");
var trans = service.database.transaction(["post"],"readwrite");
trans.onsuccess = (function(e){
var req = e.target.result.objectStore("post").get(id);
req.onsuccess = (function(ee){
cb(req.result);
});
req.onerror = (function(ee){
console.log("HAAAA?!");
postFetch(id,(function(post){
e.target.result.objcetStore.save(post);
cb(post);
}));
});
});
trans.onerror = (function(e){
console.log("Error with IDDB:",e);
threadFetch(id,cb);
});
});
service.thread = (function(id,cb){
var trans = service.database.transaction(["thread"],"readwrite");
trans.onsuccess = (function(e){
var req = e.target.result.objectStore("thread").get(id);
req.onsuccess = (function(ee){
cb(req.result);
});
req.onerror = (function(ee){
threadFetch(id,(function(post){
e.target.result.objcetStore.save(post);
cb(post);
}));
});
});
trans.onerror = (function(e){
console.log("Error with IDDB:",e);
postFetch(id,cb);
});
});
service.board = (function(id,cb){
var trans = service.database.transaction(["board"],"readwrite");
trans.onsuccess = (function(e){
var req = e.target.result.objectStore("board").get(id);
req.onsuccess = (function(ee){
cb(req.result);
});
req.onerror = (function(ee){
boardFetch(id,(function(post){
e.target.result.objcetStore.save(post);
cb(post);
}));
});
});
trans.onerror = (function(e){
console.log("Error with IDDB:",e);
boardFetch(id,cb);
});
});
});
});
})(window.indexedDB);
}
return service;
}));
});
angular.module('JSForum',["JSForumServices"]).config(
['$routeProvider',
function($routeProvider){
$routeProvider.when('/',{
templateUrl:"forum.html",
controller:ForumController
});
$routeProvider.when('/board/:id',{
templateUrl:"board.html",
controller:BoardController
});
$routeProvider.when('/thread/:id',{
templateUrl:"thread.html",
controller:ThreadController
});
$routeProvider.otherwise({redirectTo:"/"});
}]);
function ThreadController($scope,$routeParams,ForumStorage){
$scope.id = $routeParams.id.toString().toLowerCase();
$scope.thread = null;
ForumStorage.thread($scope.id,(function(thread){
$scope.thread = thread;
$scope.$apply();
var callback = (function(p){
return (function(post){
$scope.thread.posts[p] = post;
$scope.$apply();
});
});
for(var i=0;i<thread.posts.length;i++)
if(typeof(thread.posts[i].id) == 'undefined')
ForumStorage.post(thread.posts[i],callback(i));
$scope.$apply();
}));
}
function BoardController($scope,$routeParams,ForumStorage){
$scope.id = $routeParams.id.toString().toLowerCase();
$scope.board = null;
ForumStorage.board($scope.id,(function(board){
var callback = (function(p){
return (function(thread){
$scope.board.threads[p] = thread;
$scope.$apply();
});
});
$scope.board = board;
console.log("Using board:",$scope.board);
for(var i=0;i<board.threads.length;i++)
if(typeof(board.threads[i].id)=='undefined')
ForumStorage.thread(board.threads[i],callback(i));
$scope.$apply();
}));
}
function ForumController($scope,ForumStorage){
$scope.name = localStorage.forumName||"Forum";
$scope.boards = [];
ForumStorage.forum("forum",(function(forum){
document.title = $scope.name = localStorage.forumName = forum.name;
$scope.boards = forum.boards;
var callback=(function(p){
return (function(o){
$scope.boards[p] = o;
$scope.$apply();
});
});
for(var i=0;i<$scope.boards.length;i++){
if(typeof($scope.boards[i].id) == 'undefined')
ForumStorage.board(forum.boards[i],callback(i));
}
$scope.$apply();
}));
}