amWiki.storage.js 8.65 KB
/**
 * amWiki Web端 - 浏览器数据缓存模块
 * @author Tevin
 */

;
(function (win) {

    'use strict';

    var tools = win.tools;
    var wikiPath = tools.simString(win.location.pathname.replace('/', '').replace(/\//g, '_')).toUpperCase();
    var LOCAL_STORAGE_NAME = 'AMWikiDataBase@' + wikiPath;  //本地数据localStorage键名
    var LOCAL_STATES = 'AMWikiStates@' + wikiPath;  //本地状态集键名

    /**
     * 本地存储管理
     * @constructor
     */
    var Storage = function () {
        this._db = null;  //内存中的文库缓存
        this._states = null;  //内存中的状态集
        this.$e = {
            win: $(win),
            //更新全部缓存按钮
            searchUpdate: $('#searchUpdate'),
            //缓存状态
            cacheState: $('#cacheState'),
            //文档总数
            cacheDocTotal: $('#cacheDocTotal'),
            //上次全部缓存更新时间
            cacheLasttime: $('#cacheLasttime')
        };
        this._bridgeLocalStorage('read');
        this._bindCtrl();
    };

    /**
     * 存取本地存储
     * @param {String} type - read / save
     * @private
     */
    Storage.prototype._bridgeLocalStorage = function (type) {
        if (type == 'read') {
            var defaultStr = '{"documents":{},"lastBuild":0}';
            this._db = JSON.parse(win.localStorage[LOCAL_STORAGE_NAME] || defaultStr);
            //转换旧名称
            if (typeof this._db.libraries != 'undefined') {
                this._db.documents = this._db.libraries;
                delete this._db.libraries;
            }
        } else if (type == 'save') {
            win.localStorage[LOCAL_STORAGE_NAME] = JSON.stringify(this._db);
        }
    };

    /**
     * 绑定操作
     * @private
     */
    Storage.prototype._bindCtrl = function () {
        var that = this;
        this.$e.win.on('beforeunload', function () {
            that._bridgeLocalStorage('save');
        });
    };

    /**
     * 更新一篇文档,如果相同则不操作(对应内容不用重新渲染)
     * @param {String} uri
     * @param {String} content
     * @returns {Boolean}
     * @public
     */
    Storage.prototype.update = function (uri, content) {
        var id = tools.simString(uri, 'short');
        if (this._db.documents[id]) {
            if (this._db.documents[id].content == content) {
                return false;
            } else {
                this.saveDoc(uri, content, id);
                return true;
            }
        } else {
            this.saveDoc(uri, content, id);
            return true;
        }
    };

    /**
     * 保存一篇文档
     * @param {String} uri - 文档资源地址
     * @param {String} content - 文档内容
     * @param {String} [id] - 已经编码的文档地址,可选
     * @public
     */
    Storage.prototype.saveDoc = function (uri, content, id) {
        this.saveDocToDB(uri, content, id);
        this._bridgeLocalStorage('save');
        this._changeSummary('sateOnly');
    };

    /**
     * 将文档存储到内存
     * @param {String} uri
     * @param {String} content
     * @param {String} id
     * @public
     */
    Storage.prototype.saveDocToDB = function (uri, content, id) {
        if (typeof uri != 'string' && uri == '') {
            throw new Error('Error, uri must be a string!');
        }
        if (typeof id == 'undefined') {
            id = tools.simString(uri, 'short');
        }
        this._db.documents[id] = {
            id: id,
            uri: uri,
            content: content || '',
            timestamp: Date.now()
        };
        this._changeSummary('sateOnly', 'prepare');
    };

    /**
     * 读取一篇文档
     * @param {String} uri - 文档资源地址
     * @returns {String} 文档内容
     * @public
     */
    Storage.prototype.read = function (uri) {
        var id = tools.simString(uri, 'short');
        var article = '';
        if (this._db.documents[id]) {
            article = this._db.documents[id].content;
        }
        return article;
    };

    /**
     * 读取一篇文档的时间
     * @param {String} uri - 文档资源地址
     * @returns {String} 文档内容
     * @public
     */
    Storage.prototype.readTime = function (uri) {
        var id = tools.simString(uri, 'short');
        if (this._db.documents[id]) {
            return this._db.documents[id].timestamp;
        } else {
            return 0;
        }
    };

    /**
     * 删除一篇文档
     * @param {String} uri - 文档资源地址
     * @public
     */
    Storage.prototype.remove = function (uri) {
        var id = tools.simString(uri, 'short');
        delete this._db.documents[id];
        this._bridgeLocalStorage('save');
        this._changeSummary('sateOnly');
    };

    /**
     * 增涨文档打开数记录
     * @param {String} uri
     * @public
     */
    Storage.prototype.increaseOpenedCount = function (uri) {
        var id = tools.simString(uri, 'short');
        //TODO: 待续...打开次数将一定程度影响排行
    };

    /**
     * 校对列表,清除失效文档
     * @param {Array} list - 由导航树偏平化生成的文档列表
     * @public
     */
    Storage.prototype.checkLibChange = function (list) {
        this._indexing = list;
        var documents = {};
        var id = '';
        for (var i = 0; i < list.length; i++) {
            id = tools.simString(list[i], 'short');
            if (typeof this._db.documents[id] != 'undefined') {
                documents[id] = this._db.documents[id];
            }
        }
        this._db.documents = documents;
        this._bridgeLocalStorage('save');
        this._changeSummary();
    };

    /**
     * 更新缓存摘要(位于搜素面板)
     * @param {String} stateOnly - 是否为只读 stateOnly / ...
     * @param {String} prepare - 是否为预先 prepare / ...
     * @private
     */
    Storage.prototype._changeSummary = function (stateOnly, prepare) {
        var libraryiesLong = 0;
        for (var p in this._db.documents) {
            if (this._db.documents.hasOwnProperty(p)) {
                libraryiesLong++;
            }
        }
        //如果是预先,百分数减1
        if (prepare == 'prepare') {
            this.$e.cacheState.text(parseInt(libraryiesLong / this._indexing.length * 100 - 1) + '%');
        }
        //非预先则正常
        else {
            this.$e.cacheState.text(parseInt(libraryiesLong / this._indexing.length * 100) + '%');
        }
        //如果不只是状态
        if (stateOnly != 'stateOnly') {
            this.$e.cacheDocTotal.text(this._indexing.length);
            if (this._db.lastBuild) {
                this.$e.cacheLasttime.text(win.tools.formatTime(this._db.lastBuild));
            } else {
                this.$e.cacheLasttime.text('0000-00-00 00:00:00');
            }
        }
    };

    /**
     * 清除内存中的库列表
     * @public
     */
    Storage.prototype.clearLibraries = function () {
        this._db.documents = {};
        this._changeSummary('sateOnly');
    };

    /**
     * 完成本次缓存重建
     * @public
     */
    Storage.prototype.saveRebuild = function () {
        this._db.lastBuild = Date.now();
        this._bridgeLocalStorage('save');
        this._changeSummary();
    };

    /**
     * 返回导航列表
     * @returns {Array}
     * @public
     */
    Storage.prototype.getIndexList = function () {
        return this._indexing;
    };

    /**
     * 获取当前缓存的所有文档
     * @returns {{Object}}
     * @public
     */
    Storage.prototype.getAllDocs = function () {
        return this._db.documents;
    };

    /**
     * 获取缓存最后重建时间
     * @returns {Number}
     * @public
     */
    Storage.prototype.getLastBuildTs = function () {
        return this._db.lastBuild;
    };

    /**
     * 获取本地存储中指定名称的值
     * @param {String} name
     * @returns {*}
     * @public
     */
    Storage.prototype.getStates = function (name) {
        if (!this._states) {
            this._states = JSON.parse(win.localStorage[LOCAL_STATES] || '{}');
        }
        return this._states[name];
    };

    /**
     * 保持键值对到本地存储
     * @param {String} name
     * @param {*} value
     * @public
     */
    Storage.prototype.setStates = function (name, value) {
        if (!this._states) {
            this._states = JSON.parse(win.localStorage[LOCAL_STATES] || '{}');
        }
        if (typeof value == 'undefined') {
            delete this._states[name];
        } else {
            this._states[name] = value;
        }
        win.localStorage[LOCAL_STATES] = JSON.stringify(this._states);
    };

    return win.AWStorage = Storage;

})(window);