Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Issue 5931: Integrate SelectBug extension into Firebug

  • Loading branch information...
commit 34c8d8a18050537cbc1b322e267d868621fb695a 1 parent 068aef5
@janodvarko janodvarko authored
View
59 extension/content/firebug/css/selectorEditor.js
@@ -0,0 +1,59 @@
+/* See license.txt for terms of usage */
+
+define([
+ "firebug/firebug",
+ "firebug/lib/domplate",
+ "firebug/lib/locale",
+],
+function(Firebug, Domplate, Locale) {
+with (Domplate) {
+
+// ********************************************************************************************* //
+// Constants
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+// ********************************************************************************************* //
+// CSS Selector Editor
+
+function SelectorEditor(panel)
+{
+ var doc = panel.document;
+
+ this.panel = panel;
+ this.box = this.tag.replace({}, doc, this);
+ this.input = this.box;
+
+ this.tabNavigation = false;
+ this.tabCompletion = true;
+ this.completeAsYouType = false;
+ this.fixedWidth = true;
+}
+
+SelectorEditor.prototype = domplate(Firebug.InlineEditor.prototype,
+{
+ tag:
+ INPUT({"class": "fixedWidthEditor a11yFocusNoTab",
+ type: "text",
+ title: Locale.$STR("Selector"),
+ oninput: "$onInput",
+ onkeypress: "$onKeyPress"}
+ ),
+
+ endEditing: function(target, value, cancel)
+ {
+ if (cancel || value == "")
+ return;
+
+ this.panel.setTrialSelector(target, value);
+ },
+});
+
+// ********************************************************************************************* //
+// Registration
+
+return SelectorEditor;
+
+// ********************************************************************************************* //
+}});
View
392 extension/content/firebug/css/selectorPanel.js
@@ -0,0 +1,392 @@
+/* See license.txt for terms of usage */
+
+define([
+ "firebug/firebug",
+ "firebug/lib/object",
+ "firebug/lib/locale",
+ "firebug/lib/events",
+ "firebug/lib/dom",
+ "firebug/lib/domplate",
+ "firebug/css/selectorEditor",
+],
+function(Firebug, Obj, Locale, Events, Dom, Domplate, SelectorEditor) {
+with (Domplate) {
+
+// ********************************************************************************************* //
+// Constants
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+const prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch2);
+
+// ********************************************************************************************* //
+// CSS Selector Panel
+
+/**
+ * @panel Selector side panel displaying HTML elements for the current selector,
+ * either from the CSS main panel or user entry
+ */
+function SelectorPanel() {}
+SelectorPanel.prototype = Obj.extend(Firebug.Panel,
+/** @lends SelectorPanel */
+{
+ name: "selector",
+ parentPanel: "stylesheet",
+ title: Locale.$STR("css.selector.Selection"),
+ editable: true,
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+ // Initialization
+
+ initialize: function(context, doc)
+ {
+ Firebug.Panel.initialize.apply(this, arguments);
+ },
+
+ initializeNode: function(oldPanelNode)
+ {
+ Firebug.Panel.initializeNode.apply(this, arguments);
+
+ this.setSelection = Obj.bind(this.setSelection, this);
+ this.clearSelection = Obj.bind(this.clearSelection, this);
+ this.lockSelection = Obj.bind(this.lockSelection, this);
+
+ var panelNode = this.mainPanel.panelNode;
+ Events.addEventListener(panelNode, "mouseover", this.setSelection, false);
+ Events.addEventListener(panelNode, "mouseout", this.clearSelection, false);
+ Events.addEventListener(panelNode, "mousedown", this.lockSelection, false);
+ },
+
+ destroyNode: function()
+ {
+ var panelNode = this.mainPanel.panelNode;
+ Events.removeEventListener(panelNode, "mouseover", this.setSelection, false);
+ Events.removeEventListener(panelNode, "mouseout", this.clearSelection, false);
+ Events.removeEventListener(panelNode, "mousedown", this.lockSelection, false);
+
+ Firebug.Panel.destroyNode.apply(this, arguments);
+ },
+
+ show: function(state)
+ {
+ Firebug.Panel.show.apply(this, arguments);
+
+ this.refresh();
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+ getCSSStyleRule: function(event)
+ {
+ var object = Firebug.getRepObject(event.target);
+
+ if (object && (object instanceof window.CSSStyleRule))
+ return object;
+ },
+
+ getCSSRuleElement: function(element)
+ {
+ while (element && !element.classList.contains("cssRule"))
+ element = element.parentNode;
+
+ return element;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+ // Selection
+
+ setSelection: function(event)
+ {
+ var rule = this.getCSSStyleRule(event);
+
+ if (rule)
+ {
+ // then we have entered a rule element
+ var ruleElement = this.getCSSRuleElement(event.target);
+ if (ruleElement && ruleElement !== this.lockedElement)
+ ruleElement.classList.add("selectedSelectorRule");
+
+ this.selection = rule;
+ this.rebuild();
+ }
+ },
+
+ clearSelection: function(event)
+ {
+ if (this.selection !== this.lockedSelection)
+ {
+ this.selection = this.lockedSelection;
+ this.rebuild();
+ }
+
+ var rule = this.getCSSStyleRule(event);
+ if (rule)
+ {
+ // then we are leaving a rule element that we may have highlighted.
+ var ruleElement = this.getCSSRuleElement(event.target);
+ if (ruleElement)
+ ruleElement.classList.remove("selectedSelectorRule");
+ }
+ },
+
+ lockSelection: function(event)
+ {
+ var rule = this.getCSSStyleRule(event);
+ if (rule)
+ {
+ if (this.lockedElement)
+ this.lockedElement.classList.remove("lockedSelectorRule");
+
+ this.lockedElement = this.getCSSRuleElement(event.target);
+
+ if (this.lockedElement)
+ {
+ this.lockedElement.classList.add("lockedSelectorRule");
+ this.lockedElement.classList.remove("selectedSelectorRule");
+ }
+
+ this.lockedSelection = rule;
+ }
+ },
+
+ hide: function()
+ {
+ Firebug.Panel.hide.apply(this, arguments);
+ },
+
+ refresh: function()
+ {
+ var root = this.context.window.document.documentElement;
+ this.selection = this.mainPanel.selection;
+ this.rebuild(true);
+ },
+
+ /**
+ * returns an array of Elements matched from selector
+ */
+ getSelectedElements: function(selectorText)
+ {
+ var selections = Firebug.currentContext.window.document.querySelectorAll(selectorText);
+
+ // For some reason the return value of querySelectorAll()
+ // is not recognized as a NodeList anymore since Firefox 10.0.
+ // See issue 5442.
+ if (selections)
+ {
+ var elements = [];
+ for (var i=0; i<selections.length; i++)
+ elements.push(selections[i]);
+
+ return elements;
+ }
+ else
+ {
+ throw new Error("Selection Failed: " + selections);
+ }
+ },
+
+ /**
+ * Build content of the panel. The basic layout of the panel is generated by
+ * {@link SelectorTemplate} template.
+ */
+ rebuild: function()
+ {
+ if (this.selection)
+ {
+ try
+ {
+ var selectorText;
+
+ if (this.selection instanceof window.CSSStyleRule)
+ selectorText = this.selection.selectorText;
+ else
+ selectorText = this.selection;
+
+ var elements = this.getSelectedElements(selectorText);
+ if (elements && elements.length != 0)
+ {
+ SelectorTemplate.tag.replace({object: elements}, this.panelNode);
+ this.showTrialSelector(this.trialSelector);
+ return;
+ }
+ }
+ catch (e)
+ {
+ var table = SelectorTemplate.tag.replace({object: []}, this.panelNode);
+ var tbody = table.lastChild;
+
+ WarningTemplate.selectErrorTag.insertRows({object: e}, tbody.lastChild);
+ WarningTemplate.selectErrorTextTag.insertRows({object: e}, tbody.lastChild);
+
+ this.showTrialSelector(this.trialSelector);
+ return;
+ }
+ }
+
+ var table = SelectorTemplate.tag.replace({object: []}, this.panelNode);
+ var tbody = table.lastChild;
+
+ if (this.trialSelector)
+ {
+ WarningTemplate.noSelectionResultsTag.insertRows(
+ {object: this.selection}, tbody.lastChild)
+ }
+ else
+ {
+ WarningTemplate.noSelectionTag.insertRows(
+ {object: this.selection}, tbody.lastChild);
+ }
+
+ this.showTrialSelector(this.trialSelector);
+ },
+
+ getObjectPath: function(object)
+ {
+ if (FBTrace.DBG_SELECTOR)
+ FBTrace.sysout("css.selector.getObjectPath NOOP", object);
+ },
+
+ supportsObject: function(object)
+ {
+ return 0;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+ tryASelector:function(element)
+ {
+ if (!this.trialSelector)
+ this.trialSelector = this.selection ? this.selection.selectorText : "";
+
+ this.editProperty(element, this.trialSelector);
+ },
+
+ editProperty: function(row, editValue)
+ {
+ Firebug.Editor.startEditing(row, editValue);
+ },
+
+ getEditor: function(target, value)
+ {
+ if (!this.editor)
+ this.editor = new SelectorEditor(this);
+
+ return this.editor;
+ },
+
+ setTrialSelector: function(target, value)
+ {
+ if (this.lockedElement)
+ this.lockedElement.classList.remove("lockedSelectorRule");
+
+ this.trialSelector = value;
+ this.selection = this.trialSelector;
+ this.lockedElement = target;
+ this.lockedSelection = this.selection;
+ this.rebuild();
+ },
+
+ showTrialSelector: function(trialSelector)
+ {
+ var show = trialSelector ? true : false;
+ Dom.collapse(this.document.getElementById("trialHint"), show);
+
+ var trialSelectorDiv = this.document.getElementById("trialSelector");
+ trialSelectorDiv.textContent = trialSelector;
+ Dom.collapse(trialSelectorDiv, !show);
+ },
+});
+
+// ********************************************************************************************* //
+
+var BaseRep = domplate(Firebug.Rep,
+{
+ // xxxHonza: shouldn't this be in Firebug.Rep?
+ getNaturalTag: function(value)
+ {
+ var rep = Firebug.getRep(value);
+ var tag = rep.shortTag ? rep.shortTag : rep.tag;
+ return tag;
+ }
+});
+
+// ********************************************************************************************* //
+
+var TrialRow =
+ TR({"class": "watchNewRow", level: 0, onclick: "$onClickEditor"},
+ TD({"class": "watchEditCell", colspan: 3},
+ DIV({"class": "watchEditBox a11yFocusNoTab", "id": "trialHint",
+ role: "button", "tabindex" : "0",
+ "aria-label": Locale.$STR("a11y.labels.press enter to add new selector")},
+ Locale.$STR("css.selector.TryASelector")
+ ),
+ DIV({"class": "trialSelector", "id": "trialSelector"}, "")
+ )
+ );
+
+// ********************************************************************************************* //
+
+/**
+ * @domplate: Template for basic layout of the {@link SelectorPanel} panel.
+ */
+var SelectorTemplate = domplate(BaseRep,
+{
+ // object will be array of elements CSSStyleRule
+ tag:
+ TABLE({"class": "cssSelectionTable", cellpadding: 0, cellspacing: 0},
+ TBODY({"class": "cssSelectionTBody"},
+ TrialRow,
+ FOR("element", "$object",
+ TR({"class": "selectionElementRow", _repObject: "$element"},
+ TD({"class": "selectionElement"},
+ TAG( "$element|getNaturalTag", {object: "$element"})
+ )
+ )
+ )
+ )
+ ),
+
+ onClickEditor: function(event)
+ {
+ var tr = event.currentTarget;
+ var panel = Firebug.getElementPanel(tr);
+ panel.tryASelector(tr);
+ },
+});
+
+// ********************************************************************************************* //
+
+var WarningTemplate = domplate(Firebug.Rep,
+{
+ noSelectionTag:
+ TR({"class": "selectbugWarning "},
+ TD({"class": "selectionElement"}, Locale.$STR("css.selector.noSelection"))
+ ),
+
+ noSelectionResultsTag:
+ TR({"class": "selectbugWarning "},
+ TD({"class": "selectionElement"}, Locale.$STR("css.selector.noSelectionResults"))
+ ),
+
+ selectErrorTag:
+ TR({"class": "selectbugWarning"},
+ TD({"class": "selectionElement"}, Locale.$STR("css.selector.selectorError"))
+ ),
+
+ selectErrorTextTag:
+ TR({"class": "selectbugWarning"},
+ TD({"class": "selectionErrorText selectionElement"}, SPAN("$object"))
+ ),
+});
+
+// ********************************************************************************************* //
+// Registration
+
+Firebug.registerStylesheet("chrome://firebug/skin/selector.css");
+Firebug.registerPanel(SelectorPanel);
+
+return SelectorPanel;
+
+// ********************************************************************************************* //
+}});
View
1  extension/content/firebug/moduleConfig.js
@@ -59,6 +59,7 @@ Firebug.getModuleLoaderConfig = function(baseConfig)
"firebug/css/computedPanel",
"firebug/cookies/cookieModule",
"firebug/cookies/cookiePanel",
+ "firebug/css/selectorPanel",
];
return config;
View
1  extension/defaults/preferences/tracingConsole.js
@@ -68,3 +68,4 @@ pref("extensions.firebug.DBG_OBSERVERS", false); // track/untrack support
pref("extensions.firebug.DBG_EVENTLISTENERS", false); // track/untrack for registered event listeners, restart needed
pref("extensions.firebug.DBG_COMMANDEDITOR", false); // Multiline console based on SourceEditor (Orion)
pref("extensions.firebug.DBG_MENU", false); // Menus and context menus in Firebug
+pref("extensions.firebug.DBG_SELECTOR", false); // Selector side panel (in the CSS panel)
View
7 extension/locale/en-US/firebug.properties
@@ -1665,3 +1665,10 @@ console.cmd.help.help=Displays help for all available commands.
# if registered command doesn't have help URL associated and the user clicks on the command name.
# List of command names is displayed if you type "help" (without quotes) into the command line.
console.cmd.helpUrlNotAvailable=Help page for this command is not available.
+
+css.selector.noSelection=Mouseover CSS Rules to preview, Click to select one
+css.selector.noSelectionResults=No matching elements
+css.selector.selectorError=Selection failed:
+css.selector.Selection=Selection
+css.selector.TryASelector=Try a selector...
+
View
41 extension/skin/classic/selector.css
@@ -0,0 +1,41 @@
+/* Rules for selectbug's Selector panel elements */
+.cssSelectionTable {
+ width: 100%;
+}
+.selectionElement {
+ padding: 0 0 0 1ex;
+}
+
+.selectbugWarning {
+ font-size: 11px;
+ color: gray;
+ padding: 2px 0 0 1ex;
+}
+
+.selectionErrorText {
+ color: black;
+ padding: 1em;
+ background-color: #FFEBEB;
+}
+
+/* Rules for selectbug's effect on CSS stylesheet panel */
+.selectedSelectorRule {
+ border-color: Highlight !important;
+ background-color: #EBF5FF !important;
+ color: #000000 !important;
+ cursor: pointer;
+}
+
+.cssSelector,
+.cssPropName,
+.cssPropValue {
+ cursor: text;
+}
+
+.lockedSelectorRule {
+ background-color: Highlight;
+}
+
+.lockedSelectorRule * {
+ color: HighlightText !important;
+}
Please sign in to comment.
Something went wrong with that request. Please try again.