├── .gitignore
├── lint.sh
├── public
├── favicon.ico
├── css
│ ├── Images
│ │ ├── searchNext.png
│ │ ├── searchPrev.png
│ │ ├── toolbarItemSelected.png
│ │ ├── statusbarButtonGlyphs.png
│ │ ├── statusbarButtonGlyphs_2x.png
│ │ └── src
│ │ │ ├── svg2png.hashes
│ │ │ ├── optimize_png.hashes
│ │ │ ├── breakpoint.svg
│ │ │ ├── breakpointConditional.svg
│ │ │ ├── settingsListRemove.svg
│ │ │ └── responsiveDesign.svg
│ ├── jsh.css
│ ├── inspector.css
│ ├── suggestBox.css
│ ├── tabbedPane.css
│ ├── filter.css
│ ├── splitView.css
│ ├── inspectorCommon.css
│ └── dataGrid.css
├── js
│ ├── main
│ │ ├── SimpleApp.js
│ │ └── App.js
│ ├── ui
│ │ ├── ZoomManager.js
│ │ ├── DropDownMenu.js
│ │ ├── Context.js
│ │ ├── ResizerWidget.js
│ │ └── Dialog.js
│ ├── common
│ │ ├── WebInspector.js
│ │ ├── UIString.js
│ │ ├── Throttler.js
│ │ ├── Console.js
│ │ ├── Object.js
│ │ ├── Geometry.js
│ │ ├── TextRange.js
│ │ ├── modules.js
│ │ └── ParsedURL.js
│ ├── components
│ │ ├── PropertiesSection.js
│ │ ├── ExecutionContextSelector.js
│ │ ├── Section.js
│ │ ├── Panel.js
│ │ ├── DockController.js
│ │ └── Drawer.js
│ ├── InjectedScriptHost.js
│ ├── console
│ │ └── ConsolePanel.js
│ ├── host
│ │ └── Platform.js
│ ├── jsh.js
│ ├── jsh-console.js
│ └── sdk
│ │ └── ResourceUtils.js
├── index.html
└── evalFrame.html
├── .jshintrc
├── app.yaml
├── templates
├── jession.min.jinja
└── jession.jinja
├── concatCSS.js
├── jsh.py
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | #*#
3 | node_modules
4 | *.pyc
5 |
--------------------------------------------------------------------------------
/lint.sh:
--------------------------------------------------------------------------------
1 | jshint public/js | grep -v 'everything.min.js'
2 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zirak/jsh/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/css/Images/searchNext.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zirak/jsh/HEAD/public/css/Images/searchNext.png
--------------------------------------------------------------------------------
/public/css/Images/searchPrev.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zirak/jsh/HEAD/public/css/Images/searchPrev.png
--------------------------------------------------------------------------------
/public/css/Images/toolbarItemSelected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zirak/jsh/HEAD/public/css/Images/toolbarItemSelected.png
--------------------------------------------------------------------------------
/public/css/Images/statusbarButtonGlyphs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zirak/jsh/HEAD/public/css/Images/statusbarButtonGlyphs.png
--------------------------------------------------------------------------------
/public/css/Images/statusbarButtonGlyphs_2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zirak/jsh/HEAD/public/css/Images/statusbarButtonGlyphs_2x.png
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "curly" : true,
3 | "evil" : true,
4 | "immed" : true,
5 | "multistr" : true,
6 | "proto" : true
7 | }
8 |
--------------------------------------------------------------------------------
/public/css/jsh.css:
--------------------------------------------------------------------------------
1 | .dark-theme-bar-item {
2 | margin : 4px;
3 | }
4 | .dark-theme-bar-item input[type="checkbox"] {
5 | vertical-align : text-top;
6 | }
7 |
8 | /* for some reason this isn't in the regular stylesheet */
9 | .console-user-command {
10 | width : 100%;
11 | }
12 |
--------------------------------------------------------------------------------
/public/css/Images/src/svg2png.hashes:
--------------------------------------------------------------------------------
1 | {
2 | "statusbarButtonGlyphs.svg": "3f642dca97434b4cbb6491e2854dc69f",
3 | "breakpoint.svg": "69cd92d807259c022791112809b97799",
4 | "responsiveDesign.svg": "bc00a0a7fb0a47453929f94c9a4e003c",
5 | "settingsListRemove.svg": "ce9e7c5c5cdaef28e6ee51d9478d5485",
6 | "breakpointConditional.svg": "4cf90210b2af2ed84db2f60b07bcde28"
7 | }
--------------------------------------------------------------------------------
/public/css/Images/src/optimize_png.hashes:
--------------------------------------------------------------------------------
1 | {
2 | "statusbarButtonGlyphs.svg": "3f642dca97434b4cbb6491e2854dc69f",
3 | "breakpoint.svg": "69cd92d807259c022791112809b97799",
4 | "responsiveDesign.svg": "bc00a0a7fb0a47453929f94c9a4e003c",
5 | "settingsListRemove.svg": "ce9e7c5c5cdaef28e6ee51d9478d5485",
6 | "breakpointConditional.svg": "4cf90210b2af2ed84db2f60b07bcde28"
7 | }
--------------------------------------------------------------------------------
/public/css/inspector.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 The Chromium Authors. All rights reserved.
3 | * Use of this source code is governed by a BSD-style license that can be
4 | * found in the LICENSE file.
5 | */
6 |
7 | @import url("inspectorStyle.css");
8 | @import url("inspectorCommon.css");
9 | @import url("splitView.css");
10 | @import url("suggestBox.css");
11 | @import url("tabbedPane.css");
12 | @import url("jsh.css");
13 |
--------------------------------------------------------------------------------
/public/css/Images/src/breakpoint.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/css/Images/src/breakpointConditional.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app.yaml:
--------------------------------------------------------------------------------
1 | application: jshell
2 | version: 1
3 | runtime: python27
4 | api_version: 1
5 | threadsafe: true
6 |
7 | handlers:
8 | - url: /public
9 | static_dir: public
10 |
11 | - url: /favicon.ico
12 | static_files: public/favicon.ico
13 | upload: public/favicon.ico
14 |
15 | - url: /evalFrame.html
16 | static_files: public/evalFrame.html
17 | upload: public/evalFrame.html
18 |
19 | - url: /.*
20 | script: jsh.application
21 |
22 | libraries:
23 | - name: webapp2
24 | version: latest
25 | - name: jinja2
26 | version: latest
27 |
--------------------------------------------------------------------------------
/public/js/main/SimpleApp.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | /**
6 | * @constructor
7 | * @extends {WebInspector.App}
8 | */
9 | WebInspector.SimpleApp = function()
10 | {
11 | WebInspector.App.call(this);
12 | };
13 |
14 | WebInspector.SimpleApp.prototype = {
15 | createRootView: function()
16 | {
17 | var rootView = new WebInspector.RootView();
18 | WebInspector.inspectorView.show(rootView.element);
19 | rootView.attachToBody();
20 | },
21 |
22 | __proto__: WebInspector.App.prototype
23 | };
24 |
--------------------------------------------------------------------------------
/templates/jession.min.jinja:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | jsh
5 |
6 |
7 |
8 |
9 | {{ commands }}
10 |
11 |
12 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/public/css/Images/src/settingsListRemove.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/css/Images/src/responsiveDesign.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/js/ui/ZoomManager.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | /**
6 | * @constructor
7 | * @extends {WebInspector.Object}
8 | */
9 | WebInspector.ZoomManager = function()
10 | {
11 | this._zoomFactor = InspectorFrontendHost.zoomFactor();
12 | window.addEventListener("resize", this._onWindowResize.bind(this), true);
13 | };
14 |
15 | WebInspector.ZoomManager.Events = {
16 | ZoomChanged: "ZoomChanged"
17 | };
18 |
19 | WebInspector.ZoomManager.prototype = {
20 | /**
21 | * @return {number}
22 | */
23 | zoomFactor: function()
24 | {
25 | return this._zoomFactor;
26 | },
27 |
28 | _onWindowResize: function()
29 | {
30 | var oldZoomFactor = this._zoomFactor;
31 | this._zoomFactor = InspectorFrontendHost.zoomFactor();
32 | if (oldZoomFactor !== this._zoomFactor) {
33 | this.dispatchEventToListeners(WebInspector.ZoomManager.Events.ZoomChanged, {from: oldZoomFactor, to: this._zoomFactor});
34 | }
35 | },
36 |
37 | __proto__: WebInspector.Object.prototype
38 | };
39 |
40 | /**
41 | * @type {!WebInspector.ZoomManager}
42 | */
43 | WebInspector.zoomManager = WebInspector.zoomManager;
44 |
--------------------------------------------------------------------------------
/public/js/common/WebInspector.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 The Chromium Authors. All rights reserved.
3 | * Use of this source code is governed by a BSD-style license that can be
4 | * found in the LICENSE file.
5 | */
6 |
7 | self.WebInspector = {
8 | _queryParamsObject: {}
9 | };
10 |
11 | WebInspector.Events = {
12 | InspectorLoaded: "InspectorLoaded"
13 | };
14 |
15 | /**
16 | * @param {string} name
17 | * @return {?string}
18 | */
19 | WebInspector.queryParam = function(name)
20 | {
21 | return WebInspector._queryParamsObject.hasOwnProperty(name) ? WebInspector._queryParamsObject[name] : null;
22 | };
23 |
24 | {(function parseQueryParameters()
25 | {
26 | var queryParams = location.search;
27 | if (!queryParams) {
28 | return;
29 | }
30 | var params = queryParams.substring(1).split("&");
31 | for (var i = 0; i < params.length; ++i) {
32 | var pair = params[i].split("=");
33 | WebInspector._queryParamsObject[pair[0]] = pair[1];
34 | }
35 |
36 | // Patch settings from the URL param (for tests).
37 | var settingsParam = WebInspector.queryParam("settings");
38 | if (settingsParam) {
39 | try {
40 | var settings = JSON.parse(window.decodeURI(settingsParam));
41 | for (var key in settings) {
42 | window.localStorage[key] = settings[key];
43 | }
44 | } catch(e) {
45 | // Ignore malformed settings.
46 | }
47 | }
48 | })();}
49 |
50 | // zirak: my patches here
51 | WebInspector.isWorkerFrontend = function() {
52 | return false;
53 | };
54 |
--------------------------------------------------------------------------------
/concatCSS.js:
--------------------------------------------------------------------------------
1 | // everything is terrible.
2 | var Promise = require('bluebird'),
3 | pathlib = require('path'),
4 | fs = Promise.promisifyAll(require('fs'));
5 |
6 | var chunkString = function (str, re) {
7 | var match,
8 | lastIndex = 0,
9 | ret = [];
10 |
11 | while (match = re.exec(str)) {
12 | if (match.index > lastIndex) {
13 | ret.push([str.slice(lastIndex, match.index)]);
14 | }
15 |
16 | lastIndex = match.index + match[0].length;
17 | ret.push(match);
18 | }
19 |
20 | if (lastIndex < str.length) {
21 | ret.push([str.slice(lastIndex)]);
22 | }
23 |
24 | return ret;
25 | };
26 |
27 | var processFile = exports.processFile = function (path) {
28 | return fs.readFileAsync(path).then(function (imported) {
29 | return processString(imported, pathlib.dirname(path));
30 | });
31 | };
32 |
33 | var processString = exports.processString = function (data, path) {
34 | // this is incomplete by design and lack of will to make it complete.
35 | var importRegex = /^@import\s+url\(\s*"(.+)"\s*\);$/gm;
36 |
37 | return Promise.map(chunkString(data, importRegex), function (part) {
38 | // part is either the match, or an array containing just a string.
39 | if (!part[1]) {
40 | return part[0];
41 | }
42 |
43 | var importPath = part[1],
44 | relativePath;
45 |
46 | if (path) {
47 | importPath = pathlib.resolve(path, importPath);
48 | }
49 |
50 | return processFile(importPath);
51 | }).reduce(function (ret, val) {
52 | return ret + val;
53 | }, '');
54 | };
55 |
--------------------------------------------------------------------------------
/public/js/common/UIString.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2011 Google Inc. All rights reserved.
3 | * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
4 | * Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com).
5 | * Copyright (C) 2009 Joseph Pecoraro
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | * 2. Redistributions in binary form must reproduce the above copyright
14 | * notice, this list of conditions and the following disclaimer in the
15 | * documentation and/or other materials provided with the distribution.
16 | * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
17 | * its contributors may be used to endorse or promote products derived
18 | * from this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
21 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
24 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | /**
33 | * @param {string} string
34 | * @param {...*} vararg
35 | * @return {string}
36 | */
37 | WebInspector.UIString = function(string, vararg)
38 | {
39 | return String.vsprintf(string, Array.prototype.slice.call(arguments, 1));
40 | };
41 |
--------------------------------------------------------------------------------
/public/js/ui/DropDownMenu.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | /**
6 | * @constructor
7 | * @extends {WebInspector.Object}
8 | */
9 | WebInspector.DropDownMenu = function()
10 | {
11 | this.element = document.createElementWithClass("select", "drop-down-menu");
12 | this.element.addEventListener("mousedown", this._onBeforeMouseDown.bind(this), true);
13 | this.element.addEventListener("mousedown", consumeEvent, false);
14 | this.element.addEventListener("change", this._onChange.bind(this), false);
15 | };
16 |
17 | WebInspector.DropDownMenu.Events = {
18 | BeforeShow: "BeforeShow",
19 | ItemSelected: "ItemSelected"
20 | };
21 |
22 | WebInspector.DropDownMenu.prototype = {
23 | _onBeforeMouseDown: function()
24 | {
25 | this.dispatchEventToListeners(WebInspector.DropDownMenu.Events.BeforeShow, null);
26 | },
27 |
28 | _onChange: function()
29 | {
30 | var options = this.element.options;
31 | var selectedOption = options[this.element.selectedIndex];
32 | this.dispatchEventToListeners(WebInspector.DropDownMenu.Events.ItemSelected, selectedOption.id);
33 | },
34 |
35 | /**
36 | * @param {string} id
37 | * @param {string} title
38 | */
39 | addItem: function(id, title)
40 | {
41 | var option = new Option(title);
42 | option.id = id;
43 | this.element.appendChild(option);
44 | },
45 |
46 | /**
47 | * @param {?string} id
48 | */
49 | selectItem: function(id)
50 | {
51 | var children = this.element.children;
52 | for (var i = 0; i < children.length; ++i) {
53 | var child = children[i];
54 | if (child.id === id) {
55 | this.element.selectedIndex = i;
56 | return;
57 | }
58 | }
59 | this.element.selectedIndex = -1;
60 | },
61 |
62 | clear: function()
63 | {
64 | this.element.removeChildren();
65 | },
66 |
67 | __proto__: WebInspector.Object.prototype
68 | };
69 |
--------------------------------------------------------------------------------
/public/js/components/PropertiesSection.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2007 Apple Inc. All rights reserved.
3 | * Copyright (C) 2009 Google Inc. 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 BY APPLE AND ITS CONTRIBUTORS "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 | * @extends {WebInspector.Section}
33 | * @param {string|!Element} title
34 | * @param {string=} subtitle
35 | */
36 | WebInspector.PropertiesSection = function(title, subtitle)
37 | {
38 | WebInspector.Section.call(this, title, subtitle);
39 |
40 | this.headerElement.classList.add("monospace");
41 | this.propertiesElement = document.createElement("ol");
42 | this.propertiesElement.className = "properties properties-tree monospace";
43 | this.propertiesTreeOutline = new TreeOutline(this.propertiesElement, true);
44 | this.propertiesTreeOutline.setFocusable(false);
45 | this.propertiesTreeOutline.section = this;
46 |
47 | this.element.appendChild(this.propertiesElement);
48 | };
49 |
50 | WebInspector.PropertiesSection.prototype = {
51 | __proto__: WebInspector.Section.prototype
52 | };
53 |
--------------------------------------------------------------------------------
/public/js/common/Throttler.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | /**
6 | * @constructor
7 | * @param {number} timeout
8 | */
9 | WebInspector.Throttler = function(timeout)
10 | {
11 | this._timeout = timeout;
12 | this._isRunningProcess = false;
13 | this._asSoonAsPossible = false;
14 | /** @type {?function(!WebInspector.Throttler.FinishCallback)} */
15 | this._process = null;
16 | };
17 |
18 | WebInspector.Throttler.prototype = {
19 | _processCompleted: function()
20 | {
21 | this._isRunningProcess = false;
22 | if (this._process) {
23 | this._innerSchedule(false);
24 | }
25 | },
26 |
27 | _onTimeout: function()
28 | {
29 | delete this._processTimeout;
30 | this._asSoonAsPossible = false;
31 | this._isRunningProcess = true;
32 |
33 | // Process might issue synchronous calls to this throttler.
34 | var process = this._process;
35 | this._process = null;
36 | process(this._processCompleted.bind(this));
37 | },
38 |
39 | /**
40 | * @param {function(!WebInspector.Throttler.FinishCallback)} process
41 | * @param {boolean=} asSoonAsPossible
42 | */
43 | schedule: function(process, asSoonAsPossible)
44 | {
45 | // Deliberately skip previous process.
46 | this._process = process;
47 | var force = !!asSoonAsPossible && !this._asSoonAsPossible;
48 | this._asSoonAsPossible = this._asSoonAsPossible || !!asSoonAsPossible;
49 |
50 | this._innerSchedule(force);
51 | },
52 |
53 | /**
54 | * @param {boolean} force
55 | */
56 | _innerSchedule: function(force)
57 | {
58 | if (this._isRunningProcess) {
59 | return;
60 | }
61 | if (this._processTimeout && !force) {
62 | return;
63 | }
64 | if (this._processTimeout) {
65 | this._clearTimeout(this._processTimeout);
66 | }
67 |
68 | var timeout = this._asSoonAsPossible ? 0 : this._timeout;
69 | this._processTimeout = this._setTimeout(this._onTimeout.bind(this), timeout);
70 | },
71 |
72 | /**
73 | * @param {number} timeoutId
74 | */
75 | _clearTimeout: function(timeoutId)
76 | {
77 | clearTimeout(timeoutId);
78 | },
79 |
80 | /**
81 | * @param {function()} operation
82 | * @param {number} timeout
83 | * @return {number}
84 | */
85 | _setTimeout: function(operation, timeout)
86 | {
87 | return setTimeout(operation, timeout);
88 | }
89 | };
90 |
91 | /** @typedef {function()} */
92 | WebInspector.Throttler.FinishCallback = WebInspector.Throttler.FinishCallback;
93 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | jsh
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/jsh.py:
--------------------------------------------------------------------------------
1 | import webapp2, jinja2
2 |
3 | from google.appengine.ext import ndb
4 |
5 | import json
6 | import os
7 |
8 | # Models #
9 |
10 | # This name, like Britta, is the worst.
11 | # A Jession is a Session. Only with J instead of S.
12 | # And a session is really just an array of commands.
13 | class Jession(ndb.Model):
14 | commands = ndb.TextProperty(repeated=True)
15 |
16 | # Routes #
17 |
18 | class GetJession(webapp2.RequestHandler):
19 | def get(self, jession_id=None):
20 | if jession_id is not None:
21 | commands = self.get_commands(jession_id)
22 | else:
23 | commands = []
24 |
25 | # TODO actually select between min and full based on some environment
26 | #variable - for some reason GAE is being weird about them.
27 | template_path = 'jession.min.jinja'
28 | template = JINJA.get_template(template_path)
29 |
30 | self.response.write(template.render({
31 | 'commands' : json.dumps(commands)
32 | }))
33 |
34 | def get_commands(self, jession_id):
35 | # jession_id is (supposed to be) the base36 encoding of a db id
36 | try:
37 | db_id = int(jession_id, 36)
38 | except (ValueError, TypeError):
39 | return []
40 |
41 | jession = Jession.get_by_id(db_id)
42 | return jession.commands if jession else []
43 |
44 | class SaveJession(webapp2.RequestHandler):
45 | def post(self):
46 | try:
47 | data = json.loads(self.request.body)
48 | assert data['commands'], 'request has no commands'
49 | except (ValueError, AssertionError) as e:
50 | print e
51 | import traceback; traceback.format_exc()
52 |
53 | self.response.status = 400
54 | return
55 |
56 | jession = Jession(commands=data['commands'])
57 | jession.put()
58 |
59 | self.response.headers['Content-Type'] = 'application/json'
60 |
61 | self.response.write(json.dumps({
62 | 'id' : int_to_base(jession.key.id(), 36)
63 | }))
64 |
65 | # Utility crap
66 |
67 | def int_to_base(n, base, chars=None):
68 | '''
69 | Takes an integer and converts it to a given base (2 <= base <= 36).
70 | The opposite of int(n, base). And batman.
71 | '''
72 |
73 | if chars is None:
74 | import string
75 | chars = string.digits + string.lowercase
76 |
77 | if base > len(chars):
78 | err = 'Base (%d) larger than amount of chars (%d)' % (base, len(chars))
79 | raise ValueError(err)
80 |
81 | if n < base:
82 | return chars[n]
83 |
84 | mod = n % base
85 | return int_to_base(n / base, base, chars) + chars[mod]
86 |
87 | # Here be start of program
88 |
89 | JINJA = jinja2.Environment(
90 | loader=jinja2.FileSystemLoader('templates/'),
91 | extensions=['jinja2.ext.autoescape'],
92 | autoescape=True)
93 |
94 | application = webapp2.WSGIApplication([
95 | (r'/', GetJession),
96 | (r'/save', SaveJession),
97 | # Always keep this last, as it's a catch-all
98 | (r'/([\da-z]+)', GetJession)
99 | ], debug=True)
100 |
--------------------------------------------------------------------------------
/public/js/common/Console.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | /**
6 | * @constructor
7 | * @extends {WebInspector.Object}
8 | */
9 | WebInspector.Console = function()
10 | {
11 | /** @type {!Array.} */
12 | this._messages = [];
13 | };
14 |
15 | /**
16 | * @enum {string}
17 | */
18 | WebInspector.Console.Events = {
19 | MessageAdded: "messageAdded"
20 | };
21 |
22 | /**
23 | * @enum {string}
24 | */
25 | WebInspector.Console.MessageLevel = {
26 | Log: "log",
27 | Warning: "warning",
28 | Error: "error"
29 | };
30 |
31 | /**
32 | * @constructor
33 | * @param {string} text
34 | * @param {!WebInspector.Console.MessageLevel} level
35 | * @param {number} timestamp
36 | * @param {boolean} show
37 | */
38 | WebInspector.Console.Message = function(text, level, timestamp, show)
39 | {
40 | this.text = text;
41 | this.level = level;
42 | this.timestamp = (typeof timestamp === "number") ? timestamp : Date.now();
43 | this.show = show;
44 | };
45 |
46 | /**
47 | * @interface
48 | */
49 | WebInspector.Console.UIDelegate = function()
50 | {
51 | };
52 |
53 | WebInspector.Console.UIDelegate.prototype = {
54 | showConsole: function() { }
55 | };
56 |
57 | WebInspector.Console.prototype = {
58 | /**
59 | * @param {!WebInspector.Console.UIDelegate} uiDelegate
60 | */
61 | setUIDelegate: function(uiDelegate)
62 | {
63 | this._uiDelegate = uiDelegate;
64 | },
65 |
66 | /**
67 | * @param {string} text
68 | * @param {!WebInspector.Console.MessageLevel} level
69 | * @param {boolean=} show
70 | */
71 | addMessage: function(text, level, show)
72 | {
73 | var message = new WebInspector.Console.Message(text, level || WebInspector.Console.MessageLevel.Log, Date.now(), show || false);
74 | this._messages.push(message);
75 | this.dispatchEventToListeners(WebInspector.Console.Events.MessageAdded, message);
76 | },
77 |
78 | /**
79 | * @param {string} text
80 | */
81 | log: function(text)
82 | {
83 | this.addMessage(text, WebInspector.Console.MessageLevel.Log);
84 | },
85 |
86 | /**
87 | * @param {string} text
88 | */
89 | warn: function(text)
90 | {
91 | this.addMessage(text, WebInspector.Console.MessageLevel.Warning);
92 | },
93 |
94 | /**
95 | * @param {string} text
96 | */
97 | error: function(text)
98 | {
99 | this.addMessage(text, WebInspector.Console.MessageLevel.Error, true);
100 | },
101 |
102 | /**
103 | * @return {!Array.}
104 | */
105 | messages: function()
106 | {
107 | return this._messages;
108 | },
109 |
110 | show: function()
111 | {
112 | if (this._uiDelegate) {
113 | this._uiDelegate.showConsole();
114 | }
115 | },
116 |
117 | __proto__: WebInspector.Object.prototype
118 | };
119 |
120 | WebInspector.console = new WebInspector.Console();
121 |
--------------------------------------------------------------------------------
/public/js/InjectedScriptHost.js:
--------------------------------------------------------------------------------
1 | // InjectedScript depends on some native methods. This is their simulation.
2 |
3 | var InjectedScriptHost = {
4 | eval : function (code) {
5 | /*jshint -W067*/
6 | // the above stops jshint from complaining about indirect eval.
7 | return (':(', eval)(code);
8 | },
9 |
10 | evaluateWithExceptionDetails : function (code) {
11 | /*jshint -W061*/
12 | // the above stops jshint from complaining about eval.
13 | return {
14 | result : InjectedScriptHost.eval(code),
15 | exceptionDetails : undefined
16 | };
17 | },
18 |
19 | clearConsoleMessages : function () {
20 | console.clear();
21 | },
22 |
23 | isHTMLAllCollection : function (suspect) {
24 | return suspect === document.all;
25 | },
26 |
27 | type : function (obj) {
28 | /*
29 | V8InjectedScriptHost::typeMethodCustom (found in
30 | chromium/third_party/WebKit/Source/bindings/core/v8/custom/V8InjectedScriptHostCustom.cpp)
31 | does a bunch of value->IsType() calls (->isString, ->isArray etc), and
32 | then some V8Type::hasInstance (V8Mode::hasInstance, V8NodeList::hasInstance, ...)
33 |
34 | isArrayLike above got patched to capture the array ones.
35 |
36 | The best we can repliate that is a Object..toString call.
37 | */
38 |
39 | // [object Type]
40 | // ^--^
41 | var exposedType = ({}).toString.call(obj).slice(8, -1);
42 | var verbatim = ['String', 'Array', 'Boolean', 'Number', 'Date', 'RegExp'];
43 |
44 | if (typeof Symbol !== 'undefined') {
45 | verbatim.push('Symbol');
46 | }
47 |
48 | if (verbatim.indexOf(exposedType) > -1) {
49 | return exposedType.toLowerCase();
50 | }
51 |
52 | // The only thing left is checking for Node.
53 | // Since the object came from another frame, we can't use instanceof.
54 | //This is "good enough".
55 | if ('nodeType' in obj && 'ATTRIBUTE_NODE' in obj) {
56 | return 'node';
57 | }
58 |
59 | var arrayTypes = [
60 | 'Int8Array', 'Int16Array', 'Int32Array',
61 | 'Uint8Array', 'Uint16Array', 'Uint32Array',
62 | 'Uint8ClampedArray',
63 | 'Float32Array', 'Float64Array'
64 | ];
65 | // forgot anything?
66 |
67 | if (arrayTypes.indexOf(obj) > -1) {
68 | return isFinite(obj.length);
69 | }
70 |
71 | // fallback
72 | return 'object';
73 | },
74 |
75 | internalConstructorName : function (subject) {
76 | // The actual implementation does some...weird stuff.
77 | // Fuck that.
78 |
79 | var type = ({}).toString.call(subject).slice(8, -1);
80 | if (subject !== Object(subject)) {
81 | return type;
82 | }
83 |
84 | if (subject.constructor) {
85 | return subject.constructor.name;
86 | }
87 | return type;
88 | },
89 |
90 | suppressWarningsAndCall : function (obj, method) {
91 | // yeah, fuck actual implementation.
92 | var args = [].slice.call(arguments, 2);
93 | return method.apply(obj, args);
94 | }
95 | };
96 |
--------------------------------------------------------------------------------
/public/js/main/App.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | /**
6 | * @constructor
7 | * @implements {WebInspector.Console.UIDelegate}
8 | */
9 | WebInspector.App = function()
10 | {
11 | /*
12 | if (WebInspector.overridesSupport.responsiveDesignAvailable()) {
13 | this._toggleEmulationButton = new WebInspector.StatusBarButton(WebInspector.UIString("Toggle device mode."), "emulation-status-bar-item");
14 | this._toggleEmulationButton.toggled = WebInspector.overridesSupport.emulationEnabled();
15 | this._toggleEmulationButton.addEventListener("click", this._toggleEmulationEnabled, this);
16 | WebInspector.overridesSupport.addEventListener(WebInspector.OverridesSupport.Events.EmulationStateChanged, this._emulationEnabledChanged, this);
17 | WebInspector.overridesSupport.addEventListener(WebInspector.OverridesSupport.Events.OverridesWarningUpdated, this._overridesWarningUpdated, this);
18 | }
19 | */
20 | WebInspector.console.setUIDelegate(this);
21 | };
22 |
23 | WebInspector.App.prototype = {
24 | _toggleEmulationEnabled: function()
25 | {
26 | WebInspector.overridesSupport.setEmulationEnabled(!this._toggleEmulationButton.toggled);
27 | },
28 |
29 | _emulationEnabledChanged: function()
30 | {
31 | this._toggleEmulationButton.toggled = WebInspector.overridesSupport.emulationEnabled();
32 | if (!WebInspector.overridesSupport.responsiveDesignAvailable() && WebInspector.overridesSupport.emulationEnabled()) {
33 | WebInspector.inspectorView.showViewInDrawer("emulation", true);
34 | }
35 | },
36 |
37 | _overridesWarningUpdated: function()
38 | {
39 | if (!this._toggleEmulationButton) {
40 | return;
41 | }
42 | var message = WebInspector.overridesSupport.warningMessage();
43 | this._toggleEmulationButton.title = message || WebInspector.UIString("Toggle device mode.");
44 | this._toggleEmulationButton.element.classList.toggle("warning", !!message);
45 | },
46 |
47 | createRootView: function()
48 | {
49 | },
50 |
51 | /**
52 | * @param {!WebInspector.Target} mainTarget
53 | */
54 | presentUI: function(mainTarget)
55 | {
56 | WebInspector.inspectorView.showInitialPanel();
57 |
58 | /*
59 | WebInspector.overridesSupport.applyInitialOverrides();
60 | if (!WebInspector.overridesSupport.responsiveDesignAvailable() && WebInspector.overridesSupport.emulationEnabled())
61 | WebInspector.inspectorView.showViewInDrawer("emulation", true);
62 | */
63 | this._overridesWarningUpdated();
64 | },
65 |
66 | showConsole: function()
67 | {
68 | WebInspector.Revealer.reveal(WebInspector.console);
69 | }
70 | };
71 |
72 | /**
73 | * @constructor
74 | * @implements {WebInspector.StatusBarButton.Provider}
75 | */
76 | WebInspector.App.EmulationButtonProvider = function()
77 | {
78 | };
79 |
80 | WebInspector.App.EmulationButtonProvider.prototype = {
81 | /**
82 | * @return {?WebInspector.StatusBarButton}
83 | */
84 | button: function()
85 | {
86 | if (!(WebInspector.app instanceof WebInspector.App)) {
87 | return null;
88 | }
89 | return WebInspector.app._toggleEmulationButton || null;
90 | }
91 | };
92 |
93 | /**
94 | * @type {!WebInspector.App}
95 | */
96 | WebInspector.app = WebInspector.app;
97 |
--------------------------------------------------------------------------------
/public/css/suggestBox.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2011 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 | .suggest-box-overlay {
32 | position: absolute;
33 | background-color: transparent;
34 | z-index: 1000;
35 | pointer-events: none;
36 | overflow: hidden;
37 | display: flex;
38 | flex-direction: row;
39 | }
40 |
41 | .suggest-box-overlay .suggest-box-left-spacer {
42 | flex: 0 1 auto;
43 | }
44 |
45 | .suggest-box-overlay .suggest-box-horizontal {
46 | display: flex;
47 | flex-direction: column;
48 | flex: 0 0 auto;
49 | max-width: 300px;
50 | }
51 |
52 | .suggest-box-overlay .suggest-box-top-spacer {
53 | flex: auto;
54 | }
55 |
56 | .suggest-box-overlay.under-anchor .suggest-box-top-spacer,
57 | .suggest-box-overlay:not(.under-anchor) .suggest-box-bottom-spacer {
58 | flex: 0 0 auto;
59 | }
60 |
61 | .suggest-box-overlay .suggest-box {
62 | background-color: #FFFFFF;
63 | border: 1px solid rgb(66%, 66%, 66%);
64 | pointer-events: auto;
65 | margin-left: -3px;
66 | overflow-x: hidden;
67 | overflow-y: auto;
68 | display: flex;
69 | flex-direction: column;
70 | flex: 0 0 auto;
71 | border-radius: 5px 5px 5px 0;
72 | }
73 |
74 | .suggest-box-overlay.under-anchor .suggest-box {
75 | border-radius: 0 5px 5px 5px;
76 | }
77 |
78 | .suggest-box-overlay .suggest-box .suggest-box-content-item {
79 | padding: 1px;
80 | margin: 0;
81 | overflow: hidden;
82 | text-overflow: ellipsis;
83 | border: 1px solid transparent;
84 | flex: 0 0 auto;
85 | padding-right: 0px;
86 | white-space: nowrap;
87 | }
88 |
89 | .suggest-box-overlay .suggest-box .suggest-box-content-item .prefix {
90 | font-weight: bold;
91 | }
92 |
93 | .suggest-box-overlay .suggest-box .suggest-box-content-item .spacer {
94 | display: inline-block;
95 | width: 20px;
96 | }
97 |
98 | .suggest-box-overlay .suggest-box .suggest-box-content-item.selected {
99 | background-color: rgba(56, 121, 217, 0.1);
100 | }
101 |
102 | .suggest-box-overlay .suggest-box .suggest-box-content-item:hover:not(.selected) {
103 | border: 1px solid rgb(204, 204, 204);
104 | }
105 |
--------------------------------------------------------------------------------
/public/js/ui/Context.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | /**
6 | * @constructor
7 | */
8 | WebInspector.Context = function()
9 | {
10 | this._flavors = new Map();
11 | this._eventDispatchers = new Map();
12 | };
13 |
14 | /**
15 | * @enum {string}
16 | */
17 | WebInspector.Context.Events = {
18 | FlavorChanged: "FlavorChanged"
19 | };
20 |
21 | WebInspector.Context.prototype = {
22 | /**
23 | * @param {function(new:T, ...)} flavorType
24 | * @param {?T} flavorValue
25 | * @template T
26 | */
27 | setFlavor: function(flavorType, flavorValue)
28 | {
29 | var value = this._flavors.get(flavorType) || null;
30 | if (value === flavorValue) {
31 | return;
32 | }
33 | if (flavorValue) {
34 | this._flavors.put(flavorType, flavorValue);
35 | }
36 | else {
37 | this._flavors.remove(flavorType);
38 | }
39 |
40 | this._dispatchFlavorChange(flavorType, flavorValue);
41 | },
42 |
43 | /**
44 | * @param {function(new:T, ...)} flavorType
45 | * @param {?T} flavorValue
46 | * @template T
47 | */
48 | _dispatchFlavorChange: function(flavorType, flavorValue)
49 | {
50 | var dispatcher = this._eventDispatchers.get(flavorType);
51 | if (!dispatcher) {
52 | return;
53 | }
54 | dispatcher.dispatchEventToListeners(WebInspector.Context.Events.FlavorChanged, flavorValue);
55 | },
56 |
57 | /**
58 | * @param {function(new:Object, ...)} flavorType
59 | * @param {function(!WebInspector.Event)} listener
60 | * @param {!Object=} thisObject
61 | */
62 | addFlavorChangeListener: function(flavorType, listener, thisObject)
63 | {
64 | var dispatcher = this._eventDispatchers.get(flavorType);
65 | if (!dispatcher) {
66 | dispatcher = new WebInspector.Object();
67 | this._eventDispatchers.put(flavorType, dispatcher);
68 | }
69 | dispatcher.addEventListener(WebInspector.Context.Events.FlavorChanged, listener, thisObject);
70 | },
71 |
72 | /**
73 | * @param {function(new:Object, ...)} flavorType
74 | * @param {function(!WebInspector.Event)} listener
75 | * @param {!Object=} thisObject
76 | */
77 | removeFlavorChangeListener: function(flavorType, listener, thisObject)
78 | {
79 | var dispatcher = this._eventDispatchers.get(flavorType);
80 | if (!dispatcher) {
81 | return;
82 | }
83 | dispatcher.removeEventListener(WebInspector.Context.Events.FlavorChanged, listener, thisObject);
84 | if (!dispatcher.hasEventListeners(WebInspector.Context.Events.FlavorChanged)) {
85 | this._eventDispatchers.remove(flavorType);
86 | }
87 | },
88 |
89 | /**
90 | * @param {function(new:T, ...)} flavorType
91 | * @return {?T}
92 | * @template T
93 | */
94 | flavor: function(flavorType)
95 | {
96 | return this._flavors.get(flavorType) || null;
97 | },
98 |
99 | /**
100 | * @return {!Array.}
101 | */
102 | flavors: function()
103 | {
104 | return this._flavors.keys();
105 | },
106 |
107 | /**
108 | * @param {!Array.} extensions
109 | * @return {!Set.}
110 | */
111 | applicableExtensions: function(extensions)
112 | {
113 | var targetExtensionSet = new Set();
114 |
115 | var availableFlavors = Set.fromArray(this.flavors());
116 | extensions.forEach(function(extension) {
117 | if (WebInspector.moduleManager.isExtensionApplicableToContextTypes(extension, availableFlavors)) {
118 | targetExtensionSet.add(extension);
119 | }
120 | });
121 |
122 | return targetExtensionSet;
123 | }
124 | };
125 |
126 | WebInspector.context = new WebInspector.Context();
127 |
--------------------------------------------------------------------------------
/templates/jession.jinja:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | jsh
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | {{ commands }}
66 |
67 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/public/css/tabbedPane.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3 | * Copyright (C) 2009 Anthony Ricaud
4 | * Copyright (C) 2011 Google Inc. All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are
8 | * met:
9 | *
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | *
13 | * 2. Redistributions in binary form must reproduce the above
14 | * copyright notice, this list of conditions and the following disclaimer
15 | * in the documentation and/or other materials provided with the
16 | * distribution.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS 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 GOOGLE INC.
22 | * OR ITS 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 | .tabbed-pane {
32 | flex: auto;
33 | overflow: hidden;
34 | }
35 |
36 | .tabbed-pane-content {
37 | position: relative;
38 | overflow: auto;
39 | flex: auto;
40 | display: flex;
41 | flex-direction: column;
42 | }
43 |
44 | .tabbed-pane-content.has-no-tabs {
45 | background-color: lightgray;
46 | }
47 |
48 | .tabbed-pane-placeholder {
49 | font-size: 14px;
50 | text-align: center;
51 | margin-top: 20px;
52 | text-shadow: rgba(255, 255, 255, 0.75) 0 1px 0;
53 | }
54 |
55 | .tabbed-pane-header {
56 | flex: 0 0 23px;
57 | border-bottom: 1px solid rgb(163, 163, 163);
58 | overflow: hidden;
59 | width: 100%;
60 | }
61 |
62 | .tabbed-pane-header-contents {
63 | margin: 0 10px;
64 | }
65 |
66 | .tabbed-pane-header-tabs {
67 | float: left;
68 | }
69 |
70 | .tabbed-pane-header-tab {
71 | float: left;
72 | margin-top: 2px;
73 | padding: 2px 4px 2px 4px;
74 | height: 21px;
75 | border: 1px solid transparent;
76 | border-bottom: none;
77 | line-height: 15px;
78 | white-space: nowrap;
79 | text-overflow: ellipsis;
80 | overflow: hidden;
81 | cursor: default;
82 | }
83 |
84 | .tabbed-pane-header-tab.measuring {
85 | visibility: hidden;
86 | }
87 |
88 | .tabbed-pane-header-tab.selected {
89 | border: 1px solid rgb(163, 163, 163);
90 | border-bottom: none;
91 | }
92 |
93 | .tabbed-pane-header-tab.selected {
94 | background: white;
95 | border-top-color: #bbb;
96 | }
97 |
98 | .tabbed-pane-header-tab .close-button-gray {
99 | position: relative;
100 | top: 2px;
101 | left: 1px;
102 | margin-left: 2px;
103 | margin-top: -3px;
104 | visibility: hidden;
105 | }
106 |
107 | .tabbed-pane-header-tab:hover .close-button-gray,
108 | .tabbed-pane-header-tab.selected .close-button-gray {
109 | visibility: visible;
110 | }
111 |
112 | .tabbed-pane-header-tab-icon {
113 | width: 11px;
114 | height: 10px;
115 | margin-top: 3px;
116 | float: left;
117 | display: block;
118 | margin-right: 1px;
119 | }
120 |
121 | .tabbed-pane-header-tabs-drop-down-container {
122 | float: left;
123 | position: relative;
124 | vertical-align: bottom;
125 | padding-left: 3px;
126 | line-height: 20px;
127 | }
128 |
129 | .tabbed-pane-header-tabs-drop-down-container.measuring {
130 | visibility: hidden;
131 | }
132 |
133 | .tabbed-pane-header-tabs-drop-down {
134 | position: relative;
135 | opacity: 0.7;
136 | color: rgb(30, 30, 30);
137 | font-size: 133%;
138 | padding: 0 3px;
139 | }
140 |
141 | .tabbed-pane-header-tabs-drop-down:hover {
142 | opacity: 1.0;
143 | }
144 |
145 | .tabbed-pane-header-tabs-drop-down:active {
146 | opacity: 0.8;
147 | }
148 |
149 | .tabbed-pane-header-tabs-drop-down > select.drop-down-menu {
150 | position: absolute;
151 | top: 0;
152 | right: 0;
153 | bottom: 0;
154 | left: 0;
155 | opacity: 0;
156 | font-size: 75%;
157 | width: 20px;
158 | }
159 |
--------------------------------------------------------------------------------
/public/css/filter.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 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 | .filter-text-filter {
32 | display: flex;
33 | margin-left: 2px;
34 | margin-right: 2px;
35 | flex: 0 1 120px;
36 | min-width: 40px;
37 | }
38 |
39 | .filter-text-filter.supports-regex {
40 | flex: 0 0 155px;
41 | }
42 |
43 | .filter-text-filter label {
44 | margin: auto 0;
45 | }
46 |
47 | .filter-bitset-filter {
48 | padding: 0 10px !important;
49 | overflow: hidden;
50 | display: flex !important;
51 | }
52 |
53 | .filter-bitset-filter li {
54 | display: inline-block;
55 | margin: auto 2px;
56 | padding: 4px 6px 3px 6px;
57 | background: transparent;
58 | text-shadow: rgba(255, 255, 255, 0.5) 0 1px 0;
59 | border-radius: 8px;
60 | }
61 |
62 | .filter-bitset-filter-divider {
63 | background-color: #ccc;
64 | height: 16px;
65 | width: 1px;
66 | margin: auto 2px;
67 | display: inline-block;
68 | }
69 |
70 | .filter-bitset-filter li.selected,
71 | .filter-bitset-filter li:hover,
72 | .filter-bitset-filter li:active {
73 | color: white;
74 | text-shadow: rgba(0, 0, 0, 0.4) 0 1px 0;
75 | }
76 |
77 | .filter-bitset-filter li:hover {
78 | background: rgba(0, 0, 0, 0.2);
79 | }
80 |
81 | .filter-bitset-filter li.selected {
82 | background: rgba(0, 0, 0, 0.3);
83 | }
84 |
85 | .filter-bitset-filter li:active {
86 | background: rgba(0, 0, 0, 0.5);
87 | }
88 |
89 | .filter-combobox-filter {
90 | margin-left: 5px;
91 | margin-right: 2px;
92 | flex: 0 0 auto;
93 | }
94 |
95 | .filter-checkbox-filter {
96 | padding-left: 4px;
97 | padding-right: 2px;
98 | white-space: nowrap;
99 | text-overflow: ellipsis;
100 | overflow: hidden;
101 | display: flex;
102 | }
103 |
104 | .filter-checkbox-filter > label {
105 | display: flex;
106 | margin: auto 0;
107 | }
108 |
109 | .filter-text-invalid {
110 | background-color: rgb(255, 200, 200);
111 | }
112 |
113 | .filter-checkbox-filter .checkbox-filter-checkbox {
114 | width: 10px;
115 | height: 10px;
116 | margin: auto 3px;
117 | padding: 0;
118 | border-radius: 2px;
119 | border: solid 1px;
120 | display: inline-block;
121 | overflow: visible;
122 | opacity: 0.8;
123 | flex-shrink: 0;
124 | }
125 |
126 |
127 | .filter-checkbox-filter .checkbox-filter-checkbox-check {
128 | -webkit-appearance: none;
129 | width: 11px;
130 | height: 11px;
131 | margin-top: -2px;
132 | margin-left: 1px;
133 | }
134 |
135 | .filter-checkbox-filter .checkbox-filter-checkbox-checked {
136 | background-image: url(Images/statusbarButtonGlyphs.png);
137 | background-size: 320px 144px;
138 | background-position: -129px -110px;
139 | }
140 |
141 | .filters-toggle > .glyph {
142 | -webkit-mask-position: -32px -48px;
143 | }
144 |
145 | .filters-toggle.toggled-shown .glyph {
146 | background-color: rgb(66, 129, 235);
147 | }
148 |
149 | .filters-toggle.toggled-active .glyph {
150 | background-color: rgb(216, 0, 0);
151 | }
152 |
--------------------------------------------------------------------------------
/public/js/console/ConsolePanel.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 Joseph Pecoraro
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions
6 | * are met:
7 | *
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 | * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 | * its contributors may be used to endorse or promote products derived
15 | * from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | //importScript("ConsoleViewMessage.js");
30 | //importScript("ConsoleView.js");
31 |
32 | /**
33 | * @constructor
34 | * @extends {WebInspector.Panel}
35 | */
36 | WebInspector.ConsolePanel = function()
37 | {
38 | WebInspector.Panel.call(this, "console");
39 | this._view = WebInspector.ConsolePanel._view();
40 | };
41 |
42 | /**
43 | * @return {!WebInspector.ConsoleView}
44 | */
45 | WebInspector.ConsolePanel._view = function()
46 | {
47 | if (!WebInspector.ConsolePanel._consoleView) {
48 | WebInspector.ConsolePanel._consoleView = new WebInspector.ConsoleView(WebInspector.isWorkerFrontend());
49 | }
50 |
51 | return WebInspector.ConsolePanel._consoleView;
52 | };
53 |
54 | WebInspector.ConsolePanel.prototype = {
55 | /**
56 | * @return {!Element}
57 | */
58 | defaultFocusedElement: function()
59 | {
60 | return this._view.defaultFocusedElement();
61 | },
62 |
63 | wasShown: function()
64 | {
65 | WebInspector.Panel.prototype.wasShown.call(this);
66 | this._view.show(this.element);
67 | },
68 |
69 | willHide: function()
70 | {
71 | WebInspector.Panel.prototype.willHide.call(this);
72 | if (WebInspector.ConsolePanel.WrapperView._instance) {
73 | WebInspector.ConsolePanel.WrapperView._instance._showViewInWrapper();
74 | }
75 | },
76 |
77 | __proto__: WebInspector.Panel.prototype
78 | };
79 |
80 | /**
81 | * @constructor
82 | * @extends {WebInspector.VBox}
83 | */
84 | WebInspector.ConsolePanel.WrapperView = function()
85 | {
86 | WebInspector.VBox.call(this);
87 | this.element.classList.add("console-view-wrapper");
88 |
89 | WebInspector.ConsolePanel.WrapperView._instance = this;
90 |
91 | this._view = WebInspector.ConsolePanel._view();
92 | // FIXME: this won't be needed once drawer becomes a view.
93 | this.wasShown();
94 | };
95 |
96 | WebInspector.ConsolePanel.WrapperView.prototype = {
97 | wasShown: function()
98 | {
99 | if (!WebInspector.inspectorView.currentPanel() || WebInspector.inspectorView.currentPanel().name !== "console") {
100 | this._showViewInWrapper();
101 | }
102 | },
103 |
104 | /**
105 | * @return {!Element}
106 | */
107 | defaultFocusedElement: function()
108 | {
109 | return this._view.defaultFocusedElement();
110 | },
111 |
112 | focus: function()
113 | {
114 | this._view.focus();
115 | },
116 |
117 | _showViewInWrapper: function()
118 | {
119 | this._view.show(this.element);
120 | },
121 |
122 | __proto__: WebInspector.VBox.prototype
123 | };
124 |
125 | /**
126 | * @constructor
127 | * @implements {WebInspector.Revealer}
128 | */
129 | WebInspector.ConsolePanel.ConsoleRevealer = function()
130 | {
131 | };
132 |
133 | WebInspector.ConsolePanel.ConsoleRevealer.prototype = {
134 | /**
135 | * @param {!Object} object
136 | */
137 | reveal: function(object)
138 | {
139 | var consoleView = WebInspector.ConsolePanel._view();
140 | if (consoleView.isShowing()) {
141 | consoleView.focus();
142 | return;
143 | }
144 | WebInspector.inspectorView.showViewInDrawer("console");
145 | }
146 | };
147 |
--------------------------------------------------------------------------------
/public/css/splitView.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2011 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 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | *
11 | * 2. Redistributions in binary form must reproduce the above
12 | * copyright notice, this list of conditions and the following disclaimer
13 | * in the documentation and/or other materials provided with the
14 | * distribution.
15 | *
16 | * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
20 | * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | .split-view {
30 | display: flex;
31 | overflow: hidden;
32 | }
33 |
34 | .split-view-contents {
35 | overflow: auto;
36 | display: flex;
37 | position: relative;
38 | flex-direction: column;
39 | }
40 |
41 | .split-view-sidebar {
42 | flex: none;
43 | }
44 |
45 | .split-view-main, .split-view-sidebar.maximized {
46 | flex: auto;
47 | }
48 |
49 | .split-view.hbox > .split-view-resizer {
50 | position: absolute;
51 | top: 0;
52 | bottom: 0;
53 | width: 6px;
54 | z-index: 500;
55 | }
56 |
57 | .split-view.vbox > .split-view-resizer {
58 | position: absolute;
59 | left: 0;
60 | right: 0;
61 | height: 6px;
62 | z-index: 500;
63 | }
64 |
65 | .split-view-resizer-border {
66 | pointer-events: none;
67 | }
68 |
69 | .split-view.vbox > .split-view-resizer > .split-view-resizer-border {
70 | width: 100%;
71 | margin-top: 3px;
72 | height: 1px;
73 | border-top: 1px solid rgb(64%, 64%, 64%);
74 | }
75 |
76 | .split-view.hbox > .split-view-resizer > .split-view-resizer-border {
77 | height: 100%;
78 | margin-left: 3px;
79 | width: 1px;
80 | border-left: 1px solid rgb(64%, 64%, 64%);
81 | }
82 |
83 | .split-view button.sidebar-show-hide-button {
84 | position: absolute;
85 | background-image: none;
86 | height: 16px;
87 | width: 16px;
88 | border: none;
89 | z-index: 10;
90 | }
91 |
92 | .split-view button.left-sidebar-show-hide-button,
93 | .split-view button.top-sidebar-show-hide-button {
94 | top: 4px;
95 | left: 4px;
96 | }
97 |
98 | .split-view button.left-sidebar-show-hide-button:active,
99 | .split-view button.top-sidebar-show-hide-button:active {
100 | top: 5px;
101 | left: 3px;
102 | }
103 |
104 | .split-view button.right-sidebar-show-hide-button {
105 | top: 4px;
106 | right:2px;
107 | }
108 |
109 | .split-view button.right-sidebar-show-hide-button:active {
110 | top: 5px;
111 | right: 1px;
112 | }
113 |
114 | .split-view button.bottom-sidebar-show-hide-button {
115 | bottom: 0px;
116 | right: 1px;
117 | }
118 |
119 | .split-view button.bottom-sidebar-show-hide-button:active {
120 | bottom: 0;
121 | right: 0;
122 | }
123 |
124 | .split-view button.left-sidebar-show-hide-button.toggled-show > .glyph {
125 | -webkit-mask-position: -168px -76px; /* |> */
126 | }
127 |
128 | .split-view button.left-sidebar-show-hide-button.toggled-hide > .glyph {
129 | -webkit-mask-position: -199px -76px; /* |< */
130 | }
131 |
132 | .split-view button.right-sidebar-show-hide-button.toggled-show > .glyph {
133 | -webkit-mask-position: -296px -76px; /* <| */
134 | }
135 |
136 | .split-view button.right-sidebar-show-hide-button.toggled-hide > .glyph {
137 | -webkit-mask-position: -264px -76px; /* >| */
138 | }
139 |
140 | .split-view button.top-sidebar-show-hide-button.toggled-show > .glyph {
141 | -webkit-mask-position: -168px -76px; /* |> */
142 | -webkit-transform: rotate(90deg);
143 | }
144 |
145 | .split-view button.top-sidebar-show-hide-button.toggled-hide > .glyph {
146 | -webkit-mask-position: -199px -76px; /* |< */
147 | -webkit-transform: rotate(90deg);
148 | }
149 |
150 | .split-view button.bottom-sidebar-show-hide-button.toggled-show > .glyph {
151 | -webkit-mask-position: -296px -76px; /* <| */
152 | -webkit-transform: rotate(90deg);
153 | }
154 |
155 | .split-view button.bottom-sidebar-show-hide-button.toggled-hide > .glyph {
156 | -webkit-mask-position: -264px -76px; /* >| */
157 | -webkit-transform: rotate(90deg);
158 | }
159 |
--------------------------------------------------------------------------------
/public/js/ui/ResizerWidget.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | /**
6 | * @constructor
7 | * @extends {WebInspector.Object}
8 | */
9 | WebInspector.ResizerWidget = function()
10 | {
11 | WebInspector.Object.call(this);
12 |
13 | this._isEnabled = true;
14 | this._isVertical = true;
15 | this._elements = [];
16 | this._installDragOnMouseDownBound = this._installDragOnMouseDown.bind(this);
17 | };
18 |
19 | WebInspector.ResizerWidget.Events = {
20 | ResizeStart: "ResizeStart",
21 | ResizeUpdate: "ResizeUpdate",
22 | ResizeEnd: "ResizeEnd"
23 | };
24 |
25 | WebInspector.ResizerWidget.prototype = {
26 | /**
27 | * @return {boolean}
28 | */
29 | isEnabled: function()
30 | {
31 | return this._isEnabled;
32 | },
33 |
34 | /**
35 | * @param {boolean} enabled
36 | */
37 | setEnabled: function(enabled)
38 | {
39 | this._isEnabled = enabled;
40 | this._updateElementsClass();
41 | },
42 |
43 | /**
44 | * @return {boolean}
45 | */
46 | isVertical: function()
47 | {
48 | return this._isVertical;
49 | },
50 |
51 | /**
52 | * Vertical widget resizes height (along y-axis).
53 | * @param {boolean} vertical
54 | */
55 | setVertical: function(vertical)
56 | {
57 | this._isVertical = vertical;
58 | this._updateElementsClass();
59 | },
60 |
61 | /**
62 | * @return {!Array.}
63 | */
64 | elements: function()
65 | {
66 | return this._elements.slice();
67 | },
68 |
69 | /**
70 | * @param {!Element} element
71 | */
72 | addElement: function(element)
73 | {
74 | if (this._elements.indexOf(element) !== -1) {
75 | return;
76 | }
77 |
78 | this._elements.push(element);
79 | element.addEventListener("mousedown", this._installDragOnMouseDownBound, false);
80 | element.classList.toggle("ns-resizer-widget", this._isVertical && this._isEnabled);
81 | element.classList.toggle("ew-resizer-widget", !this._isVertical && this._isEnabled);
82 | },
83 |
84 | /**
85 | * @param {!Element} element
86 | */
87 | removeElement: function(element)
88 | {
89 | if (this._elements.indexOf(element) === -1) {
90 | return;
91 | }
92 |
93 | this._elements.remove(element);
94 | element.removeEventListener("mousedown", this._installDragOnMouseDownBound, false);
95 | element.classList.remove("ns-resizer-widget");
96 | element.classList.remove("ew-resizer-widget");
97 | },
98 |
99 | _updateElementsClass: function()
100 | {
101 | for (var i = 0; i < this._elements.length; ++i) {
102 | this._elements[i].classList.toggle("ns-resizer-widget", this._isVertical && this._isEnabled);
103 | this._elements[i].classList.toggle("ew-resizer-widget", !this._isVertical && this._isEnabled);
104 | }
105 | },
106 |
107 | /**
108 | * @param {!Event} event
109 | */
110 | _installDragOnMouseDown: function(event)
111 | {
112 | // Only handle drags of the nodes specified.
113 | if (this._elements.indexOf(event.target) === -1) {
114 | return false;
115 | }
116 | WebInspector.elementDragStart(this._dragStart.bind(this), this._drag.bind(this), this._dragEnd.bind(this), this._isVertical ? "ns-resize" : "ew-resize", event);
117 | },
118 |
119 | /**
120 | * @param {!MouseEvent} event
121 | * @return {boolean}
122 | */
123 | _dragStart: function(event)
124 | {
125 | if (!this._isEnabled) {
126 | return false;
127 | }
128 | this._startPosition = this._isVertical ? event.pageY : event.pageX;
129 | this.dispatchEventToListeners(WebInspector.ResizerWidget.Events.ResizeStart, { startPosition: this._startPosition, currentPosition: this._startPosition });
130 | return true;
131 | },
132 |
133 | /**
134 | * @param {!MouseEvent} event
135 | * @return {boolean}
136 | */
137 | _drag: function(event)
138 | {
139 | if (!this._isEnabled) {
140 | this._dragEnd(event);
141 | return true; // Cancel drag.
142 | }
143 |
144 | var position = this._isVertical ? event.pageY : event.pageX;
145 | this.dispatchEventToListeners(WebInspector.ResizerWidget.Events.ResizeUpdate, { startPosition: this._startPosition, currentPosition: position, shiftKey: event.shiftKey });
146 | event.preventDefault();
147 | return false; // Continue drag.
148 | },
149 |
150 | /**
151 | * @param {!MouseEvent} event
152 | */
153 | _dragEnd: function(event)
154 | {
155 | this.dispatchEventToListeners(WebInspector.ResizerWidget.Events.ResizeEnd);
156 | delete this._startPosition;
157 | },
158 |
159 | __proto__: WebInspector.Object.prototype
160 | };
161 |
--------------------------------------------------------------------------------
/public/css/inspectorCommon.css:
--------------------------------------------------------------------------------
1 | html {
2 | height: 100%;
3 | }
4 |
5 | body {
6 | cursor: default;
7 | position: relative;
8 | height: 100%;
9 | width: 100%;
10 | overflow: hidden;
11 | font-family: Lucida Grande, sans-serif;
12 | font-size: 12px;
13 | margin: 0;
14 | tab-size: 4;
15 | -webkit-user-select: none;
16 | color: #222;
17 | }
18 |
19 | body.platform-linux {
20 | color: rgb(48, 57, 66);
21 | font-family: Ubuntu, Arial, sans-serif;
22 | }
23 |
24 | body.platform-mac {
25 | color: rgb(48, 57, 66);
26 | font-family: 'Lucida Grande', sans-serif;
27 | }
28 |
29 | body.platform-windows {
30 | font-family: 'Segoe UI', Tahoma, sans-serif;
31 | }
32 |
33 | * {
34 | box-sizing: border-box;
35 | }
36 |
37 | :focus {
38 | outline: none;
39 | }
40 |
41 | img {
42 | -webkit-user-drag: none;
43 | }
44 |
45 | iframe,
46 | a img {
47 | border: none;
48 | }
49 |
50 | iframe.view {
51 | position: absolute;
52 | width: 100%;
53 | height: 100%;
54 | left: 0;
55 | right: 0;
56 | top: 0;
57 | bottom: 0;
58 | }
59 |
60 | .hidden {
61 | display: none !important;
62 | }
63 |
64 | .monospace {
65 | font-size: 11px !important;
66 | font-family: monospace;
67 | }
68 |
69 | .resources-dividers {
70 | position: absolute;
71 | left: 0;
72 | right: 0;
73 | top: 0;
74 | z-index: -100;
75 | bottom: 0;
76 | }
77 |
78 | .resources-event-dividers {
79 | position: absolute;
80 | left: 0;
81 | right: 0;
82 | height: 100%;
83 | top: 0;
84 | z-index: 300;
85 | pointer-events: none;
86 | }
87 |
88 | .resources-dividers-label-bar {
89 | position: absolute;
90 | top: 0;
91 | left: 0;
92 | right: 0;
93 | background-color: rgba(255, 255, 255, 0.85);
94 | background-clip: padding-box;
95 | height: 20px;
96 | z-index: 200;
97 | pointer-events: none;
98 | overflow: hidden;
99 | }
100 |
101 | .resources-divider {
102 | position: absolute;
103 | width: 1px;
104 | top: 0;
105 | bottom: 0;
106 | background-color: rgba(0, 0, 0, 0.1);
107 | }
108 |
109 | .resources-event-divider-padding {
110 | position: absolute;
111 | width: 8px;
112 | top: 0;
113 | bottom: 0;
114 | pointer-events: auto;
115 | }
116 |
117 | .resources-event-divider {
118 | position: absolute;
119 | width: 2px;
120 | top: 0;
121 | bottom: 0;
122 | z-index: 300;
123 | }
124 |
125 | .resources-divider-label {
126 | position: absolute;
127 | top: 4px;
128 | right: 3px;
129 | font-size: 80%;
130 | white-space: nowrap;
131 | pointer-events: none;
132 | }
133 |
134 | .overview-grid-window-selector {
135 | position: absolute;
136 | top: 0;
137 | bottom: 0;
138 | background-color: rgba(125, 173, 217, 0.5);
139 | z-index: 250;
140 | pointer-events: none;
141 | }
142 |
143 | .overview-grid-window {
144 | background-color: white;
145 | position: absolute;
146 | left: 0;
147 | right: 0;
148 | top: 0;
149 | height: 20px;
150 | z-index: 150;
151 | }
152 |
153 | .overview-grid-dividers-background {
154 | left: 0%;
155 | right: 0%;
156 | top: 0;
157 | height: 20px;
158 | background-color: black;
159 | position: absolute;
160 | }
161 |
162 | .overview-grid-window-rulers {
163 | top: 0;
164 | bottom: 0;
165 | position: absolute;
166 | opacity: 0.2;
167 | border-right: 1px solid black;
168 | border-left: 1px solid black;
169 | z-index: 250;
170 | pointer-events: none;
171 | }
172 |
173 | .overview-grid-window-resizer {
174 | position: absolute;
175 | top: 0;
176 | height: 20px;
177 | width: 5px;
178 | margin-left: -2px;
179 | margin-right: -3px;
180 | background-color: rgb(153, 153, 153);
181 | z-index: 500;
182 | border-radius: 2px;
183 | box-shadow: white 1px 0 0, white -1px 0 0, white 0 1px 0, white 0 -1px 0;
184 | }
185 |
186 | .overview-grid-window-resizer-right {
187 | margin-left: -3px;
188 | margin-right: -2px;
189 | }
190 |
191 | /* Network timing is shared between popover and network item view pane */
192 |
193 | .network-timing-table td {
194 | padding: 0;
195 | }
196 |
197 | .network-timing-table td.caution {
198 | font-weight: bold;
199 | color: rgb(255, 128, 0);
200 | padding: 2px 0;
201 | }
202 |
203 | .network-timing-row {
204 | position: relative;
205 | height: 16px;
206 | }
207 |
208 | .network-timing-bar {
209 | position: absolute;
210 | background-color: red;
211 | border-left: 1px solid red;
212 | opacity: 0.4;
213 | top: 0;
214 | bottom: 0;
215 | }
216 |
217 | .network-timing-bar-title {
218 | position: absolute;
219 | color: #222;
220 | top: 1px;
221 | }
222 |
223 | .highlighted-search-result {
224 | border-radius: 1px;
225 | padding: 1px;
226 | margin: -1px;
227 | background-color: rgba(255, 255, 0, 0.8);
228 | }
229 |
230 | .sidebar-separator {
231 | background-color: rgb(230, 230, 230);
232 | padding: 0 5px;
233 | border-top: 1px solid rgb(189, 189, 189);
234 | border-bottom: 1px solid rgb(189, 189, 189);
235 | color: rgb(50, 50, 50);
236 | white-space: nowrap;
237 | text-overflow: ellipsis;
238 | overflow: hidden;
239 | line-height: 16px;
240 | }
241 |
242 | .sidebar-label {
243 | font-size: 11px;
244 | }
245 |
246 | .pie-chart {
247 | position: relative;
248 | }
249 |
250 | .pie-chart-foreground {
251 | position: absolute;
252 | width: 100%;
253 | height: 100%;
254 | text-align: center;
255 | z-index: 10;
256 | top: 0;
257 | }
258 |
--------------------------------------------------------------------------------
/public/js/components/ExecutionContextSelector.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | /**
6 | * @constructor
7 | * @implements {WebInspector.TargetManager.Observer}
8 | */
9 | WebInspector.ExecutionContextSelector = function()
10 | {
11 | WebInspector.targetManager.observeTargets(this);
12 | WebInspector.context.addFlavorChangeListener(WebInspector.ExecutionContext, this._executionContextChanged, this);
13 | WebInspector.context.addFlavorChangeListener(WebInspector.Target, this._targetChanged, this);
14 | };
15 |
16 | WebInspector.ExecutionContextSelector.prototype = {
17 |
18 | /**
19 | * @param {!WebInspector.Target} target
20 | */
21 | targetAdded: function(target)
22 | {
23 | console.log('yaaay new target', target);
24 | if (!WebInspector.context.flavor(WebInspector.Target)) {
25 | WebInspector.context.setFlavor(WebInspector.Target, target);
26 | }
27 |
28 | target.runtimeModel.addEventListener(WebInspector.RuntimeModel.Events.ExecutionContextCreated, this._onExecutionContextCreated, this);
29 | target.runtimeModel.addEventListener(WebInspector.RuntimeModel.Events.ExecutionContextDestroyed, this._onExecutionContextDestroyed, this);
30 | },
31 |
32 | /**
33 | * @param {!WebInspector.Target} target
34 | */
35 | targetRemoved: function(target)
36 | {
37 | target.runtimeModel.removeEventListener(WebInspector.RuntimeModel.Events.ExecutionContextCreated, this._onExecutionContextCreated, this);
38 | target.runtimeModel.removeEventListener(WebInspector.RuntimeModel.Events.ExecutionContextDestroyed, this._onExecutionContextDestroyed, this);
39 | var currentExecutionContext = WebInspector.context.flavor(WebInspector.ExecutionContext);
40 | if (currentExecutionContext && currentExecutionContext.target() === target) {
41 | this._currentExecutionContextGone();
42 | }
43 |
44 | var targets = WebInspector.targetManager.targets();
45 | if (WebInspector.context.flavor(WebInspector.Target) === target && targets.length) {
46 | WebInspector.context.setFlavor(WebInspector.Target, targets[0]);
47 | }
48 | },
49 |
50 | /**
51 | * @param {!WebInspector.Event} event
52 | */
53 | _executionContextChanged: function(event)
54 | {
55 | var newContext = /** @type {?WebInspector.ExecutionContext} */ (event.data);
56 | if (newContext) {
57 | WebInspector.context.setFlavor(WebInspector.Target, newContext.target());
58 | }
59 | },
60 |
61 | /**
62 | * @param {!WebInspector.Event} event
63 | */
64 | _targetChanged: function(event)
65 | {
66 | var newTarget = /** @type {?WebInspector.Target} */(event.data);
67 | var currentContext = WebInspector.context.flavor(WebInspector.ExecutionContext);
68 |
69 | if (!newTarget || (currentContext && currentContext.target() === newTarget)) {
70 | return;
71 | }
72 |
73 | var executionContexts = newTarget.runtimeModel.executionContexts();
74 | console.log('execution contexts!', executionContexts);
75 | if (!executionContexts.length) {
76 | return;
77 | }
78 |
79 | var newContext = executionContexts[0];
80 | for (var i = 1; i < executionContexts.length; ++i) {
81 | if (executionContexts[i].isMainWorldContext) {
82 | newContext = executionContexts[i];
83 | }
84 | }
85 | WebInspector.context.setFlavor(WebInspector.ExecutionContext, newContext);
86 | },
87 |
88 | /**
89 | * @param {!WebInspector.Event} event
90 | */
91 | _onExecutionContextCreated: function(event)
92 | {
93 | var executionContext = /** @type {!WebInspector.ExecutionContext}*/ (event.data);
94 | if (!WebInspector.context.flavor(WebInspector.ExecutionContext)) {
95 | WebInspector.context.setFlavor(WebInspector.ExecutionContext, executionContext);
96 | }
97 | },
98 |
99 | /**
100 | * @param {!WebInspector.Event} event
101 | */
102 | _onExecutionContextDestroyed: function(event)
103 | {
104 | var executionContext = /** @type {!WebInspector.ExecutionContext}*/ (event.data);
105 | if (WebInspector.context.flavor(WebInspector.ExecutionContext) === executionContext) {
106 | this._currentExecutionContextGone();
107 | }
108 | },
109 |
110 | _currentExecutionContextGone: function()
111 | {
112 | var targets = WebInspector.targetManager.targets();
113 | var newContext = null;
114 | for (var i = 0; i < targets.length; ++i) {
115 | var executionContexts = targets[i].runtimeModel.executionContexts();
116 | if (executionContexts.length) {
117 | newContext = executionContexts[0];
118 | break;
119 | }
120 | }
121 | WebInspector.context.setFlavor(WebInspector.ExecutionContext, newContext);
122 | }
123 |
124 | };
125 |
126 | /**
127 | * @param {!Element} proxyElement
128 | * @param {!Range} wordRange
129 | * @param {boolean} force
130 | * @param {function(!Array., number=)} completionsReadyCallback
131 | */
132 | WebInspector.ExecutionContextSelector.completionsForTextPromptInCurrentContext = function(proxyElement, wordRange, force, completionsReadyCallback)
133 | {
134 | var executionContext = WebInspector.context.flavor(WebInspector.ExecutionContext);
135 | if (!executionContext) {
136 | completionsReadyCallback([]);
137 | return;
138 | }
139 |
140 | // Pass less stop characters to rangeOfWord so the range will be a more complete expression.
141 | var expressionRange = wordRange.startContainer.rangeOfWord(wordRange.startOffset, " =:[({;,!+-*/&|^<>", proxyElement, "backward");
142 | var expressionString = expressionRange.toString();
143 | var prefix = wordRange.toString();
144 | executionContext.completionsForExpression(expressionString, prefix, force, completionsReadyCallback);
145 | };
146 |
--------------------------------------------------------------------------------
/public/js/host/Platform.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 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
6 | * are met:
7 | *
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 | * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 | * its contributors may be used to endorse or promote products derived
15 | * from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | /**
30 | * @return {string}
31 | */
32 | WebInspector.platform = function()
33 | {
34 | if (!WebInspector._platform) {
35 | // zirak: meh. to be improved.
36 | WebInspector._platform = 'linux'; /*InspectorFrontendHost.platform();*/
37 | }
38 | return WebInspector._platform;
39 | };
40 |
41 | /**
42 | * @return {boolean}
43 | */
44 | WebInspector.isMac = function()
45 | {
46 | if (typeof WebInspector._isMac === "undefined") {
47 | WebInspector._isMac = WebInspector.platform() === "mac";
48 | }
49 |
50 | return WebInspector._isMac;
51 | };
52 |
53 | /**
54 | * @return {boolean}
55 | */
56 | WebInspector.isWin = function()
57 | {
58 | if (typeof WebInspector._isWin === "undefined") {
59 | WebInspector._isWin = WebInspector.platform() === "windows";
60 | }
61 |
62 | return WebInspector._isWin;
63 | };
64 |
65 | WebInspector.PlatformFlavor = {
66 | WindowsVista: "windows-vista",
67 | MacTiger: "mac-tiger",
68 | MacLeopard: "mac-leopard",
69 | MacSnowLeopard: "mac-snowleopard",
70 | MacLion: "mac-lion"
71 | };
72 |
73 | /**
74 | * @return {string}
75 | */
76 | WebInspector.platformFlavor = function()
77 | {
78 | function detectFlavor()
79 | {
80 | var userAgent = navigator.userAgent,
81 | match;
82 |
83 | if (WebInspector.platform() === "windows") {
84 | match = userAgent.match(/Windows NT (\d+)\.(?:\d+)/);
85 | if (match && match[1] >= 6) {
86 | return WebInspector.PlatformFlavor.WindowsVista;
87 | }
88 | return null;
89 | } else if (WebInspector.platform() === "mac") {
90 | match = userAgent.match(/Mac OS X\s*(?:(\d+)_(\d+))?/);
91 | if (!match || match[1] != 10) {
92 | return WebInspector.PlatformFlavor.MacSnowLeopard;
93 | }
94 | switch (Number(match[2])) {
95 | case 4:
96 | return WebInspector.PlatformFlavor.MacTiger;
97 | case 5:
98 | return WebInspector.PlatformFlavor.MacLeopard;
99 | case 6:
100 | return WebInspector.PlatformFlavor.MacSnowLeopard;
101 | case 7:
102 | return WebInspector.PlatformFlavor.MacLion;
103 | /*jshint -W086*/
104 | case 8: // Matches the default version
105 | case 9: // Matches the default version
106 | default:
107 | return "";
108 | }
109 | }
110 | }
111 |
112 | if (!WebInspector._platformFlavor) {
113 | WebInspector._platformFlavor = detectFlavor();
114 | }
115 |
116 | return WebInspector._platformFlavor;
117 | };
118 |
119 | /**
120 | * @return {string}
121 | */
122 | WebInspector.port = function()
123 | {
124 | if (!WebInspector._port) {
125 | WebInspector._port = InspectorFrontendHost.port();
126 | }
127 |
128 | return WebInspector._port;
129 | };
130 |
131 | /**
132 | * @return {string}
133 | */
134 | WebInspector.fontFamily = function()
135 | {
136 | if (WebInspector._fontFamily) {
137 | return WebInspector._fontFamily;
138 | }
139 | switch (WebInspector.platform()) {
140 | case "linux":
141 | WebInspector._fontFamily = "Ubuntu, Arial, sans-serif";
142 | break;
143 | case "mac":
144 | WebInspector._fontFamily = "'Lucida Grande', sans-serif";
145 | break;
146 | case "windows":
147 | WebInspector._fontFamily = "'Segoe UI', Tahoma, sans-serif";
148 | break;
149 | }
150 | return WebInspector._fontFamily;
151 | };
152 |
153 | /**
154 | * @return {string}
155 | */
156 | WebInspector.monospaceFontFamily = function()
157 | {
158 | if (WebInspector._monospaceFontFamily) {
159 | return WebInspector._monospaceFontFamily;
160 | }
161 | switch (WebInspector.platform()) {
162 | case "linux":
163 | WebInspector._monospaceFontFamily = "dejavu sans mono, monospace";
164 | break;
165 | case "mac":
166 | WebInspector._monospaceFontFamily = "Menlo, monospace";
167 | break;
168 | case "windows":
169 | WebInspector._monospaceFontFamily = "Consolas, monospace";
170 | break;
171 | }
172 | return WebInspector._monospaceFontFamily;
173 | };
174 |
175 | /**
176 | * @return {boolean}
177 | */
178 | WebInspector.isWorkerFrontend = function()
179 | {
180 | return !!WebInspector.queryParam("dedicatedWorkerId") || !!WebInspector.queryParam("isSharedWorker");
181 | };
182 |
--------------------------------------------------------------------------------
/public/css/dataGrid.css:
--------------------------------------------------------------------------------
1 | .data-grid {
2 | position: relative;
3 | border: 1px solid #aaa;
4 | font-size: 11px;
5 | line-height: 120%;
6 | }
7 |
8 | .data-grid .highlight {
9 | background-color: rgb(255, 230, 179);
10 | }
11 |
12 | .data-grid tr.selected .highlight {
13 | background-color: transparent;
14 | }
15 |
16 | .data-grid table {
17 | table-layout: fixed;
18 | border-spacing: 0;
19 | border-collapse: separate;
20 | height: 100%;
21 | width: 100%;
22 | }
23 |
24 | .data-grid .header-container,
25 | .data-grid .data-container {
26 | position: absolute;
27 | left: 0;
28 | right: 0;
29 | overflow-x: hidden;
30 | }
31 |
32 | .data-grid .header-container {
33 | top: 0;
34 | height: 17px;
35 | }
36 |
37 | .data-grid .data-container {
38 | top: 17px;
39 | bottom: 0;
40 | overflow-y: overlay;
41 | -webkit-transform: translateZ(0);
42 | }
43 |
44 | .data-grid.inline {
45 | border-left: none;
46 | }
47 |
48 | .data-grid.inline .header-container,
49 | .data-grid.inline .data-container {
50 | position: static;
51 | }
52 |
53 | .data-grid.inline col.corner,
54 | .data-grid.inline th.corner,
55 | .data-grid.inline td.corner {
56 | display: none;
57 | }
58 |
59 | .data-grid th.corner,
60 | .data-grid td.corner,
61 | .data-grid col.corner {
62 | width: 14px;
63 | padding-right: 0;
64 | padding-left: 0;
65 | border-left: 0 none transparent !important;
66 | }
67 |
68 | .data-grid tr.filler {
69 | display: table-row !important;
70 | height: 0;
71 | }
72 |
73 | .data-grid tr.filler td {
74 | height: auto !important;
75 | padding: 0 !important;
76 | }
77 |
78 | .data-grid table.data {
79 | position: absolute;
80 | left: 0;
81 | top: 0;
82 | right: 0;
83 | bottom: 0;
84 | border-top: 0 none transparent;
85 | background-image: linear-gradient(to bottom, white, white 50%, rgb(234, 243, 255) 50%, rgb(234, 243, 255));
86 | background-size: 128px 32px;
87 | table-layout: fixed;
88 | }
89 |
90 | .data-grid.inline table.data {
91 | position: static;
92 | }
93 |
94 | .data-grid table.data tr {
95 | display: none;
96 | }
97 |
98 | .data-grid table.data tr.revealed {
99 | display: table-row;
100 | }
101 |
102 | .data-grid td,
103 | .data-grid th {
104 | white-space: nowrap;
105 | text-overflow: ellipsis;
106 | overflow: hidden;
107 | line-height: 14px;
108 | border-left: 1px solid #aaa;
109 | }
110 |
111 | .data-grid td {
112 | height: 16px; /* Keep in sync with .data-grid table.data @ background-size */
113 | }
114 |
115 | .data-grid th {
116 | height: auto;
117 | }
118 |
119 | .data-grid:not(.inline) th:first-child,
120 | .data-grid:not(.inline) td:first-child {
121 | border-left: none !important;
122 | }
123 |
124 | .data-grid td {
125 | vertical-align: top;
126 | padding: 1px 4px;
127 | -webkit-user-select: text;
128 | }
129 |
130 | .data-grid th {
131 | text-align: left;
132 | background-color: rgb(236, 236, 236);
133 | border-bottom: 1px solid #aaa;
134 | font-weight: normal;
135 | vertical-align: middle;
136 | padding: 0 4px;
137 | }
138 |
139 | .data-grid td > div,
140 | .data-grid th > div {
141 | white-space: nowrap;
142 | text-overflow: ellipsis;
143 | overflow: hidden;
144 | }
145 |
146 | .data-grid th > div {
147 | overflow: hidden;
148 | }
149 |
150 | .data-grid td.editing > div {
151 | text-overflow: clip;
152 | }
153 |
154 | .data-grid .center {
155 | text-align: center;
156 | }
157 |
158 | .data-grid .right {
159 | text-align: right;
160 | }
161 |
162 | .data-grid th.sortable div {
163 | position: relative;
164 | }
165 |
166 | .data-grid th.sortable:active {
167 | background-color: rgba(0, 0, 0, 0.15);
168 | }
169 |
170 | .data-grid th.sort-ascending > div::after,
171 | .data-grid th.sort-descending > div::after {
172 | position: absolute;
173 | top: 1px;
174 | right: 0;
175 | background-image: url(Images/statusbarButtonGlyphs.png);
176 | background-size: 320px 144px;
177 | opacity: 0.5;
178 | width: 8px;
179 | height: 10px;
180 | content: "a";
181 | color: transparent;
182 | }
183 |
184 | @media (-webkit-min-device-pixel-ratio: 1.5) {
185 | .data-grid th.sort-ascending > div::after,
186 | .data-grid th.sort-descending > div::after {
187 | background-image: url(Images/statusbarButtonGlyphs_2x.png);
188 | }
189 | } /* media */
190 |
191 | .data-grid th.sort-ascending > div::after {
192 | background-position: -4px -108px;
193 | }
194 |
195 | .data-grid th.sort-descending > div::after {
196 | background-position: -20px -96px;
197 | }
198 |
199 | .data-grid th:hover {
200 | background-color: rgba(0, 0, 0, 0.1);
201 | }
202 |
203 | .data-grid button {
204 | line-height: 18px;
205 | color: inherit;
206 | }
207 |
208 | .data-grid tr.parent td.disclosure::before {
209 | -webkit-user-select: none;
210 | -webkit-mask-image: url(Images/statusbarButtonGlyphs.png);
211 | -webkit-mask-size: 320px 144px;
212 | float: left;
213 | width: 8px;
214 | margin-right: 2px;
215 | content: "a";
216 | color: transparent;
217 | position: relative;
218 | top: 1px;
219 | }
220 |
221 | .data-grid tr.parent td.disclosure::before {
222 | background-color: rgb(110, 110, 110);
223 | -webkit-mask-position: -4px -96px;
224 | }
225 |
226 | @media (-webkit-min-device-pixel-ratio: 1.5) {
227 | .data-grid tr.parent td.disclosure::before {
228 | -webkit-mask-image: url(Images/statusbarButtonGlyphs_2x.png);
229 | }
230 | } /* media */
231 |
232 | .data-grid tr.expanded td.disclosure::before {
233 | -webkit-mask-position: -20px -96px;
234 | }
235 |
236 | .data-grid tr.selected {
237 | background-color: rgb(212, 212, 212);
238 | color: inherit;
239 | }
240 |
241 | .data-grid:focus tr.selected {
242 | background-color: rgb(56, 121, 217);
243 | color: white;
244 | }
245 |
246 | .data-grid:focus tr.selected a {
247 | color: white;
248 | }
249 |
250 | .data-grid:focus tr.parent.selected td.disclosure::before {
251 | background-color: white;
252 | -webkit-mask-position: -4px -96px;
253 | }
254 |
255 | .data-grid:focus tr.expanded.selected td.disclosure::before {
256 | background-color: white;
257 | -webkit-mask-position: -20px -96px;
258 | }
259 |
260 | .data-grid tr:not(.parent) td.disclosure {
261 | text-indent: 10px;
262 | }
263 |
264 | .data-grid-resizer {
265 | position: absolute;
266 | top: 0;
267 | bottom: 0;
268 | width: 5px;
269 | z-index: 500;
270 | }
271 |
--------------------------------------------------------------------------------
/public/js/jsh.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | var jsh = window.jsh = {};
3 |
4 | jsh.save = function () {
5 | var data = {
6 | commands : this.getCommandsText()
7 | };
8 |
9 | // TODO add some XHR abstraction
10 | var xhr = new XMLHttpRequest();
11 | xhr.open('POST', 'save');
12 |
13 | xhr.setRequestHeader('Content-Type', 'application/json');
14 | xhr.responseType = 'json';
15 |
16 | xhr.onload = function () {
17 | // yeah...
18 | console.log(xhr);
19 |
20 | history.replaceState(null, '', '/' + xhr.response.id);
21 | WebInspector.console.log('Saved. ID: ' + xhr.response.id);
22 | };
23 |
24 | xhr.send(JSON.stringify(data));
25 | };
26 |
27 | jsh.loadFromText = function (text) {
28 | if (!text) {
29 | console.warn('what do you want from me?');
30 | return;
31 | }
32 |
33 | var commands = JSON.parse(text);
34 | if (!Array.isArray(commands) || !commands.length) {
35 | return;
36 | }
37 |
38 | // we can't just add the commands one after the other, since running a
39 | //command is an async operation.
40 | // what we should do is wait for a command to be evaluated before moving on
41 | //to the next.
42 | // what really *should* be done (TODO) is only run a command once the one
43 | //before has been printed.
44 | var consoleModel = WebInspector.targetManager.targets()[0].consoleModel,
45 | commandEvaluated = WebInspector.ConsoleModel.Events.CommandEvaluated;
46 |
47 | consoleModel.addEventListener(commandEvaluated, addNextCommand);
48 |
49 | addNextCommand();
50 |
51 | function addNextCommand () {
52 | var cmd = commands.shift();
53 | console.warn(cmd);
54 | if (!cmd) {
55 | consoleModel.removeEventListener(commandEvaluated, addNextCommand);
56 | return;
57 | }
58 |
59 | WebInspector.ConsolePanel._view()._appendCommand(cmd, true);
60 | }
61 | };
62 |
63 | jsh.getCommandsText = function () {
64 | // Fuck me...
65 | var messages = WebInspector.ConsolePanel._view()._consoleMessages;
66 |
67 | return messages.filter(filterCommands).map(getCommandText);
68 |
69 | function filterCommands (msg) {
70 | return msg instanceof WebInspector.ConsoleCommand;
71 | }
72 | function getCommandText (cmd) {
73 | return cmd.text;
74 | }
75 | };
76 |
77 | jsh.handleMessage = function (messageObject) {
78 | var method = messageObject.method,
79 | params = messageObject.params;
80 |
81 | console.warn('handleMessage', messageObject);
82 |
83 | var ignore = ['Runtime.enable', 'Console.enable', 'Runtime.isRunRequired'];
84 | if (ignore.indexOf(method) > -1) {
85 | return false;
86 | }
87 |
88 | messageObject.action = 'bridge';
89 | sendMessageToEvalFrame(messageObject);
90 | };
91 |
92 | // This is butt ugly. Find out when everything we need has been loaded.
93 | var jshReady = {
94 | evalFrame : false,
95 | webinspector : false
96 | };
97 |
98 | jsh.maybeLoad = function () {
99 | if (!jshReady.evalFrame || !jshReady.webinspector) {
100 | return;
101 | }
102 |
103 | // Welcome, stranger!
104 | if (!localStorage.introduced) {
105 | localStorage.introduced = true;
106 | jsh.introduce();
107 | }
108 |
109 | // Load up the commands (if there are any)
110 | var commands = document.getElementById('jsh-commands').textContent;
111 |
112 | if (commands) {
113 | jsh.loadFromText(commands);
114 | }
115 | };
116 |
117 | // Eval frame! What we do with it is laid out in detail in public/evalFrame.html
118 |
119 | jsh.evalFrame = document.createElement('iframe');
120 | jsh.evalFrame.src = 'evalFrame.html';
121 | jsh.evalFrame.hidden = true;
122 | jsh.evalFrame.sandbox = 'allow-scripts';
123 | document.body.appendChild(jsh.evalFrame);
124 | jsh.evalWindow = jsh.evalFrame.contentWindow;
125 |
126 | var frameSecret = (function () {
127 | var whyDoINeedThis = new Uint32Array(10);
128 | crypto.getRandomValues(whyDoINeedThis);
129 |
130 | var fuckayou = [].slice.call(whyDoINeedThis);
131 | return fuckayou.map(String.fromCharCode).join('');
132 | })();
133 |
134 | // sometimes, I wonder if variables are aware of their names, and my variables
135 | //are constantly walking around with their heads to the ground, being made fun
136 | //of by other programs with their fancy variables.
137 | // sometimes.
138 |
139 | jsh.evalFrame.onload = function () {
140 | jsh.evalWindow.postMessage({
141 | action : 'secret',
142 | secret : '',
143 | newSecret : frameSecret
144 | }, '*');
145 |
146 | jshReady.evalFrame = true;
147 | jsh.maybeLoad();
148 | };
149 |
150 | function sendMessageToEvalFrame (data) {
151 | data.secret = frameSecret;
152 | jsh.evalWindow.postMessage(data, '*');
153 | }
154 |
155 | window.addEventListener('message', function messageListener (e) {
156 | var data = e.data;
157 |
158 | if (e.source !== jsh.evalWindow || data.secret !== frameSecret) {
159 | console.warn(e);
160 | return;
161 | }
162 |
163 | InspectorBackend._connection.dispatch(data);
164 | });
165 |
166 | window.addEventListener('DOMContentLoaded', function () {
167 | // yes, this is horrible. I will not apologise.
168 | setTimeout(function () {
169 | jshReady.webinspector = true;
170 | jsh.maybeLoad();
171 | }, 50);
172 | // ;-;
173 | });
174 |
175 | // at the end because blobs of text.
176 | jsh.introduce = function () {
177 | var header = function () {/** @preserve
178 | _ _
179 | (_) | | Welcome to jsh, an embedded Chrome dev-tools console!
180 | _ ___| |__
181 | | / __| '_ \
182 | | \__ \ | | | Play around with javascript, hit save (Ctrl+S), share with
183 | | |___/_| |_| friends and strangers!
184 | _/ |
185 | |__/
186 |
187 | * Source code on https://github.com/Zirak/jsh.
188 | * Bug reports more than welcome: https://github.com/Zirak/jsh/issues
189 | * Hit me on twitter: @zirakertan
190 |
191 | Hit Ctrl+L to clear this message.
192 | */
193 | console.lulz = 4; delete console.lulz;
194 | }.toString().split('\n').slice(1, -2).join('\n');
195 |
196 | WebInspector.console.log(header);
197 | };
198 |
199 | /*
200 | _____ _ _____
201 | |_ _| | | __ \
202 | | | | |__ ___ | | \/ __ _ _ __ ___ ___
203 | | | | '_ \ / _ \ | | __ / _` | '_ ` _ \ / _ \
204 | | | | | | | __/ | |_\ \ (_| | | | | | | __/
205 | \_/ |_| |_|\___| \____/\__,_|_| |_| |_|\___|
206 |
207 | */
208 | })();
209 |
--------------------------------------------------------------------------------
/public/js/components/Section.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2007 Apple Inc. All rights reserved.
3 | * Copyright (C) 2009 Google Inc. 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 BY APPLE AND ITS CONTRIBUTORS "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|!Element} title
33 | * @param {string=} subtitle
34 | */
35 | WebInspector.Section = function(title, subtitle)
36 | {
37 | this.element = document.createElement("div");
38 | this.element.className = "section";
39 | this.element._section = this;
40 |
41 | this.headerElement = document.createElement("div");
42 | this.headerElement.className = "header";
43 |
44 | this.titleElement = document.createElement("div");
45 | this.titleElement.className = "title";
46 |
47 | this.subtitleElement = document.createElement("div");
48 | this.subtitleElement.className = "subtitle";
49 |
50 | this.headerElement.appendChild(this.subtitleElement);
51 | this.headerElement.appendChild(this.titleElement);
52 |
53 | this.headerElement.addEventListener("click", this.handleClick.bind(this), false);
54 | this.element.appendChild(this.headerElement);
55 |
56 | this.title = title;
57 | this.subtitle = subtitle;
58 | this._expanded = false;
59 | };
60 |
61 | WebInspector.Section.prototype = {
62 | get title()
63 | {
64 | return this._title;
65 | },
66 |
67 | set title(x)
68 | {
69 | if (this._title === x) {
70 | return;
71 | }
72 | this._title = x;
73 |
74 | if (x instanceof Node) {
75 | this.titleElement.removeChildren();
76 | this.titleElement.appendChild(x);
77 | } else {
78 | this.titleElement.textContent = x;
79 | }
80 | },
81 |
82 | get subtitle()
83 | {
84 | return this._subtitle;
85 | },
86 |
87 | set subtitle(x)
88 | {
89 | if (this._subtitle === x) {
90 | return;
91 | }
92 | this._subtitle = x;
93 | this.subtitleElement.textContent = x;
94 | },
95 |
96 | get subtitleAsTextForTest()
97 | {
98 | var result = this.subtitleElement.textContent;
99 | var child = this.subtitleElement.querySelector("[data-uncopyable]");
100 | if (child) {
101 | var linkData = child.getAttribute("data-uncopyable");
102 | if (linkData) {
103 | result += linkData;
104 | }
105 | }
106 | return result;
107 | },
108 |
109 | get expanded()
110 | {
111 | return this._expanded;
112 | },
113 |
114 | set expanded(x)
115 | {
116 | if (x) {
117 | this.expand();
118 | }
119 | else {
120 | this.collapse();
121 | }
122 | },
123 |
124 | get populated()
125 | {
126 | return this._populated;
127 | },
128 |
129 | set populated(x)
130 | {
131 | this._populated = x;
132 | if (!x && this._expanded) {
133 | this.onpopulate();
134 | this._populated = true;
135 | }
136 | },
137 |
138 | onpopulate: function()
139 | {
140 | // Overriden by subclasses.
141 | },
142 |
143 | get firstSibling()
144 | {
145 | var parent = this.element.parentElement;
146 | if (!parent) {
147 | return null;
148 | }
149 |
150 | var childElement = parent.firstChild;
151 | while (childElement) {
152 | if (childElement._section) {
153 | return childElement._section;
154 | }
155 | childElement = childElement.nextSibling;
156 | }
157 |
158 | return null;
159 | },
160 |
161 | get lastSibling()
162 | {
163 | var parent = this.element.parentElement;
164 | if (!parent) {
165 | return null;
166 | }
167 |
168 | var childElement = parent.lastChild;
169 | while (childElement) {
170 | if (childElement._section) {
171 | return childElement._section;
172 | }
173 | childElement = childElement.previousSibling;
174 | }
175 |
176 | return null;
177 | },
178 |
179 | get nextSibling()
180 | {
181 | var curElement = this.element;
182 | do {
183 | curElement = curElement.nextSibling;
184 | } while (curElement && !curElement._section);
185 |
186 | return curElement ? curElement._section : null;
187 | },
188 |
189 | get previousSibling()
190 | {
191 | var curElement = this.element;
192 | do {
193 | curElement = curElement.previousSibling;
194 | } while (curElement && !curElement._section);
195 |
196 | return curElement ? curElement._section : null;
197 | },
198 |
199 | expand: function()
200 | {
201 | if (this._expanded) {
202 | return;
203 | }
204 | this._expanded = true;
205 | this.element.classList.add("expanded");
206 |
207 | if (!this._populated) {
208 | this.onpopulate();
209 | this._populated = true;
210 | }
211 | },
212 |
213 | collapse: function()
214 | {
215 | if (!this._expanded) {
216 | return;
217 | }
218 | this._expanded = false;
219 | this.element.classList.remove("expanded");
220 | },
221 |
222 | toggleExpanded: function()
223 | {
224 | this.expanded = !this.expanded;
225 | },
226 |
227 | handleClick: function(event)
228 | {
229 | this.toggleExpanded();
230 | event.consume();
231 | }
232 | };
233 |
--------------------------------------------------------------------------------
/public/evalFrame.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
224 |
225 |
226 |
227 |
--------------------------------------------------------------------------------
/public/js/common/Object.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2008 Apple 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
6 | * are met:
7 | * 1. Redistributions of source code must retain the above copyright
8 | * notice, this list of conditions and the following disclaimer.
9 | * 2. Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | *
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 | */
25 |
26 | /**
27 | * @constructor
28 | * @implements {WebInspector.EventTarget}
29 | */
30 | WebInspector.Object = function() {
31 | };
32 |
33 | WebInspector.Object.prototype = {
34 | /**
35 | * @param {string} eventType
36 | * @param {function(!WebInspector.Event)} listener
37 | * @param {!Object=} thisObject
38 | */
39 | addEventListener: function(eventType, listener, thisObject)
40 | {
41 | if (!listener) {
42 | console.assert(false);
43 | }
44 |
45 | if (!this._listeners) {
46 | this._listeners = {};
47 | }
48 | if (!this._listeners[eventType]) {
49 | this._listeners[eventType] = [];
50 | }
51 | this._listeners[eventType].push({ thisObject: thisObject, listener: listener });
52 | },
53 |
54 | /**
55 | * @param {string} eventType
56 | * @param {function(!WebInspector.Event)} listener
57 | * @param {!Object=} thisObject
58 | */
59 | removeEventListener: function(eventType, listener, thisObject)
60 | {
61 | console.assert(listener);
62 |
63 | if (!this._listeners || !this._listeners[eventType]) {
64 | return;
65 | }
66 | var listeners = this._listeners[eventType];
67 | for (var i = 0; i < listeners.length; ++i) {
68 | if (listeners[i].listener === listener && listeners[i].thisObject === thisObject) {
69 | listeners.splice(i--, 1);
70 | }
71 | }
72 |
73 | if (!listeners.length) {
74 | delete this._listeners[eventType];
75 | }
76 | },
77 |
78 | removeAllListeners: function()
79 | {
80 | delete this._listeners;
81 | },
82 |
83 | /**
84 | * @param {string} eventType
85 | * @return {boolean}
86 | */
87 | hasEventListeners: function(eventType)
88 | {
89 | if (!this._listeners || !this._listeners[eventType]) {
90 | return false;
91 | }
92 | return true;
93 | },
94 |
95 | /**
96 | * @param {string} eventType
97 | * @param {*=} eventData
98 | * @return {boolean}
99 | */
100 | dispatchEventToListeners: function(eventType, eventData)
101 | {
102 | if (!this._listeners || !this._listeners[eventType]) {
103 | return false;
104 | }
105 |
106 | var event = new WebInspector.Event(this, eventType, eventData);
107 | var listeners = this._listeners[eventType].slice(0);
108 | for (var i = 0; i < listeners.length; ++i) {
109 | listeners[i].listener.call(listeners[i].thisObject, event);
110 | if (event._stoppedPropagation) {
111 | break;
112 | }
113 | }
114 |
115 | return event.defaultPrevented;
116 | }
117 | };
118 |
119 | /**
120 | * @constructor
121 | * @param {!WebInspector.EventTarget} target
122 | * @param {string} type
123 | * @param {*=} data
124 | */
125 | WebInspector.Event = function(target, type, data)
126 | {
127 | this.target = target;
128 | this.type = type;
129 | this.data = data;
130 | this.defaultPrevented = false;
131 | this._stoppedPropagation = false;
132 | };
133 |
134 | WebInspector.Event.prototype = {
135 | stopPropagation: function()
136 | {
137 | this._stoppedPropagation = true;
138 | },
139 |
140 | preventDefault: function()
141 | {
142 | this.defaultPrevented = true;
143 | },
144 |
145 | /**
146 | * @param {boolean=} preventDefault
147 | */
148 | consume: function(preventDefault)
149 | {
150 | this.stopPropagation();
151 | if (preventDefault) {
152 | this.preventDefault();
153 | }
154 | }
155 | };
156 |
157 | /**
158 | * @constructor
159 | * @extends {WebInspector.Object}
160 | */
161 | WebInspector.Lock = function()
162 | {
163 | this._count = 0; // Reentrant.
164 | };
165 |
166 | /**
167 | * @enum {string}
168 | */
169 | WebInspector.Lock.Events = {
170 | StateChanged: "StateChanged"
171 | };
172 |
173 | WebInspector.Lock.prototype = {
174 | /**
175 | * @return {boolean}
176 | */
177 | isAcquired: function()
178 | {
179 | return !!this._count;
180 | },
181 |
182 | acquire: function()
183 | {
184 | if (++this._count === 1) {
185 | this.dispatchEventToListeners(WebInspector.Lock.Events.StateChanged);
186 | }
187 | },
188 |
189 | release: function()
190 | {
191 | --this._count;
192 | if (this._count < 0) {
193 | console.error("WebInspector.Lock acquire/release calls are unbalanced " + new Error().stack);
194 | return;
195 | }
196 | if (!this._count) {
197 | this.dispatchEventToListeners(WebInspector.Lock.Events.StateChanged);
198 | }
199 | },
200 |
201 | __proto__: WebInspector.Object.prototype
202 | };
203 |
204 | /**
205 | * @interface
206 | */
207 | WebInspector.EventTarget = function()
208 | {
209 | };
210 |
211 | WebInspector.EventTarget.prototype = {
212 | /**
213 | * @param {string} eventType
214 | * @param {function(!WebInspector.Event)} listener
215 | * @param {!Object=} thisObject
216 | */
217 | addEventListener: function(eventType, listener, thisObject) { },
218 |
219 | /**
220 | * @param {string} eventType
221 | * @param {function(!WebInspector.Event)} listener
222 | * @param {!Object=} thisObject
223 | */
224 | removeEventListener: function(eventType, listener, thisObject) { },
225 |
226 | removeAllListeners: function() { },
227 |
228 | /**
229 | * @param {string} eventType
230 | * @return {boolean}
231 | */
232 | hasEventListeners: function(eventType) { },
233 |
234 | /**
235 | * @param {string} eventType
236 | * @param {*=} eventData
237 | * @return {boolean}
238 | */
239 | dispatchEventToListeners: function(eventType, eventData) { },
240 | };
241 |
--------------------------------------------------------------------------------
/public/js/ui/Dialog.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 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 {!Element} relativeToElement
34 | * @param {!WebInspector.DialogDelegate} delegate
35 | */
36 | WebInspector.Dialog = function(relativeToElement, delegate)
37 | {
38 | this._delegate = delegate;
39 | this._relativeToElement = relativeToElement;
40 |
41 | this._glassPane = new WebInspector.GlassPane();
42 | WebInspector.GlassPane.DefaultFocusedViewStack.push(this);
43 |
44 | // Install glass pane capturing events.
45 | this._glassPane.element.tabIndex = 0;
46 | this._glassPane.element.addEventListener("focus", this._onGlassPaneFocus.bind(this), false);
47 |
48 | this._element = this._glassPane.element.createChild("div");
49 | this._element.tabIndex = 0;
50 | this._element.addEventListener("focus", this._onFocus.bind(this), false);
51 | this._element.addEventListener("keydown", this._onKeyDown.bind(this), false);
52 | this._closeKeys = [
53 | WebInspector.KeyboardShortcut.Keys.Enter.code,
54 | WebInspector.KeyboardShortcut.Keys.Esc.code,
55 | ];
56 |
57 | delegate.show(this._element);
58 |
59 | this._position();
60 | this._delegate.focus();
61 | };
62 |
63 | /**
64 | * @return {?WebInspector.Dialog}
65 | */
66 | WebInspector.Dialog.currentInstance = function()
67 | {
68 | return WebInspector.Dialog._instance;
69 | };
70 |
71 | /**
72 | * @param {!Element} relativeToElement
73 | * @param {!WebInspector.DialogDelegate} delegate
74 | */
75 | WebInspector.Dialog.show = function(relativeToElement, delegate)
76 | {
77 | if (WebInspector.Dialog._instance) {
78 | return;
79 | }
80 | WebInspector.Dialog._instance = new WebInspector.Dialog(relativeToElement, delegate);
81 | };
82 |
83 | WebInspector.Dialog.hide = function()
84 | {
85 | if (!WebInspector.Dialog._instance) {
86 | return;
87 | }
88 | WebInspector.Dialog._instance._hide();
89 | };
90 |
91 | WebInspector.Dialog.prototype = {
92 | focus: function()
93 | {
94 | this._element.focus();
95 | },
96 |
97 | _hide: function()
98 | {
99 | if (this._isHiding) {
100 | return;
101 | }
102 | this._isHiding = true;
103 |
104 | this._delegate.willHide();
105 |
106 | delete WebInspector.Dialog._instance;
107 | WebInspector.GlassPane.DefaultFocusedViewStack.pop();
108 | this._glassPane.dispose();
109 | },
110 |
111 | _onGlassPaneFocus: function(event)
112 | {
113 | this._hide();
114 | },
115 |
116 | _onFocus: function(event)
117 | {
118 | this._delegate.focus();
119 | },
120 |
121 | _position: function()
122 | {
123 | this._delegate.position(this._element, this._relativeToElement);
124 | },
125 |
126 | _onKeyDown: function(event)
127 | {
128 | if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Tab.code) {
129 | event.preventDefault();
130 | return;
131 | }
132 |
133 | if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Enter.code) {
134 | this._delegate.onEnter(event);
135 | }
136 |
137 | if (!event.handled && this._closeKeys.indexOf(event.keyCode) >= 0) {
138 | this._hide();
139 | event.consume(true);
140 | }
141 | }
142 | };
143 |
144 | /**
145 | * @constructor
146 | * @extends {WebInspector.Object}
147 | */
148 | WebInspector.DialogDelegate = function()
149 | {
150 | /** @type {!Element} */
151 | this.element = this.element;
152 | };
153 |
154 | WebInspector.DialogDelegate.prototype = {
155 | /**
156 | * @param {!Element} element
157 | */
158 | show: function(element)
159 | {
160 | element.appendChild(this.element);
161 | this.element.classList.add("dialog-contents");
162 | element.classList.add("dialog", "toolbar-colors");
163 | },
164 |
165 | /**
166 | * @param {!Element} element
167 | * @param {!Element} relativeToElement
168 | */
169 | position: function(element, relativeToElement)
170 | {
171 | var container = WebInspector.Dialog._modalHostView.element;
172 | var box = relativeToElement.boxInWindow(window).relativeToElement(container);
173 |
174 | var positionX = box.x + (relativeToElement.offsetWidth - element.offsetWidth) / 2;
175 | positionX = Number.constrain(positionX, 0, container.offsetWidth - element.offsetWidth);
176 |
177 | var positionY = box.y + (relativeToElement.offsetHeight - element.offsetHeight) / 2;
178 | positionY = Number.constrain(positionY, 0, container.offsetHeight - element.offsetHeight);
179 |
180 | element.style.position = "absolute";
181 | element.positionAt(positionX, positionY, container);
182 | },
183 |
184 | focus: function() { },
185 |
186 | onEnter: function(event) { },
187 |
188 | willHide: function() { },
189 |
190 | __proto__: WebInspector.Object.prototype
191 | };
192 |
193 | /** @type {?WebInspector.View} */
194 | WebInspector.Dialog._modalHostView = null;
195 |
196 | /**
197 | * @param {!WebInspector.View} view
198 | */
199 | WebInspector.Dialog.setModalHostView = function(view)
200 | {
201 | WebInspector.Dialog._modalHostView = view;
202 | };
203 |
204 | /**
205 | * FIXME: make utility method in Dialog, so clients use it instead of this getter.
206 | * Method should be like Dialog.showModalElement(position params, reposition callback).
207 | * @return {?WebInspector.View}
208 | */
209 | WebInspector.Dialog.modalHostView = function()
210 | {
211 | return WebInspector.Dialog._modalHostView;
212 | };
213 |
214 | WebInspector.Dialog.modalHostRepositioned = function()
215 | {
216 | if (WebInspector.Dialog._instance) {
217 | WebInspector.Dialog._instance._position();
218 | }
219 | };
220 |
--------------------------------------------------------------------------------
/public/js/common/Geometry.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 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 | WebInspector.Geometry = {};
32 |
33 | /**
34 | * @type {number}
35 | */
36 | WebInspector.Geometry._Eps = 1e-5;
37 |
38 | /**
39 | * @constructor
40 | * @param {number} x
41 | * @param {number} y
42 | * @param {number} z
43 | */
44 | WebInspector.Geometry.Vector = function(x, y, z)
45 | {
46 | this.x = x;
47 | this.y = y;
48 | this.z = z;
49 | };
50 |
51 | WebInspector.Geometry.Vector.prototype = {
52 | /**
53 | * @return {number}
54 | */
55 | length: function()
56 | {
57 | return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
58 | },
59 |
60 | normalize: function()
61 | {
62 | var length = this.length();
63 | if (length <= WebInspector.Geometry._Eps) {
64 | return;
65 | }
66 |
67 | this.x /= length;
68 | this.y /= length;
69 | this.z /= length;
70 | }
71 | };
72 |
73 | /**
74 | * @constructor
75 | * @param {number} alpha
76 | * @param {number} beta
77 | * @param {number} gamma
78 | */
79 | WebInspector.Geometry.EulerAngles = function(alpha, beta, gamma)
80 | {
81 | this.alpha = alpha;
82 | this.beta = beta;
83 | this.gamma = gamma;
84 | };
85 |
86 | /**
87 | * @param {!CSSMatrix} rotationMatrix
88 | * @return {!WebInspector.Geometry.EulerAngles}
89 | */
90 | WebInspector.Geometry.EulerAngles.fromRotationMatrix = function(rotationMatrix)
91 | {
92 | var beta = Math.atan2(rotationMatrix.m23, rotationMatrix.m33);
93 | var gamma = Math.atan2(-rotationMatrix.m13, Math.sqrt(rotationMatrix.m11 * rotationMatrix.m11 + rotationMatrix.m12 * rotationMatrix.m12));
94 | var alpha = Math.atan2(rotationMatrix.m12, rotationMatrix.m11);
95 | return new WebInspector.Geometry.EulerAngles(WebInspector.Geometry.radToDeg(alpha), WebInspector.Geometry.radToDeg(beta), WebInspector.Geometry.radToDeg(gamma));
96 | };
97 |
98 | /**
99 | * @param {!WebInspector.Geometry.Vector} u
100 | * @param {!WebInspector.Geometry.Vector} v
101 | * @return {number}
102 | */
103 | WebInspector.Geometry.scalarProduct = function(u, v)
104 | {
105 | return u.x * v.x + u.y * v.y + u.z * v.z;
106 | };
107 |
108 | /**
109 | * @param {!WebInspector.Geometry.Vector} u
110 | * @param {!WebInspector.Geometry.Vector} v
111 | * @return {!WebInspector.Geometry.Vector}
112 | */
113 | WebInspector.Geometry.crossProduct = function(u, v)
114 | {
115 | var x = u.y * v.z - u.z * v.y;
116 | var y = u.z * v.x - u.x * v.z;
117 | var z = u.x * v.y - u.y * v.x;
118 | return new WebInspector.Geometry.Vector(x, y, z);
119 | };
120 |
121 | /**
122 | * @param {!WebInspector.Geometry.Vector} u
123 | * @param {!WebInspector.Geometry.Vector} v
124 | * @return {!WebInspector.Geometry.Vector}
125 | */
126 | WebInspector.Geometry.subtract = function(u, v)
127 | {
128 | var x = u.x - v.x;
129 | var y = u.y - v.y;
130 | var z = u.z - v.z;
131 | return new WebInspector.Geometry.Vector(x, y, z);
132 | };
133 |
134 | /**
135 | * @param {!WebInspector.Geometry.Vector} v
136 | * @param {!CSSMatrix} m
137 | * @return {!WebInspector.Geometry.Vector}
138 | */
139 | WebInspector.Geometry.multiplyVectorByMatrixAndNormalize = function(v, m)
140 | {
141 | var t = v.x * m.m14 + v.y * m.m24 + v.z * m.m34 + m.m44;
142 | var x = (v.x * m.m11 + v.y * m.m21 + v.z * m.m31 + m.m41) / t;
143 | var y = (v.x * m.m12 + v.y * m.m22 + v.z * m.m32 + m.m42) / t;
144 | var z = (v.x * m.m13 + v.y * m.m23 + v.z * m.m33 + m.m43) / t;
145 | return new WebInspector.Geometry.Vector(x, y, z);
146 | };
147 |
148 | /**
149 | * @param {!WebInspector.Geometry.Vector} u
150 | * @param {!WebInspector.Geometry.Vector} v
151 | * @return {number}
152 | */
153 | WebInspector.Geometry.calculateAngle = function(u, v)
154 | {
155 | var uLength = u.length();
156 | var vLength = v.length();
157 | if (uLength <= WebInspector.Geometry._Eps || vLength <= WebInspector.Geometry._Eps) {
158 | return 0;
159 | }
160 | var cos = WebInspector.Geometry.scalarProduct(u, v) / uLength / vLength;
161 | if (Math.abs(cos) > 1) {
162 | return 0;
163 | }
164 | return WebInspector.Geometry.radToDeg(Math.acos(cos));
165 | };
166 |
167 | /**
168 | * @param {number} rad
169 | * @return {number}
170 | */
171 | WebInspector.Geometry.radToDeg = function(rad)
172 | {
173 | return rad * 180 / Math.PI;
174 | };
175 |
176 |
177 | /**
178 | * @constructor
179 | * @param {number} width
180 | * @param {number} height
181 | */
182 | function Size(width, height)
183 | {
184 | this.width = width;
185 | this.height = height;
186 | }
187 |
188 | /**
189 | * @param {?Size} size
190 | * @return {boolean}
191 | */
192 | Size.prototype.isEqual = function(size)
193 | {
194 | return !!size && this.width === size.width && this.height === size.height;
195 | };
196 |
197 | /**
198 | * @param {!Size|number} size
199 | * @return {!Size}
200 | */
201 | Size.prototype.widthToMax = function(size)
202 | {
203 | return new Size(Math.max(this.width, (typeof size === "number" ? size : size.width)), this.height);
204 | };
205 |
206 | /**
207 | * @param {!Size|number} size
208 | * @return {!Size}
209 | */
210 | Size.prototype.addWidth = function(size)
211 | {
212 | return new Size(this.width + (typeof size === "number" ? size : size.width), this.height);
213 | };
214 |
215 | /**
216 | * @param {!Size|number} size
217 | * @return {!Size}
218 | */
219 | Size.prototype.heightToMax = function(size)
220 | {
221 | return new Size(this.width, Math.max(this.height, (typeof size === "number" ? size : size.height)));
222 | };
223 |
224 | /**
225 | * @param {!Size|number} size
226 | * @return {!Size}
227 | */
228 | Size.prototype.addHeight = function(size)
229 | {
230 | return new Size(this.width, this.height + (typeof size === "number" ? size : size.height));
231 | };
232 |
--------------------------------------------------------------------------------
/public/js/components/Panel.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2007, 2008 Apple 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
6 | * are met:
7 | *
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 | * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 | * its contributors may be used to endorse or promote products derived
15 | * from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | /**
30 | * @extends {WebInspector.VBox}
31 | * @constructor
32 | */
33 | WebInspector.Panel = function(name)
34 | {
35 | WebInspector.VBox.call(this);
36 |
37 | this.element.classList.add("panel");
38 | this.element.classList.add(name);
39 | this._panelName = name;
40 |
41 | this._shortcuts = /** !Object. */ ({});
42 | };
43 |
44 | // Should by in sync with style declarations.
45 | WebInspector.Panel.counterRightMargin = 25;
46 |
47 | WebInspector.Panel.prototype = {
48 | get name()
49 | {
50 | return this._panelName;
51 | },
52 |
53 | reset: function()
54 | {
55 | },
56 |
57 | /**
58 | * @return {!Element}
59 | */
60 | defaultFocusedElement: function()
61 | {
62 | return this.element;
63 | },
64 |
65 | /**
66 | * @return {?WebInspector.SearchableView}
67 | */
68 | searchableView: function()
69 | {
70 | return null;
71 | },
72 |
73 | /**
74 | * @param {string} text
75 | */
76 | replaceSelectionWith: function(text)
77 | {
78 | },
79 |
80 | /**
81 | * @param {string} query
82 | * @param {string} text
83 | */
84 | replaceAllWith: function(query, text)
85 | {
86 | },
87 |
88 | /**
89 | * @return {!Array.}
90 | */
91 | elementsToRestoreScrollPositionsFor: function()
92 | {
93 | return [];
94 | },
95 |
96 | /**
97 | * @param {!KeyboardEvent} event
98 | */
99 | handleShortcut: function(event)
100 | {
101 | var shortcutKey = WebInspector.KeyboardShortcut.makeKeyFromEvent(event);
102 | var handler = this._shortcuts[shortcutKey];
103 | if (handler && handler(event)) {
104 | event.handled = true;
105 | return;
106 | }
107 |
108 | var searchableView = this.searchableView();
109 | if (!searchableView) {
110 | return;
111 | }
112 |
113 | function handleSearchShortcuts(shortcuts, handler)
114 | {
115 | for (var i = 0; i < shortcuts.length; ++i) {
116 | if (shortcuts[i].key !== shortcutKey) {
117 | continue;
118 | }
119 | return handler.call(searchableView);
120 | }
121 | return false;
122 | }
123 |
124 | if (handleSearchShortcuts(WebInspector.SearchableView.findShortcuts(), searchableView.handleFindShortcut)) {
125 | event.handled = true;
126 | }
127 | else if (handleSearchShortcuts(WebInspector.SearchableView.cancelSearchShortcuts(), searchableView.handleCancelSearchShortcut)) {
128 | event.handled = true;
129 | }
130 | },
131 |
132 | /**
133 | * @param {!Array.} keys
134 | * @param {function(!Event=):boolean} handler
135 | */
136 | registerShortcuts: function(keys, handler)
137 | {
138 | for (var i = 0; i < keys.length; ++i) {
139 | this._shortcuts[keys[i].key] = handler;
140 | }
141 | },
142 |
143 | __proto__: WebInspector.VBox.prototype
144 | };
145 |
146 | /**
147 | * @extends {WebInspector.Panel}
148 | * @param {string} name
149 | * @param {number=} defaultWidth
150 | * @constructor
151 | */
152 | WebInspector.PanelWithSidebarTree = function(name, defaultWidth)
153 | {
154 | WebInspector.Panel.call(this, name);
155 |
156 | this._panelSplitView = new WebInspector.SplitView(true, false, this._panelName + "PanelSplitViewState", defaultWidth || 200);
157 | this._panelSplitView.show(this.element);
158 |
159 | var sidebarView = new WebInspector.VBox();
160 | sidebarView.setMinimumSize(100, 25);
161 | sidebarView.show(this._panelSplitView.sidebarElement());
162 |
163 | this._sidebarElement = sidebarView.element;
164 | this._sidebarElement.classList.add("sidebar");
165 | var sidebarTreeElement = this._sidebarElement.createChild("ol", "sidebar-tree");
166 | this.sidebarTree = new TreeOutline(sidebarTreeElement);
167 | };
168 |
169 | WebInspector.PanelWithSidebarTree.prototype = {
170 | /**
171 | * @return {!Element}
172 | */
173 | sidebarElement: function()
174 | {
175 | return this._sidebarElement;
176 | },
177 |
178 | /**
179 | * @return {!Element} element
180 | */
181 | mainElement: function()
182 | {
183 | return this._panelSplitView.mainElement();
184 | },
185 |
186 | /**
187 | * @return {!Element}
188 | */
189 | defaultFocusedElement: function()
190 | {
191 | return this.sidebarTree.element || this.element;
192 | },
193 |
194 | __proto__: WebInspector.Panel.prototype
195 | };
196 |
197 | /**
198 | * @interface
199 | */
200 | WebInspector.PanelDescriptor = function()
201 | {
202 | };
203 |
204 | WebInspector.PanelDescriptor.prototype = {
205 | /**
206 | * @return {string}
207 | */
208 | name: function() {},
209 |
210 | /**
211 | * @return {string}
212 | */
213 | title: function() {},
214 |
215 | /**
216 | * @return {!WebInspector.Panel}
217 | */
218 | panel: function() {}
219 | };
220 |
221 | /**
222 | * @constructor
223 | * @param {!WebInspector.ModuleManager.Extension} extension
224 | * @implements {WebInspector.PanelDescriptor}
225 | */
226 | WebInspector.ModuleManagerExtensionPanelDescriptor = function(extension)
227 | {
228 | this._name = extension.descriptor().name;
229 | this._title = WebInspector.UIString(extension.descriptor().title);
230 | this._extension = extension;
231 | };
232 |
233 | WebInspector.ModuleManagerExtensionPanelDescriptor.prototype = {
234 | /**
235 | * @return {string}
236 | */
237 | name: function()
238 | {
239 | return this._name;
240 | },
241 |
242 | /**
243 | * @return {string}
244 | */
245 | title: function()
246 | {
247 | return this._title;
248 | },
249 |
250 | /**
251 | * @return {!WebInspector.Panel}
252 | */
253 | panel: function()
254 | {
255 | return /** @type {!WebInspector.Panel} */ (this._extension.instance());
256 | }
257 | };
258 |
--------------------------------------------------------------------------------
/public/js/components/DockController.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 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 | * @extends {WebInspector.Object}
34 | * @param {boolean} canDock
35 | */
36 | WebInspector.DockController = function(canDock)
37 | {
38 | this._canDock = canDock;
39 | if (!canDock) {
40 | this._dockSide = WebInspector.DockController.State.Undocked;
41 | this._updateUI();
42 | return;
43 | }
44 |
45 | WebInspector.settings.currentDockState = WebInspector.settings.createSetting("currentDockState", "");
46 | WebInspector.settings.lastDockState = WebInspector.settings.createSetting("lastDockState", "");
47 | };
48 |
49 | WebInspector.DockController.State = {
50 | DockedToBottom: "bottom",
51 | DockedToRight: "right",
52 | DockedToLeft: "left",
53 | Undocked: "undocked"
54 | };
55 |
56 | // Use BeforeDockSideChanged to do something before all the UI bits are updated,
57 | // DockSideChanged to update UI, and AfterDockSideChanged to perform actions
58 | // after frontend is docked/undocked in the browser.
59 | WebInspector.DockController.Events = {
60 | BeforeDockSideChanged: "BeforeDockSideChanged",
61 | DockSideChanged: "DockSideChanged",
62 | AfterDockSideChanged: "AfterDockSideChanged"
63 | };
64 |
65 | WebInspector.DockController.prototype = {
66 | initialize: function()
67 | {
68 | if (!this._canDock) {
69 | return;
70 | }
71 |
72 | this._states = [WebInspector.DockController.State.DockedToBottom, WebInspector.DockController.State.Undocked, WebInspector.DockController.State.DockedToRight];
73 | this._titles = [WebInspector.UIString("Dock to main window."), WebInspector.UIString("Undock into separate window."), WebInspector.UIString("Dock to main window.")];
74 | if (WebInspector.experimentsSettings.dockToLeft.isEnabled()) {
75 | this._states.push(WebInspector.DockController.State.DockedToLeft);
76 | this._titles.push(WebInspector.UIString("Dock to main window."));
77 | }
78 | var initialState = WebInspector.settings.currentDockState.get();
79 | initialState = this._states.indexOf(initialState) >= 0 ? initialState : this._states[0];
80 | this._dockSideChanged(initialState);
81 | },
82 |
83 | /**
84 | * @return {string}
85 | */
86 | dockSide: function()
87 | {
88 | return this._dockSide;
89 | },
90 |
91 | /**
92 | * @return {boolean}
93 | */
94 | canDock: function()
95 | {
96 | return this._canDock;
97 | },
98 |
99 | /**
100 | * @return {boolean}
101 | */
102 | isVertical: function()
103 | {
104 | return this._dockSide === WebInspector.DockController.State.DockedToRight || this._dockSide === WebInspector.DockController.State.DockedToLeft;
105 | },
106 |
107 | /**
108 | * @param {string} dockSide
109 | */
110 | _dockSideChanged: function(dockSide)
111 | {
112 | if (this._dockSide === dockSide) {
113 | return;
114 | }
115 |
116 | var eventData = { from: this._dockSide, to: dockSide };
117 | this.dispatchEventToListeners(WebInspector.DockController.Events.BeforeDockSideChanged, eventData);
118 | console.timeStamp("DockController.setIsDocked");
119 | InspectorFrontendHost.setIsDocked(dockSide !== WebInspector.DockController.State.Undocked, this._setIsDockedResponse.bind(this, eventData));
120 | this._dockSide = dockSide;
121 | this._updateUI();
122 | this.dispatchEventToListeners(WebInspector.DockController.Events.DockSideChanged, eventData);
123 | },
124 |
125 | /**
126 | * @param {{from: string, to: string}} eventData
127 | */
128 | _setIsDockedResponse: function(eventData)
129 | {
130 | this.dispatchEventToListeners(WebInspector.DockController.Events.AfterDockSideChanged, eventData);
131 | },
132 |
133 | _updateUI: function()
134 | {
135 | var body = document.body;
136 | switch (this._dockSide) {
137 | case WebInspector.DockController.State.DockedToBottom:
138 | body.classList.remove("undocked");
139 | body.classList.remove("dock-to-right");
140 | body.classList.remove("dock-to-left");
141 | body.classList.add("dock-to-bottom");
142 | break;
143 | case WebInspector.DockController.State.DockedToRight:
144 | body.classList.remove("undocked");
145 | body.classList.add("dock-to-right");
146 | body.classList.remove("dock-to-left");
147 | body.classList.remove("dock-to-bottom");
148 | break;
149 | case WebInspector.DockController.State.DockedToLeft:
150 | body.classList.remove("undocked");
151 | body.classList.remove("dock-to-right");
152 | body.classList.add("dock-to-left");
153 | body.classList.remove("dock-to-bottom");
154 | break;
155 | case WebInspector.DockController.State.Undocked:
156 | body.classList.add("undocked");
157 | body.classList.remove("dock-to-right");
158 | body.classList.remove("dock-to-left");
159 | body.classList.remove("dock-to-bottom");
160 | break;
161 | }
162 | },
163 |
164 | __proto__: WebInspector.Object.prototype
165 | };
166 |
167 | /**
168 | * @constructor
169 | * @implements {WebInspector.StatusBarButton.Provider}
170 | */
171 | WebInspector.DockController.ButtonProvider = function()
172 | {
173 | };
174 |
175 | WebInspector.DockController.ButtonProvider.prototype = {
176 | /**
177 | * @return {?WebInspector.StatusBarButton}
178 | */
179 | button: function()
180 | {
181 | if (!WebInspector.dockController.canDock()) {
182 | return null;
183 | }
184 |
185 | if (!this._dockToggleButton) {
186 | this._dockToggleButton = new WebInspector.StatusBarStatesSettingButton(
187 | "dock-status-bar-item",
188 | WebInspector.dockController._states,
189 | WebInspector.dockController._titles,
190 | WebInspector.dockController.dockSide(),
191 | WebInspector.settings.currentDockState,
192 | WebInspector.settings.lastDockState,
193 | WebInspector.dockController._dockSideChanged.bind(WebInspector.dockController));
194 | }
195 | return this._dockToggleButton;
196 | }
197 | };
198 |
199 | /**
200 | * @type {!WebInspector.DockController}
201 | */
202 | WebInspector.dockController = WebInspector.dockController;
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Hello.
2 | Have you ever wanted to show someone something really cool in javascript, maybe
3 | an extra sexy `reduce` or a cool syntactical trick? Of course you did. You wrote
4 | your code, and it turned out fucking rad. Now how do you send this that special
5 | somebody?
6 |
7 | Sites like jsbin and codepen are cool for showing off full-blown demos. But you
8 | want to show off some juicy javascript. You probaly hacked it around in the dev
9 | tools of the browser of your choice, because they are a great environment for
10 | just playing around with javascript.
11 |
12 | But what if you could have a javascript console...in your browser?
13 |
14 | And then share that hacking around session with those you love (or hate (or
15 | feel no particular emotion for))?
16 |
17 | http://jsh.zirak.me . It could take a bit to load.
18 |
19 |
20 | 
21 |
22 |
23 | ## What is this?
24 | As the introduction above says, this is Chrome's dev tools javascript console in
25 | a regular web page. To see how it was done, see the [How stuff works](#how-stuff-works)
26 | section below.
27 |
28 | Write some javascript, invite your friends, write some javascript on your
29 | friends. You'll be the life of the party.
30 |
31 | It's quite alpha but usable. Things work generally pretty well on Chrome,
32 | Firefox has some jitters, IE will likely stay a mess for some time.
33 |
34 | ## Features
35 | What you'd expect of Chrome dev tools' excellent console:
36 |
37 | * JavaScript REPL
38 | * Object inspection
39 | * Completion suggestions
40 | * Nice stack traces
41 | * History
42 | * Monkeys
43 |
44 | ### Roadmap
45 |
46 | * [x] Introduction message
47 | * [x] Saving and sharing
48 | * [x] Implement ---all--- most console methods (dir, group, table, time, ...)
49 | * [x] Find functionality
50 | * [ ] Make it work across modern-ish browsers
51 | * [ ] Inspect nodes.
52 | * [ ] Stream a session (like [TogetherJS](https://togetherjs.com/))
53 | * [ ] Themes (?)
54 | * [ ] Settings (?)
55 | * [ ] Better editing (tab button support)
56 |
57 | ## Running
58 | A bit unfortunately, this is meant to run on Google App Engine, so to run you'll
59 | need to [download the SDK for Python](https://cloud.google.com/appengine/downloads).
60 |
61 | Unzip/install/whatever, and run:
62 |
63 | ```sh
64 | $ python2.7 path/to/google_appengine/dev_appserver.py path/to/jsh
65 | ```
66 |
67 | (if 2.7 is already your Python version you can omit that first part.)
68 |
69 | Pay a visit to localhost:8080 and have fun.
70 |
71 | ## How stuff works
72 | The best way to learn how the dev tools works is by looking at the source and
73 | playing around with it. The sources here are taken freshly squeezed from
74 | chromium/chromium@66fbff9d3e1c441db581024895a959efc32deac2 . You can find it in
75 | `third_party/WebKit/devtools/front_end`. May God have mercy on your soul.
76 |
77 | (Yes, I'm planning on writing my findings down.)
78 |
79 | Poke around, understand that `InspectorFrontendHost` and some other objects are
80 | actually native bindings, be angry that that's the case. Raaaargh!!!!
81 |
82 | You can actually inspect the dev-tools using the dev-tools. Hit Ctrl-Shift-J and
83 | undock them if necessary. Then, simply hit Ctrl-Shift-J again. Have fun.
84 |
85 | To make things even more fun, in your inceptioned dev tools, run:
86 |
87 | ```javascript
88 | InspectorBackendClass.Options.dumpInspectorProtocolMessages = true;
89 | ```
90 |
91 | And proceed to do things. The bazingaload of messages you'll see are part of the
92 | [protocol](https://developer.chrome.com/devtools/docs/protocol/1.1/index).
93 |
94 | I wrote this clone by first including what seemed like obvious core console
95 | functionality (that is, everything in the console directory), followed by
96 | main/Main.js (because hey, it's main), and then started to slowly (ssllloooowwwllllyyyy)
97 | fix the `ReferenceError`s and `TypeError`s.
98 |
99 | This means that while at its base the console "works", there are a lot of hidden
100 | booby-traps and unimplemented functionality. At the same time, there is a lot of
101 | code which just isn't useful (why do we need a VBox and the SplitView and the
102 | tabs pane and so forth?). The way forward is implementing more and more console
103 | related functionality while trimming unnecessary portions.
104 |
105 | All messages to the native backend funnel down to `jsh.handleMessage`.
106 |
107 | ### Structure
108 | Frontend is in the `public/` directory; `/templates` and the rest are Google
109 | App Engine boilerplate.
110 |
111 | The directory structure is also of course copied directly from the dev tools'
112 | source. I don't quite get it either. It's a mess.
113 |
114 | If you want a starting point to hack things around, the index file is a bad
115 | place to start. It's just a blob of scripts.
116 |
117 | `jsh.js` is one place, as it contains the code for dealing with
118 | messages ("evaluate this expression", "give me the properties of this object").
119 |
120 | `InjectedScript.js` contains most if not all of the interesting logic.
121 |
122 | `main/Main.js` is where most things happen: Settings up the UI, settings up the
123 | different objects the UI uses. It's mostly baloney, though.
124 |
125 | `sdk/ConsoleModel.js` is where the runtime/console API gets tied up to the UI,
126 | and the good friends in the `console/` folder are where all the console UI logic
127 | is done.
128 |
129 | It's a lot of being confusing and `grep`ing for things.
130 |
131 | ### What happens when I press enter?
132 |
133 | That's a very good question. It all starts from `public/js/concole/ConsoleView.js`,
134 | in a nice little function called `_promptKeyDown`. Oh look, `_enterKeyPressed`,
135 | that looks simple!
136 |
137 | And then it's HELL. Let's go through a partial trace (which is of course broken
138 | at times because async, and partial because I'm not doing a full call graph):
139 |
140 | 1. `ConsoleView.._promptKeyDown`
141 | 2. `ConsoleView.._enterKeyPressed`
142 | 3. `ConsoleView.._appendCommand`
143 | 4. `ConsoleModel.evaluateCommandInConsole`
144 | 5. `ExecutionContext..evaluate`
145 |
146 | (lots of redirections between this and next)
147 | 6. `InspectorBackendClass.AgentPrototype..registerCommand#sendMessage`
148 | 7. `InspectorBackendClass.AgentPrototype.._sendMessageToBackend`
149 | 8. `InspectorBackendClass.MainConnection.._wrapCallbackAndSendMessageObject`
150 | 9. `InspectorBackendClass.StubConnection..sendMessage`
151 |
152 | This is where we come in. We're a `StubConnection` because our backend isn't
153 | the real native backend Chrome has. But we'll show it! Next part will
154 | change as jsh changes.
155 | 10. `jsh.handleMessage`
156 | 11. `jsh#sendMessageToEvalFrame`
157 |
158 | And from now on we've passed control to the eval frame. Until further notice
159 | all functions are one there.
160 | 12. `messageListener`
161 | 13. `actions.bridge`
162 | 14. `bridge.evaluate`
163 | 15. `eval` (finally!)
164 | 16. `sendToParent`
165 |
166 | Aaannndd back to the jsh frame.
167 | 17. `messageListener`
168 |
169 | Aaannndd this is where jsh leaves off.
170 | 18. `InspectorBackendClass.MainConnection..dispatch`
171 |
172 | ...*lots* of indirections...
173 | 19. `ExecutionContext..evaluate#evalCallback`
174 | 20. `ConsoleModel.evaluateCommandInConsole#printResult`
175 | 21. `ConsoleView.._commandEvaluated`
176 | 22. `ConsoleView.._printResult`
177 |
178 | ...and it just goes boring UI from here. Real nice, right?
179 |
180 | ### wat
181 |
182 | To give you a hand, here are some useful variables to have.
183 |
184 | * You're going to see `target` this and `target` that a lot. You can get it like
185 | this: `WebInspector.targetManager.targets()[0]`
186 | * Same goes for `connection` or `_connection`: `InspectorBackend.connection()`
187 | * ConsoleView: `WebInspector.ConsolePanel._view()`
188 |
189 | And it's late now so I can't think of anything else.
190 |
191 | ## License
192 | 99% of the files here have a giant license block at the top. Basically, it's
193 | directly from the dev tools source. This goes for any images in `css/Images`.
194 |
195 | Favicon is from Github's [Octicon](https://octicons.github.com/) set. Expect a
196 | new one.
197 |
198 | Any code *I* write is under the [WTFPL](http://www.wtfpl.net/).
199 |
--------------------------------------------------------------------------------
/public/js/common/TextRange.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 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 {number} startLine
34 | * @param {number} startColumn
35 | * @param {number} endLine
36 | * @param {number} endColumn
37 | */
38 | WebInspector.TextRange = function(startLine, startColumn, endLine, endColumn)
39 | {
40 | this.startLine = startLine;
41 | this.startColumn = startColumn;
42 | this.endLine = endLine;
43 | this.endColumn = endColumn;
44 | };
45 |
46 | /**
47 | * @param {number} line
48 | * @param {number} column
49 | * @return {!WebInspector.TextRange}
50 | */
51 | WebInspector.TextRange.createFromLocation = function(line, column)
52 | {
53 | return new WebInspector.TextRange(line, column, line, column);
54 | };
55 |
56 | /**
57 | * @param {!Object} serializedTextRange
58 | * @return {!WebInspector.TextRange}
59 | */
60 | WebInspector.TextRange.fromObject = function(serializedTextRange)
61 | {
62 | return new WebInspector.TextRange(serializedTextRange.startLine, serializedTextRange.startColumn, serializedTextRange.endLine, serializedTextRange.endColumn);
63 | };
64 |
65 | /**
66 | * @param {!WebInspector.TextRange} range1
67 | * @param {!WebInspector.TextRange} range2
68 | * @return {number}
69 | */
70 | WebInspector.TextRange.comparator = function(range1, range2)
71 | {
72 | return range1.compareTo(range2);
73 | };
74 |
75 | WebInspector.TextRange.prototype = {
76 | /**
77 | * @return {boolean}
78 | */
79 | isEmpty: function()
80 | {
81 | return this.startLine === this.endLine && this.startColumn === this.endColumn;
82 | },
83 |
84 | /**
85 | * @param {!WebInspector.TextRange} range
86 | * @return {boolean}
87 | */
88 | immediatelyPrecedes: function(range)
89 | {
90 | if (!range) {
91 | return false;
92 | }
93 | return this.endLine === range.startLine && this.endColumn === range.startColumn;
94 | },
95 |
96 | /**
97 | * @param {!WebInspector.TextRange} range
98 | * @return {boolean}
99 | */
100 | immediatelyFollows: function(range)
101 | {
102 | if (!range) {
103 | return false;
104 | }
105 | return range.immediatelyPrecedes(this);
106 | },
107 |
108 | /**
109 | * @param {!WebInspector.TextRange} range
110 | * @return {boolean}
111 | */
112 | follows: function(range)
113 | {
114 | return (
115 | range.endLine === this.startLine &&
116 | range.endColumn <= this.startColumn
117 | ) || range.endLine < this.startLine;
118 | },
119 |
120 | /**
121 | * @return {number}
122 | */
123 | get linesCount()
124 | {
125 | return this.endLine - this.startLine;
126 | },
127 |
128 | /**
129 | * @return {!WebInspector.TextRange}
130 | */
131 | collapseToEnd: function()
132 | {
133 | return new WebInspector.TextRange(this.endLine, this.endColumn, this.endLine, this.endColumn);
134 | },
135 |
136 | /**
137 | * @return {!WebInspector.TextRange}
138 | */
139 | collapseToStart: function()
140 | {
141 | return new WebInspector.TextRange(this.startLine, this.startColumn, this.startLine, this.startColumn);
142 | },
143 |
144 | /**
145 | * @return {!WebInspector.TextRange}
146 | */
147 | normalize: function()
148 | {
149 | if (this.startLine > this.endLine || (this.startLine === this.endLine && this.startColumn > this.endColumn)) {
150 | return new WebInspector.TextRange(this.endLine, this.endColumn, this.startLine, this.startColumn);
151 | }
152 | else {
153 | return this.clone();
154 | }
155 | },
156 |
157 | /**
158 | * @return {!WebInspector.TextRange}
159 | */
160 | clone: function()
161 | {
162 | return new WebInspector.TextRange(this.startLine, this.startColumn, this.endLine, this.endColumn);
163 | },
164 |
165 | /**
166 | * @return {!Object}
167 | */
168 | serializeToObject: function()
169 | {
170 | var serializedTextRange = {};
171 | serializedTextRange.startLine = this.startLine;
172 | serializedTextRange.startColumn = this.startColumn;
173 | serializedTextRange.endLine = this.endLine;
174 | serializedTextRange.endColumn = this.endColumn;
175 | return serializedTextRange;
176 | },
177 |
178 | /**
179 | * @param {!WebInspector.TextRange} other
180 | * @return {number}
181 | */
182 | compareTo: function(other)
183 | {
184 | if (this.startLine > other.startLine) {
185 | return 1;
186 | }
187 | if (this.startLine < other.startLine) {
188 | return -1;
189 | }
190 | if (this.startColumn > other.startColumn) {
191 | return 1;
192 | }
193 | if (this.startColumn < other.startColumn) {
194 | return -1;
195 | }
196 | return 0;
197 | },
198 |
199 | /**
200 | * @param {!WebInspector.TextRange} other
201 | * @return {boolean}
202 | */
203 | equal: function(other)
204 | {
205 | return this.startLine === other.startLine && this.endLine === other.endLine &&
206 | this.startColumn === other.startColumn && this.endColumn === other.endColumn;
207 | },
208 |
209 | /**
210 | * @param {number} lineOffset
211 | * @return {!WebInspector.TextRange}
212 | */
213 | shift: function(lineOffset)
214 | {
215 | return new WebInspector.TextRange(this.startLine + lineOffset, this.startColumn, this.endLine + lineOffset, this.endColumn);
216 | },
217 |
218 | /**
219 | * @param {!WebInspector.TextRange} originalRange
220 | * @param {!WebInspector.TextRange} editedRange
221 | * @return {!WebInspector.TextRange}
222 | */
223 | rebaseAfterTextEdit: function(originalRange, editedRange)
224 | {
225 | console.assert(originalRange.startLine === editedRange.startLine);
226 | console.assert(originalRange.startColumn === editedRange.startColumn);
227 | var rebase = this.clone();
228 | if (!this.follows(originalRange)) {
229 | return rebase;
230 | }
231 | var lineDelta = editedRange.endLine - originalRange.endLine;
232 | var columnDelta = editedRange.endColumn - originalRange.endColumn;
233 | rebase.startLine += lineDelta;
234 | rebase.endLine += lineDelta;
235 | if (rebase.startLine === editedRange.endLine) {
236 | rebase.startColumn += columnDelta;
237 | }
238 | if (rebase.endLine === editedRange.endLine) {
239 | rebase.endColumn += columnDelta;
240 | }
241 | return rebase;
242 | },
243 |
244 | /**
245 | * @return {string}
246 | */
247 | toString: function()
248 | {
249 | return JSON.stringify(this);
250 | }
251 | };
252 |
253 | /**
254 | * @constructor
255 | * @param {number} offset
256 | * @param {number} length
257 | */
258 | WebInspector.SourceRange = function(offset, length)
259 | {
260 | this.offset = offset;
261 | this.length = length;
262 | };
263 |
--------------------------------------------------------------------------------
/public/js/jsh-console.js:
--------------------------------------------------------------------------------
1 | var createConsole = function (bridge, realConsole, sendMessage) {
2 | /*
3 | TODO:
4 | * count
5 | */
6 |
7 | var console = {},
8 | times = {};
9 |
10 | ['log', 'info', 'error'].forEach(function (level) {
11 | console[level] = function () {
12 | var message = {
13 | level : level,
14 | type : 'log',
15 |
16 | parameters : wrapObjects(arguments),
17 | text : [].join.call(arguments, ' ')
18 | };
19 |
20 | sendConsoleMessage(message);
21 | };
22 | });
23 |
24 | console.debug = console.log;
25 |
26 | console.warn = function () {
27 | var message = {
28 | level : 'warning',
29 | type : 'log',
30 |
31 | parameters : wrapObjects(arguments),
32 | text : [].join.call(arguments, ' ')
33 | };
34 |
35 | sendConsoleMessage(message);
36 | };
37 |
38 | console.assert = function (condition) {
39 | if (condition) {
40 | return;
41 | }
42 |
43 | // TODO add Array.from to utilities.js
44 | var args = [].slice.call(arguments, 1);
45 |
46 | var message = {
47 | level : 'error',
48 | type : 'assert'
49 | };
50 |
51 | if (args.length) {
52 | message.parameters = wrapObjects(args);
53 | message.text = String(args[0]);
54 | }
55 |
56 | sendConsoleMessage(message);
57 | };
58 |
59 | console.dir = function dir () {
60 | if (!arguments.length) {
61 | return;
62 | }
63 |
64 | var message = {
65 | level : 'log',
66 | type : 'dir',
67 |
68 | parameters : wrapObjects(arguments),
69 | text : String(arguments[0])
70 | };
71 |
72 | sendConsoleMessage(message);
73 | };
74 |
75 | console.table = function table (parameter) {
76 | var message = {
77 | level : 'log',
78 | type : 'table',
79 | parameters : [bridge.wrapObject({
80 | object : parameter,
81 | columnNames : null,
82 | isTable : true
83 | })],
84 | text : String([].map.call(arguments, String))
85 | };
86 |
87 | sendConsoleMessage(message);
88 | };
89 |
90 | // FIXME: there's a weird bug where console.trace calls are "taller" than other
91 | //lines.
92 | console.trace = function trace () {
93 | var message = {
94 | level : 'log',
95 | type : 'trace',
96 | text : ''
97 | };
98 |
99 | if (arguments.length) {
100 | message.parameters = wrapObjects(arguments);
101 | message.text = String(arguments[0]);
102 | }
103 |
104 | sendConsoleMessage(message);
105 | };
106 |
107 | // grouping
108 |
109 | console.group = function group () {
110 | var message = {
111 | level : 'log',
112 | type : 'startGroup',
113 | text : ''
114 | };
115 |
116 | if (arguments.length) {
117 | message.parameters = wrapObjects(arguments);
118 | }
119 |
120 | sendConsoleMessage(message);
121 | };
122 |
123 | console.groupEnd = function groupEnd () {
124 | sendConsoleMessage({
125 | level : 'log',
126 | type : 'endGroup',
127 | text : ''
128 | });
129 | };
130 |
131 | console.groupCollapsed = function groupCollapsed () {
132 | var message = {
133 | level : 'log',
134 | type : 'startGroupCollapsed',
135 | text : ''
136 | };
137 |
138 | if (arguments.length) {
139 | message.parameters = wrapObjects(arguments);
140 | }
141 |
142 | sendConsoleMessage(message);
143 | };
144 |
145 | // TODO: what should this do? clear history? the user needs to be alerted if so.
146 | // do we even want this?
147 | console.clear = function clear () {
148 | sendMessage({
149 | method : 'Console.messagesCleared'
150 | });
151 |
152 | sendConsoleMessage({
153 | level : 'log',
154 | type : 'clear',
155 | text : ''
156 | });
157 | };
158 |
159 | // timing
160 |
161 | console.time = function (name) {
162 | // Just following Firebug's convention...
163 | if (!name) {
164 | return;
165 | }
166 |
167 | times[name] = performance.now();
168 | };
169 | console.timeEnd = function (name) {
170 | var end = performance.now();
171 |
172 | if (!name) {
173 | return;
174 | }
175 |
176 | var begin = times[name];
177 | if (!begin) {
178 | return;
179 | }
180 |
181 | delete times[name];
182 |
183 | var elapsed = end - begin,
184 | elapsedString = elapsed.toFixed(3) + 'ms';
185 |
186 | // TODO should output be smarter? Instead of just showing ms, also show
187 | //seconds for larger inputs (e.g. 1355ms => 1s 355ms or 1.355s)
188 |
189 | sendConsoleMessage({
190 | level : 'debug',
191 | type : 'log',
192 | text : name + ': ' + elapsedString
193 | });
194 | };
195 |
196 | // utility crap from here
197 |
198 | function sendConsoleMessage (consoleMessage) {
199 | if (!consoleMessage.source) {
200 | consoleMessage.source = 'console-api';
201 | }
202 |
203 | if (!consoleMessage.stackTrace) {
204 | var stackTrace = parseLogStackTrace((new Error()).stack);
205 | consoleMessage.line = stackTrace[0].lineNumber;
206 | consoleMessage.column = stackTrace[0].columnNumber;
207 | consoleMessage.stackTrace = stackTrace;
208 | }
209 |
210 | consoleMessage.timestamp = Date.now() / 1000;
211 |
212 |
213 | var message = {
214 | method : 'Console.messageAdded',
215 | params : { message : consoleMessage }
216 | };
217 |
218 | sendMessage(message);
219 | }
220 |
221 | function wrapObjects (objs) {
222 | return [].map.call(objs, bridge.wrapObject, bridge);
223 | }
224 |
225 | // Takes a strung stack trace (err.stack) and makes sense out of it: Extracts
226 | //function names, line and column numbers.
227 | function parseLogStackTrace (stack) {
228 | /*
229 | The stack trace in Chrome looks something like:
230 | Error
231 | at Object.jsh.sendConsoleMessage (http://localhost:8080/js/jsh-console.js:158:22)
232 | at Object.jsh.console.(anonymous function) (http://localhost:8080/js/jsh-console.js:25:24)
233 | at eval (eval at (http://localhost:8080/js/jsh.js:263:40), :1:9)
234 | at eval (native)
235 | at Object.jsh.eval (http://localhost:8080/js/jsh.js:263:40)
236 | at Object.jsh.bridge.evaluate (http://localhost:8080/js/jsh.js:126:22)
237 | at Object.jsh.handleMessage (http://localhost:8080/js/jsh.js:73:32)
238 | at Object.actualSendMessage (http://localhost:8080/js/sdk/InspectorBackend.js:698:27)
239 |
240 | We want to do away with the first and last three lines.
241 |
242 | OTOH, in Firefox, they look like this:
243 | jsh.sendConsoleMessage@http://localhost:8080/js/jsh-console.js:158:9
244 | jsh.console[level]@http://localhost:8080/js/jsh-console.js:25:9
245 | @http://localhost:8080/js/jsh.js line 263 > eval:1:1
246 | jsh.eval@http://localhost:8080/js/jsh.js:263:5
247 | jsh.bridge.evaluate@http://localhost:8080/js/jsh.js:126:9
248 | jsh.handleMessage@http://localhost:8080/js/jsh.js:73:9
249 | actualSendMessage@http://localhost:8080/js/sdk/InspectorBackend.js:698:17
250 |
251 | Where we want to do away with the firt two and last three.
252 | */
253 | var stackLines = stack.split('\n'),
254 | parser;
255 |
256 | if (stackLines[0] === 'Error') {
257 | stackLines.shift();
258 | parser = chromeParseLine;
259 | }
260 | else {
261 | parser = firefoxParseLine;
262 | }
263 |
264 | return stackLines.filter(Boolean).map(parser);
265 |
266 | function chromeParseLine (line) {
267 | realConsole.log(line);
268 | // at obj.funcName (crap)
269 | // at obj.funcName.(anonymous function) (crap)
270 | var funcMatch = /^\s*at ([^\(]*(?:\(anonymous function\))?)/.exec(line) || ['', ''];
271 |
272 | // (crap:line:column)
273 | var positionMatch = /:(\d+):(\d+)\)\s*$/.exec(line) || ['', '', ''];
274 |
275 | return {
276 | functionName : funcMatch[1],
277 | lineNumber : Number(positionMatch[1]),
278 | columnNumber : Number(positionMatch[2]),
279 |
280 | // protocol stuff.
281 | scriptId : 0,
282 | url : ''
283 | };
284 | }
285 | function firefoxParseLine (line) {
286 | realConsole.log(line);
287 | // jsh.handleMessage@http://localhost:8080/js/jsh.js:123231273:12312319
288 | // ^---------------^ ^-----------------------------^ ^-------^ ^------^
289 | // (.+) @ (.+) : (\d+) : (\d+)
290 | var match = (/^(.+)?@(.+):(\d+):(\d+)$/).exec(line);
291 | var func, file, col;
292 |
293 | if (match) {
294 | func = match[1];
295 | file = match[2];
296 | line = match[3];
297 | col = match[4];
298 | }
299 | else {
300 | // @http://localhost:8080/js/jsh.js line 263 > eval:1:1
301 | match = (/^@(.+) line (\d+) > eval:\d+:\d+$/).exec(line);
302 |
303 | if (!match) {
304 | realConsole.error('wat', line);
305 | }
306 |
307 | func = 'eval';
308 | file = match[1];
309 | line = match[2];
310 | col = 0; // we receive no indication
311 | }
312 |
313 | return {
314 | functionName : func,
315 | lineNumber : file,
316 | columnNumber : col,
317 |
318 | scriptId : 0,
319 | url : ''
320 | };
321 | }
322 | }
323 |
324 | return console;
325 | };
326 |
--------------------------------------------------------------------------------
/public/js/common/modules.js:
--------------------------------------------------------------------------------
1 | var allDescriptors = [
2 | {
3 | "name" : "main",
4 | "extensions": [
5 | {
6 | "type": "@WebInspector.ContextMenu.Provider",
7 | "contextTypes": ["WebInspector.UISourceCode", "WebInspector.Resource", "WebInspector.NetworkRequest", "Node"],
8 | "className": "WebInspector.HandlerRegistry.ContextMenuProvider"
9 | },
10 | {
11 | "type": "@WebInspector.ActionDelegate",
12 | "actionId": "main.reload",
13 | "className": "WebInspector.Main.ReloadActionDelegate",
14 | "bindings": [
15 | {
16 | "platform": "windows,linux",
17 | "shortcut": "F5 Ctrl+R"
18 | },
19 | {
20 | "platform": "mac",
21 | "shortcut": "Meta+R"
22 | }
23 | ]
24 | },
25 | {
26 | "type": "@WebInspector.ActionDelegate",
27 | "actionId": "main.hard-reload",
28 | "className": "WebInspector.Main.HardReloadActionDelegate",
29 | "bindings": [
30 | {
31 | "platform": "windows,linux",
32 | "shortcut": "Shift+F5 Ctrl+F5 Ctrl+Shift+F5 Shift+Ctrl+R"
33 | },
34 | {
35 | "platform": "mac",
36 | "shortcut": "Shift+Meta+R"
37 | }
38 | ]
39 | },
40 | {
41 | "type": "@WebInspector.ActionDelegate",
42 | "actionId": "main.toggle-drawer",
43 | "className": "WebInspector.InspectorView.DrawerToggleActionDelegate",
44 | "bindings": [
45 | {
46 | "shortcut": "Esc"
47 | }
48 | ]
49 | },
50 | {
51 | "type": "@WebInspector.ActionDelegate",
52 | "actionId": "main.debug-reload",
53 | "className": "WebInspector.Main.DebugReloadActionDelegate",
54 | "bindings": [
55 | {
56 | "shortcut": "Alt+R"
57 | }
58 | ]
59 | },
60 | /*
61 | {
62 | "type": "@WebInspector.ActionDelegate",
63 | "actionId": "main.toggle-element-search",
64 | "className": "WebInspector.InspectElementModeController.ToggleSearchActionDelegate",
65 | "bindings": [
66 | {
67 | "platform": "windows,linux",
68 | "shortcut": "Ctrl+Shift+C"
69 | },
70 | {
71 | "platform": "mac",
72 | "shortcut": "Meta+Shift+C"
73 | }
74 | ]
75 | },
76 | */
77 | {
78 | "type": "@WebInspector.ActionDelegate",
79 | "actionId": "main.zoom-in",
80 | "className": "WebInspector.Main.ZoomInActionDelegate",
81 | "bindings": [
82 | {
83 | "platform": "windows,linux",
84 | "shortcut": "Ctrl+Plus Ctrl+Shift+Plus Ctrl+NumpadPlus Ctrl+Shift+NumpadPlus"
85 | },
86 | {
87 | "platform": "mac",
88 | "shortcut": "Meta+Plus Meta+Shift+Plus Meta+NumpadPlus Meta+Shift+NumpadPlus"
89 | }
90 | ]
91 | },
92 | {
93 | "type": "@WebInspector.ActionDelegate",
94 | "actionId": "main.zoom-out",
95 | "className": "WebInspector.Main.ZoomOutActionDelegate",
96 | "bindings": [
97 | {
98 | "platform": "windows,linux",
99 | "shortcut": "Ctrl+Minus Ctrl+Shift+Minus Ctrl+NumpadMinus Ctrl+Shift+NumpadMinus"
100 | },
101 | {
102 | "platform": "mac",
103 | "shortcut": "Meta+Minus Meta+Shift+Minus Meta+NumpadMinus Meta+Shift+NumpadMinus"
104 | }
105 | ]
106 | },
107 | {
108 | "type": "@WebInspector.ActionDelegate",
109 | "actionId": "main.zoom-reset",
110 | "className": "WebInspector.Main.ZoomResetActionDelegate",
111 | "bindings": [
112 | {
113 | "platform": "windows,linux",
114 | "shortcut": "Ctrl+0 Ctrl+Numpad0"
115 | },
116 | {
117 | "platform": "mac",
118 | "shortcut": "Meta+0 Meta+Numpad0"
119 | }
120 | ]
121 | },
122 | /*
123 | {
124 | "type": "drawer-view",
125 | "name": "emulation",
126 | "title": "Emulation",
127 | "order": "10",
128 | "className": "WebInspector.OverridesView"
129 | },
130 | {
131 | "type": "drawer-view",
132 | "name": "rendering",
133 | "title": "Rendering",
134 | "order": "11",
135 | "className": "WebInspector.RenderingOptions.View"
136 | },
137 | */
138 | {
139 | "type": "@WebInspector.Revealer",
140 | "contextTypes": ["WebInspector.OverridesSupport"],
141 | "className": "WebInspector.OverridesView.Revealer"
142 | },
143 | /*
144 | {
145 | "type": "@WebInspector.StatusBarButton.Provider",
146 | "className": "WebInspector.InspectElementModeController.ToggleButtonProvider",
147 | "location": "toolbar-left",
148 | "order": 0,
149 | "actionId": "main.toggle-element-search"
150 | },
151 |
152 | {
153 | "type": "@WebInspector.StatusBarButton.Provider",
154 | "className": "WebInspector.App.EmulationButtonProvider",
155 | "order": 1,
156 | "location": "toolbar-left"
157 | },
158 | {
159 | "type": "@WebInspector.StatusBarButton.Provider",
160 | "className": "WebInspector.DockController.ButtonProvider",
161 | "order": 1,
162 | "location": "toolbar-right"
163 | },
164 | */
165 | /*
166 | {
167 | "type": "@WebInspector.StatusBarButton.Provider",
168 | "className": "WebInspector.ScreencastApp.StatusBarButtonProvider",
169 | "order": 2,
170 | "location": "toolbar-right"
171 | },
172 | {
173 | "type": "ui-setting",
174 | "title": "Disable cache (while DevTools is open)",
175 | "settingName": "cacheDisabled",
176 | "settingType": "checkbox"
177 | },
178 | {
179 | "type": "ui-setting",
180 | "section": "Appearance",
181 | "title": "Split panels vertically when docked to right",
182 | "settingName": "splitVerticallyWhenDockedToRight",
183 | "settingType": "checkbox"
184 | },
185 | {
186 | "type": "ui-setting",
187 | "section": "Appearance",
188 | "settingType": "custom",
189 | "className": "WebInspector.Main.ShortcutPanelSwitchSettingDelegate"
190 | },
191 | {
192 | "type": "ui-setting",
193 | "section": "Appearance",
194 | "title": "Don't show emulation warnings",
195 | "settingName": "disableOverridesWarning",
196 | "settingType": "checkbox"
197 | },
198 | {
199 | "type": "ui-setting",
200 | "section": "Extensions",
201 | "settingType": "custom",
202 | "className": "WebInspector.HandlerRegistry.OpenAnchorLocationSettingDelegate"
203 | }
204 | */
205 | ]
206 | },
207 | {
208 | "name" : "console",
209 | "extensions": [
210 | {
211 | "type": "@WebInspector.Panel",
212 | "name": "console",
213 | "title": "Console",
214 | "order": 20,
215 | "className": "WebInspector.ConsolePanel"
216 | },
217 | {
218 | "type": "drawer-view",
219 | "name": "console",
220 | "title": "Console",
221 | "order": "0",
222 | "className": "WebInspector.ConsolePanel.WrapperView"
223 | },
224 | {
225 | "type": "@WebInspector.Revealer",
226 | "contextTypes": ["WebInspector.Console"],
227 | "className": "WebInspector.ConsolePanel.ConsoleRevealer"
228 | },
229 | {
230 | "type": "@WebInspector.ActionDelegate",
231 | "actionId": "console.show",
232 | "className": "WebInspector.ConsoleView.ShowConsoleActionDelegate",
233 | "bindings": [
234 | {
235 | "shortcut": "Ctrl+`"
236 | }
237 | ]
238 | },
239 | {
240 | "type": "ui-setting",
241 | "section": "Console",
242 | "title": "Log XMLHttpRequests",
243 | "settingName": "monitoringXHREnabled",
244 | "settingType": "checkbox"
245 | },
246 | {
247 | "type": "ui-setting",
248 | "section": "Console",
249 | "title": "Preserve log upon navigation",
250 | "settingName": "preserveConsoleLog",
251 | "settingType": "checkbox"
252 | },
253 | {
254 | "type": "ui-setting",
255 | "section": "Console",
256 | "title": "Show timestamps",
257 | "settingName": "consoleTimestampsEnabled",
258 | "settingType": "checkbox"
259 | }
260 | ],
261 | //"scripts": [ "ConsolePanel.js" ]
262 | }
263 |
264 | ];
265 |
--------------------------------------------------------------------------------
/public/js/sdk/ResourceUtils.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3 | * Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com).
4 | * Copyright (C) 2009 Joseph Pecoraro
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions
8 | * are met:
9 | *
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
16 | * its contributors may be used to endorse or promote products derived
17 | * from this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 | */
30 |
31 | /**
32 | * @param {string} url
33 | * @return {?WebInspector.Resource}
34 | */
35 | WebInspector.resourceForURL = function(url)
36 | {
37 | // zirak
38 | /*jshint -W027*/
39 | return null;
40 | return WebInspector.resourceTreeModel.resourceForURL(url);
41 | };
42 |
43 | /**
44 | * @param {function(!WebInspector.Resource)} callback
45 | */
46 | WebInspector.forAllResources = function(callback)
47 | {
48 | WebInspector.resourceTreeModel.forAllResources(callback);
49 | };
50 |
51 | /**
52 | * @param {string} url
53 | * @return {string}
54 | */
55 | WebInspector.displayNameForURL = function(url)
56 | {
57 | if (!url) {
58 | return "";
59 | }
60 |
61 | var resource = WebInspector.resourceForURL(url);
62 | if (resource) {
63 | return resource.displayName;
64 | }
65 |
66 | var uiSourceCode = WebInspector.workspace.uiSourceCodeForURL(url);
67 | if (uiSourceCode) {
68 | return uiSourceCode.displayName();
69 | }
70 |
71 | if (!WebInspector.resourceTreeModel.inspectedPageURL()) {
72 | return url.trimURL("");
73 | }
74 |
75 | var parsedURL = WebInspector.resourceTreeModel.inspectedPageURL().asParsedURL();
76 | var lastPathComponent = parsedURL ? parsedURL.lastPathComponent : parsedURL;
77 | var index = WebInspector.resourceTreeModel.inspectedPageURL().indexOf(lastPathComponent);
78 | if (index !== -1 && index + lastPathComponent.length === WebInspector.resourceTreeModel.inspectedPageURL().length) {
79 | var baseURL = WebInspector.resourceTreeModel.inspectedPageURL().substring(0, index);
80 | if (url.startsWith(baseURL)) {
81 | return url.substring(index);
82 | }
83 | }
84 |
85 | if (!parsedURL) {
86 | return url;
87 | }
88 |
89 | var displayName = url.trimURL(parsedURL.host);
90 | return displayName === "/" ? parsedURL.host + "/" : displayName;
91 | };
92 |
93 | /**
94 | * @param {string} string
95 | * @param {function(string,string,number=,number=):!Node} linkifier
96 | * @return {!DocumentFragment}
97 | */
98 | WebInspector.linkifyStringAsFragmentWithCustomLinkifier = function(string, linkifier)
99 | {
100 | var container = document.createDocumentFragment();
101 | var linkStringRegEx = /(?:[a-zA-Z][a-zA-Z0-9+.-]{2,}:\/\/|data:|www\.)[\w$\-_+*'=\|\/\\(){}[\]^%@~,:;.!?]{2,}[\w$\-_+*=\|\/\\({^%@~]/;
102 | var lineColumnRegEx = /:(\d+)(:(\d+))?$/;
103 |
104 | while (string) {
105 | var linkString = linkStringRegEx.exec(string);
106 | if (!linkString) {
107 | break;
108 | }
109 |
110 | linkString = linkString[0];
111 | var linkIndex = string.indexOf(linkString);
112 | var nonLink = string.substring(0, linkIndex);
113 | container.appendChild(document.createTextNode(nonLink));
114 |
115 | var title = linkString;
116 | var realURL = (linkString.startsWith("www.") ? "http://" + linkString : linkString);
117 | var lineColumnMatch = lineColumnRegEx.exec(realURL);
118 | var lineNumber;
119 | var columnNumber;
120 | if (lineColumnMatch) {
121 | realURL = realURL.substring(0, realURL.length - lineColumnMatch[0].length);
122 | lineNumber = parseInt(lineColumnMatch[1], 10);
123 | // Immediately convert line and column to 0-based numbers.
124 | lineNumber = isNaN(lineNumber) ? undefined : lineNumber - 1;
125 | if (typeof(lineColumnMatch[3]) === "string") {
126 | columnNumber = parseInt(lineColumnMatch[3], 10);
127 | columnNumber = isNaN(columnNumber) ? undefined : columnNumber - 1;
128 | }
129 | }
130 |
131 | var linkNode = linkifier(title, realURL, lineNumber, columnNumber);
132 | container.appendChild(linkNode);
133 | string = string.substring(linkIndex + linkString.length, string.length);
134 | }
135 |
136 | if (string) {
137 | container.appendChild(document.createTextNode(string));
138 | }
139 |
140 | return container;
141 | };
142 |
143 | /**
144 | * @param {string} string
145 | * @return {!DocumentFragment}
146 | */
147 | WebInspector.linkifyStringAsFragment = function(string)
148 | {
149 | /**
150 | * @param {string} title
151 | * @param {string} url
152 | * @param {number=} lineNumber
153 | * @param {number=} columnNumber
154 | * @return {!Node}
155 | */
156 | function linkifier(title, url, lineNumber, columnNumber)
157 | {
158 | //var isExternal = !WebInspector.resourceForURL(url) && !WebInspector.workspace.uiSourceCodeForURL(url);
159 | var isExternal = false;
160 | var urlNode = WebInspector.linkifyURLAsNode(url, title, undefined, isExternal);
161 | if (typeof lineNumber !== "undefined") {
162 | urlNode.lineNumber = lineNumber;
163 | if (typeof columnNumber !== "undefined") {
164 | urlNode.columnNumber = columnNumber;
165 | }
166 | }
167 |
168 | return urlNode;
169 | }
170 |
171 | return WebInspector.linkifyStringAsFragmentWithCustomLinkifier(string, linkifier);
172 | };
173 |
174 | /**
175 | * @param {string} url
176 | * @param {string=} linkText
177 | * @param {string=} classes
178 | * @param {boolean=} isExternal
179 | * @param {string=} tooltipText
180 | * @return {!Element}
181 | */
182 | WebInspector.linkifyURLAsNode = function(url, linkText, classes, isExternal, tooltipText)
183 | {
184 | if (!linkText) {
185 | linkText = url;
186 | }
187 | classes = (classes ? classes + " " : "");
188 | classes += isExternal ? "webkit-html-external-link" : "webkit-html-resource-link";
189 |
190 | var a = document.createElement("a");
191 | var href = sanitizeHref(url);
192 | if (href !== null) {
193 | a.href = href;
194 | }
195 | a.className = classes;
196 | if (typeof tooltipText === "undefined") {
197 | a.title = url;
198 | }
199 | else if (typeof tooltipText !== "string" || tooltipText.length) {
200 | a.title = tooltipText;
201 | }
202 | a.textContent = linkText.trimMiddle(WebInspector.Linkifier.MaxLengthForDisplayedURLs);
203 | if (isExternal) {
204 | a.setAttribute("target", "_blank");
205 | }
206 |
207 | return a;
208 | };
209 |
210 | /**
211 | * @param {string} url
212 | * @param {number=} lineNumber
213 | * @return {string}
214 | */
215 | WebInspector.formatLinkText = function(url, lineNumber)
216 | {
217 | var text = url ? WebInspector.displayNameForURL(url) : WebInspector.UIString("(program)");
218 | if (typeof lineNumber === "number") {
219 | text += ":" + (lineNumber + 1);
220 | }
221 | return text;
222 | };
223 |
224 | /**
225 | * @param {string} url
226 | * @param {number=} lineNumber
227 | * @param {string=} classes
228 | * @param {string=} tooltipText
229 | * @return {!Element}
230 | */
231 | WebInspector.linkifyResourceAsNode = function(url, lineNumber, classes, tooltipText)
232 | {
233 | var linkText = WebInspector.formatLinkText(url, lineNumber);
234 | var anchor = WebInspector.linkifyURLAsNode(url, linkText, classes, false, tooltipText);
235 | anchor.lineNumber = lineNumber;
236 | return anchor;
237 | };
238 |
239 | /**
240 | * @param {!WebInspector.NetworkRequest} request
241 | * @return {!Element}
242 | */
243 | WebInspector.linkifyRequestAsNode = function(request)
244 | {
245 | var anchor = WebInspector.linkifyURLAsNode(request.url);
246 | anchor.requestId = request.requestId;
247 | return anchor;
248 | };
249 |
250 | /**
251 | * @param {?string} content
252 | * @param {string} mimeType
253 | * @param {boolean} contentEncoded
254 | * @return {?string}
255 | */
256 | WebInspector.contentAsDataURL = function(content, mimeType, contentEncoded)
257 | {
258 | var maxDataUrlSize = 1024 * 1024;
259 | if (content === null || content.length > maxDataUrlSize) {
260 | return null;
261 | }
262 |
263 | return "data:" + mimeType + (contentEncoded ? ";base64," : ",") + content;
264 | };
265 |
--------------------------------------------------------------------------------
/public/js/common/ParsedURL.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 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 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | *
11 | * 2. Redistributions in binary form must reproduce the above
12 | * copyright notice, this list of conditions and the following disclaimer
13 | * in the documentation and/or other materials provided with the
14 | * distribution.
15 | *
16 | * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
20 | * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | /**
30 | * @constructor
31 | * @param {string} url
32 | */
33 | WebInspector.ParsedURL = function(url)
34 | {
35 | this.isValid = false;
36 | this.url = url;
37 | this.scheme = "";
38 | this.host = "";
39 | this.port = "";
40 | this.path = "";
41 | this.queryParams = "";
42 | this.fragment = "";
43 | this.folderPathComponents = "";
44 | this.lastPathComponent = "";
45 |
46 | // RegExp groups:
47 | // 1 - scheme (using the RFC3986 grammar)
48 | // 2 - hostname
49 | // 3 - ?port
50 | // 4 - ?path
51 | // 5 - ?fragment
52 | var match = url.match(/^([A-Za-z][A-Za-z0-9+.-]*):\/\/([^\/:]*)(?::([\d]+))?(?:(\/[^#]*)(?:#(.*))?)?$/i);
53 | if (match) {
54 | this.isValid = true;
55 | this.scheme = match[1].toLowerCase();
56 | this.host = match[2];
57 | this.port = match[3];
58 | this.path = match[4] || "/";
59 | this.fragment = match[5];
60 | } else {
61 | if (this.url.startsWith("data:")) {
62 | this.scheme = "data";
63 | return;
64 | }
65 | if (this.url === "about:blank") {
66 | this.scheme = "about";
67 | return;
68 | }
69 | this.path = this.url;
70 | }
71 |
72 | // First cut the query params.
73 | var path = this.path;
74 | var indexOfQuery = path.indexOf("?");
75 | if (indexOfQuery !== -1) {
76 | this.queryParams = path.substring(indexOfQuery + 1);
77 | path = path.substring(0, indexOfQuery);
78 | }
79 |
80 | // Then take last path component.
81 | var lastSlashIndex = path.lastIndexOf("/");
82 | if (lastSlashIndex !== -1) {
83 | this.folderPathComponents = path.substring(0, lastSlashIndex);
84 | this.lastPathComponent = path.substring(lastSlashIndex + 1);
85 | } else {
86 | this.lastPathComponent = path;
87 | }
88 | };
89 |
90 | /**
91 | * @param {string} url
92 | * @return {!Array.}
93 | */
94 | WebInspector.ParsedURL.splitURL = function(url)
95 | {
96 | var parsedURL = new WebInspector.ParsedURL(url);
97 | var origin;
98 | var folderPath;
99 | var name;
100 | if (parsedURL.isValid) {
101 | origin = parsedURL.scheme + "://" + parsedURL.host;
102 | if (parsedURL.port) {
103 | origin += ":" + parsedURL.port;
104 | }
105 | folderPath = parsedURL.folderPathComponents;
106 | name = parsedURL.lastPathComponent;
107 | if (parsedURL.queryParams) {
108 | name += "?" + parsedURL.queryParams;
109 | }
110 | } else {
111 | origin = "";
112 | folderPath = "";
113 | name = url;
114 | }
115 | var result = [origin];
116 | var splittedPath = folderPath.split("/");
117 | for (var i = 1; i < splittedPath.length; ++i) {
118 | if (!splittedPath[i]) {
119 | continue;
120 | }
121 | result.push(splittedPath[i]);
122 | }
123 | result.push(name);
124 | return result;
125 | };
126 |
127 |
128 | /**
129 | * http://tools.ietf.org/html/rfc3986#section-5.2.4
130 | * @param {string} path
131 | * @return {string}
132 | */
133 |
134 | WebInspector.ParsedURL.normalizePath = function(path)
135 | {
136 | if (path.indexOf("..") === -1 && path.indexOf('.') === -1) {
137 | return path;
138 | }
139 |
140 | var normalizedSegments = [];
141 | var segments = path.split("/");
142 | for (var i = 0; i < segments.length; i++) {
143 | var segment = segments[i];
144 | if (segment === ".") {
145 | continue;
146 | }
147 | else if (segment === "..") {
148 | normalizedSegments.pop();
149 | }
150 | else if (segment) {
151 | normalizedSegments.push(segment);
152 | }
153 | }
154 | var normalizedPath = normalizedSegments.join("/");
155 | if (normalizedPath[normalizedPath.length - 1] === "/") {
156 | return normalizedPath;
157 | }
158 | if (path[0] === "/" && normalizedPath) {
159 | normalizedPath = "/" + normalizedPath;
160 | }
161 | if ((path[path.length - 1] === "/") || (segments[segments.length - 1] === ".") || (segments[segments.length - 1] === "..")) {
162 | normalizedPath = normalizedPath + "/";
163 | }
164 |
165 | return normalizedPath;
166 | };
167 |
168 | /**
169 | * @param {string} baseURL
170 | * @param {string} href
171 | * @return {?string}
172 | */
173 | WebInspector.ParsedURL.completeURL = function(baseURL, href)
174 | {
175 | /*jshint -W107*/
176 | // above ignores script urls (javascript:)
177 | if (href) {
178 | // Return special URLs as-is.
179 | var trimmedHref = href.trim();
180 | if (trimmedHref.startsWith("data:") || trimmedHref.startsWith("blob:") || trimmedHref.startsWith("javascript:")) {
181 | return href;
182 | }
183 |
184 | // Return absolute URLs as-is.
185 | var parsedHref = trimmedHref.asParsedURL();
186 | if (parsedHref && parsedHref.scheme) {
187 | return trimmedHref;
188 | }
189 | } else {
190 | return baseURL;
191 | }
192 |
193 | var parsedURL = baseURL.asParsedURL();
194 | if (parsedURL) {
195 | if (parsedURL.isDataURL()) {
196 | return href;
197 | }
198 | var path = href;
199 |
200 | var query = path.indexOf("?");
201 | var postfix = "";
202 | if (query !== -1) {
203 | postfix = path.substring(query);
204 | path = path.substring(0, query);
205 | } else {
206 | var fragment = path.indexOf("#");
207 | if (fragment !== -1) {
208 | postfix = path.substring(fragment);
209 | path = path.substring(0, fragment);
210 | }
211 | }
212 |
213 | if (!path) { // empty path, must be postfix
214 | var basePath = parsedURL.path;
215 | if (postfix.charAt(0) === "?") {
216 | // A href of "?foo=bar" implies "basePath?foo=bar".
217 | // With "basePath?a=b" and "?foo=bar" we should get "basePath?foo=bar".
218 | var baseQuery = parsedURL.path.indexOf("?");
219 | if (baseQuery !== -1) {
220 | basePath = basePath.substring(0, baseQuery);
221 | }
222 | } // else it must be a fragment
223 | return parsedURL.scheme + "://" + parsedURL.host + (parsedURL.port ? (":" + parsedURL.port) : "") + basePath + postfix;
224 | } else if (path.charAt(0) !== "/") { // relative path
225 | var prefix = parsedURL.path;
226 | var prefixQuery = prefix.indexOf("?");
227 | if (prefixQuery !== -1) {
228 | prefix = prefix.substring(0, prefixQuery);
229 | }
230 | prefix = prefix.substring(0, prefix.lastIndexOf("/")) + "/";
231 | path = prefix + path;
232 | } else if (path.length > 1 && path.charAt(1) === "/") {
233 | // href starts with "//" which is a full URL with the protocol dropped (use the baseURL protocol).
234 | return parsedURL.scheme + ":" + path + postfix;
235 | } // else absolute path
236 | return parsedURL.scheme + "://" + parsedURL.host + (parsedURL.port ? (":" + parsedURL.port) : "") + WebInspector.ParsedURL.normalizePath(path) + postfix;
237 | }
238 | return null;
239 | };
240 |
241 | WebInspector.ParsedURL.prototype = {
242 | get displayName()
243 | {
244 | if (this._displayName) {
245 | return this._displayName;
246 | }
247 |
248 | if (this.isDataURL()) {
249 | return this.dataURLDisplayName();
250 | }
251 | if (this.isAboutBlank()) {
252 | return this.url;
253 | }
254 |
255 | this._displayName = this.lastPathComponent;
256 | if (!this._displayName) {
257 | this._displayName = (this.host || "") + "/";
258 | }
259 | if (this._displayName === "/") {
260 | this._displayName = this.url;
261 | }
262 | return this._displayName;
263 | },
264 |
265 | /**
266 | * @return {string}
267 | */
268 | dataURLDisplayName: function()
269 | {
270 | if (this._dataURLDisplayName) {
271 | return this._dataURLDisplayName;
272 | }
273 | if (!this.isDataURL()) {
274 | return "";
275 | }
276 | this._dataURLDisplayName = this.url.trimEnd(20);
277 | return this._dataURLDisplayName;
278 | },
279 |
280 | /**
281 | * @return {boolean}
282 | */
283 | isAboutBlank: function()
284 | {
285 | return this.url === "about:blank";
286 | },
287 |
288 | /**
289 | * @return {boolean}
290 | */
291 | isDataURL: function()
292 | {
293 | return this.scheme === "data";
294 | }
295 | };
296 |
297 | /**
298 | * @return {?WebInspector.ParsedURL}
299 | */
300 | String.prototype.asParsedURL = function()
301 | {
302 | var parsedURL = new WebInspector.ParsedURL(this.toString());
303 | if (parsedURL.isValid) {
304 | return parsedURL;
305 | }
306 | return null;
307 | };
308 |
--------------------------------------------------------------------------------
/public/js/components/Drawer.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3 | * Copyright (C) 2009 Joseph Pecoraro
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 BY APPLE AND ITS CONTRIBUTORS "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 | * @extends {WebInspector.VBox}
33 | * @param {!WebInspector.SplitView} splitView
34 | */
35 | WebInspector.Drawer = function(splitView)
36 | {
37 | WebInspector.VBox.call(this);
38 | this.element.id = "drawer-contents";
39 |
40 | this._splitView = splitView;
41 | splitView.hideDefaultResizer();
42 | // this.show(splitView.sidebarElement());
43 |
44 | this._drawerEditorSplitView = new WebInspector.SplitView(true, true, "editorInDrawerSplitViewState", 0.5, 0.5);
45 | this._drawerEditorSplitView.hideSidebar();
46 | this._drawerEditorSplitView.addEventListener(WebInspector.SplitView.Events.ShowModeChanged, this._drawerEditorSplitViewShowModeChanged, this);
47 | this._drawerEditorShownSetting = WebInspector.settings.createSetting("drawerEditorShown", true);
48 | this._drawerEditorSplitView.show(this.element);
49 |
50 | this._toggleDrawerButton = new WebInspector.StatusBarButton(WebInspector.UIString("Show drawer."), "console-status-bar-item");
51 | this._toggleDrawerButton.addEventListener("click", this.toggle, this);
52 |
53 | this._tabbedPane = new WebInspector.TabbedPane();
54 | this._tabbedPane.element.id = "drawer-tabbed-pane";
55 | this._tabbedPane.closeableTabs = false;
56 | this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this);
57 | new WebInspector.ExtensibleTabbedPaneController(this._tabbedPane, "drawer-view");
58 |
59 | this._toggleDrawerEditorButton = this._drawerEditorSplitView.createShowHideSidebarButton("editor in drawer", "drawer-editor-show-hide-button");
60 | this._tabbedPane.element.appendChild(this._toggleDrawerEditorButton.element);
61 | if (!WebInspector.experimentsSettings.editorInDrawer.isEnabled()) {
62 | // this.setDrawerEditorAvailable(false);
63 | }
64 |
65 | // splitView.installResizer(this._tabbedPane.headerElement());
66 | this._lastSelectedViewSetting = WebInspector.settings.createSetting("WebInspector.Drawer.lastSelectedView", "console");
67 | this._tabbedPane.show(this._drawerEditorSplitView.mainElement());
68 |
69 | this.closeDrawer();
70 | };
71 |
72 | WebInspector.Drawer.prototype = {
73 | /**
74 | * @return {!WebInspector.StatusBarButton}
75 | */
76 | toggleButton: function()
77 | {
78 | return this._toggleDrawerButton;
79 | },
80 |
81 | /**
82 | * @param {string} id
83 | */
84 | closeView: function(id)
85 | {
86 | this._tabbedPane.closeTab(id);
87 | },
88 |
89 | /**
90 | * @param {string} id
91 | * @param {boolean=} immediate
92 | */
93 | showView: function(id, immediate)
94 | {
95 | if (!this._tabbedPane.hasTab(id)) {
96 | // Hidden tab.
97 | this._innerShow(immediate);
98 | return;
99 | }
100 | this._innerShow(immediate);
101 | this._tabbedPane.selectTab(id, true);
102 | // In case this id is already selected, anyways persist it as the last saved value.
103 | this._lastSelectedViewSetting.set(id);
104 | },
105 |
106 | /**
107 | * @param {string} id
108 | * @param {string} title
109 | * @param {!WebInspector.View} view
110 | */
111 | showCloseableView: function(id, title, view)
112 | {
113 | if (!this._tabbedPane.hasTab(id)) {
114 | this._tabbedPane.appendTab(id, title, view, undefined, false, true);
115 | } else {
116 | this._tabbedPane.changeTabView(id, view);
117 | this._tabbedPane.changeTabTitle(id, title);
118 | }
119 | this._innerShow();
120 | this._tabbedPane.selectTab(id, true);
121 | },
122 |
123 | showDrawer: function()
124 | {
125 | this.showView(this._lastSelectedViewSetting.get());
126 | },
127 |
128 | wasShown: function()
129 | {
130 | this.showView(this._lastSelectedViewSetting.get());
131 | this._toggleDrawerButton.toggled = true;
132 | this._toggleDrawerButton.title = WebInspector.UIString("Hide drawer.");
133 | this._ensureDrawerEditorExistsIfNeeded();
134 | },
135 |
136 | willHide: function()
137 | {
138 | this._toggleDrawerButton.toggled = false;
139 | this._toggleDrawerButton.title = WebInspector.UIString("Show drawer.");
140 | },
141 |
142 | /**
143 | * @param {boolean=} immediate
144 | */
145 | _innerShow: function(immediate)
146 | {
147 | if (this.isShowing()) {
148 | return;
149 | }
150 |
151 | this._splitView.showBoth(!immediate);
152 |
153 | if (this._visibleView()) {
154 | this._visibleView().focus();
155 | }
156 | },
157 |
158 | closeDrawer: function()
159 | {
160 | if (!this.isShowing()) {
161 | return;
162 | }
163 |
164 | WebInspector.restoreFocusFromElement(this.element);
165 | this._splitView.hideSidebar(true);
166 | },
167 |
168 | /**
169 | * @return {?WebInspector.View} view
170 | */
171 | _visibleView: function()
172 | {
173 | return this._tabbedPane.visibleView;
174 | },
175 |
176 | /**
177 | * @param {!WebInspector.Event} event
178 | */
179 | _tabSelected: function(event)
180 | {
181 | var tabId = this._tabbedPane.selectedTabId;
182 | if (tabId && event.data.isUserGesture && !this._tabbedPane.isTabCloseable(tabId)) {
183 | this._lastSelectedViewSetting.set(tabId);
184 | }
185 | },
186 |
187 | toggle: function()
188 | {
189 | if (this._toggleDrawerButton.toggled) {
190 | this.closeDrawer();
191 | }
192 | else {
193 | this.showDrawer();
194 | }
195 | },
196 |
197 | /**
198 | * @return {boolean}
199 | */
200 | visible: function()
201 | {
202 | return this._toggleDrawerButton.toggled;
203 | },
204 |
205 | /**
206 | * @return {?string}
207 | */
208 | selectedViewId: function()
209 | {
210 | return this._tabbedPane.selectedTabId;
211 | },
212 |
213 | /**
214 | * @param {!WebInspector.Event} event
215 | */
216 | _drawerEditorSplitViewShowModeChanged: function(event)
217 | {
218 | var mode = /** @type {string} */ (event.data);
219 | var shown = mode === WebInspector.SplitView.ShowMode.Both;
220 |
221 | if (this._isHidingDrawerEditor) {
222 | return;
223 | }
224 |
225 | this._drawerEditorShownSetting.set(shown);
226 |
227 | if (!shown) {
228 | return;
229 | }
230 |
231 | this._ensureDrawerEditor();
232 | this._drawerEditor.view().show(this._drawerEditorSplitView.sidebarElement());
233 | },
234 |
235 | initialPanelShown: function()
236 | {
237 | this._initialPanelWasShown = true;
238 | this._ensureDrawerEditorExistsIfNeeded();
239 | },
240 |
241 | _ensureDrawerEditorExistsIfNeeded: function()
242 | {
243 | if (!this._initialPanelWasShown || !this.isShowing() || !this._drawerEditorShownSetting.get() || !WebInspector.experimentsSettings.editorInDrawer.isEnabled()) {
244 | return;
245 | }
246 | this._ensureDrawerEditor();
247 | },
248 |
249 | _ensureDrawerEditor: function()
250 | {
251 | if (this._drawerEditor) {
252 | return;
253 | }
254 | this._drawerEditor = WebInspector.moduleManager.instance(WebInspector.DrawerEditor);
255 | this._drawerEditor.installedIntoDrawer();
256 | },
257 |
258 | /**
259 | * @param {boolean} available
260 | */
261 | setDrawerEditorAvailable: function(available)
262 | {
263 | if (!WebInspector.experimentsSettings.editorInDrawer.isEnabled()) {
264 | available = false;
265 | }
266 | this._toggleDrawerEditorButton.element.classList.toggle("hidden", !available);
267 | },
268 |
269 | showDrawerEditor: function()
270 | {
271 | if (!WebInspector.experimentsSettings.editorInDrawer.isEnabled()) {
272 | return;
273 | }
274 |
275 | this._splitView.showBoth();
276 | this._drawerEditorSplitView.showBoth();
277 | },
278 |
279 | hideDrawerEditor: function()
280 | {
281 | this._isHidingDrawerEditor = true;
282 | this._drawerEditorSplitView.hideSidebar();
283 | this._isHidingDrawerEditor = false;
284 | },
285 |
286 | /**
287 | * @return {boolean}
288 | */
289 | isDrawerEditorShown: function()
290 | {
291 | return this._drawerEditorShownSetting.get();
292 | },
293 |
294 | __proto__: WebInspector.VBox.prototype
295 | };
296 |
297 | /**
298 | * @interface
299 | */
300 | WebInspector.Drawer.ViewFactory = function()
301 | {
302 | };
303 |
304 | WebInspector.Drawer.ViewFactory.prototype = {
305 | /**
306 | * @return {!WebInspector.View}
307 | */
308 | createView: function() {}
309 | };
310 |
311 | /**
312 | * @constructor
313 | * @implements {WebInspector.Drawer.ViewFactory}
314 | * @param {function(new:T)} constructor
315 | * @template T
316 | */
317 | WebInspector.Drawer.SingletonViewFactory = function(constructor)
318 | {
319 | this._constructor = constructor;
320 | };
321 |
322 | WebInspector.Drawer.SingletonViewFactory.prototype = {
323 | /**
324 | * @return {!WebInspector.View}
325 | */
326 | createView: function()
327 | {
328 | if (!this._instance) {
329 | this._instance = /** @type {!WebInspector.View} */(new this._constructor());
330 | }
331 | return this._instance;
332 | }
333 | };
334 |
335 | /**
336 | * @interface
337 | */
338 | WebInspector.DrawerEditor = function()
339 | {
340 | };
341 |
342 | WebInspector.DrawerEditor.prototype = {
343 | /**
344 | * @return {!WebInspector.View}
345 | */
346 | view: function() { },
347 |
348 | installedIntoDrawer: function() { },
349 | };
350 |
--------------------------------------------------------------------------------