Home | History | Annotate | Download | only in front_end
      1 /*
      2  * Copyright (C) 2009 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  * @param {WebInspector.ContextSubMenuItem} topLevelMenu
     34  * @param {string} type
     35  * @param {string=} label
     36  * @param {boolean=} disabled
     37  * @param {boolean=} checked
     38  */
     39 WebInspector.ContextMenuItem = function(topLevelMenu, type, label, disabled, checked)
     40 {
     41     this._type = type;
     42     this._label = label;
     43     this._disabled = disabled;
     44     this._checked = checked;
     45     this._contextMenu = topLevelMenu;
     46     if (type === "item" || type === "checkbox")
     47         this._id = topLevelMenu.nextId();
     48 }
     49 
     50 WebInspector.ContextMenuItem.prototype = {
     51     id: function()
     52     {
     53         return this._id;
     54     },
     55 
     56     type: function()
     57     {
     58         return this._type;
     59     },
     60 
     61     /**
     62      * @return {boolean}
     63      */
     64     isEnabled: function()
     65     {
     66         return !this._disabled;
     67     },
     68 
     69     /**
     70      * @param {boolean} enabled
     71      */
     72     setEnabled: function(enabled)
     73     {
     74         this._disabled = !enabled;
     75     },
     76 
     77     _buildDescriptor: function()
     78     {
     79         switch (this._type) {
     80         case "item":
     81             return { type: "item", id: this._id, label: this._label, enabled: !this._disabled };
     82         case "separator":
     83             return { type: "separator" };
     84         case "checkbox":
     85             return { type: "checkbox", id: this._id, label: this._label, checked: !!this._checked, enabled: !this._disabled };
     86         }
     87     }
     88 }
     89 
     90 /**
     91  * @constructor
     92  * @extends {WebInspector.ContextMenuItem}
     93  * @param topLevelMenu
     94  * @param {string=} label
     95  * @param {boolean=} disabled
     96  */
     97 WebInspector.ContextSubMenuItem = function(topLevelMenu, label, disabled)
     98 {
     99     WebInspector.ContextMenuItem.call(this, topLevelMenu, "subMenu", label, disabled);
    100     /** @type {!Array.<!WebInspector.ContextMenuItem>} */
    101     this._items = [];
    102 }
    103 
    104 WebInspector.ContextSubMenuItem.prototype = {
    105     /**
    106      * @param {string} label
    107      * @param {function(?)} handler
    108      * @param {boolean=} disabled
    109      * @return {WebInspector.ContextMenuItem}
    110      */
    111     appendItem: function(label, handler, disabled)
    112     {
    113         var item = new WebInspector.ContextMenuItem(this._contextMenu, "item", label, disabled);
    114         this._pushItem(item);
    115         this._contextMenu._setHandler(item.id(), handler);
    116         return item;
    117     },
    118 
    119     /**
    120      * @param {string} label
    121      * @param {boolean=} disabled
    122      * @return {WebInspector.ContextMenuItem}
    123      */
    124     appendSubMenuItem: function(label, disabled)
    125     {
    126         var item = new WebInspector.ContextSubMenuItem(this._contextMenu, label, disabled);
    127         this._pushItem(item);
    128         return item;
    129     },
    130 
    131     /**
    132      * @param {boolean=} disabled
    133      */
    134     appendCheckboxItem: function(label, handler, checked, disabled)
    135     {
    136         var item = new WebInspector.ContextMenuItem(this._contextMenu, "checkbox", label, disabled, checked);
    137         this._pushItem(item);
    138         this._contextMenu._setHandler(item.id(), handler);
    139         return item;
    140     },
    141 
    142     appendSeparator: function()
    143     {
    144         if (this._items.length)
    145             this._pendingSeparator = true;
    146     },
    147 
    148     /**
    149      * @param {!WebInspector.ContextMenuItem} item
    150      */
    151     _pushItem: function(item)
    152     {
    153         if (this._pendingSeparator) {
    154             this._items.push(new WebInspector.ContextMenuItem(this._contextMenu, "separator"));
    155             delete this._pendingSeparator;
    156         }
    157         this._items.push(item);
    158     },
    159 
    160     /**
    161      * @return {boolean}
    162      */
    163     isEmpty: function()
    164     {
    165         return !this._items.length;
    166     },
    167 
    168     _buildDescriptor: function()
    169     {
    170         var result = { type: "subMenu", label: this._label, enabled: !this._disabled, subItems: [] };
    171         for (var i = 0; i < this._items.length; ++i)
    172             result.subItems.push(this._items[i]._buildDescriptor());
    173         return result;
    174     },
    175 
    176     __proto__: WebInspector.ContextMenuItem.prototype
    177 }
    178 
    179 /**
    180  * @constructor
    181  * @extends {WebInspector.ContextSubMenuItem}
    182  */
    183 WebInspector.ContextMenu = function(event) {
    184     WebInspector.ContextSubMenuItem.call(this, this, "");
    185     this._event = event;
    186     this._handlers = {};
    187     this._id = 0;
    188 }
    189 
    190 WebInspector.ContextMenu.prototype = {
    191     nextId: function()
    192     {
    193         return this._id++;
    194     },
    195 
    196     show: function()
    197     {
    198         var menuObject = this._buildDescriptor();
    199 
    200         if (menuObject.length) {
    201             WebInspector._contextMenu = this;
    202             InspectorFrontendHost.showContextMenu(this._event, menuObject);
    203             this._event.consume();
    204         }
    205     },
    206 
    207     showSoftMenu: function()
    208     {
    209         var menuObject = this._buildDescriptor();
    210 
    211         if (menuObject.length) {
    212             WebInspector._contextMenu = this;
    213             var softMenu = new WebInspector.SoftContextMenu(menuObject);
    214             softMenu.show(this._event, true);
    215         }
    216         this._event.consume();
    217     },
    218 
    219     _setHandler: function(id, handler)
    220     {
    221         if (handler)
    222             this._handlers[id] = handler;
    223     },
    224 
    225     _buildDescriptor: function()
    226     {
    227         var result = [];
    228         for (var i = 0; i < this._items.length; ++i)
    229             result.push(this._items[i]._buildDescriptor());
    230         return result;
    231     },
    232 
    233     _itemSelected: function(id)
    234     {
    235         if (this._handlers[id])
    236             this._handlers[id].call(this);
    237     },
    238 
    239     /**
    240      * @param {Object} target
    241      */
    242     appendApplicableItems: function(target)
    243     {
    244         for (var i = 0; i < WebInspector.ContextMenu._providers.length; ++i) {
    245             var provider = WebInspector.ContextMenu._providers[i];
    246             this.appendSeparator();
    247             provider.appendApplicableItems(this._event, this, target);
    248             this.appendSeparator();
    249         }
    250     },
    251 
    252     __proto__: WebInspector.ContextSubMenuItem.prototype
    253 }
    254 
    255 /**
    256  * @interface
    257  */
    258 WebInspector.ContextMenu.Provider = function() {
    259 }
    260 
    261 WebInspector.ContextMenu.Provider.prototype = {
    262     /**
    263      * @param {WebInspector.ContextMenu} contextMenu
    264      * @param {Object} target
    265      */
    266     appendApplicableItems: function(event, contextMenu, target) { }
    267 }
    268 
    269 /**
    270  * @param {WebInspector.ContextMenu.Provider} provider
    271  */
    272 WebInspector.ContextMenu.registerProvider = function(provider)
    273 {
    274     WebInspector.ContextMenu._providers.push(provider);
    275 }
    276 
    277 WebInspector.ContextMenu._providers = [];
    278 
    279 WebInspector.contextMenuItemSelected = function(id)
    280 {
    281     if (WebInspector._contextMenu)
    282         WebInspector._contextMenu._itemSelected(id);
    283 }
    284 
    285 WebInspector.contextMenuCleared = function()
    286 {
    287     // FIXME: Unfortunately, contextMenuCleared is invoked between show and item selected
    288     // so we can't delete last menu object from WebInspector. Fix the contract.
    289 }
    290