Home | History | Annotate | Download | only in front_end
      1 /*
      2  * Copyright (C) 2008 Nokia Inc.  All rights reserved.
      3  * Copyright (C) 2013 Samsung Electronics. All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *
      9  * 1.  Redistributions of source code must retain the above copyright
     10  *     notice, this list of conditions and the following disclaimer.
     11  * 2.  Redistributions in binary form must reproduce the above copyright
     12  *     notice, this list of conditions and the following disclaimer in the
     13  *     documentation and/or other materials provided with the distribution.
     14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     15  *     its contributors may be used to endorse or promote products derived
     16  *     from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY
     19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 /**
     31  * @constructor
     32  * @param {string} securityOrigin
     33  * @param {boolean} isLocalStorage
     34  */
     35 WebInspector.DOMStorage = function(securityOrigin, isLocalStorage)
     36 {
     37     this._securityOrigin = securityOrigin;
     38     this._isLocalStorage = isLocalStorage;
     39     this._storageHistory = new WebInspector.DOMStorageHistory(this);
     40 }
     41 
     42 /**
     43  * @param {string} securityOrigin
     44  * @param {boolean} isLocalStorage
     45  * @return {DOMStorageAgent.StorageId}
     46  */
     47 WebInspector.DOMStorage.storageId = function(securityOrigin, isLocalStorage)
     48 {
     49     return { securityOrigin: securityOrigin, isLocalStorage: isLocalStorage };
     50 }
     51 
     52 WebInspector.DOMStorage.prototype = {
     53 
     54     /** @return {DOMStorageAgent.StorageId} */
     55     get id()
     56     {
     57         return WebInspector.DOMStorage.storageId(this._securityOrigin, this._isLocalStorage);
     58     },
     59 
     60     /** @return {string} */
     61     get securityOrigin()
     62     {
     63         return this._securityOrigin;
     64     },
     65 
     66     /** @return {boolean} */
     67     get isLocalStorage()
     68     {
     69         return this._isLocalStorage;
     70     },
     71 
     72     /**
     73      * @param {function(?Protocol.Error, Array.<DOMStorageAgent.Item>):void=} callback
     74      */
     75     getItems: function(callback)
     76     {
     77         DOMStorageAgent.getDOMStorageItems(this.id, callback);
     78     },
     79 
     80     /**
     81      * @param {string} key
     82      * @param {string} value
     83      */
     84     setItem: function(key, value)
     85     {
     86         this._storageHistory.perform(new WebInspector.DOMStorageSetItemAction(this, key, value));
     87     },
     88 
     89     /**
     90      * @param {string} key
     91      */
     92     removeItem: function(key)
     93     {
     94         this._storageHistory.perform(new WebInspector.DOMStorageRemoveItemAction(this, key));
     95     },
     96 
     97     undo: function()
     98     {
     99         this._storageHistory.undo();
    100     },
    101 
    102     redo: function()
    103     {
    104         this._storageHistory.redo();
    105     }
    106 }
    107 
    108 /**
    109  * @constructor
    110  * @param {WebInspector.DOMStorage} domStorage
    111  */
    112 WebInspector.DOMStorageAction = function(domStorage)
    113 {
    114     this._domStorage = domStorage;
    115 }
    116 
    117 WebInspector.DOMStorageAction.prototype = {
    118     /**
    119      * @param {function()} callback
    120      */
    121     perform: function(callback)
    122     {
    123     },
    124 
    125     undo: function()
    126     {
    127     },
    128 
    129     redo: function()
    130     {
    131     }
    132 }
    133 
    134 /**
    135  * @constructor
    136  * @extends {WebInspector.DOMStorageAction}
    137  * @param {WebInspector.DOMStorage} domStorage
    138  * @param {string} key
    139  */
    140 WebInspector.DOMStorageRemoveItemAction = function(domStorage, key)
    141 {
    142     WebInspector.DOMStorageAction.call(this, domStorage);
    143     this._key = key;
    144 }
    145 
    146 WebInspector.DOMStorageRemoveItemAction.prototype = {
    147     /**
    148      * @override
    149      */
    150     perform: function(callback)
    151     {
    152         DOMStorageAgent.getValue(this._domStorage.id, this._key, valueReceived.bind(this));
    153 
    154         /**
    155          * @param {?Protocol.Error} error
    156          * @param {string=} value
    157          */
    158         function valueReceived(error, value)
    159         {
    160             if (error)
    161                 return;
    162 
    163             this._value = value;
    164             this.redo();
    165             callback();
    166         }
    167     },
    168 
    169     /**
    170      * @override
    171      */
    172     undo: function()
    173     {
    174         DOMStorageAgent.setDOMStorageItem(this._domStorage.id, this._key, this._value);
    175     },
    176 
    177     /**
    178      * @override
    179      */
    180     redo: function()
    181     {
    182         DOMStorageAgent.removeDOMStorageItem(this._domStorage.id, this._key);
    183     },
    184 
    185     __proto__: WebInspector.DOMStorageAction.prototype
    186 }
    187 
    188 /**
    189  * @constructor
    190  * @extends {WebInspector.DOMStorageAction}
    191  * @param {WebInspector.DOMStorage} domStorage
    192  * @param {string} key
    193  * @param {string} value
    194  */
    195 WebInspector.DOMStorageSetItemAction = function(domStorage, key, value)
    196 {
    197     WebInspector.DOMStorageAction.call(this, domStorage);
    198     this._key = key;
    199     this._value = value;
    200 }
    201 
    202 WebInspector.DOMStorageSetItemAction.prototype = {
    203     /**
    204      * @override
    205      */
    206     perform: function(callback)
    207     {
    208         DOMStorageAgent.getValue(this._domStorage.id, this._key, valueReceived.bind(this));
    209 
    210         /**
    211          * @param {?Protocol.Error} error
    212          * @param {string=} value
    213          */
    214         function valueReceived(error, value)
    215         {
    216             if (error)
    217                 return;
    218 
    219             if (typeof value === "undefined")
    220                 delete this._exists;
    221             else {
    222                 this._exists = true;
    223                 this._oldValue = value;
    224             }
    225             this.redo();
    226             callback();
    227         }
    228     },
    229 
    230     /**
    231      * @override
    232      */
    233     undo: function()
    234     {
    235         if (!this._exists)
    236             DOMStorageAgent.removeDOMStorageItem(this._domStorage.id, this._key);
    237         else
    238             DOMStorageAgent.setDOMStorageItem(this._domStorage.id, this._key, this._oldValue);
    239     },
    240 
    241     /**
    242      * @override
    243      */
    244     redo: function()
    245     {
    246         DOMStorageAgent.setDOMStorageItem(this._domStorage.id, this._key, this._value);
    247     },
    248 
    249     __proto__: WebInspector.DOMStorageAction.prototype
    250 }
    251 
    252 /**
    253  * @constructor
    254  * @param {WebInspector.DOMStorage} domStorage
    255  */
    256 WebInspector.DOMStorageHistory = function(domStorage)
    257 {
    258     this._domStorage = domStorage;
    259 
    260     /** @type {!Array.<!WebInspector.DOMStorageAction>} */
    261     this._actions = [];
    262     this._undoableActionIndex = -1;
    263 }
    264 
    265 WebInspector.DOMStorageHistory.MAX_UNDO_STACK_DEPTH = 256;
    266 
    267 WebInspector.DOMStorageHistory.prototype = {
    268     /**
    269      * @param {WebInspector.DOMStorageAction} action
    270      */
    271     perform: function(action)
    272     {
    273         if (!action)
    274             return;
    275 
    276         action.perform(actionCompleted.bind(this));
    277         function actionCompleted()
    278         {
    279             if (this._undoableActionIndex + 1 === WebInspector.DOMStorageHistory.MAX_UNDO_STACK_DEPTH) {
    280                 this._actions.shift();
    281                 --this._undoableActionIndex;
    282             } else if (this._undoableActionIndex + 1 < this._actions.length)
    283                 this._actions.splice(this._undoableActionIndex + 1);
    284 
    285             this._actions.push(action);
    286             ++this._undoableActionIndex;
    287         }
    288     },
    289 
    290     undo: function()
    291     {
    292         if (this._undoableActionIndex < 0)
    293             return;
    294 
    295         var action = this._actions[this._undoableActionIndex];
    296         console.assert(action);
    297         action.undo();
    298         --this._undoableActionIndex;
    299     },
    300 
    301     redo: function()
    302     {
    303         if (this._undoableActionIndex >= this._actions.length - 1)
    304             return;
    305 
    306         var action = this._actions[++this._undoableActionIndex];
    307         console.assert(action);
    308         action.redo();
    309     }
    310 }
    311 
    312 /**
    313  * @constructor
    314  * @extends {WebInspector.Object}
    315  */
    316 WebInspector.DOMStorageModel = function()
    317 {
    318     /** @type {!Object.<string, !WebInspector.DOMStorage>} */
    319     this._storages = {};
    320     InspectorBackend.registerDOMStorageDispatcher(new WebInspector.DOMStorageDispatcher(this));
    321     DOMStorageAgent.enable();
    322     WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.SecurityOriginAdded, this._securityOriginAdded, this);
    323     WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.SecurityOriginRemoved, this._securityOriginRemoved, this);
    324 }
    325 
    326 WebInspector.DOMStorageModel.Events = {
    327     DOMStorageAdded: "DOMStorageAdded",
    328     DOMStorageRemoved: "DOMStorageRemoved",
    329     DOMStorageItemsCleared: "DOMStorageItemsCleared",
    330     DOMStorageItemRemoved: "DOMStorageItemRemoved",
    331     DOMStorageItemAdded: "DOMStorageItemAdded",
    332     DOMStorageItemUpdated: "DOMStorageItemUpdated"
    333 }
    334 
    335 WebInspector.DOMStorageModel.prototype = {
    336 
    337     /**
    338      * @param {WebInspector.Event} event
    339      */
    340     _securityOriginAdded: function(event)
    341     {
    342         var securityOrigin = /** @type {string} */ (event.data);
    343         var localStorageKey = this._storageKey(securityOrigin, true);
    344         console.assert(!this._storages[localStorageKey]);
    345         var localStorage = new WebInspector.DOMStorage(securityOrigin, true);
    346         this._storages[localStorageKey] = localStorage;
    347         this.dispatchEventToListeners(WebInspector.DOMStorageModel.Events.DOMStorageAdded, localStorage);
    348 
    349         var sessionStorageKey = this._storageKey(securityOrigin, false);
    350         console.assert(!this._storages[sessionStorageKey]);
    351         var sessionStorage = new WebInspector.DOMStorage(securityOrigin, false);
    352         this._storages[sessionStorageKey] = sessionStorage;
    353         this.dispatchEventToListeners(WebInspector.DOMStorageModel.Events.DOMStorageAdded, sessionStorage);
    354     },
    355 
    356     /**
    357      * @param {WebInspector.Event} event
    358      */
    359     _securityOriginRemoved: function(event)
    360     {
    361         var securityOrigin = /** @type {string} */ (event.data);
    362         var localStorageKey = this._storageKey(securityOrigin, true);
    363         var localStorage = this._storages[localStorageKey];
    364         console.assert(localStorage);
    365         delete this._storages[localStorageKey];
    366         this.dispatchEventToListeners(WebInspector.DOMStorageModel.Events.DOMStorageRemoved, localStorage);
    367 
    368         var sessionStorageKey = this._storageKey(securityOrigin, false);
    369         var sessionStorage = this._storages[sessionStorageKey];
    370         console.assert(sessionStorage);
    371         delete this._storages[sessionStorageKey];
    372         this.dispatchEventToListeners(WebInspector.DOMStorageModel.Events.DOMStorageRemoved, sessionStorage);
    373     },
    374 
    375     /**
    376      * @param {string} securityOrigin
    377      * @param {boolean} isLocalStorage
    378      * @return {string}
    379      */
    380     _storageKey: function(securityOrigin, isLocalStorage)
    381     {
    382         return JSON.stringify(WebInspector.DOMStorage.storageId(securityOrigin, isLocalStorage));
    383     },
    384 
    385     /**
    386      * @param {DOMStorageAgent.StorageId} storageId
    387      */
    388     _domStorageItemsCleared: function(storageId)
    389     {
    390         var domStorage = this.storageForId(storageId);
    391         var storageData = {
    392             storage: domStorage
    393         };
    394         this.dispatchEventToListeners(WebInspector.DOMStorageModel.Events.DOMStorageItemsCleared, storageData);
    395     },
    396 
    397     /**
    398      * @param {DOMStorageAgent.StorageId} storageId
    399      * @param {string} key
    400      */
    401     _domStorageItemRemoved: function(storageId, key)
    402     {
    403         var domStorage = this.storageForId(storageId);
    404         var storageData = {
    405             storage: domStorage,
    406             key: key
    407         };
    408         this.dispatchEventToListeners(WebInspector.DOMStorageModel.Events.DOMStorageItemRemoved, storageData);
    409     },
    410 
    411     /**
    412      * @param {DOMStorageAgent.StorageId} storageId
    413      * @param {string} key
    414      * @param {string} newValue
    415      */
    416     _domStorageItemAdded: function(storageId, key, newValue)
    417     {
    418         var domStorage = this.storageForId(storageId);
    419         var storageData = {
    420             storage: domStorage,
    421             key: key,
    422             newValue: newValue
    423         };
    424         this.dispatchEventToListeners(WebInspector.DOMStorageModel.Events.DOMStorageItemAdded, storageData);
    425     },
    426 
    427     /**
    428      * @param {DOMStorageAgent.StorageId} storageId
    429      * @param {string} key
    430      * @param {string} oldValue
    431      * @param {string} newValue
    432      */
    433     _domStorageItemUpdated: function(storageId, key, oldValue, newValue)
    434     {
    435         var domStorage = this.storageForId(storageId);
    436         var storageData = {
    437             storage: domStorage,
    438             key: key,
    439             oldValue: oldValue,
    440             newValue: newValue
    441         };
    442         this.dispatchEventToListeners(WebInspector.DOMStorageModel.Events.DOMStorageItemUpdated, storageData);
    443     },
    444 
    445     /**
    446      * @param {DOMStorageAgent.StorageId} storageId
    447      * @return {WebInspector.DOMStorage}
    448      */
    449     storageForId: function(storageId)
    450     {
    451         return this._storages[JSON.stringify(storageId)];
    452     },
    453 
    454     /**
    455      * @return {Array.<WebInspector.DOMStorage>}
    456      */
    457     storages: function()
    458     {
    459         var result = [];
    460         for (var id in this._storages)
    461             result.push(this._storages[id]);
    462         return result;
    463     },
    464 
    465     __proto__: WebInspector.Object.prototype
    466 }
    467 
    468 /**
    469  * @constructor
    470  * @implements {DOMStorageAgent.Dispatcher}
    471  * @param {WebInspector.DOMStorageModel} model
    472  */
    473 WebInspector.DOMStorageDispatcher = function(model)
    474 {
    475     this._model = model;
    476 }
    477 
    478 WebInspector.DOMStorageDispatcher.prototype = {
    479 
    480     /**
    481      * @param {DOMStorageAgent.StorageId} storageId
    482      */
    483     domStorageItemsCleared: function(storageId)
    484     {
    485         this._model._domStorageItemsCleared(storageId);
    486     },
    487 
    488     /**
    489      * @param {DOMStorageAgent.StorageId} storageId
    490      * @param {string} key
    491      */
    492     domStorageItemRemoved: function(storageId, key)
    493     {
    494         this._model._domStorageItemRemoved(storageId, key);
    495     },
    496 
    497     /**
    498      * @param {DOMStorageAgent.StorageId} storageId
    499      * @param {string} key
    500      * @param {string} newValue
    501      */
    502     domStorageItemAdded: function(storageId, key, newValue)
    503     {
    504         this._model._domStorageItemAdded(storageId, key, newValue);
    505     },
    506 
    507     /**
    508      * @param {DOMStorageAgent.StorageId} storageId
    509      * @param {string} key
    510      * @param {string} oldValue
    511      * @param {string} newValue
    512      */
    513     domStorageItemUpdated: function(storageId, key, oldValue, newValue)
    514     {
    515         this._model._domStorageItemUpdated(storageId, key, oldValue, newValue);
    516     },
    517 }
    518 
    519 /**
    520  * @type {WebInspector.DOMStorageModel}
    521  */
    522 WebInspector.domStorageModel = null;
    523