mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-18 13:17:29 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
510
devtools/client/inspector/shared/style-inspector-menu.js
Normal file
510
devtools/client/inspector/shared/style-inspector-menu.js
Normal file
|
|
@ -0,0 +1,510 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {PREF_ORIG_SOURCES} = require("devtools/client/styleeditor/utils");
|
||||
const Services = require("Services");
|
||||
const {Task} = require("devtools/shared/task");
|
||||
|
||||
const Menu = require("devtools/client/framework/menu");
|
||||
const MenuItem = require("devtools/client/framework/menu-item");
|
||||
|
||||
const {
|
||||
VIEW_NODE_SELECTOR_TYPE,
|
||||
VIEW_NODE_PROPERTY_TYPE,
|
||||
VIEW_NODE_VALUE_TYPE,
|
||||
VIEW_NODE_IMAGE_URL_TYPE,
|
||||
VIEW_NODE_LOCATION_TYPE,
|
||||
} = require("devtools/client/inspector/shared/node-types");
|
||||
const clipboardHelper = require("devtools/shared/platform/clipboard");
|
||||
|
||||
const STYLE_INSPECTOR_PROPERTIES = "devtools/shared/locales/styleinspector.properties";
|
||||
const {LocalizationHelper} = require("devtools/shared/l10n");
|
||||
const STYLE_INSPECTOR_L10N = new LocalizationHelper(STYLE_INSPECTOR_PROPERTIES);
|
||||
|
||||
const PREF_ENABLE_MDN_DOCS_TOOLTIP =
|
||||
"devtools.inspector.mdnDocsTooltip.enabled";
|
||||
|
||||
/**
|
||||
* Style inspector context menu
|
||||
*
|
||||
* @param {RuleView|ComputedView} view
|
||||
* RuleView or ComputedView instance controlling this menu
|
||||
* @param {Object} options
|
||||
* Option menu configuration
|
||||
*/
|
||||
function StyleInspectorMenu(view, options) {
|
||||
this.view = view;
|
||||
this.inspector = this.view.inspector;
|
||||
this.styleDocument = this.view.styleDocument;
|
||||
this.styleWindow = this.view.styleWindow;
|
||||
|
||||
this.isRuleView = options.isRuleView;
|
||||
|
||||
this._onAddNewRule = this._onAddNewRule.bind(this);
|
||||
this._onCopy = this._onCopy.bind(this);
|
||||
this._onCopyColor = this._onCopyColor.bind(this);
|
||||
this._onCopyImageDataUrl = this._onCopyImageDataUrl.bind(this);
|
||||
this._onCopyLocation = this._onCopyLocation.bind(this);
|
||||
this._onCopyPropertyDeclaration = this._onCopyPropertyDeclaration.bind(this);
|
||||
this._onCopyPropertyName = this._onCopyPropertyName.bind(this);
|
||||
this._onCopyPropertyValue = this._onCopyPropertyValue.bind(this);
|
||||
this._onCopyRule = this._onCopyRule.bind(this);
|
||||
this._onCopySelector = this._onCopySelector.bind(this);
|
||||
this._onCopyUrl = this._onCopyUrl.bind(this);
|
||||
this._onSelectAll = this._onSelectAll.bind(this);
|
||||
this._onShowMdnDocs = this._onShowMdnDocs.bind(this);
|
||||
this._onToggleOrigSources = this._onToggleOrigSources.bind(this);
|
||||
}
|
||||
|
||||
module.exports = StyleInspectorMenu;
|
||||
|
||||
StyleInspectorMenu.prototype = {
|
||||
/**
|
||||
* Display the style inspector context menu
|
||||
*/
|
||||
show: function (event) {
|
||||
try {
|
||||
this._openMenu({
|
||||
target: event.explicitOriginalTarget,
|
||||
screenX: event.screenX,
|
||||
screenY: event.screenY,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
|
||||
_openMenu: function ({ target, screenX = 0, screenY = 0 } = { }) {
|
||||
// In the sidebar we do not have this.styleDocument.popupNode
|
||||
// so we need to save the node ourselves.
|
||||
this.styleDocument.popupNode = target;
|
||||
this.styleWindow.focus();
|
||||
|
||||
let menu = new Menu();
|
||||
|
||||
let menuitemCopy = new MenuItem({
|
||||
label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copy"),
|
||||
accesskey: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copy.accessKey"),
|
||||
click: () => {
|
||||
this._onCopy();
|
||||
},
|
||||
disabled: !this._hasTextSelected(),
|
||||
});
|
||||
let menuitemCopyLocation = new MenuItem({
|
||||
label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyLocation"),
|
||||
click: () => {
|
||||
this._onCopyLocation();
|
||||
},
|
||||
visible: false,
|
||||
});
|
||||
let menuitemCopyRule = new MenuItem({
|
||||
label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyRule"),
|
||||
click: () => {
|
||||
this._onCopyRule();
|
||||
},
|
||||
visible: this.isRuleView,
|
||||
});
|
||||
let copyColorAccessKey = "styleinspector.contextmenu.copyColor.accessKey";
|
||||
let menuitemCopyColor = new MenuItem({
|
||||
label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyColor"),
|
||||
accesskey: STYLE_INSPECTOR_L10N.getStr(copyColorAccessKey),
|
||||
click: () => {
|
||||
this._onCopyColor();
|
||||
},
|
||||
visible: this._isColorPopup(),
|
||||
});
|
||||
let copyUrlAccessKey = "styleinspector.contextmenu.copyUrl.accessKey";
|
||||
let menuitemCopyUrl = new MenuItem({
|
||||
label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyUrl"),
|
||||
accesskey: STYLE_INSPECTOR_L10N.getStr(copyUrlAccessKey),
|
||||
click: () => {
|
||||
this._onCopyUrl();
|
||||
},
|
||||
visible: this._isImageUrl(),
|
||||
});
|
||||
let copyImageAccessKey = "styleinspector.contextmenu.copyImageDataUrl.accessKey";
|
||||
let menuitemCopyImageDataUrl = new MenuItem({
|
||||
label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyImageDataUrl"),
|
||||
accesskey: STYLE_INSPECTOR_L10N.getStr(copyImageAccessKey),
|
||||
click: () => {
|
||||
this._onCopyImageDataUrl();
|
||||
},
|
||||
visible: this._isImageUrl(),
|
||||
});
|
||||
let copyPropDeclarationLabel = "styleinspector.contextmenu.copyPropertyDeclaration";
|
||||
let menuitemCopyPropertyDeclaration = new MenuItem({
|
||||
label: STYLE_INSPECTOR_L10N.getStr(copyPropDeclarationLabel),
|
||||
click: () => {
|
||||
this._onCopyPropertyDeclaration();
|
||||
},
|
||||
visible: false,
|
||||
});
|
||||
let menuitemCopyPropertyName = new MenuItem({
|
||||
label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyPropertyName"),
|
||||
click: () => {
|
||||
this._onCopyPropertyName();
|
||||
},
|
||||
visible: false,
|
||||
});
|
||||
let menuitemCopyPropertyValue = new MenuItem({
|
||||
label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyPropertyValue"),
|
||||
click: () => {
|
||||
this._onCopyPropertyValue();
|
||||
},
|
||||
visible: false,
|
||||
});
|
||||
let menuitemCopySelector = new MenuItem({
|
||||
label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copySelector"),
|
||||
click: () => {
|
||||
this._onCopySelector();
|
||||
},
|
||||
visible: false,
|
||||
});
|
||||
|
||||
this._clickedNodeInfo = this._getClickedNodeInfo();
|
||||
if (this.isRuleView && this._clickedNodeInfo) {
|
||||
switch (this._clickedNodeInfo.type) {
|
||||
case VIEW_NODE_PROPERTY_TYPE :
|
||||
menuitemCopyPropertyDeclaration.visible = true;
|
||||
menuitemCopyPropertyName.visible = true;
|
||||
break;
|
||||
case VIEW_NODE_VALUE_TYPE :
|
||||
menuitemCopyPropertyDeclaration.visible = true;
|
||||
menuitemCopyPropertyValue.visible = true;
|
||||
break;
|
||||
case VIEW_NODE_SELECTOR_TYPE :
|
||||
menuitemCopySelector.visible = true;
|
||||
break;
|
||||
case VIEW_NODE_LOCATION_TYPE :
|
||||
menuitemCopyLocation.visible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
menu.append(menuitemCopy);
|
||||
menu.append(menuitemCopyLocation);
|
||||
menu.append(menuitemCopyRule);
|
||||
menu.append(menuitemCopyColor);
|
||||
menu.append(menuitemCopyUrl);
|
||||
menu.append(menuitemCopyImageDataUrl);
|
||||
menu.append(menuitemCopyPropertyDeclaration);
|
||||
menu.append(menuitemCopyPropertyName);
|
||||
menu.append(menuitemCopyPropertyValue);
|
||||
menu.append(menuitemCopySelector);
|
||||
|
||||
menu.append(new MenuItem({
|
||||
type: "separator",
|
||||
}));
|
||||
|
||||
// Select All
|
||||
let selectAllAccessKey = "styleinspector.contextmenu.selectAll.accessKey";
|
||||
let menuitemSelectAll = new MenuItem({
|
||||
label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.selectAll"),
|
||||
accesskey: STYLE_INSPECTOR_L10N.getStr(selectAllAccessKey),
|
||||
click: () => {
|
||||
this._onSelectAll();
|
||||
},
|
||||
});
|
||||
menu.append(menuitemSelectAll);
|
||||
|
||||
menu.append(new MenuItem({
|
||||
type: "separator",
|
||||
}));
|
||||
|
||||
// Add new rule
|
||||
let addRuleAccessKey = "styleinspector.contextmenu.addNewRule.accessKey";
|
||||
let menuitemAddRule = new MenuItem({
|
||||
label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.addNewRule"),
|
||||
accesskey: STYLE_INSPECTOR_L10N.getStr(addRuleAccessKey),
|
||||
click: () => {
|
||||
this._onAddNewRule();
|
||||
},
|
||||
visible: this.isRuleView,
|
||||
disabled: !this.isRuleView ||
|
||||
this.inspector.selection.isAnonymousNode(),
|
||||
});
|
||||
menu.append(menuitemAddRule);
|
||||
|
||||
// Show MDN Docs
|
||||
let mdnDocsAccessKey = "styleinspector.contextmenu.showMdnDocs.accessKey";
|
||||
let menuitemShowMdnDocs = new MenuItem({
|
||||
label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.showMdnDocs"),
|
||||
accesskey: STYLE_INSPECTOR_L10N.getStr(mdnDocsAccessKey),
|
||||
click: () => {
|
||||
this._onShowMdnDocs();
|
||||
},
|
||||
visible: (Services.prefs.getBoolPref(PREF_ENABLE_MDN_DOCS_TOOLTIP) &&
|
||||
this._isPropertyName()),
|
||||
});
|
||||
menu.append(menuitemShowMdnDocs);
|
||||
|
||||
// Show Original Sources
|
||||
let sourcesAccessKey = "styleinspector.contextmenu.toggleOrigSources.accessKey";
|
||||
let menuitemSources = new MenuItem({
|
||||
label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.toggleOrigSources"),
|
||||
accesskey: STYLE_INSPECTOR_L10N.getStr(sourcesAccessKey),
|
||||
click: () => {
|
||||
this._onToggleOrigSources();
|
||||
},
|
||||
type: "checkbox",
|
||||
checked: Services.prefs.getBoolPref(PREF_ORIG_SOURCES),
|
||||
});
|
||||
menu.append(menuitemSources);
|
||||
|
||||
menu.popup(screenX, screenY, this.inspector._toolbox);
|
||||
return menu;
|
||||
},
|
||||
|
||||
_hasTextSelected: function () {
|
||||
let hasTextSelected;
|
||||
let selection = this.styleWindow.getSelection();
|
||||
|
||||
let node = this._getClickedNode();
|
||||
if (node.nodeName == "input" || node.nodeName == "textarea") {
|
||||
let { selectionStart, selectionEnd } = node;
|
||||
hasTextSelected = isFinite(selectionStart) && isFinite(selectionEnd)
|
||||
&& selectionStart !== selectionEnd;
|
||||
} else {
|
||||
hasTextSelected = selection.toString() && !selection.isCollapsed;
|
||||
}
|
||||
|
||||
return hasTextSelected;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the type of the currently clicked node
|
||||
*/
|
||||
_getClickedNodeInfo: function () {
|
||||
let node = this._getClickedNode();
|
||||
return this.view.getNodeInfo(node);
|
||||
},
|
||||
|
||||
/**
|
||||
* A helper that determines if the popup was opened with a click to a color
|
||||
* value and saves the color to this._colorToCopy.
|
||||
*
|
||||
* @return {Boolean}
|
||||
* true if click on color opened the popup, false otherwise.
|
||||
*/
|
||||
_isColorPopup: function () {
|
||||
this._colorToCopy = "";
|
||||
|
||||
let container = this._getClickedNode();
|
||||
if (!container) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let isColorNode = el => el.dataset && "color" in el.dataset;
|
||||
|
||||
while (!isColorNode(container)) {
|
||||
container = container.parentNode;
|
||||
if (!container) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
this._colorToCopy = container.dataset.color;
|
||||
return true;
|
||||
},
|
||||
|
||||
_isPropertyName: function () {
|
||||
let nodeInfo = this._getClickedNodeInfo();
|
||||
if (!nodeInfo) {
|
||||
return false;
|
||||
}
|
||||
return nodeInfo.type == VIEW_NODE_PROPERTY_TYPE;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the current node (clicked node) is an image URL
|
||||
*
|
||||
* @return {Boolean} true if the node is an image url
|
||||
*/
|
||||
_isImageUrl: function () {
|
||||
let nodeInfo = this._getClickedNodeInfo();
|
||||
if (!nodeInfo) {
|
||||
return false;
|
||||
}
|
||||
return nodeInfo.type == VIEW_NODE_IMAGE_URL_TYPE;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the DOM Node container for the current popupNode.
|
||||
* If popupNode is a textNode, return the parent node, otherwise return
|
||||
* popupNode itself.
|
||||
*
|
||||
* @return {DOMNode}
|
||||
*/
|
||||
_getClickedNode: function () {
|
||||
let container = null;
|
||||
let node = this.styleDocument.popupNode;
|
||||
|
||||
if (node) {
|
||||
let isTextNode = node.nodeType == node.TEXT_NODE;
|
||||
container = isTextNode ? node.parentElement : node;
|
||||
}
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
/**
|
||||
* Select all text.
|
||||
*/
|
||||
_onSelectAll: function () {
|
||||
let selection = this.styleWindow.getSelection();
|
||||
selection.selectAllChildren(this.view.element);
|
||||
},
|
||||
|
||||
/**
|
||||
* Copy the most recently selected color value to clipboard.
|
||||
*/
|
||||
_onCopy: function () {
|
||||
this.view.copySelection(this.styleDocument.popupNode);
|
||||
},
|
||||
|
||||
/**
|
||||
* Copy the most recently selected color value to clipboard.
|
||||
*/
|
||||
_onCopyColor: function () {
|
||||
clipboardHelper.copyString(this._colorToCopy);
|
||||
},
|
||||
|
||||
/*
|
||||
* Retrieve the url for the selected image and copy it to the clipboard
|
||||
*/
|
||||
_onCopyUrl: function () {
|
||||
if (!this._clickedNodeInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
clipboardHelper.copyString(this._clickedNodeInfo.value.url);
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve the image data for the selected image url and copy it to the
|
||||
* clipboard
|
||||
*/
|
||||
_onCopyImageDataUrl: Task.async(function* () {
|
||||
if (!this._clickedNodeInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
let message;
|
||||
try {
|
||||
let inspectorFront = this.inspector.inspector;
|
||||
let imageUrl = this._clickedNodeInfo.value.url;
|
||||
let data = yield inspectorFront.getImageDataFromURL(imageUrl);
|
||||
message = yield data.data.string();
|
||||
} catch (e) {
|
||||
message =
|
||||
STYLE_INSPECTOR_L10N.getStr("styleinspector.copyImageDataUrlError");
|
||||
}
|
||||
|
||||
clipboardHelper.copyString(message);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Show docs from MDN for a CSS property.
|
||||
*/
|
||||
_onShowMdnDocs: function () {
|
||||
let cssPropertyName = this.styleDocument.popupNode.textContent;
|
||||
let anchor = this.styleDocument.popupNode.parentNode;
|
||||
let cssDocsTooltip = this.view.tooltips.cssDocs;
|
||||
cssDocsTooltip.show(anchor, cssPropertyName);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a new rule to the current element.
|
||||
*/
|
||||
_onAddNewRule: function () {
|
||||
this.view._onAddRule();
|
||||
},
|
||||
|
||||
/**
|
||||
* Copy the rule source location of the current clicked node.
|
||||
*/
|
||||
_onCopyLocation: function () {
|
||||
if (!this._clickedNodeInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
clipboardHelper.copyString(this._clickedNodeInfo.value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Copy the rule property declaration of the current clicked node.
|
||||
*/
|
||||
_onCopyPropertyDeclaration: function () {
|
||||
if (!this._clickedNodeInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
let textProp = this._clickedNodeInfo.value.textProperty;
|
||||
clipboardHelper.copyString(textProp.stringifyProperty());
|
||||
},
|
||||
|
||||
/**
|
||||
* Copy the rule property name of the current clicked node.
|
||||
*/
|
||||
_onCopyPropertyName: function () {
|
||||
if (!this._clickedNodeInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
clipboardHelper.copyString(this._clickedNodeInfo.value.property);
|
||||
},
|
||||
|
||||
/**
|
||||
* Copy the rule property value of the current clicked node.
|
||||
*/
|
||||
_onCopyPropertyValue: function () {
|
||||
if (!this._clickedNodeInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
clipboardHelper.copyString(this._clickedNodeInfo.value.value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Copy the rule of the current clicked node.
|
||||
*/
|
||||
_onCopyRule: function () {
|
||||
let ruleEditor =
|
||||
this.styleDocument.popupNode.parentNode.offsetParent._ruleEditor;
|
||||
let rule = ruleEditor.rule;
|
||||
clipboardHelper.copyString(rule.stringifyRule());
|
||||
},
|
||||
|
||||
/**
|
||||
* Copy the rule selector of the current clicked node.
|
||||
*/
|
||||
_onCopySelector: function () {
|
||||
if (!this._clickedNodeInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
clipboardHelper.copyString(this._clickedNodeInfo.value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle the original sources pref.
|
||||
*/
|
||||
_onToggleOrigSources: function () {
|
||||
let isEnabled = Services.prefs.getBoolPref(PREF_ORIG_SOURCES);
|
||||
Services.prefs.setBoolPref(PREF_ORIG_SOURCES, !isEnabled);
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
this.popupNode = null;
|
||||
this.styleDocument.popupNode = null;
|
||||
this.view = null;
|
||||
this.inspector = null;
|
||||
this.styleDocument = null;
|
||||
this.styleWindow = null;
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue