1/*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/**
32 * @constructor
33 */
34WebInspector.ShortcutsScreen = function()
35{
36    this._sections = /** @type {Object.<string, !WebInspector.ShortcutsSection>} */ ({});
37}
38
39WebInspector.ShortcutsScreen.prototype = {
40    /**
41     * @param {string} name
42     * @return {!WebInspector.ShortcutsSection}
43     */
44    section: function(name)
45    {
46        var section = this._sections[name];
47        if (!section)
48            this._sections[name] = section = new WebInspector.ShortcutsSection(name);
49        return section;
50    },
51
52    /**
53     * @return {!WebInspector.View}
54     */
55    createShortcutsTabView: function()
56    {
57        var orderedSections = [];
58        for (var section in this._sections)
59            orderedSections.push(this._sections[section]);
60        function compareSections(a, b)
61        {
62            return a.order - b.order;
63        }
64        orderedSections.sort(compareSections);
65
66        var view = new WebInspector.View();
67
68        view.element.className = "settings-tab-container";
69        view.element.createChild("header").createChild("h3").appendChild(document.createTextNode(WebInspector.UIString("Shortcuts")));
70        var container = view.element.createChild("div", "help-container-wrapper").createChild("div");
71        container.className = "help-content help-container";
72        for (var i = 0; i < orderedSections.length; ++i)
73            orderedSections[i].renderSection(container);
74
75        return view;
76    }
77}
78
79/**
80 * We cannot initialize it here as localized strings are not loaded yet.
81 * @type {?WebInspector.ShortcutsScreen}
82 */
83WebInspector.shortcutsScreen = null;
84
85/**
86 * @constructor
87 * @param {string} name
88 */
89WebInspector.ShortcutsSection = function(name)
90{
91    this.name = name;
92    this._lines = /** @type {!Array.<{key: !Node, text: string}>} */ ([]);
93    this.order = ++WebInspector.ShortcutsSection._sequenceNumber;
94};
95
96WebInspector.ShortcutsSection._sequenceNumber = 0;
97
98WebInspector.ShortcutsSection.prototype = {
99    /**
100     * @param {!WebInspector.KeyboardShortcut.Descriptor} key
101     * @param {string} description
102     */
103    addKey: function(key, description)
104    {
105        this._addLine(this._renderKey(key), description);
106    },
107
108    /**
109     * @param {!Array.<!WebInspector.KeyboardShortcut.Descriptor>} keys
110     * @param {string} description
111     */
112    addRelatedKeys: function(keys, description)
113    {
114        this._addLine(this._renderSequence(keys, "/"), description);
115    },
116
117    /**
118     * @param {!Array.<!WebInspector.KeyboardShortcut.Descriptor>} keys
119     * @param {string} description
120     */
121    addAlternateKeys: function(keys, description)
122    {
123        this._addLine(this._renderSequence(keys, WebInspector.UIString("or")), description);
124    },
125
126    /**
127     * @param {!Node} keyElement
128     * @param {string} description
129     */
130    _addLine: function(keyElement, description)
131    {
132        this._lines.push({ key: keyElement, text: description })
133    },
134
135    /**
136     * @param {!Element} container
137     */
138    renderSection: function(container)
139    {
140        var parent = container.createChild("div", "help-block");
141
142        var headLine = parent.createChild("div", "help-line");
143        headLine.createChild("div", "help-key-cell");
144        headLine.createChild("div", "help-section-title help-cell").textContent = this.name;
145
146        for (var i = 0; i < this._lines.length; ++i) {
147            var line = parent.createChild("div", "help-line");
148            var keyCell = line.createChild("div", "help-key-cell");
149            keyCell.appendChild(this._lines[i].key);
150            keyCell.appendChild(this._createSpan("help-key-delimiter", ":"));
151            line.createChild("div", "help-cell").textContent = this._lines[i].text;
152        }
153    },
154
155    /**
156     * @param {!Array.<!WebInspector.KeyboardShortcut.Descriptor>} sequence
157     * @param {string} delimiter
158     * @return {!Node}
159     */
160    _renderSequence: function(sequence, delimiter)
161    {
162        var delimiterSpan = this._createSpan("help-key-delimiter", delimiter);
163        return this._joinNodes(sequence.map(this._renderKey.bind(this)), delimiterSpan);
164    },
165
166    /**
167     * @param {!WebInspector.KeyboardShortcut.Descriptor} key
168     * @return {!Node}
169     */
170    _renderKey: function(key)
171    {
172        var keyName = key.name;
173        var plus = this._createSpan("help-combine-keys", "+");
174        return this._joinNodes(keyName.split(" + ").map(this._createSpan.bind(this, "help-key monospace")), plus);
175    },
176
177    /**
178     * @param {string} className
179     * @param {string} textContent
180     * @return {!Element}
181     */
182    _createSpan: function(className, textContent)
183    {
184        var node = document.createElement("span");
185        node.className = className;
186        node.textContent = textContent;
187        return node;
188    },
189
190    /**
191     * @param {!Array.<!Element>} nodes
192     * @param {!Element} delimiter
193     * @return {!Node}
194     */
195    _joinNodes: function(nodes, delimiter)
196    {
197        var result = document.createDocumentFragment();
198        for (var i = 0; i < nodes.length; ++i) {
199            if (i > 0)
200                result.appendChild(delimiter.cloneNode(true));
201            result.appendChild(nodes[i]);
202        }
203        return result;
204    }
205}
206