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 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27/**
28 * @constructor
29 * @extends {WebInspector.View}
30 */
31WebInspector.DOMStorageItemsView = function(domStorage, domStorageModel)
32{
33    WebInspector.View.call(this);
34
35    this.domStorage = domStorage;
36    this.domStorageModel = domStorageModel;
37
38    this.element.addStyleClass("storage-view");
39    this.element.addStyleClass("table");
40
41    this.deleteButton = new WebInspector.StatusBarButton(WebInspector.UIString("Delete"), "delete-storage-status-bar-item");
42    this.deleteButton.visible = false;
43    this.deleteButton.addEventListener("click", this._deleteButtonClicked, this);
44
45    this.refreshButton = new WebInspector.StatusBarButton(WebInspector.UIString("Refresh"), "refresh-storage-status-bar-item");
46    this.refreshButton.addEventListener("click", this._refreshButtonClicked, this);
47
48    this.domStorageModel.addEventListener(WebInspector.DOMStorageModel.Events.DOMStorageItemsCleared, this._domStorageItemsCleared, this);
49    this.domStorageModel.addEventListener(WebInspector.DOMStorageModel.Events.DOMStorageItemRemoved, this._domStorageItemRemoved, this);
50    this.domStorageModel.addEventListener(WebInspector.DOMStorageModel.Events.DOMStorageItemAdded, this._domStorageItemAdded, this);
51    this.domStorageModel.addEventListener(WebInspector.DOMStorageModel.Events.DOMStorageItemUpdated, this._domStorageItemUpdated, this);
52}
53
54WebInspector.DOMStorageItemsView.prototype = {
55    statusBarItems: function()
56    {
57        return [this.refreshButton.element, this.deleteButton.element];
58    },
59
60    wasShown: function()
61    {
62        this._update();
63    },
64
65    willHide: function()
66    {
67        this.deleteButton.visible = false;
68    },
69
70    /**
71     * @param {WebInspector.Event} event
72     */
73    _domStorageItemsCleared: function(event)
74    {
75        if (!this.isShowing())
76            return;
77
78        this._dataGrid.rootNode().removeChildren();
79        this._dataGrid.addCreationNode(false);
80        this.deleteButton.visible = false;
81        event.consume(true);
82    },
83
84    /**
85     * @param {WebInspector.Event} event
86     */
87    _domStorageItemRemoved: function(event)
88    {
89        if (!this.isShowing())
90            return;
91
92        var storageData = event.data;
93        var rootNode = this._dataGrid.rootNode();
94        var children = rootNode.children;
95
96        event.consume(true);
97
98        for (var i = 0; i < children.length; ++i) {
99            var childNode = children[i];
100            if (childNode.data.key === storageData.key) {
101                rootNode.removeChild(childNode);
102                this.deleteButton.visible = (children.length > 1);
103                return;
104            }
105        }
106    },
107
108    /**
109     * @param {WebInspector.Event} event
110     */
111    _domStorageItemAdded: function(event)
112    {
113        if (!this.isShowing())
114            return;
115
116        var storageData = event.data;
117        var rootNode = this._dataGrid.rootNode();
118        var children = rootNode.children;
119
120        event.consume(true);
121        this.deleteButton.visible = true;
122
123        for (var i = 0; i < children.length; ++i)
124            if (children[i].data.key === storageData.key)
125                return;
126
127        var childNode = new WebInspector.DataGridNode({key: storageData.key, value: storageData.newValue}, false);
128        rootNode.insertChild(childNode, children.length - 1);
129    },
130
131    /**
132     * @param {WebInspector.Event} event
133     */
134    _domStorageItemUpdated: function(event)
135    {
136        if (!this.isShowing())
137            return;
138
139        var storageData = event.data;
140        var rootNode = this._dataGrid.rootNode();
141        var children = rootNode.children;
142
143        event.consume(true);
144
145        var keyFound = false;
146        for (var i = 0; i < children.length; ++i) {
147            var childNode = children[i];
148            if (childNode.data.key === storageData.key) {
149                if (keyFound) {
150                    rootNode.removeChild(childNode);
151                    return;
152                }
153                keyFound = true;
154                if (childNode.data.value !== storageData.newValue) {
155                    childNode.data.value = storageData.newValue;
156                    childNode.refresh();
157                    childNode.select();
158                    childNode.reveal();
159                }
160                this.deleteButton.visible = true;
161            }
162        }
163    },
164
165    _update: function()
166    {
167        this.detachChildViews();
168        this.domStorage.getItems(this._showDOMStorageItems.bind(this));
169    },
170
171    _showDOMStorageItems: function(error, items)
172    {
173        if (error)
174            return;
175
176        this._dataGrid = this._dataGridForDOMStorageItems(items);
177        this._dataGrid.show(this.element);
178        this._dataGrid.autoSizeColumns(10);
179        this.deleteButton.visible = (this._dataGrid.rootNode().children.length > 1);
180    },
181
182    _dataGridForDOMStorageItems: function(items)
183    {
184        var columns = [
185            {id: "key", title: WebInspector.UIString("Key"), editable: true},
186            {id: "value", title: WebInspector.UIString("Value"), editable: true}
187        ];
188
189        var nodes = [];
190
191        var keys = [];
192        var length = items.length;
193        for (var i = 0; i < items.length; i++) {
194            var key = items[i][0];
195            var value = items[i][1];
196            var node = new WebInspector.DataGridNode({key: key, value: value}, false);
197            node.selectable = true;
198            nodes.push(node);
199            keys.push(key);
200        }
201
202        var dataGrid = new WebInspector.DataGrid(columns, this._editingCallback.bind(this), this._deleteCallback.bind(this));
203        length = nodes.length;
204        for (var i = 0; i < length; ++i)
205            dataGrid.rootNode().appendChild(nodes[i]);
206        dataGrid.addCreationNode(false);
207        if (length > 0)
208            nodes[0].selected = true;
209        return dataGrid;
210    },
211
212    _deleteButtonClicked: function(event)
213    {
214        if (!this._dataGrid || !this._dataGrid.selectedNode)
215            return;
216
217        this._deleteCallback(this._dataGrid.selectedNode);
218        this._dataGrid.changeNodeAfterDeletion();
219    },
220
221    _refreshButtonClicked: function(event)
222    {
223        this._update();
224    },
225
226    _editingCallback: function(editingNode, columnIdentifier, oldText, newText)
227    {
228        var domStorage = this.domStorage;
229        if ("key" === columnIdentifier) {
230            if (oldText)
231                domStorage.removeItem(oldText);
232            domStorage.setItem(newText, editingNode.data.value);
233            this._removeDupes(editingNode);
234        } else
235            domStorage.setItem(editingNode.data.key, newText);
236    },
237
238    /**
239     * @param {!WebInspector.DataGridNode} masterNode
240     */
241    _removeDupes: function(masterNode)
242    {
243        var rootNode = this._dataGrid.rootNode();
244        var children = rootNode.children;
245        for (var i = children.length - 1; i >= 0; --i) {
246            var childNode = children[i];
247            if ((childNode.data.key === masterNode.data.key) && (masterNode !== childNode))
248                rootNode.removeChild(childNode);
249        }
250    },
251
252    _deleteCallback: function(node)
253    {
254        if (!node || node.isCreationNode)
255            return;
256
257        if (this.domStorage)
258            this.domStorage.removeItem(node.data.key);
259    },
260
261    __proto__: WebInspector.View.prototype
262}
263