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
|
||||
// why the content script also asks for this stuff.
|
||||
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
|
||||
// (https://developer.chrome.com/extensions/tabs#method-sendMessage)
|
||||
// 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.
|
||||
if (data.frameId != 0) {
|
||||
// Skip doing this for frames in pre-41 to prevent page flicker.
|
||||
if (data.frameId != 0 && !frameIdMessageable) {
|
||||
return;
|
||||
}
|
||||
getStyles({matchUrl: data.url, enabled: true, asHash: true}, function(styleHash) {
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -65,15 +76,17 @@ chrome.commands.onCommand.addListener(function(command) {
|
|||
|
||||
// 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.
|
||||
|
||||
chrome.contextMenus.create({
|
||||
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({
|
||||
}, 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; });
|
||||
}, function() { var clearError = chrome.runtime.lastError });
|
||||
});
|
||||
|
||||
chrome.contextMenus.onClicked.addListener(function(info, tab) {
|
||||
if (info.menuItemId == "disableAll") {
|
||||
disableAllStylesToggle(info.checked);
|
||||
|
@ -239,13 +252,12 @@ function sectionAppliesToUrl(section, url) {
|
|||
if (regexp[regexp.length - 1] != "$") {
|
||||
regexp += "$";
|
||||
}
|
||||
try {
|
||||
var re = new RegExp(regexp);
|
||||
} catch (ex) {
|
||||
console.log(section.id + "'s regexp '" + regexp + "' is not valid");
|
||||
return false;
|
||||
}
|
||||
var re = runTryCatch(function() { return new RegExp(regexp) });
|
||||
if (re) {
|
||||
return (re).test(url);
|
||||
} else {
|
||||
console.log(section.id + "'s regexp '" + regexp + "' is not valid");
|
||||
}
|
||||
})) {
|
||||
//console.log(section.id + " applies to " + url + " due to regexp rules");
|
||||
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;
|
||||
getCodeMirrorThemes(function(themes) {
|
||||
codeMirrorThemes = themes;
|
||||
|
|
117
edit.js
117
edit.js
|
@ -58,10 +58,34 @@ var jumpToLineTemplate = t('editGotoLine') + ': <input class="CodeMirror-jump-fi
|
|||
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
|
||||
var commandsToReroute = {
|
||||
var hotkeyRerouter = {
|
||||
commands: {
|
||||
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) {
|
||||
|
@ -261,6 +285,8 @@ function initCodeMirror() {
|
|||
document.getElementById("options").addEventListener("change", acmeEventListener, false);
|
||||
loadPrefs(controlPrefs);
|
||||
});
|
||||
|
||||
hotkeyRerouter.setState(true);
|
||||
}
|
||||
initCodeMirror();
|
||||
|
||||
|
@ -313,7 +339,11 @@ function setupCodeMirror(textarea, index) {
|
|||
var cm = CodeMirror.fromTextArea(textarea);
|
||||
|
||||
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"));
|
||||
resizeGrip.className = "resize-grip";
|
||||
|
@ -371,26 +401,6 @@ function getCodeMirrorForSection(section) {
|
|||
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
|
||||
// this bug is present in some versions of Chrome (v37-40 or something)
|
||||
document.addEventListener("scroll", function(event) {
|
||||
|
@ -451,7 +461,11 @@ window.onbeforeunload = function() {
|
|||
});
|
||||
}
|
||||
document.activeElement.blur();
|
||||
return !isCleanGlobal() ? t('styleChangesNotSaved') : null;
|
||||
if (isCleanGlobal()) {
|
||||
return;
|
||||
}
|
||||
updateLintReport(null, 0);
|
||||
return confirm(t('styleChangesNotSaved'));
|
||||
}
|
||||
|
||||
function addAppliesTo(list, name, value) {
|
||||
|
@ -753,13 +767,32 @@ 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;
|
||||
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
|
||||
var html = this.state.lint.marked.length == 0 ? "" : "<tbody>" +
|
||||
this.state.lint.marked.map(function(mark) {
|
||||
var scope = this ? [this] : editors;
|
||||
var changed = false;
|
||||
scope.forEach(function(cm) {
|
||||
var html = cm.state.lint.marked.length == 0 ? "" : "<tbody>" +
|
||||
cm.state.lint.marked.map(function(mark) {
|
||||
var info = mark.__annotation;
|
||||
return "<tr class='" + info.severity + "'>" +
|
||||
"<td role='severity' class='CodeMirror-lint-marker-" + info.severity + "'>" +
|
||||
|
@ -769,8 +802,12 @@ function updateLintReport(cm) {
|
|||
"<td role='col'>" + (info.from.ch+1) + "</td>" +
|
||||
"<td role='message'>" + info.message.replace(/ at line \d.+$/, "") + "</td></tr>";
|
||||
}).join("") + "</tbody>";
|
||||
if (this.state.lint.html != html) {
|
||||
this.state.lint.html = html;
|
||||
if (cm.state.lint.html != html) {
|
||||
cm.state.lint.html = html;
|
||||
changed = true;
|
||||
}
|
||||
});
|
||||
if (changed) {
|
||||
renderLintReport(true);
|
||||
}
|
||||
}
|
||||
|
@ -949,19 +986,23 @@ function initWithStyle(style) {
|
|||
});
|
||||
var queue = style.sections.length ? style.sections : [{code: ""}];
|
||||
var queueStart = new Date().getTime();
|
||||
// after 200ms the sections will be added asynchronously
|
||||
while (new Date().getTime() - queueStart <= 200 && queue.length) {
|
||||
maximizeCodeHeight(addSection(null, queue.shift()), !queue.length);
|
||||
// after 100ms the sections will be added asynchronously
|
||||
while (new Date().getTime() - queueStart <= 100 && queue.length) {
|
||||
add();
|
||||
}
|
||||
(function processQueue() {
|
||||
if (queue.length) {
|
||||
setTimeout(function processQueue() {
|
||||
maximizeCodeHeight(addSection(null, queue.shift()), !queue.length);
|
||||
if (queue.length) {
|
||||
add();
|
||||
setTimeout(processQueue, 0);
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
})();
|
||||
initHooks();
|
||||
|
||||
function add() {
|
||||
var sectionDiv = addSection(null, queue.shift());
|
||||
maximizeCodeHeight(sectionDiv, !queue.length);
|
||||
updateLintReport(getCodeMirrorForSection(sectionDiv), 500);
|
||||
}
|
||||
}
|
||||
|
||||
function initHooks() {
|
||||
|
@ -1071,6 +1112,8 @@ function validate() {
|
|||
}
|
||||
|
||||
function save() {
|
||||
updateLintReport(null, 0);
|
||||
|
||||
// save the contents of the CodeMirror editors back into the textareas
|
||||
for (var i=0; i < editors.length; i++) {
|
||||
editors[i].save();
|
||||
|
|
|
@ -35,13 +35,14 @@ function tNodeList(nodes) {
|
|||
if (node.nodeType != 1) { // not an ELEMENT_NODE
|
||||
continue;
|
||||
}
|
||||
for (var a = 0; a < node.attributes.length; a++) {
|
||||
var name = node.attributes[a].nodeName;
|
||||
for (var a = node.attributes.length - 1; a >= 0; a--) {
|
||||
var attr = node.attributes[a];
|
||||
var name = attr.nodeName;
|
||||
if (name.indexOf("i18n-") != 0) {
|
||||
continue;
|
||||
}
|
||||
name = name.substr(5); // "i18n-".length
|
||||
var value = t(node.attributes[a].nodeValue);
|
||||
var value = t(attr.nodeValue);
|
||||
switch (name) {
|
||||
case "text":
|
||||
node.insertBefore(document.createTextNode(value), node.firstChild);
|
||||
|
@ -52,6 +53,7 @@ function tNodeList(nodes) {
|
|||
default:
|
||||
node.setAttribute(name, value);
|
||||
}
|
||||
node.removeAttributeNode(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,5 +71,6 @@ function tDocLoader() {
|
|||
observer.observe(document, {subtree: true, childList: true});
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
observer.disconnect();
|
||||
tNodeList(document.querySelectorAll("*"));
|
||||
});
|
||||
}
|
||||
|
|
13
messaging.js
13
messaging.js
|
@ -76,14 +76,9 @@ function getActiveTabRealURL(callback) {
|
|||
function getTabRealURL(tab, callback) {
|
||||
if (tab.url != "chrome://newtab/") {
|
||||
callback(tab.url);
|
||||
return;
|
||||
}
|
||||
chrome.webNavigation.getAllFrames({tabId: tab.id}, function(frames) {
|
||||
frames.some(function(frame) {
|
||||
if (frame.parentFrameId == -1) { // parentless frame is the main frame
|
||||
callback(frame.url);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
chrome.webNavigation.getFrame({tabId: tab.id, frameId: 0, processId: -1}, function(frame) {
|
||||
frame && callback(frame.url);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -271,7 +271,7 @@ function shallowCopy(obj) {
|
|||
}
|
||||
|
||||
function equal(a, b) {
|
||||
if (!a || !b || typeof a != "object") {
|
||||
if (!a || !b || typeof a != "object" || typeof b != "object") {
|
||||
return a === b;
|
||||
}
|
||||
if (Object.keys(a).length != Object.keys(b).length) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user