commit
2319c5c4ac
|
@ -1,3 +1,11 @@
|
||||||
|
var frameIdMessageable;
|
||||||
|
runTryCatch(function() {
|
||||||
|
chrome.tabs.sendMessage(0, {}, {frameId: 0}, function() {
|
||||||
|
var clearError = chrome.runtime.lastError;
|
||||||
|
frameIdMessageable = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// This happens right away, sometimes so fast that the content script isn't even ready. That's
|
// This happens right away, sometimes so fast that the content script isn't even ready. That's
|
||||||
// why the content script also asks for this stuff.
|
// why the content script also asks for this stuff.
|
||||||
chrome.webNavigation.onCommitted.addListener(webNavigationListener.bind(this, "styleApply"));
|
chrome.webNavigation.onCommitted.addListener(webNavigationListener.bind(this, "styleApply"));
|
||||||
|
@ -7,15 +15,18 @@ function webNavigationListener(method, data) {
|
||||||
// Until Chrome 41, we can't target a frame with a message
|
// Until Chrome 41, we can't target a frame with a message
|
||||||
// (https://developer.chrome.com/extensions/tabs#method-sendMessage)
|
// (https://developer.chrome.com/extensions/tabs#method-sendMessage)
|
||||||
// so a style affecting a page with an iframe will affect the main page as well.
|
// so a style affecting a page with an iframe will affect the main page as well.
|
||||||
// Skip doing this for frames for now, which can result in flicker.
|
// Skip doing this for frames in pre-41 to prevent page flicker.
|
||||||
if (data.frameId != 0) {
|
if (data.frameId != 0 && !frameIdMessageable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
getStyles({matchUrl: data.url, enabled: true, asHash: true}, function(styleHash) {
|
getStyles({matchUrl: data.url, enabled: true, asHash: true}, function(styleHash) {
|
||||||
if (method) {
|
if (method) {
|
||||||
chrome.tabs.sendMessage(data.tabId, {method: method, styles: styleHash});
|
chrome.tabs.sendMessage(data.tabId, {method: method, styles: styleHash},
|
||||||
|
frameIdMessageable ? {frameId: data.frameId} : undefined);
|
||||||
|
}
|
||||||
|
if (data.frameId == 0) {
|
||||||
|
updateIcon({id: data.tabId, url: data.url}, styleHash);
|
||||||
}
|
}
|
||||||
updateIcon({id: data.tabId, url: data.url}, styleHash);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,15 +76,17 @@ chrome.commands.onCommand.addListener(function(command) {
|
||||||
|
|
||||||
// contextMenus API is present in ancient Chrome but it throws an exception
|
// contextMenus API is present in ancient Chrome but it throws an exception
|
||||||
// upon encountering the unsupported parameter value "browser_action", so we have to catch it.
|
// upon encountering the unsupported parameter value "browser_action", so we have to catch it.
|
||||||
|
runTryCatch(function() {
|
||||||
|
chrome.contextMenus.create({
|
||||||
|
id: "show-badge", title: chrome.i18n.getMessage("menuShowBadge"),
|
||||||
|
type: "checkbox", contexts: ["browser_action"], checked: prefs.getPref("show-badge")
|
||||||
|
}, function() { var clearError = chrome.runtime.lastError });
|
||||||
|
chrome.contextMenus.create({
|
||||||
|
id: "disableAll", title: chrome.i18n.getMessage("disableAllStyles"),
|
||||||
|
type: "checkbox", contexts: ["browser_action"], checked: prefs.getPref("disableAll")
|
||||||
|
}, function() { var clearError = chrome.runtime.lastError });
|
||||||
|
});
|
||||||
|
|
||||||
chrome.contextMenus.create({
|
|
||||||
id: "show-badge", title: chrome.i18n.getMessage("menuShowBadge"),
|
|
||||||
type: "checkbox", contexts: ["browser_action"], checked: prefs.getPref("show-badge")
|
|
||||||
}, function() { var clearError = chrome.runtime.lastError; });
|
|
||||||
chrome.contextMenus.create({
|
|
||||||
id: "disableAll", title: chrome.i18n.getMessage("disableAllStyles"),
|
|
||||||
type: "checkbox", contexts: ["browser_action"], checked: prefs.getPref("disableAll")
|
|
||||||
}, function() { var clearError = chrome.runtime.lastError; });
|
|
||||||
chrome.contextMenus.onClicked.addListener(function(info, tab) {
|
chrome.contextMenus.onClicked.addListener(function(info, tab) {
|
||||||
if (info.menuItemId == "disableAll") {
|
if (info.menuItemId == "disableAll") {
|
||||||
disableAllStylesToggle(info.checked);
|
disableAllStylesToggle(info.checked);
|
||||||
|
@ -239,13 +252,12 @@ function sectionAppliesToUrl(section, url) {
|
||||||
if (regexp[regexp.length - 1] != "$") {
|
if (regexp[regexp.length - 1] != "$") {
|
||||||
regexp += "$";
|
regexp += "$";
|
||||||
}
|
}
|
||||||
try {
|
var re = runTryCatch(function() { return new RegExp(regexp) });
|
||||||
var re = new RegExp(regexp);
|
if (re) {
|
||||||
} catch (ex) {
|
return (re).test(url);
|
||||||
|
} else {
|
||||||
console.log(section.id + "'s regexp '" + regexp + "' is not valid");
|
console.log(section.id + "'s regexp '" + regexp + "' is not valid");
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return (re).test(url);
|
|
||||||
})) {
|
})) {
|
||||||
//console.log(section.id + " applies to " + url + " due to regexp rules");
|
//console.log(section.id + " applies to " + url + " due to regexp rules");
|
||||||
return true;
|
return true;
|
||||||
|
@ -391,6 +403,13 @@ function openURL(options) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// js engine can't optimize the entire function if it contains try-catch
|
||||||
|
// so we should keep it isolated from normal code in a minimal wrapper
|
||||||
|
function runTryCatch(func) {
|
||||||
|
try { return func() }
|
||||||
|
catch(e) {}
|
||||||
|
}
|
||||||
|
|
||||||
var codeMirrorThemes;
|
var codeMirrorThemes;
|
||||||
getCodeMirrorThemes(function(themes) {
|
getCodeMirrorThemes(function(themes) {
|
||||||
codeMirrorThemes = themes;
|
codeMirrorThemes = themes;
|
||||||
|
|
145
edit.js
145
edit.js
|
@ -58,10 +58,34 @@ var jumpToLineTemplate = t('editGotoLine') + ': <input class="CodeMirror-jump-fi
|
||||||
NodeList.prototype[method]= Array.prototype[method];
|
NodeList.prototype[method]= Array.prototype[method];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Chrome pre-34
|
||||||
|
Element.prototype.matches = Element.prototype.matches || Element.prototype.webkitMatchesSelector;
|
||||||
|
|
||||||
// reroute handling to nearest editor when keypress resolves to one of these commands
|
// reroute handling to nearest editor when keypress resolves to one of these commands
|
||||||
var commandsToReroute = {
|
var hotkeyRerouter = {
|
||||||
save: true, jumpToLine: true, nextEditor: true, prevEditor: true,
|
commands: {
|
||||||
find: true, findNext: true, findPrev: true, replace: true, replaceAll: true
|
save: true, jumpToLine: true, nextEditor: true, prevEditor: true,
|
||||||
|
find: true, findNext: true, findPrev: true, replace: true, replaceAll: true
|
||||||
|
},
|
||||||
|
setState: function(enable) {
|
||||||
|
setTimeout(function() {
|
||||||
|
document[(enable ? "add" : "remove") + "EventListener"]("keydown", hotkeyRerouter.eventHandler);
|
||||||
|
}, 0);
|
||||||
|
},
|
||||||
|
eventHandler: function(event) {
|
||||||
|
var keyName = CodeMirror.keyName(event);
|
||||||
|
if ("handled" == CodeMirror.lookupKey(keyName, CodeMirror.getOption("keyMap"), handleCommand)
|
||||||
|
|| "handled" == CodeMirror.lookupKey(keyName, CodeMirror.defaults.extraKeys, handleCommand)) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
function handleCommand(command) {
|
||||||
|
if (hotkeyRerouter.commands[command] === true) {
|
||||||
|
CodeMirror.commands[command](getEditorInSight(event.target));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function onChange(event) {
|
function onChange(event) {
|
||||||
|
@ -261,6 +285,8 @@ function initCodeMirror() {
|
||||||
document.getElementById("options").addEventListener("change", acmeEventListener, false);
|
document.getElementById("options").addEventListener("change", acmeEventListener, false);
|
||||||
loadPrefs(controlPrefs);
|
loadPrefs(controlPrefs);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
hotkeyRerouter.setState(true);
|
||||||
}
|
}
|
||||||
initCodeMirror();
|
initCodeMirror();
|
||||||
|
|
||||||
|
@ -313,7 +339,11 @@ function setupCodeMirror(textarea, index) {
|
||||||
var cm = CodeMirror.fromTextArea(textarea);
|
var cm = CodeMirror.fromTextArea(textarea);
|
||||||
|
|
||||||
cm.on("change", indicateCodeChange);
|
cm.on("change", indicateCodeChange);
|
||||||
cm.on("blur", function(cm) { editors.lastActive = cm });
|
cm.on("blur", function(cm) {
|
||||||
|
editors.lastActive = cm;
|
||||||
|
hotkeyRerouter.setState(true);
|
||||||
|
});
|
||||||
|
cm.on("focus", hotkeyRerouter.setState.bind(null, false));
|
||||||
|
|
||||||
var resizeGrip = cm.display.wrapper.appendChild(document.createElement("div"));
|
var resizeGrip = cm.display.wrapper.appendChild(document.createElement("div"));
|
||||||
resizeGrip.className = "resize-grip";
|
resizeGrip.className = "resize-grip";
|
||||||
|
@ -371,26 +401,6 @@ function getCodeMirrorForSection(section) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// prevent the browser from seeing hotkeys that should be handled by nearest editor
|
|
||||||
document.addEventListener("keydown", function(event) {
|
|
||||||
if (event.target.localName == "textarea") {
|
|
||||||
return; // let CodeMirror handle it
|
|
||||||
}
|
|
||||||
var keyName = CodeMirror.keyName(event);
|
|
||||||
if ("handled" == CodeMirror.lookupKey(keyName, CodeMirror.getOption("keyMap"), handleCommand)
|
|
||||||
|| "handled" == CodeMirror.lookupKey(keyName, CodeMirror.defaults.extraKeys, handleCommand)) {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleCommand(command) {
|
|
||||||
if (commandsToReroute[command] === true) {
|
|
||||||
CodeMirror.commands[command](getEditorInSight(event.target));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// remind Chrome to repaint a previously invisible editor box by toggling any element's transform
|
// remind Chrome to repaint a previously invisible editor box by toggling any element's transform
|
||||||
// this bug is present in some versions of Chrome (v37-40 or something)
|
// this bug is present in some versions of Chrome (v37-40 or something)
|
||||||
document.addEventListener("scroll", function(event) {
|
document.addEventListener("scroll", function(event) {
|
||||||
|
@ -451,7 +461,11 @@ window.onbeforeunload = function() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
document.activeElement.blur();
|
document.activeElement.blur();
|
||||||
return !isCleanGlobal() ? t('styleChangesNotSaved') : null;
|
if (isCleanGlobal()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateLintReport(null, 0);
|
||||||
|
return confirm(t('styleChangesNotSaved'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function addAppliesTo(list, name, value) {
|
function addAppliesTo(list, name, value) {
|
||||||
|
@ -753,24 +767,47 @@ function getEditorInSight(nearbyElement) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateLintReport(cm) {
|
function updateLintReport(cm, delay) {
|
||||||
|
if (delay == 0) {
|
||||||
|
// immediately show pending csslint messages in onbeforeunload and save
|
||||||
|
update.call(cm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (delay > 0) {
|
||||||
|
// give csslint some time to find the issues, e.g. 500 (1/10 of our default 5s)
|
||||||
|
// by settings its internal delay to 1ms and restoring it back later
|
||||||
|
var lintOpt = editors[0].state.lint.options;
|
||||||
|
setTimeout((function(opt, delay) {
|
||||||
|
opt.delay = delay;
|
||||||
|
update(this);
|
||||||
|
}).bind(cm, lintOpt, lintOpt.delay), delay);
|
||||||
|
lintOpt.delay = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
var state = cm.state.lint;
|
var state = cm.state.lint;
|
||||||
clearTimeout(state.reportTimeout);
|
clearTimeout(state.reportTimeout);
|
||||||
state.reportTimeout = setTimeout(update.bind(cm), (state.options.delay || 500) + 500);
|
state.reportTimeout = setTimeout(update.bind(cm), (state.options.delay || 500) + 4500);
|
||||||
function update() { // this == cm
|
function update() { // this == cm
|
||||||
var html = this.state.lint.marked.length == 0 ? "" : "<tbody>" +
|
var scope = this ? [this] : editors;
|
||||||
this.state.lint.marked.map(function(mark) {
|
var changed = false;
|
||||||
var info = mark.__annotation;
|
scope.forEach(function(cm) {
|
||||||
return "<tr class='" + info.severity + "'>" +
|
var html = cm.state.lint.marked.length == 0 ? "" : "<tbody>" +
|
||||||
"<td role='severity' class='CodeMirror-lint-marker-" + info.severity + "'>" +
|
cm.state.lint.marked.map(function(mark) {
|
||||||
info.severity + "</td>" +
|
var info = mark.__annotation;
|
||||||
"<td role='line'>" + (info.from.line+1) + "</td>" +
|
return "<tr class='" + info.severity + "'>" +
|
||||||
"<td role='sep'>:</td>" +
|
"<td role='severity' class='CodeMirror-lint-marker-" + info.severity + "'>" +
|
||||||
"<td role='col'>" + (info.from.ch+1) + "</td>" +
|
info.severity + "</td>" +
|
||||||
"<td role='message'>" + info.message.replace(/ at line \d.+$/, "") + "</td></tr>";
|
"<td role='line'>" + (info.from.line+1) + "</td>" +
|
||||||
}).join("") + "</tbody>";
|
"<td role='sep'>:</td>" +
|
||||||
if (this.state.lint.html != html) {
|
"<td role='col'>" + (info.from.ch+1) + "</td>" +
|
||||||
this.state.lint.html = html;
|
"<td role='message'>" + info.message.replace(/ at line \d.+$/, "") + "</td></tr>";
|
||||||
|
}).join("") + "</tbody>";
|
||||||
|
if (cm.state.lint.html != html) {
|
||||||
|
cm.state.lint.html = html;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (changed) {
|
||||||
renderLintReport(true);
|
renderLintReport(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -949,19 +986,23 @@ function initWithStyle(style) {
|
||||||
});
|
});
|
||||||
var queue = style.sections.length ? style.sections : [{code: ""}];
|
var queue = style.sections.length ? style.sections : [{code: ""}];
|
||||||
var queueStart = new Date().getTime();
|
var queueStart = new Date().getTime();
|
||||||
// after 200ms the sections will be added asynchronously
|
// after 100ms the sections will be added asynchronously
|
||||||
while (new Date().getTime() - queueStart <= 200 && queue.length) {
|
while (new Date().getTime() - queueStart <= 100 && queue.length) {
|
||||||
maximizeCodeHeight(addSection(null, queue.shift()), !queue.length);
|
add();
|
||||||
}
|
|
||||||
if (queue.length) {
|
|
||||||
setTimeout(function processQueue() {
|
|
||||||
maximizeCodeHeight(addSection(null, queue.shift()), !queue.length);
|
|
||||||
if (queue.length) {
|
|
||||||
setTimeout(processQueue, 0);
|
|
||||||
}
|
|
||||||
}, 0);
|
|
||||||
}
|
}
|
||||||
|
(function processQueue() {
|
||||||
|
if (queue.length) {
|
||||||
|
add();
|
||||||
|
setTimeout(processQueue, 0);
|
||||||
|
}
|
||||||
|
})();
|
||||||
initHooks();
|
initHooks();
|
||||||
|
|
||||||
|
function add() {
|
||||||
|
var sectionDiv = addSection(null, queue.shift());
|
||||||
|
maximizeCodeHeight(sectionDiv, !queue.length);
|
||||||
|
updateLintReport(getCodeMirrorForSection(sectionDiv), 500);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function initHooks() {
|
function initHooks() {
|
||||||
|
@ -1071,6 +1112,8 @@ function validate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function save() {
|
function save() {
|
||||||
|
updateLintReport(null, 0);
|
||||||
|
|
||||||
// save the contents of the CodeMirror editors back into the textareas
|
// save the contents of the CodeMirror editors back into the textareas
|
||||||
for (var i=0; i < editors.length; i++) {
|
for (var i=0; i < editors.length; i++) {
|
||||||
editors[i].save();
|
editors[i].save();
|
||||||
|
|
|
@ -35,13 +35,14 @@ function tNodeList(nodes) {
|
||||||
if (node.nodeType != 1) { // not an ELEMENT_NODE
|
if (node.nodeType != 1) { // not an ELEMENT_NODE
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (var a = 0; a < node.attributes.length; a++) {
|
for (var a = node.attributes.length - 1; a >= 0; a--) {
|
||||||
var name = node.attributes[a].nodeName;
|
var attr = node.attributes[a];
|
||||||
|
var name = attr.nodeName;
|
||||||
if (name.indexOf("i18n-") != 0) {
|
if (name.indexOf("i18n-") != 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
name = name.substr(5); // "i18n-".length
|
name = name.substr(5); // "i18n-".length
|
||||||
var value = t(node.attributes[a].nodeValue);
|
var value = t(attr.nodeValue);
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case "text":
|
case "text":
|
||||||
node.insertBefore(document.createTextNode(value), node.firstChild);
|
node.insertBefore(document.createTextNode(value), node.firstChild);
|
||||||
|
@ -52,6 +53,7 @@ function tNodeList(nodes) {
|
||||||
default:
|
default:
|
||||||
node.setAttribute(name, value);
|
node.setAttribute(name, value);
|
||||||
}
|
}
|
||||||
|
node.removeAttributeNode(attr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,5 +71,6 @@ function tDocLoader() {
|
||||||
observer.observe(document, {subtree: true, childList: true});
|
observer.observe(document, {subtree: true, childList: true});
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
observer.disconnect();
|
observer.disconnect();
|
||||||
|
tNodeList(document.querySelectorAll("*"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
13
messaging.js
13
messaging.js
|
@ -76,14 +76,9 @@ function getActiveTabRealURL(callback) {
|
||||||
function getTabRealURL(tab, callback) {
|
function getTabRealURL(tab, callback) {
|
||||||
if (tab.url != "chrome://newtab/") {
|
if (tab.url != "chrome://newtab/") {
|
||||||
callback(tab.url);
|
callback(tab.url);
|
||||||
return;
|
} else {
|
||||||
}
|
chrome.webNavigation.getFrame({tabId: tab.id, frameId: 0, processId: -1}, function(frame) {
|
||||||
chrome.webNavigation.getAllFrames({tabId: tab.id}, function(frames) {
|
frame && callback(frame.url);
|
||||||
frames.some(function(frame) {
|
|
||||||
if (frame.parentFrameId == -1) { // parentless frame is the main frame
|
|
||||||
callback(frame.url);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -271,7 +271,7 @@ function shallowCopy(obj) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function equal(a, b) {
|
function equal(a, b) {
|
||||||
if (!a || !b || typeof a != "object") {
|
if (!a || !b || typeof a != "object" || typeof b != "object") {
|
||||||
return a === b;
|
return a === b;
|
||||||
}
|
}
|
||||||
if (Object.keys(a).length != Object.keys(b).length) {
|
if (Object.keys(a).length != Object.keys(b).length) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user