1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/devtools/gcli/commands/pagemod.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,268 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +"use strict"; 1.9 + 1.10 +const { Cc, Ci, Cu } = require("chrome"); 1.11 +const gcli = require("gcli/index"); 1.12 + 1.13 +exports.items = [ 1.14 + { 1.15 + name: "pagemod", 1.16 + description: gcli.lookup("pagemodDesc"), 1.17 + }, 1.18 + { 1.19 + name: "pagemod replace", 1.20 + description: gcli.lookup("pagemodReplaceDesc"), 1.21 + params: [ 1.22 + { 1.23 + name: "search", 1.24 + type: "string", 1.25 + description: gcli.lookup("pagemodReplaceSearchDesc"), 1.26 + }, 1.27 + { 1.28 + name: "replace", 1.29 + type: "string", 1.30 + description: gcli.lookup("pagemodReplaceReplaceDesc"), 1.31 + }, 1.32 + { 1.33 + name: "ignoreCase", 1.34 + type: "boolean", 1.35 + description: gcli.lookup("pagemodReplaceIgnoreCaseDesc"), 1.36 + }, 1.37 + { 1.38 + name: "selector", 1.39 + type: "string", 1.40 + description: gcli.lookup("pagemodReplaceSelectorDesc"), 1.41 + defaultValue: "*:not(script):not(style):not(embed):not(object):not(frame):not(iframe):not(frameset)", 1.42 + }, 1.43 + { 1.44 + name: "root", 1.45 + type: "node", 1.46 + description: gcli.lookup("pagemodReplaceRootDesc"), 1.47 + defaultValue: null, 1.48 + }, 1.49 + { 1.50 + name: "attrOnly", 1.51 + type: "boolean", 1.52 + description: gcli.lookup("pagemodReplaceAttrOnlyDesc"), 1.53 + }, 1.54 + { 1.55 + name: "contentOnly", 1.56 + type: "boolean", 1.57 + description: gcli.lookup("pagemodReplaceContentOnlyDesc"), 1.58 + }, 1.59 + { 1.60 + name: "attributes", 1.61 + type: "string", 1.62 + description: gcli.lookup("pagemodReplaceAttributesDesc"), 1.63 + defaultValue: null, 1.64 + }, 1.65 + ], 1.66 + // Make a given string safe to use in a regular expression. 1.67 + escapeRegex: function(aString) { 1.68 + return aString.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 1.69 + }, 1.70 + exec: function(args, context) { 1.71 + let searchTextNodes = !args.attrOnly; 1.72 + let searchAttributes = !args.contentOnly; 1.73 + let regexOptions = args.ignoreCase ? "ig" : "g"; 1.74 + let search = new RegExp(this.escapeRegex(args.search), regexOptions); 1.75 + let attributeRegex = null; 1.76 + if (args.attributes) { 1.77 + attributeRegex = new RegExp(args.attributes, regexOptions); 1.78 + } 1.79 + 1.80 + let root = args.root || context.environment.document; 1.81 + let elements = root.querySelectorAll(args.selector); 1.82 + elements = Array.prototype.slice.call(elements); 1.83 + 1.84 + let replacedTextNodes = 0; 1.85 + let replacedAttributes = 0; 1.86 + 1.87 + function replaceAttribute() { 1.88 + replacedAttributes++; 1.89 + return args.replace; 1.90 + } 1.91 + function replaceTextNode() { 1.92 + replacedTextNodes++; 1.93 + return args.replace; 1.94 + } 1.95 + 1.96 + for (let i = 0; i < elements.length; i++) { 1.97 + let element = elements[i]; 1.98 + if (searchTextNodes) { 1.99 + for (let y = 0; y < element.childNodes.length; y++) { 1.100 + let node = element.childNodes[y]; 1.101 + if (node.nodeType == node.TEXT_NODE) { 1.102 + node.textContent = node.textContent.replace(search, replaceTextNode); 1.103 + } 1.104 + } 1.105 + } 1.106 + 1.107 + if (searchAttributes) { 1.108 + if (!element.attributes) { 1.109 + continue; 1.110 + } 1.111 + for (let y = 0; y < element.attributes.length; y++) { 1.112 + let attr = element.attributes[y]; 1.113 + if (!attributeRegex || attributeRegex.test(attr.name)) { 1.114 + attr.value = attr.value.replace(search, replaceAttribute); 1.115 + } 1.116 + } 1.117 + } 1.118 + } 1.119 + 1.120 + return gcli.lookupFormat("pagemodReplaceResult", 1.121 + [elements.length, replacedTextNodes, 1.122 + replacedAttributes]); 1.123 + } 1.124 + }, 1.125 + { 1.126 + name: "pagemod remove", 1.127 + description: gcli.lookup("pagemodRemoveDesc"), 1.128 + }, 1.129 + { 1.130 + name: "pagemod remove element", 1.131 + description: gcli.lookup("pagemodRemoveElementDesc"), 1.132 + params: [ 1.133 + { 1.134 + name: "search", 1.135 + type: "string", 1.136 + description: gcli.lookup("pagemodRemoveElementSearchDesc"), 1.137 + }, 1.138 + { 1.139 + name: "root", 1.140 + type: "node", 1.141 + description: gcli.lookup("pagemodRemoveElementRootDesc"), 1.142 + defaultValue: null, 1.143 + }, 1.144 + { 1.145 + name: "stripOnly", 1.146 + type: "boolean", 1.147 + description: gcli.lookup("pagemodRemoveElementStripOnlyDesc"), 1.148 + }, 1.149 + { 1.150 + name: "ifEmptyOnly", 1.151 + type: "boolean", 1.152 + description: gcli.lookup("pagemodRemoveElementIfEmptyOnlyDesc"), 1.153 + }, 1.154 + ], 1.155 + exec: function(args, context) { 1.156 + let root = args.root || context.environment.document; 1.157 + let elements = Array.prototype.slice.call(root.querySelectorAll(args.search)); 1.158 + 1.159 + let removed = 0; 1.160 + for (let i = 0; i < elements.length; i++) { 1.161 + let element = elements[i]; 1.162 + let parentNode = element.parentNode; 1.163 + if (!parentNode || !element.removeChild) { 1.164 + continue; 1.165 + } 1.166 + if (args.stripOnly) { 1.167 + while (element.hasChildNodes()) { 1.168 + parentNode.insertBefore(element.childNodes[0], element); 1.169 + } 1.170 + } 1.171 + if (!args.ifEmptyOnly || !element.hasChildNodes()) { 1.172 + element.parentNode.removeChild(element); 1.173 + removed++; 1.174 + } 1.175 + } 1.176 + 1.177 + return gcli.lookupFormat("pagemodRemoveElementResultMatchedAndRemovedElements", 1.178 + [elements.length, removed]); 1.179 + } 1.180 + }, 1.181 + { 1.182 + name: "pagemod remove attribute", 1.183 + description: gcli.lookup("pagemodRemoveAttributeDesc"), 1.184 + params: [ 1.185 + { 1.186 + name: "searchAttributes", 1.187 + type: "string", 1.188 + description: gcli.lookup("pagemodRemoveAttributeSearchAttributesDesc"), 1.189 + }, 1.190 + { 1.191 + name: "searchElements", 1.192 + type: "string", 1.193 + description: gcli.lookup("pagemodRemoveAttributeSearchElementsDesc"), 1.194 + }, 1.195 + { 1.196 + name: "root", 1.197 + type: "node", 1.198 + description: gcli.lookup("pagemodRemoveAttributeRootDesc"), 1.199 + defaultValue: null, 1.200 + }, 1.201 + { 1.202 + name: "ignoreCase", 1.203 + type: "boolean", 1.204 + description: gcli.lookup("pagemodRemoveAttributeIgnoreCaseDesc"), 1.205 + }, 1.206 + ], 1.207 + exec: function(args, context) { 1.208 + let root = args.root || context.environment.document; 1.209 + let regexOptions = args.ignoreCase ? "ig" : "g"; 1.210 + let attributeRegex = new RegExp(args.searchAttributes, regexOptions); 1.211 + let elements = root.querySelectorAll(args.searchElements); 1.212 + elements = Array.prototype.slice.call(elements); 1.213 + 1.214 + let removed = 0; 1.215 + for (let i = 0; i < elements.length; i++) { 1.216 + let element = elements[i]; 1.217 + if (!element.attributes) { 1.218 + continue; 1.219 + } 1.220 + 1.221 + var attrs = Array.prototype.slice.call(element.attributes); 1.222 + for (let y = 0; y < attrs.length; y++) { 1.223 + let attr = attrs[y]; 1.224 + if (attributeRegex.test(attr.name)) { 1.225 + element.removeAttribute(attr.name); 1.226 + removed++; 1.227 + } 1.228 + } 1.229 + } 1.230 + 1.231 + return gcli.lookupFormat("pagemodRemoveAttributeResult", 1.232 + [elements.length, removed]); 1.233 + } 1.234 + }, 1.235 + // This command allows the user to export the page to HTML after DOM changes 1.236 + { 1.237 + name: "export", 1.238 + description: gcli.lookup("exportDesc"), 1.239 + }, 1.240 + { 1.241 + name: "export html", 1.242 + description: gcli.lookup("exportHtmlDesc"), 1.243 + params: [ 1.244 + { 1.245 + name: "destination", 1.246 + type: { 1.247 + name: "selection", 1.248 + data: [ "window", "stdout", "clipboard" ] 1.249 + }, 1.250 + defaultValue: "window" 1.251 + } 1.252 + ], 1.253 + exec: function(args, context) { 1.254 + let html = context.environment.document.documentElement.outerHTML; 1.255 + if (args.destination === "stdout") { 1.256 + return html; 1.257 + } 1.258 + 1.259 + if (args.desination === "clipboard") { 1.260 + let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"] 1.261 + .getService(Ci.nsIClipboardHelper); 1.262 + clipboard.copyString(url); 1.263 + return ''; 1.264 + } 1.265 + 1.266 + let url = "data:text/plain;charset=utf8," + encodeURIComponent(html); 1.267 + context.environment.window.open(url); 1.268 + return ''; 1.269 + } 1.270 + } 1.271 +];