Home | History | Annotate | Download | only in host
      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 /** @interface */
     32 function InspectorFrontendHostAPI()
     33 {
     34 }
     35 
     36 /** @typedef {{type:string, id:(number|undefined),
     37                label:(string|undefined), enabled:(boolean|undefined), checked:(boolean|undefined),
     38                subItems:(!Array.<!InspectorFrontendHostAPI.ContextMenuDescriptor>|undefined)}} */
     39 InspectorFrontendHostAPI.ContextMenuDescriptor;
     40 
     41 InspectorFrontendHostAPI.Events = {
     42     AppendedToURL: "appendedToURL",
     43     CanceledSaveURL: "canceledSaveURL",
     44     ContextMenuCleared: "contextMenuCleared",
     45     ContextMenuItemSelected: "contextMenuItemSelected",
     46     DeviceCountUpdated: "deviceCountUpdated",
     47     DevicesUpdated: "devicesUpdated",
     48     DispatchMessage: "dispatchMessage",
     49     EnterInspectElementMode: "enterInspectElementMode",
     50     FileSystemsLoaded: "fileSystemsLoaded",
     51     FileSystemRemoved: "fileSystemRemoved",
     52     FileSystemAdded: "fileSystemAdded",
     53     IndexingTotalWorkCalculated: "indexingTotalWorkCalculated",
     54     IndexingWorked: "indexingWorked",
     55     IndexingDone: "indexingDone",
     56     KeyEventUnhandled: "keyEventUnhandled",
     57     RevealSourceLine: "revealSourceLine",
     58     SavedURL: "savedURL",
     59     SearchCompleted: "searchCompleted",
     60     SetToolbarColors: "setToolbarColors",
     61     SetUseSoftMenu: "setUseSoftMenu",
     62     ShowConsole: "showConsole"
     63 }
     64 
     65 InspectorFrontendHostAPI.EventDescriptors = [
     66     [InspectorFrontendHostAPI.Events.AppendedToURL, ["url"]],
     67     [InspectorFrontendHostAPI.Events.CanceledSaveURL, ["url"]],
     68     [InspectorFrontendHostAPI.Events.ContextMenuCleared, []],
     69     [InspectorFrontendHostAPI.Events.ContextMenuItemSelected, ["id"]],
     70     [InspectorFrontendHostAPI.Events.DeviceCountUpdated, ["count"]],
     71     [InspectorFrontendHostAPI.Events.DevicesUpdated, ["devices"]],
     72     [InspectorFrontendHostAPI.Events.DispatchMessage, ["messageObject"]],
     73     [InspectorFrontendHostAPI.Events.EnterInspectElementMode, [], true],
     74     [InspectorFrontendHostAPI.Events.FileSystemsLoaded, ["fileSystems"]],
     75     [InspectorFrontendHostAPI.Events.FileSystemRemoved, ["fileSystemPath"]],
     76     [InspectorFrontendHostAPI.Events.FileSystemAdded, ["errorMessage", "fileSystem"]],
     77     [InspectorFrontendHostAPI.Events.IndexingTotalWorkCalculated, ["requestId", "fileSystemPath", "totalWork"]],
     78     [InspectorFrontendHostAPI.Events.IndexingWorked, ["requestId", "fileSystemPath", "worked"]],
     79     [InspectorFrontendHostAPI.Events.IndexingDone, ["requestId", "fileSystemPath"]],
     80     [InspectorFrontendHostAPI.Events.KeyEventUnhandled, ["event"], true],
     81     [InspectorFrontendHostAPI.Events.RevealSourceLine, ["url", "lineNumber", "columnNumber"], true],
     82     [InspectorFrontendHostAPI.Events.SavedURL, ["url"]],
     83     [InspectorFrontendHostAPI.Events.SearchCompleted, ["requestId", "fileSystemPath", "files"]],
     84     [InspectorFrontendHostAPI.Events.SetToolbarColors, ["backgroundColor", "color"]],
     85     [InspectorFrontendHostAPI.Events.SetUseSoftMenu, ["useSoftMenu"]],
     86     [InspectorFrontendHostAPI.Events.ShowConsole, [], true]
     87 ];
     88 
     89 InspectorFrontendHostAPI.prototype = {
     90     addFileSystem: function() { },
     91 
     92     /**
     93      * @param {string} url
     94      * @param {string} content
     95      */
     96     append: function(url, content) { },
     97 
     98     /**
     99      * @param {number} requestId
    100      * @param {string} fileSystemPath
    101      */
    102     indexPath: function(requestId, fileSystemPath) { },
    103 
    104     /**
    105      * @return {string}
    106      */
    107     getSelectionBackgroundColor: function() { },
    108 
    109     /**
    110      * @return {string}
    111      */
    112     getSelectionForegroundColor: function() { },
    113 
    114     /**
    115      * Requests inspected page to be placed atop of the inspector frontend with specified bounds.
    116      * @param {{x: number, y: number, width: number, height: number}} bounds
    117      */
    118     setInspectedPageBounds: function(bounds) { },
    119 
    120     /**
    121      * Requests inspected page to be placed atop of the inspector frontend
    122      * with passed insets from the frontend sides, respecting minimum size passed.
    123      * @param {{top: number, left: number, right: number, bottom: number}} insets
    124      * @param {{width: number, height: number}} minSize
    125      */
    126     setContentsResizingStrategy: function(insets, minSize) { },
    127 
    128     /**
    129      * @param {string} shortcuts
    130      */
    131     setWhitelistedShortcuts: function(shortcuts) { },
    132 
    133     inspectElementCompleted: function() { },
    134 
    135     /**
    136      * @param {number} x
    137      * @param {number} y
    138      */
    139     moveWindowBy: function(x, y) { },
    140 
    141     /**
    142      * @param {string} url
    143      */
    144     openInNewTab: function(url) { },
    145 
    146     /**
    147      * @param {string} fileSystemPath
    148      */
    149     removeFileSystem: function(fileSystemPath) { },
    150 
    151     requestFileSystems: function() { },
    152 
    153     /**
    154      * @param {string} url
    155      * @param {string} content
    156      * @param {boolean} forceSaveAs
    157      */
    158     save: function(url, content, forceSaveAs) { },
    159 
    160     /**
    161      * @param {number} requestId
    162      * @param {string} fileSystemPath
    163      * @param {string} query
    164      */
    165     searchInPath: function(requestId, fileSystemPath, query) { },
    166 
    167     /**
    168      * @param {number} requestId
    169      */
    170     stopIndexing: function(requestId) { },
    171 
    172     bringToFront: function() { },
    173 
    174     /**
    175      * @param {string} browserId
    176      * @param {string} url
    177      */
    178     openUrlOnRemoteDeviceAndInspect: function(browserId, url) { },
    179 
    180     closeWindow: function() { },
    181 
    182     copyText: function(text) { },
    183 
    184     /**
    185      * @param {string} url
    186      */
    187     inspectedURLChanged: function(url) { },
    188 
    189     /**
    190      * @param {string} fileSystemId
    191      * @param {string} registeredName
    192      * @return {?DOMFileSystem}
    193      */
    194     isolatedFileSystem: function(fileSystemId, registeredName) { },
    195 
    196     /**
    197      * @param {!FileSystem} fileSystem
    198      */
    199     upgradeDraggedFileSystemPermissions: function(fileSystem) { },
    200 
    201     /**
    202      * @return {string}
    203      */
    204     platform: function() { },
    205 
    206     /**
    207      * @return {string}
    208      */
    209     port: function() { },
    210 
    211     /**
    212      * @param {number} actionCode
    213      */
    214     recordActionTaken: function(actionCode) { },
    215 
    216     /**
    217      * @param {number} panelCode
    218      */
    219     recordPanelShown: function(panelCode) { },
    220 
    221     /**
    222      * @param {string} message
    223      */
    224     sendMessageToBackend: function(message) { },
    225 
    226     /**
    227      * @param {string} message
    228      */
    229     sendMessageToEmbedder: function(message) { },
    230 
    231     /**
    232      * @param {boolean} enabled
    233      */
    234     setDeviceCountUpdatesEnabled: function(enabled) { },
    235 
    236     /**
    237      * @param {boolean} enabled
    238      */
    239     setDevicesUpdatesEnabled: function(enabled) { },
    240 
    241     /**
    242      * @param {string} origin
    243      * @param {string} script
    244      */
    245     setInjectedScriptForOrigin: function(origin, script) { },
    246 
    247     /**
    248      * @param {boolean} isDocked
    249      * @param {!function()} callback
    250      */
    251     setIsDocked: function(isDocked, callback) { },
    252 
    253     /**
    254      * @param {number} zoom
    255      */
    256     setZoomFactor: function(zoom) { },
    257 
    258     /**
    259      * @return {number}
    260      */
    261     zoomFactor: function() { },
    262 
    263     zoomIn: function() { },
    264 
    265     zoomOut: function() { },
    266 
    267     resetZoom: function() { },
    268 
    269     /**
    270      * @param {number} x
    271      * @param {number} y
    272      * @param {!Array.<!InspectorFrontendHostAPI.ContextMenuDescriptor>} items
    273      */
    274     showContextMenuAtPoint: function(x, y, items) { },
    275 
    276     /**
    277      * @return {boolean}
    278      */
    279     isUnderTest: function() { },
    280 
    281     /**
    282      * @return {boolean}
    283      */
    284     isHostedMode: function() { }
    285 }
    286 
    287 /**
    288  * @constructor
    289  * @implements {InspectorFrontendHostAPI}
    290  */
    291 WebInspector.InspectorFrontendHostStub = function()
    292 {
    293 }
    294 
    295 WebInspector.InspectorFrontendHostStub.prototype = {
    296     /**
    297      * @return {string}
    298      */
    299     getSelectionBackgroundColor: function()
    300     {
    301         return "#6e86ff";
    302     },
    303 
    304     /**
    305      * @return {string}
    306      */
    307     getSelectionForegroundColor: function()
    308     {
    309         return "#ffffff";
    310     },
    311 
    312     /**
    313      * @return {string}
    314      */
    315     platform: function()
    316     {
    317         var match = navigator.userAgent.match(/Windows NT/);
    318         if (match)
    319             return "windows";
    320         match = navigator.userAgent.match(/Mac OS X/);
    321         if (match)
    322             return "mac";
    323         return "linux";
    324     },
    325 
    326     /**
    327      * @return {string}
    328      */
    329     port: function()
    330     {
    331         return "unknown";
    332     },
    333 
    334     bringToFront: function()
    335     {
    336         this._windowVisible = true;
    337     },
    338 
    339     closeWindow: function()
    340     {
    341         this._windowVisible = false;
    342     },
    343 
    344     /**
    345      * @param {boolean} isDocked
    346      * @param {!function()} callback
    347      */
    348     setIsDocked: function(isDocked, callback)
    349     {
    350     },
    351 
    352     /**
    353      * Requests inspected page to be placed atop of the inspector frontend with specified bounds.
    354      * @param {{x: number, y: number, width: number, height: number}} bounds
    355      */
    356     setInspectedPageBounds: function(bounds)
    357     {
    358     },
    359 
    360     /**
    361      * Requests inspected page to be placed atop of the inspector frontend
    362      * with passed insets from the frontend sides, respecting minimum size passed.
    363      * @param {{top: number, left: number, right: number, bottom: number}} insets
    364      * @param {{width: number, height: number}} minSize
    365      */
    366     setContentsResizingStrategy: function(insets, minSize)
    367     {
    368     },
    369 
    370     inspectElementCompleted: function()
    371     {
    372     },
    373 
    374     /**
    375      * @param {number} x
    376      * @param {number} y
    377      */
    378     moveWindowBy: function(x, y)
    379     {
    380     },
    381 
    382     /**
    383      * @param {string} origin
    384      * @param {string} script
    385      */
    386     setInjectedScriptForOrigin: function(origin, script)
    387     {
    388     },
    389 
    390     /**
    391      * @param {string} url
    392      */
    393     inspectedURLChanged: function(url)
    394     {
    395         document.title = WebInspector.UIString("Developer Tools - %s", url);
    396     },
    397 
    398     /**
    399      * @param {string} text
    400      */
    401     copyText: function(text)
    402     {
    403         WebInspector.console.error("Clipboard is not enabled in hosted mode. Please inspect using chrome://inspect");
    404     },
    405 
    406     /**
    407      * @param {string} url
    408      */
    409     openInNewTab: function(url)
    410     {
    411         window.open(url, "_blank");
    412     },
    413 
    414     /**
    415      * @param {string} url
    416      * @param {string} content
    417      * @param {boolean} forceSaveAs
    418      */
    419     save: function(url, content, forceSaveAs)
    420     {
    421         WebInspector.console.error("Saving files is not enabled in hosted mode. Please inspect using chrome://inspect");
    422         this.events.dispatchEventToListeners(InspectorFrontendHostAPI.Events.CanceledSaveURL, url);
    423     },
    424 
    425     /**
    426      * @param {string} url
    427      * @param {string} content
    428      */
    429     append: function(url, content)
    430     {
    431         WebInspector.console.error("Saving files is not enabled in hosted mode. Please inspect using chrome://inspect");
    432     },
    433 
    434     /**
    435      * @param {string} message
    436      */
    437     sendMessageToBackend: function(message)
    438     {
    439     },
    440 
    441     /**
    442      * @param {string} message
    443      */
    444     sendMessageToEmbedder: function(message)
    445     {
    446     },
    447 
    448     /**
    449      * @param {number} actionCode
    450      */
    451     recordActionTaken: function(actionCode)
    452     {
    453     },
    454 
    455     /**
    456      * @param {number} panelCode
    457      */
    458     recordPanelShown: function(panelCode)
    459     {
    460     },
    461 
    462     requestFileSystems: function()
    463     {
    464     },
    465 
    466     addFileSystem: function()
    467     {
    468     },
    469 
    470     /**
    471      * @param {string} fileSystemPath
    472      */
    473     removeFileSystem: function(fileSystemPath)
    474     {
    475     },
    476 
    477     /**
    478      * @param {string} fileSystemId
    479      * @param {string} registeredName
    480      * @return {?DOMFileSystem}
    481      */
    482     isolatedFileSystem: function(fileSystemId, registeredName)
    483     {
    484         return null;
    485     },
    486 
    487     /**
    488      * @param {!FileSystem} fileSystem
    489      */
    490     upgradeDraggedFileSystemPermissions: function(fileSystem)
    491     {
    492     },
    493 
    494     /**
    495      * @param {number} requestId
    496      * @param {string} fileSystemPath
    497      */
    498     indexPath: function(requestId, fileSystemPath)
    499     {
    500     },
    501 
    502     /**
    503      * @param {number} requestId
    504      */
    505     stopIndexing: function(requestId)
    506     {
    507     },
    508 
    509     /**
    510      * @param {number} requestId
    511      * @param {string} fileSystemPath
    512      * @param {string} query
    513      */
    514     searchInPath: function(requestId, fileSystemPath, query)
    515     {
    516     },
    517 
    518     /**
    519      * @param {number} zoom
    520      */
    521     setZoomFactor: function(zoom)
    522     {
    523     },
    524 
    525     /**
    526      * @return {number}
    527      */
    528     zoomFactor: function()
    529     {
    530         return 1;
    531     },
    532 
    533     zoomIn: function()
    534     {
    535     },
    536 
    537     zoomOut: function()
    538     {
    539     },
    540 
    541     resetZoom: function()
    542     {
    543     },
    544 
    545     setWhitelistedShortcuts: function(shortcuts)
    546     {
    547     },
    548 
    549     /**
    550      * @return {boolean}
    551      */
    552     isUnderTest: function()
    553     {
    554         return false;
    555     },
    556 
    557     /**
    558      * @param {string} browserId
    559      * @param {string} url
    560      */
    561     openUrlOnRemoteDeviceAndInspect: function(browserId, url)
    562     {
    563     },
    564 
    565     /**
    566      * @param {boolean} enabled
    567      */
    568     setDeviceCountUpdatesEnabled: function(enabled)
    569     {
    570     },
    571 
    572     /**
    573      * @param {boolean} enabled
    574      */
    575     setDevicesUpdatesEnabled: function(enabled)
    576     {
    577     },
    578 
    579     /**
    580      * @param {number} x
    581      * @param {number} y
    582      * @param {!Array.<!InspectorFrontendHostAPI.ContextMenuDescriptor>} items
    583      */
    584     showContextMenuAtPoint: function(x, y, items)
    585     {
    586         throw "Soft context menu should be used";
    587     },
    588 
    589     /**
    590      * @return {boolean}
    591      */
    592     isHostedMode: function()
    593     {
    594         return true;
    595     }
    596 };
    597 
    598 /**
    599  * @type {!InspectorFrontendHostAPI}
    600  */
    601 var InspectorFrontendHost = window.InspectorFrontendHost || null;
    602 
    603 (function() {
    604     if (!InspectorFrontendHost) {
    605         // Instantiate stub for web-hosted mode if necessary.
    606         InspectorFrontendHost = new WebInspector.InspectorFrontendHostStub();
    607     } else {
    608         // Otherwise add stubs for missing methods that are declared in the interface.
    609         var proto = WebInspector.InspectorFrontendHostStub.prototype;
    610         for (var name in proto) {
    611             var value = proto[name];
    612             if (typeof value !== "function" || InspectorFrontendHost[name])
    613                 continue;
    614 
    615             InspectorFrontendHost[name] = stub.bind(null, name);
    616         }
    617     }
    618 
    619     /**
    620      * @param {string} name
    621      */
    622     function stub(name)
    623     {
    624         console.error("Incompatible embedder: method InspectorFrontendHost." + name + " is missing. Using stub instead.");
    625         var args = Array.prototype.slice.call(arguments, 1);
    626         return proto[name].apply(InspectorFrontendHost, args);
    627     }
    628 
    629     // Attach the events object.
    630     InspectorFrontendHost.events = new WebInspector.Object();
    631 })();
    632 
    633 /**
    634  * @constructor
    635  */
    636 function InspectorFrontendAPIImpl()
    637 {
    638     this._isLoaded = false;
    639     this._pendingCommands = [];
    640     this._debugFrontend = !!Runtime.queryParam("debugFrontend");
    641 
    642     var descriptors = InspectorFrontendHostAPI.EventDescriptors;
    643     for (var i = 0; i < descriptors.length; ++i)
    644         this[descriptors[i][0]] = this._dispatch.bind(this, descriptors[i][0], descriptors[i][1], descriptors[i][2]);
    645 }
    646 
    647 InspectorFrontendAPIImpl.prototype = {
    648     loadCompleted: function()
    649     {
    650         this._isLoaded = true;
    651         for (var i = 0; i < this._pendingCommands.length; ++i)
    652             this._pendingCommands[i]();
    653         this._pendingCommands = [];
    654         if (window.opener)
    655             window.opener.postMessage(["loadCompleted"], "*");
    656     },
    657 
    658     /**
    659      * @param {string} name
    660      * @param {!Array.<string>} signature
    661      * @param {boolean} runOnceLoaded
    662      */
    663     _dispatch: function(name, signature, runOnceLoaded)
    664     {
    665         var params = Array.prototype.slice.call(arguments, 3);
    666 
    667         if (this._debugFrontend)
    668             setImmediate(innerDispatch.bind(this));
    669         else
    670             innerDispatch.call(this);
    671 
    672         /**
    673          * @this {!InspectorFrontendAPIImpl}
    674          */
    675         function innerDispatch()
    676         {
    677             if (runOnceLoaded)
    678                 this._runOnceLoaded(dispatchAfterLoad);
    679             else
    680                 dispatchAfterLoad();
    681 
    682             function dispatchAfterLoad()
    683             {
    684                 // Single argument methods get dispatched with the param.
    685                 if (signature.length < 2) {
    686                     InspectorFrontendHost.events.dispatchEventToListeners(name, params[0]);
    687                     return;
    688                 }
    689                 var data = {};
    690                 for (var i = 0; i < signature.length; ++i)
    691                     data[signature[i]] = params[i];
    692                 InspectorFrontendHost.events.dispatchEventToListeners(name, data);
    693             }
    694         }
    695     },
    696 
    697     /**
    698      * @param {function()} command
    699      */
    700     _runOnceLoaded: function(command)
    701     {
    702         if (this._isLoaded) {
    703             command();
    704             return;
    705         }
    706         this._pendingCommands.push(command);
    707     },
    708 
    709     /**
    710      * @param {number} id
    711      * @param {?string} error
    712      */
    713     embedderMessageAck: function(id, error)
    714     {
    715         InspectorFrontendHost["embedderMessageAck"](id, error);
    716     }
    717 }
    718 
    719 var InspectorFrontendAPI = new InspectorFrontendAPIImpl();
    720