localstorage.js 11.6 KB
Newer Older
Tristan Cavelier's avatar
Tristan Cavelier committed
1 2
/**
 * JIO Local Storage. Type = 'local'.
Sven Franck's avatar
Sven Franck committed
3
 * Local browser "database" storage.
Tristan Cavelier's avatar
Tristan Cavelier committed
4
 */
Sven Franck's avatar
Sven Franck committed
5
var newLocalStorage = function (spec, my) {
Tristan Cavelier's avatar
Tristan Cavelier committed
6

Sven Franck's avatar
Sven Franck committed
7
    spec = spec || {};
8 9 10
    var that, priv, localstorage;
    that = my.basicStorage(spec, my);
    priv = {};
Sven Franck's avatar
Sven Franck committed
11

12 13 14 15 16 17
    /*
     * Wrapper for the localStorage used to simplify instion of any kind of
     * values
     */
    localstorage = {
        getItem: function (item) {
18 19
            var value = localStorage.getItem(item);
            return value === null? null: JSON.parse(value);
20
        },
21 22 23
        setItem: function (item, value) {
            return localStorage.setItem(item, JSON.stringify(value));
        },
24 25
        removeItem: function (item) {
            return localStorage.removeItem(item);
26 27
        }
    };
28

29
    // attributes
Tristan Cavelier's avatar
Tristan Cavelier committed
30 31 32
    priv.username = spec.username || '';
    priv.applicationname = spec.applicationname || 'untitled';

33
    priv.localpath = 'jio/localstorage/' +
Sven Franck's avatar
Sven Franck committed
34
        priv.username + '/' + priv.applicationname;
Tristan Cavelier's avatar
Tristan Cavelier committed
35

36
    // ==================== Tools ====================
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
    /**
     * Update [doc] the document object and remove [doc] keys
     * which are not in [new_doc]. It only changes [doc] keys not starting
     * with an underscore.
     * ex: doc:     {key:value1,_key:value2} with
     *     new_doc: {key:value3,_key:value4} updates
     *     doc:     {key:value3,_key:value2}.
     * @param  {object} doc The original document object.
     * @param  {object} new_doc The new document object
     */
    priv.documentObjectUpdate = function (doc, new_doc) {
        var k;
        for (k in doc) {
            if (k[0] !== '_') {
                delete doc[k];
            }
        }
        for (k in new_doc) {
            if (k[0] !== '_') {
                doc[k] = new_doc[k];
            }
        }
    };

61 62 63 64 65 66 67 68 69 70 71 72 73 74
    /**
     * Checks if an object has no enumerable keys
     * @method objectIsEmpty
     * @param  {object} obj The object
     * @return {boolean} true if empty, else false
     */
    priv.objectIsEmpty = function (obj) {
        var k;
        for (k in obj) {
            return false;
        }
        return true;
    };

Sven Franck's avatar
Sven Franck committed
75
    // ===================== overrides ======================
76
    that.specToStore = function () {
77 78 79 80
        return {
            "applicationname": priv.applicationname,
            "username": priv.username
        };
Sven Franck's avatar
Sven Franck committed
81 82 83
    };

    that.validateState = function() {
84 85
        if (typeof priv.username === "string" &&
            priv.username !== '') {
Sven Franck's avatar
Sven Franck committed
86 87 88 89 90
            return '';
        }
        return 'Need at least one parameter: "username".';
    };

91
    // ==================== commands ====================
92
    /**
Sven Franck's avatar
Sven Franck committed
93
     * Create a document in local storage.
94
     * @method post
Sven Franck's avatar
Sven Franck committed
95
     * @param  {object} command The JIO command
96
     */
97
    that.post = function (command) {
98
        setTimeout (function () {
99 100 101 102 103 104 105 106 107 108 109
            var doc = command.getDocId();
            if (!(typeof doc === "string" && doc !== "")) {
                that.error({
                    "status": 405,
                    "statusText": "Method Not Allowed",
                    "error": "method_not_allowed",
                    "message": "Cannot create document which id is undefined",
                    "reason": "Document id is undefined"
                });
                return;
            }
110
            doc = localstorage.getItem(
111
                priv.localpath + "/" + doc);
112
            if (doc === null) {
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
                // the document does not exists
                localstorage.setItem(
                    priv.localpath + "/" + command.getDocId(),
                    command.cloneDoc());
                that.success({"ok":true,"id":command.getDocId()});
            } else {
                // the document already exists
                that.error({
                    "status": 409,
                    "statusText": "Conflicts",
                    "error": "conflicts",
                    "message": "Cannot create a new document",
                    "reason": "Document already exists"
                });
            }
128
        });
129
    };
Tristan Cavelier's avatar
Tristan Cavelier committed
130 131

    /**
Sven Franck's avatar
Sven Franck committed
132
     * Create or update a document in local storage.
133
     * @method put
Sven Franck's avatar
Sven Franck committed
134
     * @param  {object} command The JIO command
Tristan Cavelier's avatar
Tristan Cavelier committed
135
     */
136
    that.put = function (command) {
Sven Franck's avatar
Sven Franck committed
137
        setTimeout(function () {
138 139 140
            var doc;
            doc = localstorage.getItem(
                priv.localpath + "/" + command.getDocId());
141
            if (doc === null) {
142 143
                //  the document does not exists
                doc = command.cloneDoc();
Sven Franck's avatar
Sven Franck committed
144
            } else {
145
                // the document already exists
146
                priv.documentObjectUpdate(doc, command.cloneDoc());
Sven Franck's avatar
Sven Franck committed
147
            }
148 149 150 151 152
            // write
            localstorage.setItem(
                priv.localpath + "/" + command.getDocId(),
                doc);
            that.success({"ok":true,"id":command.getDocId()});
153 154 155 156
        });
    };

    /**
157
     * Add an attachment to a document
158
     * @method  putAttachment
Sven Franck's avatar
Sven Franck committed
159
     * @param  {object} command The JIO command
160
     */
161
    that.putAttachment = function (command) {
Sven Franck's avatar
Sven Franck committed
162
        setTimeout(function () {
163 164 165
            var doc;
            doc = localstorage.getItem(
                priv.localpath + "/" + command.getDocId());
166
            if (doc === null) {
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
                //  the document does not exists
                that.error({
                    "status": 404,
                    "statusText": "Not Found",
                    "error": "not_found",
                    "message": "Impossible to add attachment",
                    "reason": "Document not found"
                });
                return;
            } else {
                // the document already exists
                doc["_attachments"] = doc["_attachments"] || {};
                doc["_attachments"][command.getAttachmentId()] = {
                    "content_type": command.getAttachmentMimeType(),
                    "digest": "md5-"+command.md5SumAttachmentData(),
                    "length": command.getAttachmentLength()
                };
            }
            // upload data
            localstorage.setItem(
187 188 189 190
                priv.localpath + "/" + command.getDocId() + "/" +
                    command.getAttachmentId(),
                command.getAttachmentData()
            );
191 192 193 194 195 196
            // write document
            localstorage.setItem(
                priv.localpath + "/" + command.getDocId(),
                doc);
            that.success({
                "ok":true,
197
                "id":command.getDocId()+"/"+command.getAttachmentId()
198
            });
Tristan Cavelier's avatar
Tristan Cavelier committed
199
        });
Sven Franck's avatar
Sven Franck committed
200 201
    };

Tristan Cavelier's avatar
Tristan Cavelier committed
202
    /**
203
     * Get a document or attachment
204
     * @method get
205
     * @param  {object} command The JIO command
Tristan Cavelier's avatar
Tristan Cavelier committed
206
     */
207
    that.get = function (command) {
Sven Franck's avatar
Sven Franck committed
208
        setTimeout (function () {
209 210 211 212 213 214
            var doc;
            if (typeof command.getAttachmentId() === "string") {
                // seeking for an attachment
                doc = localstorage.getItem(
                    priv.localpath + "/" + command.getDocId() + "/" +
                        command.getAttachmentId());
215
                if (doc !== null) {
216 217 218 219 220 221 222 223 224 225 226 227 228 229
                    that.success(doc);
                } else {
                    that.error({
                        "status": 404,
                        "statusText": "Not Found",
                        "error": "not_found",
                        "message": "Cannot find the attachment ",
                        "reason": "attachment does not exists"
                    });
                }
            } else {
                // seeking for a document
                doc = localstorage.getItem(
                    priv.localpath + "/" + command.getDocId());
230
                if (doc !== null) {
231 232 233 234 235 236 237 238 239 240 241
                    that.success(doc);
                } else {
                    that.error({
                        "status": 404,
                        "statusText": "Not Found",
                        "error": "not_found",
                        "message": "Cannot find the document",
                        "reason": "Document does not exists"
                    });
                }
            }
Tristan Cavelier's avatar
Tristan Cavelier committed
242
        });
Sven Franck's avatar
Sven Franck committed
243 244
    };

Tristan Cavelier's avatar
Tristan Cavelier committed
245
    /**
246
     * Remove a document or attachment
247
     * @method remove
248
     * @param  {object} command The JIO command
Tristan Cavelier's avatar
Tristan Cavelier committed
249
     */
250
    that.remove = function (command) {
Sven Franck's avatar
Sven Franck committed
251
        setTimeout (function () {
252 253 254 255 256 257 258 259 260 261
            var doc, error;
            error = function (word) {
                that.error({
                    "status": 404,
                    "statusText": "Not Found",
                    "error": "not_found",
                    "message": word+" not found",
                    "reason": "missing"
                });
            };
262 263
            doc = localstorage.getItem(
                priv.localpath + "/" + command.getDocId());
264 265
            if (typeof command.getAttachmentId() === "string") {
                // remove attachment from document
266 267
                if (doc !== null && typeof doc === "object" &&
                    typeof doc["_attachments"] === "object") {
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
                    if (typeof doc["_attachments"][
                        command.getAttachmentId()] === "object") {
                        delete doc["_attachments"][command.getAttachmentId()];
                        if (priv.objectIsEmpty(doc["_attachments"])) {
                            delete doc["_attachments"];
                        }
                        localstorage.setItem(
                            priv.localpath + "/" + command.getDocId(),
                            doc);
                        localstorage.removeItem(
                            priv.localpath + "/" + command.getDocId() + "/" +
                                command.getAttachmentId());
                        that.success({
                            "ok": true,
                            "id": command.getDocId()+"/"+
                                command.getAttachmentId()
                        });
                    } else {
                        error("Attachment");
287
                    }
288 289
                } else {
                    error("Document");
290 291 292
                }
            } else {
                // seeking for a document
293
                var attachment_list = [], i;
294 295 296 297 298 299
                if (doc !== null && typeof doc === "object") {
                    if (typeof doc["_attachments"] === "object") {
                        // prepare list of attachments
                        for (i in doc["_attachments"]) {
                            attachment_list.push(i);
                        }
300
                    }
301 302
                } else {
                    return error("Document");
303
                }
304
                localstorage.removeItem(
305
                    priv.localpath + "/" + command.getDocId());
306 307
                // delete all attachments
                for (i = 0; i < attachment_list.length; i += 1) {
308
                    localstorage.removeItem(
309 310 311
                        priv.localpath+"/"+command.getDocId()+"/"+
                            attachment_list[i]);
                }
312 313 314 315 316
                that.success({
                    "ok": true,
                    "id": command.getDocId()
                });
            }
Tristan Cavelier's avatar
Tristan Cavelier committed
317
        });
Sven Franck's avatar
Sven Franck committed
318 319
    };

Tristan Cavelier's avatar
Tristan Cavelier committed
320
    /**
321 322
     * Get all filenames belonging to a user from the document index
     * @method allDocs
323
     * @param  {object} command The JIO command
Tristan Cavelier's avatar
Tristan Cavelier committed
324
     */
325
    that.allDocs = function (command) {
326
        setTimeout(function () {
327 328 329 330 331 332 333
            that.error({
                "status": 405,
                "statusText": "Method Not Allowed",
                "error": "method_not_allowed",
                "message": "Your are not allowed to use this command",
                "reason": "LocalStorage forbids AllDocs command executions"
            });
Tristan Cavelier's avatar
Tristan Cavelier committed
334
        });
Sven Franck's avatar
Sven Franck committed
335
    };
Tristan Cavelier's avatar
Tristan Cavelier committed
336 337 338 339

    return that;
};
jIO.addStorageType('local', newLocalStorage);