toolkit/devtools/gcli/commands/pagemod.js

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:27545ab3255e
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 "use strict";
6
7 const { Cc, Ci, Cu } = require("chrome");
8 const gcli = require("gcli/index");
9
10 exports.items = [
11 {
12 name: "pagemod",
13 description: gcli.lookup("pagemodDesc"),
14 },
15 {
16 name: "pagemod replace",
17 description: gcli.lookup("pagemodReplaceDesc"),
18 params: [
19 {
20 name: "search",
21 type: "string",
22 description: gcli.lookup("pagemodReplaceSearchDesc"),
23 },
24 {
25 name: "replace",
26 type: "string",
27 description: gcli.lookup("pagemodReplaceReplaceDesc"),
28 },
29 {
30 name: "ignoreCase",
31 type: "boolean",
32 description: gcli.lookup("pagemodReplaceIgnoreCaseDesc"),
33 },
34 {
35 name: "selector",
36 type: "string",
37 description: gcli.lookup("pagemodReplaceSelectorDesc"),
38 defaultValue: "*:not(script):not(style):not(embed):not(object):not(frame):not(iframe):not(frameset)",
39 },
40 {
41 name: "root",
42 type: "node",
43 description: gcli.lookup("pagemodReplaceRootDesc"),
44 defaultValue: null,
45 },
46 {
47 name: "attrOnly",
48 type: "boolean",
49 description: gcli.lookup("pagemodReplaceAttrOnlyDesc"),
50 },
51 {
52 name: "contentOnly",
53 type: "boolean",
54 description: gcli.lookup("pagemodReplaceContentOnlyDesc"),
55 },
56 {
57 name: "attributes",
58 type: "string",
59 description: gcli.lookup("pagemodReplaceAttributesDesc"),
60 defaultValue: null,
61 },
62 ],
63 // Make a given string safe to use in a regular expression.
64 escapeRegex: function(aString) {
65 return aString.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
66 },
67 exec: function(args, context) {
68 let searchTextNodes = !args.attrOnly;
69 let searchAttributes = !args.contentOnly;
70 let regexOptions = args.ignoreCase ? "ig" : "g";
71 let search = new RegExp(this.escapeRegex(args.search), regexOptions);
72 let attributeRegex = null;
73 if (args.attributes) {
74 attributeRegex = new RegExp(args.attributes, regexOptions);
75 }
76
77 let root = args.root || context.environment.document;
78 let elements = root.querySelectorAll(args.selector);
79 elements = Array.prototype.slice.call(elements);
80
81 let replacedTextNodes = 0;
82 let replacedAttributes = 0;
83
84 function replaceAttribute() {
85 replacedAttributes++;
86 return args.replace;
87 }
88 function replaceTextNode() {
89 replacedTextNodes++;
90 return args.replace;
91 }
92
93 for (let i = 0; i < elements.length; i++) {
94 let element = elements[i];
95 if (searchTextNodes) {
96 for (let y = 0; y < element.childNodes.length; y++) {
97 let node = element.childNodes[y];
98 if (node.nodeType == node.TEXT_NODE) {
99 node.textContent = node.textContent.replace(search, replaceTextNode);
100 }
101 }
102 }
103
104 if (searchAttributes) {
105 if (!element.attributes) {
106 continue;
107 }
108 for (let y = 0; y < element.attributes.length; y++) {
109 let attr = element.attributes[y];
110 if (!attributeRegex || attributeRegex.test(attr.name)) {
111 attr.value = attr.value.replace(search, replaceAttribute);
112 }
113 }
114 }
115 }
116
117 return gcli.lookupFormat("pagemodReplaceResult",
118 [elements.length, replacedTextNodes,
119 replacedAttributes]);
120 }
121 },
122 {
123 name: "pagemod remove",
124 description: gcli.lookup("pagemodRemoveDesc"),
125 },
126 {
127 name: "pagemod remove element",
128 description: gcli.lookup("pagemodRemoveElementDesc"),
129 params: [
130 {
131 name: "search",
132 type: "string",
133 description: gcli.lookup("pagemodRemoveElementSearchDesc"),
134 },
135 {
136 name: "root",
137 type: "node",
138 description: gcli.lookup("pagemodRemoveElementRootDesc"),
139 defaultValue: null,
140 },
141 {
142 name: "stripOnly",
143 type: "boolean",
144 description: gcli.lookup("pagemodRemoveElementStripOnlyDesc"),
145 },
146 {
147 name: "ifEmptyOnly",
148 type: "boolean",
149 description: gcli.lookup("pagemodRemoveElementIfEmptyOnlyDesc"),
150 },
151 ],
152 exec: function(args, context) {
153 let root = args.root || context.environment.document;
154 let elements = Array.prototype.slice.call(root.querySelectorAll(args.search));
155
156 let removed = 0;
157 for (let i = 0; i < elements.length; i++) {
158 let element = elements[i];
159 let parentNode = element.parentNode;
160 if (!parentNode || !element.removeChild) {
161 continue;
162 }
163 if (args.stripOnly) {
164 while (element.hasChildNodes()) {
165 parentNode.insertBefore(element.childNodes[0], element);
166 }
167 }
168 if (!args.ifEmptyOnly || !element.hasChildNodes()) {
169 element.parentNode.removeChild(element);
170 removed++;
171 }
172 }
173
174 return gcli.lookupFormat("pagemodRemoveElementResultMatchedAndRemovedElements",
175 [elements.length, removed]);
176 }
177 },
178 {
179 name: "pagemod remove attribute",
180 description: gcli.lookup("pagemodRemoveAttributeDesc"),
181 params: [
182 {
183 name: "searchAttributes",
184 type: "string",
185 description: gcli.lookup("pagemodRemoveAttributeSearchAttributesDesc"),
186 },
187 {
188 name: "searchElements",
189 type: "string",
190 description: gcli.lookup("pagemodRemoveAttributeSearchElementsDesc"),
191 },
192 {
193 name: "root",
194 type: "node",
195 description: gcli.lookup("pagemodRemoveAttributeRootDesc"),
196 defaultValue: null,
197 },
198 {
199 name: "ignoreCase",
200 type: "boolean",
201 description: gcli.lookup("pagemodRemoveAttributeIgnoreCaseDesc"),
202 },
203 ],
204 exec: function(args, context) {
205 let root = args.root || context.environment.document;
206 let regexOptions = args.ignoreCase ? "ig" : "g";
207 let attributeRegex = new RegExp(args.searchAttributes, regexOptions);
208 let elements = root.querySelectorAll(args.searchElements);
209 elements = Array.prototype.slice.call(elements);
210
211 let removed = 0;
212 for (let i = 0; i < elements.length; i++) {
213 let element = elements[i];
214 if (!element.attributes) {
215 continue;
216 }
217
218 var attrs = Array.prototype.slice.call(element.attributes);
219 for (let y = 0; y < attrs.length; y++) {
220 let attr = attrs[y];
221 if (attributeRegex.test(attr.name)) {
222 element.removeAttribute(attr.name);
223 removed++;
224 }
225 }
226 }
227
228 return gcli.lookupFormat("pagemodRemoveAttributeResult",
229 [elements.length, removed]);
230 }
231 },
232 // This command allows the user to export the page to HTML after DOM changes
233 {
234 name: "export",
235 description: gcli.lookup("exportDesc"),
236 },
237 {
238 name: "export html",
239 description: gcli.lookup("exportHtmlDesc"),
240 params: [
241 {
242 name: "destination",
243 type: {
244 name: "selection",
245 data: [ "window", "stdout", "clipboard" ]
246 },
247 defaultValue: "window"
248 }
249 ],
250 exec: function(args, context) {
251 let html = context.environment.document.documentElement.outerHTML;
252 if (args.destination === "stdout") {
253 return html;
254 }
255
256 if (args.desination === "clipboard") {
257 let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"]
258 .getService(Ci.nsIClipboardHelper);
259 clipboard.copyString(url);
260 return '';
261 }
262
263 let url = "data:text/plain;charset=utf8," + encodeURIComponent(html);
264 context.environment.window.open(url);
265 return '';
266 }
267 }
268 ];

mercurial