Add AutoplayStopper v1.8.7
This commit is contained in:
parent
f5620cbc84
commit
69eb447c28
5
AutoplayStopper/README.txt
Normal file
5
AutoplayStopper/README.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
This is an extracted copy of https://chrome.google.com/webstore/detail/autoplaystopper/ejddcgojdblidajhngkogefpkknnebdh version 1.8.7. I then loaded it into Chrome as an unpacked extension.
|
||||||
|
This was done to bypass auto extension updates that may eventually be injected with malware.
|
||||||
|
The extraction was done using the "Chrome extension source viewer" addon (https://github.com/Rob--W/crxviewer).
|
||||||
|
|
||||||
|
I reviewed the code for malicious changes and made other small tweaks.
|
201
AutoplayStopper/_locales/en/messages.json
Normal file
201
AutoplayStopper/_locales/en/messages.json
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
{
|
||||||
|
"extensionDescription": {
|
||||||
|
"message": "Stops video autoplay gracefully."
|
||||||
|
},
|
||||||
|
|
||||||
|
"allowSite": {
|
||||||
|
"message": "Allow autoplay for %S"
|
||||||
|
},
|
||||||
|
|
||||||
|
"allowSession": {
|
||||||
|
"message": "Allow session autoplay for %S"
|
||||||
|
},
|
||||||
|
|
||||||
|
"disableSite": {
|
||||||
|
"message": "Block flash detection for %S"
|
||||||
|
},
|
||||||
|
|
||||||
|
"allowAll": {
|
||||||
|
"message": "Disable everywhere"
|
||||||
|
},
|
||||||
|
|
||||||
|
"settings": {
|
||||||
|
"message": "Settings"
|
||||||
|
},
|
||||||
|
|
||||||
|
"version": {
|
||||||
|
"message": "Version"
|
||||||
|
},
|
||||||
|
|
||||||
|
"autoplayTabLabel": {
|
||||||
|
"message": "Autoplay"
|
||||||
|
},
|
||||||
|
|
||||||
|
"permissions": {
|
||||||
|
"message": "Websites Permissions:"
|
||||||
|
},
|
||||||
|
|
||||||
|
"manageExceptions": {
|
||||||
|
"message": "Exceptions..."
|
||||||
|
},
|
||||||
|
|
||||||
|
"defaultMode": {
|
||||||
|
"message": "Default Mode:"
|
||||||
|
},
|
||||||
|
|
||||||
|
"disableAutoplay": {
|
||||||
|
"message": "Block Autoplay"
|
||||||
|
},
|
||||||
|
|
||||||
|
"allowAutoplay": {
|
||||||
|
"message": "Allow Autoplay"
|
||||||
|
},
|
||||||
|
|
||||||
|
"flashTabLabel": {
|
||||||
|
"message": "Flash"
|
||||||
|
},
|
||||||
|
|
||||||
|
"allowFlash": {
|
||||||
|
"message": "Allow Detection"
|
||||||
|
},
|
||||||
|
|
||||||
|
"disableFlash": {
|
||||||
|
"message": "Block Detection"
|
||||||
|
},
|
||||||
|
|
||||||
|
"autoplayExceptions": {
|
||||||
|
"message": "Autoplay exceptions"
|
||||||
|
},
|
||||||
|
|
||||||
|
"flashExceptions": {
|
||||||
|
"message": "Flash detection exceptions"
|
||||||
|
},
|
||||||
|
|
||||||
|
"exceptionHostnameHeader": {
|
||||||
|
"message": "Hostname"
|
||||||
|
},
|
||||||
|
|
||||||
|
"exceptionBehaviorHeader": {
|
||||||
|
"message": "Behavior"
|
||||||
|
},
|
||||||
|
|
||||||
|
"exceptionAllow": {
|
||||||
|
"message": "Allow"
|
||||||
|
},
|
||||||
|
|
||||||
|
"exceptionBlock": {
|
||||||
|
"message": "Block"
|
||||||
|
},
|
||||||
|
|
||||||
|
"exceptionPrompt": {
|
||||||
|
"message": "Block (strict)"
|
||||||
|
},
|
||||||
|
|
||||||
|
"exceptionSession": {
|
||||||
|
"message": "Session"
|
||||||
|
},
|
||||||
|
|
||||||
|
"exceptionUndefined": {
|
||||||
|
"message": "Undefined"
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"message": "Apply"
|
||||||
|
},
|
||||||
|
|
||||||
|
"removeAll": {
|
||||||
|
"message": "Remove All"
|
||||||
|
},
|
||||||
|
|
||||||
|
"done": {
|
||||||
|
"message": "Done"
|
||||||
|
},
|
||||||
|
|
||||||
|
"play": {
|
||||||
|
"message": "Play"
|
||||||
|
},
|
||||||
|
|
||||||
|
"pause": {
|
||||||
|
"message": "Pause"
|
||||||
|
},
|
||||||
|
|
||||||
|
"selector": {
|
||||||
|
"message": "Selector"
|
||||||
|
},
|
||||||
|
|
||||||
|
"text": {
|
||||||
|
"message": "Text"
|
||||||
|
},
|
||||||
|
|
||||||
|
"reset": {
|
||||||
|
"message": "Reset"
|
||||||
|
},
|
||||||
|
|
||||||
|
"script": {
|
||||||
|
"message": "Script"
|
||||||
|
},
|
||||||
|
|
||||||
|
"userScript": {
|
||||||
|
"message": "User Script"
|
||||||
|
},
|
||||||
|
|
||||||
|
"path": {
|
||||||
|
"message": "Path"
|
||||||
|
},
|
||||||
|
|
||||||
|
"actions": {
|
||||||
|
"message": "Actions"
|
||||||
|
},
|
||||||
|
|
||||||
|
"edit": {
|
||||||
|
"message": "Edit"
|
||||||
|
},
|
||||||
|
|
||||||
|
"load": {
|
||||||
|
"message": "Load"
|
||||||
|
},
|
||||||
|
|
||||||
|
"export": {
|
||||||
|
"message": "Export..."
|
||||||
|
},
|
||||||
|
|
||||||
|
"setPath": {
|
||||||
|
"message": "Set Path"
|
||||||
|
},
|
||||||
|
|
||||||
|
"selectFile": {
|
||||||
|
"message": "File..."
|
||||||
|
},
|
||||||
|
|
||||||
|
"advanced": {
|
||||||
|
"message": "Advanced"
|
||||||
|
},
|
||||||
|
|
||||||
|
"devtools": {
|
||||||
|
"message": "Devtools Panel"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overwrite": {
|
||||||
|
"message": "Disable overwrite on update"
|
||||||
|
},
|
||||||
|
|
||||||
|
"debug": {
|
||||||
|
"message": "Log debug info"
|
||||||
|
},
|
||||||
|
|
||||||
|
"loadError": {
|
||||||
|
"message": "Load script error: "
|
||||||
|
},
|
||||||
|
|
||||||
|
"allowFileUrls": {
|
||||||
|
"message": "Error: Cannot use user script without permission to access file URLs."
|
||||||
|
},
|
||||||
|
|
||||||
|
"fileNotFound": {
|
||||||
|
"message": "AutoplayStopper - error: File not found.\n Check that the script folder is in the workspace and verify the path."
|
||||||
|
},
|
||||||
|
|
||||||
|
"evalError": {
|
||||||
|
"message": "AutoplayStopper - exception: "
|
||||||
|
}
|
||||||
|
}
|
186
AutoplayStopper/background.js
Normal file
186
AutoplayStopper/background.js
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var Background = new function() {
|
||||||
|
|
||||||
|
console.log("loading background.js ...");
|
||||||
|
|
||||||
|
const {js, css} = chrome.runtime.getManifest().content_scripts[0];
|
||||||
|
const badgeColor = "#646464";
|
||||||
|
const playMsg = chrome.i18n.getMessage("play");
|
||||||
|
const pauseMsg = chrome.i18n.getMessage("pause");
|
||||||
|
const sArea = "local";
|
||||||
|
const permsAutoplayKey = Permissions.key("autoplay");
|
||||||
|
const permsAutoplayDefaultKey = Permissions.defaultKey("autoplay");
|
||||||
|
const permsFlashKey = Permissions.key("flash");
|
||||||
|
const permsFlashDefaultKey = Permissions.defaultKey("flash");
|
||||||
|
const sKeys = ["disabled", "debug", permsFlashKey, permsFlashDefaultKey, permsAutoplayKey,
|
||||||
|
permsAutoplayDefaultKey, "selector-css", "uhandler", "handler", "disableOverwrite", "devtools"];
|
||||||
|
|
||||||
|
var selector = null;
|
||||||
|
var permissions = null;
|
||||||
|
var permsAutoplayCache = {};
|
||||||
|
var permsFlashCache = {};
|
||||||
|
var tabs = { get(id) { return this[id] || (this[id] = {id, count: 0})}};
|
||||||
|
var menuitem = null;
|
||||||
|
|
||||||
|
var storage = new Storage(sKeys, sArea);
|
||||||
|
storage.addChangeListener(function(changes){
|
||||||
|
if (changes.indexOf("selector-css") != -1) selector = storage.data["selector-css"].split("{")[0];
|
||||||
|
if (changes.indexOf(permsAutoplayKey) != -1 || changes.indexOf(permsAutoplayDefaultKey) != -1) permsAutoplayCache = {};
|
||||||
|
if (changes.indexOf(permsFlashKey) != -1 || changes.indexOf(permsFlashDefaultKey) != -1) permsFlashCache = {};
|
||||||
|
if (changes.indexOf("disabled") != -1) updateIcon();
|
||||||
|
});
|
||||||
|
|
||||||
|
storage.ready.then(function() {
|
||||||
|
console.log("storage.ready");
|
||||||
|
updateIcon();
|
||||||
|
permissions = new Permissions(storage.data);
|
||||||
|
if (permissions.default("autoplay") === undefined) permissions.setDefault("autoplay", Permission.DENY_ACTION);
|
||||||
|
if (permissions.default("flash") === undefined) permissions.setDefault("flash", Permission.ALLOW_ACTION);
|
||||||
|
chrome.webNavigation.onCommitted.addListener(onCommitted, {url: [{schemes: ["http", "https", "about"]}]});
|
||||||
|
if (!storage.data.uhandler)
|
||||||
|
loadScript("uhandler", chrome.extension.getURL("script/userhandler.js"));
|
||||||
|
if (!storage.data.handler)
|
||||||
|
loadScript("handler", chrome.extension.getURL("script/handler.js"));
|
||||||
|
if (!storage.data["selector-css"])
|
||||||
|
loadScript("selector-css", chrome.extension.getURL("script/selector.css"));
|
||||||
|
selector = storage.data["selector-css"].split("{")[0];
|
||||||
|
js.forEach(function(a) { execScript(a, null, 0)});
|
||||||
|
});
|
||||||
|
|
||||||
|
chrome.browserAction.setBadgeBackgroundColor({color: badgeColor});
|
||||||
|
chrome.tabs.onRemoved.addListener(function(tabid){ delete tabs[tabid]; });
|
||||||
|
chrome.tabs.onActivated.addListener(resetMenuitem);
|
||||||
|
chrome.runtime.onMessage.addListener(handleMessage);
|
||||||
|
chrome.runtime.onInstalled.addListener(function(details) {
|
||||||
|
if (details.reason == "update" && !storage.data.disableOverwrite) {
|
||||||
|
loadScript("handler", chrome.extension.getURL("script/handler.js"));
|
||||||
|
loadScript("selector-css", chrome.extension.getURL("script/selector.css"));
|
||||||
|
selector = storage.data["selector-css"].split("{")[0];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
get i18n() { return i18n; },
|
||||||
|
get storage() { return storage; },
|
||||||
|
get permissions() { return permissions; },
|
||||||
|
openOptionsPage: function openOptionsPage(hash) {
|
||||||
|
chrome.runtime.openOptionsPage();
|
||||||
|
if (hash) addEventListener("message", function(e) {
|
||||||
|
if (location.origin == e.origin && e.data == "optionsPageActive")
|
||||||
|
e.source.location.hash = hash;
|
||||||
|
}, { once: true});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function resetMenuitem(){ if (menuitem) menuitem = chrome.contextMenus.remove("play-menuitem"); }
|
||||||
|
|
||||||
|
function updateIcon() { chrome.browserAction.setIcon({ path: "/icons/" + (storage.data.disabled ? "icon32d.png" : "icon32.png")})};
|
||||||
|
|
||||||
|
function handleMessage(request, sender, sendResponse)
|
||||||
|
{
|
||||||
|
if (!storage.data.handler) {
|
||||||
|
console.log("handleMessage delayed -", request, sender);
|
||||||
|
storage.ready.then(function() { handleMessage(request, sender, sendResponse)});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (request == "permission") {
|
||||||
|
var data = {debug: !!storage.data.debug};
|
||||||
|
var allow = true, host = sender.tab && new URL(sender.tab.url).origin;
|
||||||
|
if (host && !storage.data.disabled) {
|
||||||
|
var permission = permsAutoplayCache[host] ||
|
||||||
|
(permsAutoplayCache[host] = permissions.testPermission("autoplay", sender.tab.url));
|
||||||
|
allow = permission == Permission.ALLOW_ACTION ||
|
||||||
|
(permission == Permission.ACCESS_SESSION && tabs.get(sender.tab.id).last == host);
|
||||||
|
data.strict = permission == Permission.PROMPT_ACTION;
|
||||||
|
}
|
||||||
|
var msg = {msg: "permission", data, allow, selector, handler: storage.data.handler, uhandler: storage.data.uhandler};
|
||||||
|
// console.log("background send:", msg, sender.url, sender.tab.url);
|
||||||
|
sendResponse(msg);
|
||||||
|
}
|
||||||
|
if (request == "count")
|
||||||
|
chrome.browserAction.setBadgeText({text: String(++tabs.get(sender.tab.id).count), tabId: sender.tab.id});
|
||||||
|
if (request.msg == "contextmenu") {
|
||||||
|
resetMenuitem();
|
||||||
|
if (request.media)
|
||||||
|
menuitem = chrome.contextMenus.create({ id: "play-menuitem", title: request.paused ? playMsg : pauseMsg,
|
||||||
|
contexts: ["all"], onclick: function onClick(info, tab) { if (info.menuItemId == "play-menuitem") sendResponse();}
|
||||||
|
})
|
||||||
|
return !!request.media;
|
||||||
|
}
|
||||||
|
if (request.msg == "select") {
|
||||||
|
fetch(request.url, {cache: "no-store"}).then(function(res) {
|
||||||
|
res.blob().then(function(file){ sendResponse({url: URL.createObjectURL(file), name: file.name}); });
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (request.msg == "load") {
|
||||||
|
var res = loadScript(request.script, request.file);
|
||||||
|
sendResponse(res);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function onCommitted(details)
|
||||||
|
{
|
||||||
|
var allow = true, url = new URL(details.url);
|
||||||
|
if (url.protocol.search("^chrome") != -1) return;
|
||||||
|
|
||||||
|
var tab = tabs.get(details.tabId);
|
||||||
|
if (details.frameId == 0) {
|
||||||
|
tab.last = tab.host;
|
||||||
|
tab.host = url.origin;
|
||||||
|
tab.url = details.url;
|
||||||
|
tab.count = 0;
|
||||||
|
chrome.browserAction.setBadgeText({text:'', tabId: tab.id});
|
||||||
|
chrome.tabs.query({ active: true, currentWindow: true}, function(tabs) {
|
||||||
|
if (tabs[0] && tabs[0].id == tab.id) resetMenuitem();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!storage.data.disabled && tab.url) {
|
||||||
|
var permission = permsFlashCache[tab.host] ||
|
||||||
|
(permsFlashCache[tab.host] = permissions.testPermission("flash", tab.url));
|
||||||
|
if (permission == Permission.DENY_ACTION)
|
||||||
|
execScript("content/navigator.js", details.tabId, details.frameId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function execScript(file, tabId, frameId) {
|
||||||
|
chrome.tabs.executeScript(tabId, {file, frameId, matchAboutBlank: true, runAt: "document_start"}, function() {
|
||||||
|
if (chrome.runtime.lastError && storage.data.debug)
|
||||||
|
console.error("chrome.tabs.executeScript - error", chrome.runtime.lastError, {tabId, frameId, file});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function insertCSS(file, tabId, frameId) {
|
||||||
|
chrome.tabs.insertCSS(tabId, {file, frameId, matchAboutBlank: true, runAt: "document_start"}, function() {
|
||||||
|
if (chrome.runtime.lastError && storage.data.debug)
|
||||||
|
console.error("chrome.tabs.insertCSS - error", chrome.runtime.lastError, {tabId, frameId, file});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function loadScript(script, url){
|
||||||
|
try {
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.overrideMimeType("text/plain");
|
||||||
|
request.open("GET", url, false);
|
||||||
|
request.setRequestHeader("pragma", "no-cache");
|
||||||
|
request.send();
|
||||||
|
if (request.statusText == "Not Found" || !request.responseURL)
|
||||||
|
throw new DOMException(`Failed to load '${url}'.`, "NetworkError");
|
||||||
|
|
||||||
|
storage.data[script] = request.responseText;
|
||||||
|
storage.commit([script]);
|
||||||
|
} catch (e) {
|
||||||
|
chrome.extension.isAllowedFileSchemeAccess(function(allowed) {
|
||||||
|
if(!allowed && url.search(/^blob:/) == -1)
|
||||||
|
return alert(chrome.i18n.getMessage("allowFileUrls"));
|
||||||
|
alert(`${chrome.i18n.getMessage("loadError")} ${e.name}\n ${e.message}`);
|
||||||
|
});
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//</>
|
310
AutoplayStopper/content/content.js
Normal file
310
AutoplayStopper/content/content.js
Normal file
|
@ -0,0 +1,310 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const ContentScript = new function() {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const start = Date.now();
|
||||||
|
const any = (window.wrappedJSObject ? "-moz" : "-webkit") + "-any";
|
||||||
|
const frameSelector = `iframe:${any}(:not([src]), [src^='javascript:' i], [src^='about:blank' i]):not([flashstopped])`;
|
||||||
|
|
||||||
|
var data = {debug: false};
|
||||||
|
const _trace = function TRACE(format, ...etc) {
|
||||||
|
if (!data.debug) return TRACE._noop || (TRACE._noop = function(){});
|
||||||
|
return console.log.bind(console, "### " + format + " ###", ...etc);
|
||||||
|
};
|
||||||
|
|
||||||
|
var selector = null;
|
||||||
|
var handler = null; //loadURL(chrome.extension.getURL("script/handler.js"));
|
||||||
|
var href = frameElement !== null ? frameElement.src || "about:blank" : location.href;
|
||||||
|
var ret = 0;
|
||||||
|
|
||||||
|
_trace("ready(%s) content.js - iframe: %s href: %s loc: %s fs: %s")(start - Date.now(),
|
||||||
|
!!frameElement && frameElement.id, href == location.href || href, location.href, window.flashstopped);
|
||||||
|
|
||||||
|
if (window.flashstopped) return;
|
||||||
|
window.flashstopped = true;
|
||||||
|
|
||||||
|
chrome.runtime.sendMessage("permission", handlePermission);
|
||||||
|
function handlePermission(response) {
|
||||||
|
if (chrome.runtime.lastError && ret <= 3) {
|
||||||
|
console.error(`handlePermission - error ret: ${ret} msg: ${chrome.runtime.lastError.message}`);
|
||||||
|
window.setTimeout(function() { chrome.runtime.sendMessage("permission", handlePermission)}, ret++ * 250);
|
||||||
|
};
|
||||||
|
if (!response) return;
|
||||||
|
data = response.data;
|
||||||
|
selector = response.selector;
|
||||||
|
handler = `${response.uhandler}\n\n${response.handler}`;
|
||||||
|
if (!response.allow) load(window);
|
||||||
|
addEventListener("message", function(e) {
|
||||||
|
if (e.data && e.data.id == "userinput") e.stopImmediatePropagation();
|
||||||
|
}, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (parent && parent != window)
|
||||||
|
parent.postMessage({id: "userinput"}, "*");
|
||||||
|
|
||||||
|
function load({window, frameElement, location})
|
||||||
|
{
|
||||||
|
var href = frameElement !== null ? frameElement.src || "about:blank" : location.href;
|
||||||
|
_trace("loading(%s) content.js - iframe: %s href: %s loc: %s")(start - Date.now(),
|
||||||
|
!!frameElement && frameElement.id, href == location.href || href, location.href);
|
||||||
|
|
||||||
|
var match = 0, query = 0;
|
||||||
|
var injected = false;
|
||||||
|
var body = window.document.body;
|
||||||
|
var userInput = null;
|
||||||
|
|
||||||
|
var n = handleDocument();
|
||||||
|
_trace("body: %s n: %s")(!!body, n);
|
||||||
|
|
||||||
|
var docObserver = new MutationObserver(function(mutations) {
|
||||||
|
|
||||||
|
_trace("!!! docObserver - body: %s neb: %s !!!")(!!body, body != window.document.body);
|
||||||
|
if (window.document.body && body != window.document.body) {
|
||||||
|
if (body) observer.observe(window.document.body, { subtree: true, childList: true});
|
||||||
|
body = window.document.body;
|
||||||
|
requestAnimationFrame(function() {
|
||||||
|
var n = handleDocument();
|
||||||
|
_trace(">>>>>>> requestAnimationFrame n: %s <<<<<<<")(n);
|
||||||
|
});
|
||||||
|
window.setTimeout(function() {
|
||||||
|
var n = handleDocument();
|
||||||
|
_trace(">>>>>>> setting body observer - n: %s <<<<<<<<")(n);
|
||||||
|
}, 500);
|
||||||
|
var n = handleDocument();
|
||||||
|
_trace("!!! docObserver - out n: %s !!!")(n);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var observer = new MutationObserver(function(mutations) {
|
||||||
|
|
||||||
|
for (var i = 0; i < mutations.length; i++)
|
||||||
|
for (var j = 0; j < mutations[i].addedNodes.length; j++) {
|
||||||
|
var addedNode = mutations[i].addedNodes[j];
|
||||||
|
if (addedNode.nodeType === 1){
|
||||||
|
match++;
|
||||||
|
if (addedNode.children.length) query++;
|
||||||
|
if (handleNodesDeep(addedNode, true)) {
|
||||||
|
_trace(">>>>>>> MutationObserver: tag: %s id: %s <<<<<<<")(addedNode.localName, addedNode.id);
|
||||||
|
}
|
||||||
|
var frames = addedNode.matches(frameSelector) ? [addedNode] : [];
|
||||||
|
if (frames.push(...addedNode.querySelectorAll(frameSelector)))
|
||||||
|
handleFrames(frames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (window.document.body)
|
||||||
|
observer.observe((href.search("^https?:") == -1) ? window.document : window.document.body
|
||||||
|
, { subtree: true, childList: true});
|
||||||
|
else
|
||||||
|
docObserver.observe(window.document.documentElement, { childList: true});
|
||||||
|
|
||||||
|
// workaround for chrome no events on blank iframe ...
|
||||||
|
setTimeout( function() {
|
||||||
|
window.addEventListener("mousedown", onContextMenu, true);
|
||||||
|
["mousedown","click"].forEach((a) => window.addEventListener(a, function(e) {
|
||||||
|
if (e.isTrusted && e.button == 0) {
|
||||||
|
userInput = {e: e, time: Date.now()};
|
||||||
|
if (injected) dispatchUserInput(userInput);
|
||||||
|
}
|
||||||
|
}, true));
|
||||||
|
if (data.debug) chrome.storage.local.get(["selector-css"], function(data) {
|
||||||
|
window.document.head.appendChild(document.createElement("style"))
|
||||||
|
.textContent = data["selector-css"];
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
window.addEventListener("DOMContentLoaded", function() {
|
||||||
|
observer.observe(window.document.body, { subtree: true, childList: true});
|
||||||
|
var n = handleDocument();
|
||||||
|
_trace(">>>>>>> DOMContentLoaded n: %s match: %s query: %s iframe: %s loc: %s <<<<<<<")
|
||||||
|
(n , match, query, !!frameElement && frameElement.id, location.href);
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
window.addEventListener("message", function(e) {
|
||||||
|
if (!e.data || e.data.id != "userinput") return;
|
||||||
|
if (e.source == window.parent) {
|
||||||
|
_trace("@@@ handleMessage(userinput) @@@@")();
|
||||||
|
var si = new MouseEvent("siminput", Object.assign({view: window}, e.data));
|
||||||
|
userInput = {e: Object.defineProperty(si, "target", {value: window}), time: e.data.time};
|
||||||
|
if (injected) dispatchUserInput(userInput);
|
||||||
|
}
|
||||||
|
if (e.source && e.source.parent == window && userInput) {
|
||||||
|
var iframe, iframes = [...window.document.querySelectorAll("iframe")];
|
||||||
|
if (userInput.e.target.shadowRoot) iframes.push(...userInput.e.target.shadowRoot.querySelectorAll("iframe"));
|
||||||
|
if (iframe = iframes.find((a) => a.contentWindow == e.source)) {
|
||||||
|
var ue = userInput.e, time = userInput.time, r = iframe.getBoundingClientRect();
|
||||||
|
var data = {id: "userinput", clientX: ue.pageX - r.left - scrollX, clientY: ue.pageY - r.top - scrollY, time};
|
||||||
|
e.source.postMessage(data, "*");
|
||||||
|
_trace("@@@ iframe.postMessage(userinput) @@@")();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
function handleDocument()
|
||||||
|
{
|
||||||
|
var nodes = handleNodesDeep(window.document.body || window.document.documentElement);
|
||||||
|
var frames = (window.document.body || window.document.documentElement).querySelectorAll(frameSelector);
|
||||||
|
if (frames.length) handleFrames(frames);
|
||||||
|
return nodes;
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleNodes(nodes, delayed)
|
||||||
|
{
|
||||||
|
if (!injected) {
|
||||||
|
if (href.search("^https?:") == -1 && !delayed)
|
||||||
|
return window.setTimeout(function(){ handleNodes(nodes, true)});
|
||||||
|
injected = loadScript();
|
||||||
|
if (userInput) dispatchUserInput(userInput);
|
||||||
|
}
|
||||||
|
nodes.forEach(function(node) {
|
||||||
|
node.setAttribute("flashstopped", true);
|
||||||
|
try { node.parentNode.setAttribute("flashstopped_p", true)} catch(e){};
|
||||||
|
if (!node.flashstopped) {
|
||||||
|
node.dispatchEvent(new Event("flashstop:bind", {bubbles: true, composed: true}));
|
||||||
|
chrome.runtime.sendMessage("count");
|
||||||
|
_trace("match: %s query: %s")(match, query);
|
||||||
|
}
|
||||||
|
node.flashstopped = true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleFrames(frames)
|
||||||
|
{
|
||||||
|
if (!window.wrappedJSObject) frames.forEach(function(frame) {
|
||||||
|
if (!frame.contentWindow) return;
|
||||||
|
_trace("!!! iframe - id: %s src: %s fs: %s !!!")(frame.id, frame.src, frame.contentWindow.flashstopped);
|
||||||
|
if (!frame.contentWindow.flashstopped) {
|
||||||
|
frame.setAttribute("flashstopped", true);
|
||||||
|
frame.contentWindow.flashstopped = true;
|
||||||
|
frame.contentWindow.Function('parent.postMessage({id: "userinput"}, "*")')();
|
||||||
|
window.setTimeout(function(){ load(frame.contentWindow)});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleNodesDeep(node, match)
|
||||||
|
{
|
||||||
|
var nodes = match && (node.matches(selector) || node.shadowRoot) ? [node] : [];
|
||||||
|
var count = nodes.push(...node.querySelectorAll(selector));
|
||||||
|
for (var el of nodes.filter((a) => a.shadowRoot)) {
|
||||||
|
nodes.splice(nodes.indexOf(el), 1)[0].setAttribute("flashstopped", true);
|
||||||
|
count += handleNodesDeep(el.shadowRoot) - 1;
|
||||||
|
observer.observe(el.shadowRoot, { subtree: true, childList: true});
|
||||||
|
}
|
||||||
|
if (nodes.length) handleNodes(nodes);
|
||||||
|
return count;
|
||||||
|
};
|
||||||
|
|
||||||
|
function loadScript()
|
||||||
|
{
|
||||||
|
var code = `(function(data){ ${_trace} ${Handlers} ${handler} (${init})()})(${JSON.stringify(data)})`;
|
||||||
|
var script = window.document.createElement("script");
|
||||||
|
script.textContent = code;
|
||||||
|
if (window.wrappedJSObject)
|
||||||
|
script.textContent += "\ndocument.currentScript.dispatchEvent(new Event('load'));";
|
||||||
|
script.onload = function() { this.executed = true};
|
||||||
|
(window.document.head || window.document.documentElement).appendChild(script);
|
||||||
|
script.remove();
|
||||||
|
|
||||||
|
if (window.wrappedJSObject && !script.executed) // fff
|
||||||
|
try { window.eval(code); } catch(e) {};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
// initilaizer & adapter for the injection code...
|
||||||
|
function init()
|
||||||
|
{
|
||||||
|
var handlingUserInput = false
|
||||||
|
var lastUserInput = null;
|
||||||
|
var handlers = new Handlers(TRACE);
|
||||||
|
function isHandlingUserInput() { return handlingUserInput = handlingUserInput && Date.now() - lastUserInput.time < 100 };
|
||||||
|
|
||||||
|
registerUserHandlers(handlers, TRACE, isHandlingUserInput, () => TRACE("setHandlingUserInput")(), () => lastUserInput, data);
|
||||||
|
registerHandlers(handlers, TRACE, isHandlingUserInput, () => TRACE("setHandlingUserInput")(), () => lastUserInput, data);
|
||||||
|
|
||||||
|
window.addEventListener("userinput", function(e) {
|
||||||
|
handlingUserInput = true;
|
||||||
|
setTimeout(function() { handlingUserInput = false;});
|
||||||
|
lastUserInput = {e: Object.assign({target: e.target}, e.detail.e), time: e.detail.time};
|
||||||
|
}, true);
|
||||||
|
window.addEventListener("flashstop:bind", function onbind(e){
|
||||||
|
var aElement = e.target, path = e.composedPath();
|
||||||
|
if (path && path[0] != aElement) aElement = path[0];
|
||||||
|
TRACE("onElementBinding - tag: %s id: %s loc: %s")(aElement.localName, aElement.id, window.location.href);
|
||||||
|
window.wrappedJSObject = window;
|
||||||
|
try {
|
||||||
|
handlers.apply(wrapper(aElement));
|
||||||
|
} catch(e) {
|
||||||
|
aElement.addEventListener("playing", () => {
|
||||||
|
if (!lastUserInput || Date.now() - lastUserInput.time > 1500) aElement.pause();
|
||||||
|
})};
|
||||||
|
delete window.wrappedJSObject;
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
function wrapper(node)
|
||||||
|
{
|
||||||
|
var proxy = new Proxy(node, { get: function(target, prop, receiver) {
|
||||||
|
var proto = Object.getPrototypeOf(node);
|
||||||
|
var res = Reflect.get(proto, prop, node);
|
||||||
|
return typeof res == "function" && res.bind ? res.bind(node) : res;
|
||||||
|
}, set: function(target, prop, value, receiver) {
|
||||||
|
var proto = Object.getPrototypeOf(node);
|
||||||
|
return Reflect.set(proto, prop, value, Reflect.has(proto, prop) ? node : receiver);
|
||||||
|
}});
|
||||||
|
return Object.create(proxy, {wrappedJSObject: { value: node}});
|
||||||
|
};
|
||||||
|
|
||||||
|
TRACE("addEventListener - flashstop:bind")();
|
||||||
|
};
|
||||||
|
|
||||||
|
function inRect(x, y, el){ var b = el.getBoundingClientRect(); return (x > b.left && x < b.right && y > b.top && y < b.bottom) ? el : null};
|
||||||
|
function matchDeep(el, x, y, res) {
|
||||||
|
if (!el.shadowRoot) return el.matches("video, audio") ? el : null;
|
||||||
|
for (var n of [...el.shadowRoot.elementsFromPoint(x, y)].filter((a) => a.getRootNode().host == el))
|
||||||
|
if (res = matchDeep(n, x, y)) return res;
|
||||||
|
};
|
||||||
|
function getMediaElement(aWin, aPrev, x, y)
|
||||||
|
{
|
||||||
|
try {aWin.document} catch(e) { _trace("getMediaElement - %s")(e); return };
|
||||||
|
var res, sx = x + aWin.mozInnerScreenX, sy = y + aWin.mozInnerScreenY, round = Math.round;
|
||||||
|
_trace("sc(%s,%s) win(%s,%s) win: %s prev: %s")(round(sx), round(sy), round(x), round(y), aWin.location.host, aPrev && aPrev.location.host);
|
||||||
|
for (var node of aWin.document.elementsFromPoint(x, y))
|
||||||
|
if (res = (node.localName != "iframe" || node.contentWindow == aPrev) ? matchDeep(node, x, y) :
|
||||||
|
getMediaElement(node.contentWindow, null, x - node.getBoundingClientRect().left, y - node.getBoundingClientRect().top))
|
||||||
|
return (res.localName != "iframe" && _trace("getMediaElement - success id: %s")(res.id), res);
|
||||||
|
if (res = [...aWin.document.querySelectorAll("video:not([src^='data:'])")].find((node) => inRect(x, y, node)))
|
||||||
|
return (_trace("getMediaElement - success id: %s")(res.id), res);
|
||||||
|
return (aPrev && aWin != aWin.parent && aWin.frameElement) && getMediaElement(aWin.parent, aWin, x +
|
||||||
|
aWin.frameElement.getBoundingClientRect().left, y + aWin.frameElement.getBoundingClientRect().top);
|
||||||
|
};
|
||||||
|
|
||||||
|
function onContextMenu(e)
|
||||||
|
{ // before
|
||||||
|
if (e.isTrusted && e.button == 2){
|
||||||
|
var media = e.target instanceof HTMLMediaElement ? e.target : getMediaElement(e.view, e.view, e.clientX, e.clientY);
|
||||||
|
var paused = media && media.paused;
|
||||||
|
if (media) {
|
||||||
|
chrome.runtime.sendMessage({ msg: "contextmenu", media: true, paused },
|
||||||
|
function(){ if (!chrome.runtime.lastError) paused ? media.play() : media.pause(); });
|
||||||
|
if (e.ctrlKey)
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
chrome.runtime.sendMessage({ msg: "contextmenu", media: false});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function dispatchUserInput({e, time, e: {view: window}})
|
||||||
|
{ // fff!
|
||||||
|
with(e) var Obj = window.Object, data = Object.assign(new Obj, {clientX, clientY, pageX, pageY});
|
||||||
|
var target = e.target != window && window.document.contains(e.target) ? e.target : window;
|
||||||
|
target.dispatchEvent(new CustomEvent("userinput", {detail: Object.assign(new Obj,{e: data, time})}));
|
||||||
|
};
|
||||||
|
|
||||||
|
// </>
|
49
AutoplayStopper/content/handler-utils.js
Normal file
49
AutoplayStopper/content/handler-utils.js
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
|
||||||
|
// handler-utils.js See license.txt for terms of usage and credits
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handlers - content handlers manager...
|
||||||
|
* ----------------------------------------
|
||||||
|
* @bYO!
|
||||||
|
*/
|
||||||
|
|
||||||
|
function Handlers(TRACE){
|
||||||
|
|
||||||
|
var _handlers = [], _mapRemoved = new Map();
|
||||||
|
return {
|
||||||
|
unload: function unload(){
|
||||||
|
for (var win of _mapRemoved.keys()) {
|
||||||
|
win.removeEventListener("unload", onUnload, false);
|
||||||
|
TRACE("Handlers.unload - remove wnd loc: %s")(win.location);
|
||||||
|
};
|
||||||
|
_handlers = [];
|
||||||
|
_mapRemoved = new Map();
|
||||||
|
},
|
||||||
|
add: function add(handler) { _handlers.push(handler); },
|
||||||
|
remove: function remove(win, handler) {
|
||||||
|
if (!_mapRemoved.has(win)){
|
||||||
|
win.addEventListener("unload", onUnload, false);
|
||||||
|
_mapRemoved.set(win, []);
|
||||||
|
}
|
||||||
|
_mapRemoved.get(win).push(handler);
|
||||||
|
TRACE("Handlers.remove - handler: %s")(handler.name);
|
||||||
|
},
|
||||||
|
apply: function apply(element){
|
||||||
|
var removed = _mapRemoved.get(element.ownerDocument.defaultView);
|
||||||
|
for (var handler, i = 0; i < _handlers.length; i++)
|
||||||
|
if ((handler = _handlers[i]) && (!removed || removed.indexOf(handler) == -1))
|
||||||
|
try {
|
||||||
|
if (handler(element)) break;
|
||||||
|
} catch (e) { TRACE("!!!!!!!!! handler: %s Exception: %s !!!!!!!!!")(handler.name, e); };
|
||||||
|
},
|
||||||
|
get length() { return _handlers.length; }
|
||||||
|
};
|
||||||
|
|
||||||
|
function onUnload(e){
|
||||||
|
var win = e.target.defaultView;
|
||||||
|
TRACE("Handlers.onUnload - remove wnd has: %s loc: %s")(_mapRemoved.has(win), win.location);
|
||||||
|
_mapRemoved.delete(win);
|
||||||
|
}
|
||||||
|
};
|
39
AutoplayStopper/content/navigator.js
Normal file
39
AutoplayStopper/content/navigator.js
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
|
||||||
|
// setTimeout(function() {
|
||||||
|
var script = document.createElement("script");
|
||||||
|
script.textContent = `(${setNavigator})()`;
|
||||||
|
(document.head || document.documentElement || document).appendChild(script);
|
||||||
|
script.remove();
|
||||||
|
// });
|
||||||
|
|
||||||
|
function setNavigator(nav = { plugins: navigator.plugins, mimeTypes: navigator.mimeTypes}) {
|
||||||
|
|
||||||
|
console.log("setNavigator - uri: " + location);
|
||||||
|
|
||||||
|
var plugins = Object.assign(Object.create(PluginArray.prototype), [...nav.plugins]);
|
||||||
|
Object.defineProperties(plugins, { item: {value: (a) => plugins[a]}, namedItem: {value: (a) => plugins[a]},
|
||||||
|
refresh: {value: () => { nav.plugins.refresh(); setNavigator(nav)}},
|
||||||
|
length: { writable: true, value: nav.plugins.length}});
|
||||||
|
for (var a of plugins) { Object.defineProperty(plugins, a.name, {configurable: true, value: a}); };
|
||||||
|
[].splice.call(plugins, [].findIndex.call(plugins, (a) => a.name == "Shockwave Flash"), 1);
|
||||||
|
delete plugins["Shockwave Flash"];
|
||||||
|
Object.defineProperty(navigator, "plugins", {configurable: true, value: plugins});
|
||||||
|
|
||||||
|
var mimetypes = Object.assign(Object.create(MimeTypeArray.prototype), [...nav.mimeTypes]);
|
||||||
|
Object.defineProperties(mimetypes, { item: {value: (a) => mimetypes[a]}, namedItem: {value: (a) => mimetypes[a]},
|
||||||
|
refresh: {value: () => { plugins.refresh()}}, length: { writable: true, value: nav.mimeTypes.length}});
|
||||||
|
for (var a of mimetypes) { Object.defineProperty(mimetypes, a.type, {configurable: true, value: a}); };
|
||||||
|
[].forEach.call(nav.plugins["Shockwave Flash"] || [], ({type}) =>
|
||||||
|
delete mimetypes[[].splice.call(mimetypes, [].findIndex.call(mimetypes, (a) => a.type == type), 1)[0].type]);
|
||||||
|
Object.defineProperty(navigator, "mimeTypes", {configurable: true, value: mimetypes});
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
// </>
|
||||||
|
|
144
AutoplayStopper/devtools.js
Normal file
144
AutoplayStopper/devtools.js
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const DevTools = new function() {
|
||||||
|
|
||||||
|
const sArea = "local";
|
||||||
|
const sKeys = ["debug", "devtools", "codefile", "ucodefile", "codefilename", "ucodefilename", "disableOverwrite", "selector-css", "uhandler", "handler"];
|
||||||
|
|
||||||
|
var storage = new Storage(sKeys, sArea);
|
||||||
|
|
||||||
|
storage.ready.then(function() {
|
||||||
|
|
||||||
|
if (!storage.data.devtools)
|
||||||
|
return;
|
||||||
|
// devtools page - create panel ...
|
||||||
|
if (location.search == "?view=page")
|
||||||
|
return chrome.devtools.panels.create("AutoplayStopper", "/icons/icon48.png", "/skin/devtools.html?view=panel");
|
||||||
|
|
||||||
|
// devtools panel ...
|
||||||
|
var fileinput = Object.assign(document.createElement("input"), {type: "file", hidden: true});
|
||||||
|
document.body.appendChild(fileinput);
|
||||||
|
document.readyState == "complete" ? load() : addEventListener("load", load);
|
||||||
|
|
||||||
|
function load() {
|
||||||
|
|
||||||
|
i18n.process(document);
|
||||||
|
document.getElementById("ver").textContent = chrome.runtime.getManifest().version;
|
||||||
|
setCheckbox("overwrite", "disableOverwrite");
|
||||||
|
setCheckbox("debug");
|
||||||
|
setSelector();
|
||||||
|
setup("");
|
||||||
|
setup("u");
|
||||||
|
};
|
||||||
|
|
||||||
|
function setSelector()
|
||||||
|
{
|
||||||
|
var selector = document.getElementById("selector");
|
||||||
|
var apply = document.getElementById("apply");
|
||||||
|
selector.value = storage.data["selector-css"];
|
||||||
|
selector.oninput = function() { apply.disabled = selector.value == storage.data["selector-css"]; };
|
||||||
|
apply.onclick = function() {
|
||||||
|
storage.data["selector-css"] = selector.value;
|
||||||
|
storage.commit(["selector-css"]);
|
||||||
|
apply.disabled = true;
|
||||||
|
};
|
||||||
|
document.getElementById("reset").onclick = function() {
|
||||||
|
var url = chrome.extension.getURL("script/selector.css");
|
||||||
|
chrome.runtime.sendMessage({ msg: "load", script: "selector-css", file: url });
|
||||||
|
};
|
||||||
|
storage.addChangeListener(function(changes){
|
||||||
|
if (changes.includes("selector-css")) selector.value = storage.data["selector-css"];
|
||||||
|
apply.disabled = true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function setup(pfx)
|
||||||
|
{
|
||||||
|
var file = pfx + "codefile";
|
||||||
|
var filename = file + "name";
|
||||||
|
|
||||||
|
document.getElementById(pfx + "path-input").textContent = storage.data[file];
|
||||||
|
document.getElementById(pfx + "filename").textContent = storage.data[filename];
|
||||||
|
updateState();
|
||||||
|
|
||||||
|
document.getElementById(pfx + "load-button").onclick = function() {
|
||||||
|
var url = storage.data[file] || chrome.extension.getURL("script/") + (pfx && "user") + "handler.js";
|
||||||
|
chrome.runtime.sendMessage({ msg: "load", script: pfx + "handler", file: url});
|
||||||
|
};
|
||||||
|
document.getElementById(pfx + "export-button").onclick = function() {
|
||||||
|
var a = document.getElementById("export-link");
|
||||||
|
a.download = (pfx && "user") + "handler.js";
|
||||||
|
a.href = "data:application/javascript," + encodeURIComponent(storage.data[pfx + "handler"]);
|
||||||
|
a.click();
|
||||||
|
};
|
||||||
|
document.getElementById(pfx + "edit-button").onclick = function() {
|
||||||
|
var open = chrome.devtools.panels.openResource || function(){};
|
||||||
|
open(getURL(file), null, function(res){
|
||||||
|
if (res.isError && res.code == "E_NOTFOUND")
|
||||||
|
alert(chrome.i18n.getMessage("fileNotFound"));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var committed = chrome.devtools && chrome.devtools.inspectedWindow.onResourceContentCommitted;
|
||||||
|
committed && committed.addListener(function(resource){
|
||||||
|
if (resource.url == getURL(file))
|
||||||
|
resource.getContent(function(content, encoding) {
|
||||||
|
chrome.devtools.inspectedWindow.eval(content, function(result, isException) {
|
||||||
|
if (isException)
|
||||||
|
alert(chrome.i18n.getMessage("evalError") + isException.value);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
document.getElementById(pfx + "path-input").oninput = updateState;
|
||||||
|
document.getElementById(pfx + "path-button").onclick = function(e) {
|
||||||
|
storage.data[filename] = document.getElementById(pfx + "filename").textContent = "";
|
||||||
|
storage.data[file] = document.getElementById(pfx + "path-input").textContent;
|
||||||
|
storage.commit([file, filename]);
|
||||||
|
updateState();
|
||||||
|
};
|
||||||
|
document.getElementById(pfx + "select-button").onclick = function(e) {
|
||||||
|
fileinput.onchange = function() {
|
||||||
|
if (!chrome.extension.getBackgroundPage) { // fff...
|
||||||
|
var data = {msg: "select", url: URL.createObjectURL(this.files[0])};
|
||||||
|
chrome.runtime.sendMessage(data, function(res) { updateSelected(res.url, res.name); });
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var url = chrome.extension.getBackgroundPage().URL.createObjectURL(this.files[0]);
|
||||||
|
updateSelected(url, this.files[0].name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fileinput.click();
|
||||||
|
};
|
||||||
|
|
||||||
|
function updateSelected(url, name) {
|
||||||
|
storage.data[file] = document.getElementById(pfx + "path-input").textContent = url;
|
||||||
|
storage.data[filename] = document.getElementById(pfx + "filename").textContent = name;
|
||||||
|
storage.commit([file, filename]);
|
||||||
|
updateState();
|
||||||
|
};
|
||||||
|
|
||||||
|
function updateState()
|
||||||
|
{
|
||||||
|
var a = document.getElementById(pfx + "path-input").textContent == (storage.data[file] || "");
|
||||||
|
document.getElementById(pfx + "path-button").disabled = a;
|
||||||
|
document.getElementById(pfx + "load-button").disabled = !a;
|
||||||
|
document.getElementById(pfx + "edit-button").disabled = !a || !storage.data[file];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function getURL(file) { try { return new URL(storage.data[file]).href } catch(e) {}; };
|
||||||
|
|
||||||
|
function setCheckbox(id, key = id)
|
||||||
|
{
|
||||||
|
var node = document.getElementById(id);
|
||||||
|
node.checked = !!storage.data[key];
|
||||||
|
node.onchange = function() {
|
||||||
|
storage.data[key] = this.checked;
|
||||||
|
storage.commit([key]);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
//</>
|
BIN
AutoplayStopper/icons/icon32.png
Normal file
BIN
AutoplayStopper/icons/icon32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
BIN
AutoplayStopper/icons/icon32d.png
Normal file
BIN
AutoplayStopper/icons/icon32d.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
BIN
AutoplayStopper/icons/icon48.png
Normal file
BIN
AutoplayStopper/icons/icon48.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
53
AutoplayStopper/manifest.json
Normal file
53
AutoplayStopper/manifest.json
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
{
|
||||||
|
"description": "[MODIFIED BY ME] Stops video autoplay gracefully.",
|
||||||
|
"manifest_version": 2,
|
||||||
|
"name": "AutoplayStopper",
|
||||||
|
"version": "1.8.7",
|
||||||
|
|
||||||
|
"default_locale": "en",
|
||||||
|
|
||||||
|
"icons": {
|
||||||
|
"32": "icons/icon32.png",
|
||||||
|
"48": "icons/icon48.png"
|
||||||
|
},
|
||||||
|
|
||||||
|
"permissions": [
|
||||||
|
"http://*/*", "https://*/*",
|
||||||
|
"tabs",
|
||||||
|
"contextMenus",
|
||||||
|
"storage",
|
||||||
|
"webNavigation"
|
||||||
|
],
|
||||||
|
|
||||||
|
"background": {
|
||||||
|
"scripts": ["utils.js", "background.js"]
|
||||||
|
},
|
||||||
|
|
||||||
|
"browser_action": {
|
||||||
|
"default_icon": {
|
||||||
|
"32": "icons/icon32.png"
|
||||||
|
},
|
||||||
|
"default_title": "AutoplayStopper",
|
||||||
|
"default_popup": "skin/popup.html",
|
||||||
|
"browser_style": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"content_scripts": [
|
||||||
|
{
|
||||||
|
"run_at": "document_start",
|
||||||
|
"all_frames": true,
|
||||||
|
"match_about_blank": true,
|
||||||
|
"matches": ["http://*/*", "https://*/*"],
|
||||||
|
"js": ["content/handler-utils.js", "content/content.js"]
|
||||||
|
}],
|
||||||
|
|
||||||
|
"options_ui": {
|
||||||
|
"chrome_style": true,
|
||||||
|
"browser_style": true,
|
||||||
|
"page": "skin/options.html"
|
||||||
|
},
|
||||||
|
|
||||||
|
"devtools_page": "skin/devtools.html?view=page",
|
||||||
|
|
||||||
|
"optional_permissions": ["file://*/*"]
|
||||||
|
}
|
292
AutoplayStopper/options.js
Normal file
292
AutoplayStopper/options.js
Normal file
|
@ -0,0 +1,292 @@
|
||||||
|
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const Options = new function() {
|
||||||
|
|
||||||
|
const {i18n, storage, permissions: perms} = chrome.extension.getBackgroundPage().Background;
|
||||||
|
const permsAutoplayKey = perms.key("autoplay");
|
||||||
|
const permsAutoplayDefaultKey = perms.defaultKey("autoplay");
|
||||||
|
const permsFlashKey = perms.key("flash");
|
||||||
|
const permsFlashDefaultKey = perms.defaultKey("flash");
|
||||||
|
const data = { flash: { type: "flash", dirty: false}, autoplay: { type: "autoplay", dirty: false}};
|
||||||
|
const { autoplay, flash } = data;
|
||||||
|
|
||||||
|
var tabId = null;
|
||||||
|
var selected = null;
|
||||||
|
|
||||||
|
// chrome.tabs.getCurrent(function(tab) { tabId = tab.id; }); // chrome workaround ...
|
||||||
|
chrome.tabs.query({ active: true, currentWindow: true}, function(tabs) { tabId = tabs[0].id; });
|
||||||
|
chrome.tabs.onActivated.addListener(function(info){ if (tabId == info.tabId) postActive(); });
|
||||||
|
addEventListener("load", init);
|
||||||
|
addEventListener("hashchange", function() { updateState(location.hash.slice(1)); });
|
||||||
|
|
||||||
|
function init()
|
||||||
|
{
|
||||||
|
i18n.process(document);
|
||||||
|
var listener = storage.addChangeListener(function(changes){
|
||||||
|
if (changes.indexOf(permsAutoplayKey) != -1) {
|
||||||
|
autoplay.exceptions.init(perms.entries("autoplay"));
|
||||||
|
autoplay.dirty = false;
|
||||||
|
updateApply();
|
||||||
|
}
|
||||||
|
if(changes.indexOf(permsAutoplayDefaultKey) != -1) {
|
||||||
|
document.getElementById("autoplay-default").value = perms.default("autoplay");
|
||||||
|
}
|
||||||
|
if (changes.indexOf(permsFlashKey) != -1) {
|
||||||
|
flash.exceptions.init(perms.entries("flash"));
|
||||||
|
flash.dirty = false;
|
||||||
|
updateApply();
|
||||||
|
}
|
||||||
|
if(changes.indexOf(permsFlashDefaultKey) != -1) {
|
||||||
|
document.getElementById("flash-default").value = perms.default("flash");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
addEventListener("unload", function(){ storage.removeChangeListener(listener); });
|
||||||
|
|
||||||
|
var manifest = chrome.runtime.getManifest();
|
||||||
|
document.getElementById("extension-version").appendChild(document.createTextNode(manifest.version));
|
||||||
|
document.getElementById("autoplay-default").value = perms.default("autoplay");
|
||||||
|
document.getElementById("flash-default").value = perms.default("flash");
|
||||||
|
document.getElementById("devtools").checked = storage.data.devtools;
|
||||||
|
autoplay.exceptions = new ExceptionsList(document.getElementById("autoplay-list"));
|
||||||
|
autoplay.exceptions.init(perms.entries("autoplay"));
|
||||||
|
document.getElementById("autoplay-default").addEventListener("change", function(e) {
|
||||||
|
perms.setDefault("autoplay", e.target.value);
|
||||||
|
storage.commit([permsAutoplayDefaultKey]);
|
||||||
|
});
|
||||||
|
flash.exceptions = new ExceptionsList(document.getElementById("flash-list"));
|
||||||
|
flash.exceptions.init(perms.entries("flash"));
|
||||||
|
document.getElementById("flash-default").addEventListener("change", function(e) {
|
||||||
|
perms.setDefault("flash", e.target.value);
|
||||||
|
storage.commit([permsFlashDefaultKey]);
|
||||||
|
});
|
||||||
|
document.querySelectorAll(".exceptions-list-button").forEach(function(button) {
|
||||||
|
button.onclick = function(e) { location.hash = `${button.getAttribute("contenttype")}`; };
|
||||||
|
});
|
||||||
|
autoplay.exceptions.addDirtyListener(function(d) { autoplay.dirty = d; updateApply(); });
|
||||||
|
flash.exceptions.addDirtyListener(function(d) { flash.dirty = d; updateApply(); });
|
||||||
|
document.querySelector(".close-button").onclick = function() { location.hash = ""; };
|
||||||
|
document.getElementById("exceptions-clear").onclick = function() { selected.exceptions.clear(); };
|
||||||
|
document.getElementById("exceptions-apply").onclick = apply;
|
||||||
|
document.getElementById("exceptions-confirm").onclick = function() { apply(); location.hash = ""; };
|
||||||
|
document.getElementById("devtools").onclick = function(e) {
|
||||||
|
storage.data.devtools = this.checked;
|
||||||
|
storage.commit(["devtools"]);
|
||||||
|
};
|
||||||
|
if (location.hash) updateState(location.hash.slice(1));
|
||||||
|
postActive();
|
||||||
|
};
|
||||||
|
|
||||||
|
function postActive() { chrome.extension.getBackgroundPage().postMessage("optionsPageActive", "*"); };
|
||||||
|
function updateApply() { document.getElementById("exceptions-apply").disabled = !selected || !selected.dirty; };
|
||||||
|
|
||||||
|
function apply()
|
||||||
|
{
|
||||||
|
if (selected.dirty) {
|
||||||
|
perms.clear(selected.type);
|
||||||
|
for (var [url, perm] of selected.exceptions.entries()) { perms.set(selected.type, url, perm); };
|
||||||
|
storage.commit([perms.key(selected.type)], function(err){
|
||||||
|
if (err) { selected.dirty = true; };
|
||||||
|
updateApply();
|
||||||
|
});
|
||||||
|
selected.dirty = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function updateState(state)
|
||||||
|
{
|
||||||
|
// console.log(`updateState(${state})`);
|
||||||
|
if (state) {
|
||||||
|
document.querySelector("div[contenttype]:not([hidden])").hidden = true;
|
||||||
|
document.querySelector("h2[contenttype]:not([hidden])").hidden = true;
|
||||||
|
document.querySelector(`div[contenttype=${state}]`).hidden = false;
|
||||||
|
document.querySelector(`h2[contenttype=${state}]`).hidden = false;
|
||||||
|
var overlay = document.querySelector(".overlay");
|
||||||
|
overlay.hidden = false;
|
||||||
|
setTimeout(function() { overlay.classList.remove("transparent"); }, 20);
|
||||||
|
selected = data[state];
|
||||||
|
updateApply();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var overlay = document.querySelector(".overlay");
|
||||||
|
overlay.classList.add("transparent");
|
||||||
|
setTimeout(function() { overlay.hidden = true; }, 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const ExceptionsList = function ExceptionsList(list){
|
||||||
|
|
||||||
|
var itemid = 0;
|
||||||
|
var baseitem = list.querySelector("#listitem");
|
||||||
|
var inputitem = list.querySelector("#inputitem");
|
||||||
|
var selected = list.querySelector("[selected]");
|
||||||
|
var listeners = [];
|
||||||
|
var dirty = false;
|
||||||
|
|
||||||
|
baseitem.remove();
|
||||||
|
list.addEventListener("mousedown", handleMousedown.bind(this));
|
||||||
|
list.addEventListener("click", handleClick.bind(this));
|
||||||
|
list.addEventListener("keydown", handleKeyDown.bind(this));
|
||||||
|
list.addEventListener("change", handleChange.bind(this));
|
||||||
|
list.addEventListener("focus", function(e) {
|
||||||
|
if (!e.target.classList.contains("row-delete-button")) {
|
||||||
|
list.setAttribute("has-element-focus", "hasElementFocus");
|
||||||
|
handleSelection(e.target.closest("[role=listitem]"));
|
||||||
|
if (e.target.getAttribute("displaymode") == "static") e.target.nextSibling.focus();
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
list.addEventListener("blur", function(e) {
|
||||||
|
if (!list.contains(e.relatedTarget) && !e.target.classList.contains("row-delete-button")) {
|
||||||
|
list.removeAttribute("has-element-focus");
|
||||||
|
handleSelection();
|
||||||
|
if (!e.relatedTarget) list.parentNode.closest("[tabindex]").focus();
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
return {
|
||||||
|
init: function init(entries) {
|
||||||
|
this.clear();
|
||||||
|
entries.sort(function(a, b) { return a[0].localeCompare(b[0]); });
|
||||||
|
for (var [key, type] of entries) { appendItem(key, type); };
|
||||||
|
dirty = false;
|
||||||
|
},
|
||||||
|
entries: function * entries()
|
||||||
|
{
|
||||||
|
for (var node of list.children)
|
||||||
|
if (node.id.search("listitem") == 0 && node != inputitem)
|
||||||
|
yield [node.querySelector("#perms-host").textContent, parseInt(node.querySelector("#perms-type-select").value)];
|
||||||
|
},
|
||||||
|
clear: function clear()
|
||||||
|
{
|
||||||
|
for (var node of [].slice.apply(list.children))
|
||||||
|
if (node.id.search("listitem") == 0 && node != inputitem) node.remove();
|
||||||
|
inputitem.querySelector("#perms-host-input").focus();
|
||||||
|
fireDirty(true);
|
||||||
|
},
|
||||||
|
get dirty() { return dirty; },
|
||||||
|
addDirtyListener: function(listener) { listeners.push(listener); },
|
||||||
|
removeDirtyListener: function(listener) { var idx = listeners.indexOf(listener); if (idx != -1) listeners.splice(idx); }
|
||||||
|
};
|
||||||
|
|
||||||
|
function appendItem(host, type, scroll)
|
||||||
|
{
|
||||||
|
var item = baseitem.cloneNode(true);
|
||||||
|
item.id = item.id + "-" + (++itemid);
|
||||||
|
item.querySelector("#perms-host-input").value = item.querySelector("#perms-host").textContent = host;
|
||||||
|
var select = item.querySelector("#perms-type-select");
|
||||||
|
select.value = type;
|
||||||
|
if (type != 0) item.querySelector("#perms-type").textContent = select[select.selectedIndex].text;
|
||||||
|
list.insertBefore(item, inputitem);
|
||||||
|
if (scroll) scrollToBottom(inputitem);
|
||||||
|
};
|
||||||
|
|
||||||
|
function scrollToBottom(node)
|
||||||
|
{
|
||||||
|
if (node.clientHeight < node.scrollHeight)
|
||||||
|
return node.scrollTop = node.scrollHeight - node.clientHeight;
|
||||||
|
if (node.parentNode) scrollToBottom(node.parentNode);
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleMousedown(e)
|
||||||
|
{
|
||||||
|
var target = e.target;
|
||||||
|
var item = target.closest("[role=listitem]");
|
||||||
|
if (target.classList.contains("row-delete-button")) return;
|
||||||
|
if (target.id == "perms-host") {
|
||||||
|
var x = e.clientX, y = e.clientY, offset = document.caretPositionFromPoint ?
|
||||||
|
document.caretPositionFromPoint(x, y).offset : document.caretRangeFromPoint(x, y).startOffset;
|
||||||
|
var input = item.querySelector("#perms-host-input");
|
||||||
|
var inside = x < inputitem.querySelector("#perms-host-input").getBoundingClientRect().right;
|
||||||
|
input.selectionStart = input.selectionEnd = inside ? 0 : input.value.length;
|
||||||
|
setTimeout(function() { input.selectionStart = input.selectionEnd = offset; }, 25);
|
||||||
|
}
|
||||||
|
if (item && !target.hasAttribute("tabindex") && !item.hasAttribute("editing")) {
|
||||||
|
item.querySelector("[id^=perms-host]").focus();
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleSelection(item)
|
||||||
|
{
|
||||||
|
if (selected && item != selected) {
|
||||||
|
selected.removeAttribute("lead");
|
||||||
|
selected.removeAttribute("editing");
|
||||||
|
if (item) selected.removeAttribute("selected");
|
||||||
|
if (selected == inputitem) handleInput(!item);
|
||||||
|
selected.querySelectorAll("[id^=perms]").forEach(function(a) { a.tabIndex = item ? -1 : 0; });
|
||||||
|
}
|
||||||
|
if (item && !item.hasAttribute("editing")) {
|
||||||
|
item.setAttribute("selected", "selected");
|
||||||
|
item.setAttribute("lead", "lead");
|
||||||
|
item.setAttribute("editing", "");
|
||||||
|
item.querySelectorAll("[id^=perms]")
|
||||||
|
.forEach(function(a) { a.tabIndex = a.getAttribute("displaymode") == "static" ? -1 : 0; });
|
||||||
|
selected = item;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleClick(e)
|
||||||
|
{
|
||||||
|
var target = e.target;
|
||||||
|
if (target.classList.contains("row-delete-button")) {
|
||||||
|
var item = target.closest("[role=listitem]");
|
||||||
|
if (item == selected) handleSelection(inputitem);
|
||||||
|
item.remove();
|
||||||
|
list.focus({preventScroll: true});
|
||||||
|
fireDirty(true);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleKeyDown(e)
|
||||||
|
{
|
||||||
|
if (selected && selected != inputitem && e.target.id != "perms-host-input" && e.keyCode == 46)
|
||||||
|
selected.querySelector(".row-delete-button").click();
|
||||||
|
if (selected && e.key == "Enter") selected == inputitem ? handleInput(true) : list.focus({preventScroll: true});
|
||||||
|
if (selected && e.key == "ArrowUp" && e.target.id != "perms-type-select" && selected != list.querySelector("[role=listitem]"))
|
||||||
|
selected.previousSibling.querySelector("[id^=perms-host]").focus();
|
||||||
|
if (selected && e.key == "ArrowDown" && e.target.id != "perms-type-select" && selected != inputitem)
|
||||||
|
selected.nextSibling.querySelector("[id^=perms-host]").focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleChange(e)
|
||||||
|
{
|
||||||
|
var target = e.target;
|
||||||
|
var item = target.closest("[role=listitem]");
|
||||||
|
if (item != inputitem) {
|
||||||
|
if (target.id == "perms-type-select") {
|
||||||
|
item.querySelector("#perms-type").textContent =
|
||||||
|
target.value != 0 ? target[target.selectedIndex].text : "";
|
||||||
|
fireDirty(true);
|
||||||
|
}
|
||||||
|
if (target.id == "perms-host-input"){
|
||||||
|
try {
|
||||||
|
var url = new URL(target.value);
|
||||||
|
target.value = url.origin;
|
||||||
|
item.querySelector("#perms-host").textContent = target.value;
|
||||||
|
fireDirty(true);
|
||||||
|
}
|
||||||
|
catch (e) { target.value = item.querySelector("#perms-host").textContent; };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleInput(scroll)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
var target = inputitem.querySelector("#perms-host-input")
|
||||||
|
var url = new URL(target.value);
|
||||||
|
target.value = url.origin;
|
||||||
|
appendItem(target.value, inputitem.querySelector("#perms-type-select").value, scroll);
|
||||||
|
target.value = null;
|
||||||
|
fireDirty(true);
|
||||||
|
}
|
||||||
|
catch (e) {};
|
||||||
|
};
|
||||||
|
|
||||||
|
function fireDirty(d) { dirty = d; for (var listener of listeners) listener(d); };
|
||||||
|
};
|
||||||
|
|
||||||
|
// </>
|
94
AutoplayStopper/popup.js
Normal file
94
AutoplayStopper/popup.js
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const Popup = new function(){
|
||||||
|
|
||||||
|
const start = Date.now();
|
||||||
|
const {i18n, storage, permissions: perms, openOptionsPage} = chrome.extension.getBackgroundPage().Background;
|
||||||
|
|
||||||
|
while (Date.now() - start < 50);
|
||||||
|
setTimeout(function() {
|
||||||
|
while (Date.now() - start < 150);
|
||||||
|
addEventListener("unload", function() {
|
||||||
|
if (Date.now() - start < 250) {
|
||||||
|
storage.data.disabled = !storage.data.disabled;
|
||||||
|
storage.commit(["disabled"]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const permsAutoplayKey = perms.key("autoplay");
|
||||||
|
const permsFlashKey = perms.key("flash");
|
||||||
|
|
||||||
|
var url = null;
|
||||||
|
var ready = new Promise( function(resolve) {
|
||||||
|
chrome.tabs.query({ active: true, currentWindow: true}, function(tabs) {
|
||||||
|
url = new URL(tabs[0].url);
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
addEventListener("load", function() { ready.then(init); });
|
||||||
|
|
||||||
|
function init()
|
||||||
|
{
|
||||||
|
i18n.process(document);
|
||||||
|
var permission = perms.testPermission("autoplay", url);
|
||||||
|
var permissionFlash = perms.testPermission("flash", url);
|
||||||
|
initItem( document.getElementById("allow_site"), !!permission.origin && permission != perms.ACCESS_SESSION && permission, [url.origin]);
|
||||||
|
initItem( document.getElementById("allow_session"), !!permission.origin && permission == perms.ACCESS_SESSION, [url.origin]);
|
||||||
|
initItem( document.getElementById("disable_site"), !!permissionFlash.origin && permissionFlash, [url.origin]);
|
||||||
|
initItem( document.getElementById("allow_all"), storage.data.disabled);
|
||||||
|
initItem( document.getElementById("settings"));
|
||||||
|
document.getElementById("popupmenu")
|
||||||
|
.classList.toggle("restricted", url.protocol.search("^http") == -1 || !!storage.data.disabled);
|
||||||
|
|
||||||
|
window.onclick = function(e) {
|
||||||
|
|
||||||
|
switch (e.target.id) {
|
||||||
|
case "settings":
|
||||||
|
openOptionsPage();
|
||||||
|
close();
|
||||||
|
break;
|
||||||
|
case "allow_site":
|
||||||
|
if ( [undefined, perms.UNKNOWN_ACTION].indexOf(perms.get("autoplay", url)) != -1
|
||||||
|
&& permission != perms.default("autoplay")) { openOptionsPage("#autoplay"); close(); break; };
|
||||||
|
perms.set("autoplay", url, (permission == perms.ALLOW_ACTION) ? perms.DENY_ACTION : perms.ALLOW_ACTION);
|
||||||
|
storage.commit([permsAutoplayKey]);
|
||||||
|
init();
|
||||||
|
break;
|
||||||
|
case "allow_session":
|
||||||
|
if ( [undefined, perms.UNKNOWN_ACTION].indexOf(perms.get("autoplay", url)) != -1
|
||||||
|
&& permission != perms.default("autoplay")) { openOptionsPage("#autoplay"); close(); break; };
|
||||||
|
(permission == perms.ACCESS_SESSION) ? perms.remove("autoplay", url) :
|
||||||
|
perms.set("autoplay", url, perms.ACCESS_SESSION);
|
||||||
|
storage.commit([permsAutoplayKey]);
|
||||||
|
init();
|
||||||
|
break;
|
||||||
|
case "disable_site":
|
||||||
|
if ( [undefined, perms.UNKNOWN_ACTION].indexOf(perms.get("flash", url)) != -1
|
||||||
|
&& permissionFlash != perms.default("flash")) { openOptionsPage("#flash"); close(); break; };
|
||||||
|
perms.set("flash", url, (permissionFlash == perms.ALLOW_ACTION) ? perms.DENY_ACTION : perms.ALLOW_ACTION);
|
||||||
|
storage.commit([permsFlashKey]);
|
||||||
|
init();
|
||||||
|
break;
|
||||||
|
case "allow_all":
|
||||||
|
storage.data.disabled = !storage.data.disabled;
|
||||||
|
storage.commit(["disabled"]);
|
||||||
|
init();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function initItem(item, check, args)
|
||||||
|
{
|
||||||
|
if (check !== undefined) check ? item.setAttribute("checked", check) : item.removeAttribute("checked");
|
||||||
|
if (args) { var i = 0; item.textContent = item.textContent.replace(/%S/g, function () { return args[i++]; }); };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//</>
|
289
AutoplayStopper/script/handler.js
Normal file
289
AutoplayStopper/script/handler.js
Normal file
|
@ -0,0 +1,289 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function registerHandlers(handlers, TRACE, isHandlingUserInput, setHandlingUserInput, lastUserInput, data = {})
|
||||||
|
{
|
||||||
|
var dummyid = Math.floor(Math.random() * 100);
|
||||||
|
|
||||||
|
function testUserInput(el, delay)
|
||||||
|
{
|
||||||
|
var win = el.ownerDocument.defaultView, _last = lastUserInput(win), e = _last && _last.e;
|
||||||
|
if (!e || Date.now() - _last.time > delay) return false;
|
||||||
|
var px = e.pageX - win.scrollX, py = win.scrollY ? e.pageY - win.scrollY : e.clientY, r = el.getBoundingClientRect(), {width ,height} = r;
|
||||||
|
for (var i = 0; i < 5 && el.parentNode && (r.top + win.scrollY < 0 || r.left + win.scrollX < 0 || r.width < 10 || r.height < 10); i++) r = (el = el.parentNode).getBoundingClientRect();
|
||||||
|
r.width = Math.max(r.width, width), r.height = Math.max(r.height, height);
|
||||||
|
return px >= r.left && px <= r.right && py >= r.top && py <= r.bottom;
|
||||||
|
};
|
||||||
|
// htmlmedia
|
||||||
|
handlers.add(function handleHtmlMedia(aElement){
|
||||||
|
|
||||||
|
const simEvents = {play: 0, playing: 50, pause: 350}, eventTypes = Object.keys(simEvents), props = ["preload","autoplay","poster","setAttribute","removeAttribute"];
|
||||||
|
const document = aElement.ownerDocument, window = document.defaultView;
|
||||||
|
if (aElement.localName == "video" || aElement.localName == "audio")
|
||||||
|
{
|
||||||
|
aElement.id || (aElement.id = "dummyid" + (++dummyid % 100));
|
||||||
|
TRACE('handleElement html5 media - tag: %s id: %s autoplay: %s preload: "%s" poster: %s paused: %s')(aElement.localName, aElement.id, aElement.autoplay, aElement.preload, !!aElement.poster, aElement.paused);
|
||||||
|
if (aElement.wrappedJSObject.play !== window.wrappedJSObject.HTMLMediaElement.prototype.play) TRACE('handleElement html5 media - %s.play() != HTMLMediaElement.play !!!')(aElement.id);
|
||||||
|
// Yendifplayer .autoplay = 1 => ...
|
||||||
|
var autoplay = aElement.autoplay || !aElement.paused, count = 0, released = false;
|
||||||
|
Object.defineProperties(aElement.wrappedJSObject, { preload: {configurable: true, set: (a) => TRACE('%s.preload = "%s"')(aElement.id, a)/* || (aElement.preload = "metadata")*/, get: () => aElement.preload}
|
||||||
|
, autoplay: {configurable: true, set: (a) => TRACE("%s.autoplay = %s")(aElement.id, a) || (a && aElement.wrappedJSObject.play()), get: () => aElement.autoplay}});
|
||||||
|
aElement.wrappedJSObject.setAttribute = (a, b) => (props.indexOf(a) != -1) ? TRACE("%s.setAttribute(%s, %s)")(aElement.id, a, b) || (aElement.wrappedJSObject[a] = b): aElement.setAttribute(a, b);
|
||||||
|
aElement.wrappedJSObject.removeAttribute = (a) => (props.indexOf(a) != -1) ? TRACE("%s.removeAttribute(%s)")(aElement.id, a) : aElement.removeAttribute(a);
|
||||||
|
|
||||||
|
function simPlay(e) {
|
||||||
|
e && aElement.removeEventListener(e.type, simPlay);
|
||||||
|
if (aElement.simPlay !== false && aElement.paused)
|
||||||
|
eventTypes.forEach((key) => window.setTimeout(() => !released && (TRACE("simPlay - %s.%s")(aElement.id, key) || aElement.dispatchEvent(new window.Event(key))), simEvents[key]));
|
||||||
|
};
|
||||||
|
|
||||||
|
aElement.wrappedJSObject.play = () => {
|
||||||
|
var force = aElement.allowPlay || testUserInput(aElement, 5000);
|
||||||
|
var userInput = isHandlingUserInput(window);
|
||||||
|
TRACE("%s.play(%s) - force: %s state: %s user: %s")(aElement.id, count, !!force, aElement.readyState, userInput);
|
||||||
|
if (!userInput && !force) {
|
||||||
|
count++ == 0 && (aElement.preload = "metadata") && (aElement.simPlay || aElement.readyState >= 2 ? simPlay() : aElement.addEventListener("loadeddata", simPlay));
|
||||||
|
return count < 5 ? Promise.reject(new window.DOMException("The play method is not allowed by the user agent.", "NotAllowedError")) : simPlay() || Promise.resolve();
|
||||||
|
}
|
||||||
|
released = !data.strict && delete aElement.wrappedJSObject.play; // jwplayer: zapiks.fr rottentomatoes baeblemusic
|
||||||
|
force && !userInput && setHandlingUserInput(window);
|
||||||
|
return aElement.play();
|
||||||
|
};
|
||||||
|
window.wrappedJSObject.Object.defineProperty(aElement.wrappedJSObject.play, "toString", window.Object.assign(window.Object(), {value: () => "[native code]"}));
|
||||||
|
aElement.autoplay = false;
|
||||||
|
aElement.preload != "none" && (aElement.preload = "metadata"); // mediaelement.js
|
||||||
|
!data.strict && aElement.addEventListener("play", function cleanup(e){ e.isTrusted && !aElement.paused && (aElement.removeEventListener("play", cleanup), aElement.muted = false,
|
||||||
|
TRACE("%s cleanup...")(aElement.id), props.forEach((prop) => delete aElement.wrappedJSObject[prop]), delete aElement.wrappedJSObject.play)});
|
||||||
|
autoplay && aElement.wrappedJSObject.play(); // flowplayer
|
||||||
|
!aElement.paused ? !released && aElement.pause() : window.setTimeout(() => !released && aElement.pause(), 0); // dbtv.no html5box
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// simplay
|
||||||
|
const hosts = [{host: "cnn.com$", val: true}, {host: "twitch.tv$"}, {host: "yastatic.net$"},
|
||||||
|
{host: "bbc.(com|co.uk)$"}, {host: "(yahoo|yimg).com$", class: "html5-video", val: true}, {class: "\\b(video-js|vjs-tech)\\b"}];
|
||||||
|
handlers.add(function handleSimplay(aElement){
|
||||||
|
if (aElement.localName == "video")
|
||||||
|
for (var a of hosts) if (aElement.ownerDocument.location.hostname.match(a.host) && aElement.className.match(a.class)) aElement.simPlay = !!a.val;
|
||||||
|
});
|
||||||
|
// YouTube
|
||||||
|
handlers.add(function handleYouTube(aElement){
|
||||||
|
|
||||||
|
const document = aElement.ownerDocument, window = document.defaultView, jsWin = window.wrappedJSObject;
|
||||||
|
if (document.location.hostname.search("\.youtube(-nocookie)?\.com$") != -1)
|
||||||
|
{
|
||||||
|
TRACE("handleElement ytplayer - tag: %s player: %s")(aElement.localName, aElement.id);
|
||||||
|
if (document.location.search.search("feature=youtube-anywhere-player") == -1)
|
||||||
|
{
|
||||||
|
function stopPlayer(ytplayer){
|
||||||
|
if (testUserInput(ytplayer, 5000)) return !TRACE("ytplayer released...")();
|
||||||
|
var vid = ytplayer.getVideoData && ytplayer.getVideoData().video_id;
|
||||||
|
TRACE("ytplayer stopPlayer(%s) - videoId: %s t: %s")(ytplayer.id || "", vid, ytplayer.getCurrentTime());
|
||||||
|
ytplayer.cueVideoById(vid, ytplayer.getCurrentTime());
|
||||||
|
var nop = false, _seekTo = ytplayer.seekTo, _playVideo = ytplayer.playVideo;
|
||||||
|
ytplayer.playVideo = function doNothing() { nop || (nop = testUserInput(ytplayer, 1000)) ? _playVideo.apply(this) : TRACE("@@@@@@ ytplayer doNothing @@@@@")()};
|
||||||
|
ytplayer.seekTo = function seekTo(tm) { nop || (nop = testUserInput(ytplayer, 1000)) ? _seekTo.apply(this, arguments) : ytplayer.cueVideoById(vid, tm), TRACE("ytplayer seekTo(%s)")(tm); };
|
||||||
|
function onstate(a) { if (a == 1) { nop = true; ytplayer.playVideo = _playVideo; ytplayer.seekTo = _seekTo; TRACE("ytplayer - removed doNothing")(); ytplayer.removeEventListener("onStateChange", onstate); }};
|
||||||
|
ytplayer.addEventListener("onStateChange", onstate);
|
||||||
|
}
|
||||||
|
if (aElement.localName == "video" && aElement.parentNode.classList.contains("html5-video-container")) {
|
||||||
|
if (!data.strict && aElement.parentNode.parentNode.id == "movie_player")
|
||||||
|
window.setTimeout(() => aElement.allowPlay = true, document.location.search.search("feature=youtube-anywhere-player") == -1 ? 5000 : 0);
|
||||||
|
aElement.simPlay = false;
|
||||||
|
if (aElement.parentNode.parentNode.classList.contains("html5-video-player"))
|
||||||
|
window.setTimeout(() => stopPlayer(aElement.wrappedJSObject.parentNode.parentNode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// googleads
|
||||||
|
handlers.add(function handleGoogleAds(aElement){
|
||||||
|
const document = aElement.ownerDocument, window = document.defaultView;
|
||||||
|
var host = aElement.getRootNode().host;
|
||||||
|
if (host && host.localName == "lima-video") {
|
||||||
|
TRACE("handleElement googleads - tag: %s")(aElement.localName);
|
||||||
|
window.addEventListener("visibilitychange", (e) => e.stopPropagation(), true);
|
||||||
|
aElement.wrappedJSObject.addEventListener("play", function(){ if (!testUserInput(this, 100)) this.pause()}, {once: true});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// ifunny.co
|
||||||
|
handlers.add(function handleIFunny(aElement){
|
||||||
|
const document = aElement.ownerDocument, window = document.defaultView;
|
||||||
|
if (document.location.hostname.match("ifunny.co$") && aElement.paused) {
|
||||||
|
(isHandlingUserInput(window) || testUserInput(aElement.parentNode, 1000)) ? aElement.play() : aElement.src = "";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// msn.com
|
||||||
|
handlers.add(function handleMsn(aElement){
|
||||||
|
|
||||||
|
const document = aElement.ownerDocument, window = document.defaultView, jsWin = window.wrappedJSObject;
|
||||||
|
if (document.location.hostname.search(/\.msn\.com$/) != -1)
|
||||||
|
{
|
||||||
|
var obj = aElement.wrappedJSObject;
|
||||||
|
if (aElement.className.indexOf("vxFlashPlayer") != -1 && aElement.localName == "embed"){
|
||||||
|
obj.MsnVideoCallback = function(msg) { msg == "playVideo" ? delete obj.MsnVideoCallback : obj.__proto__.MsnVideoCallback.apply(obj, arguments)};
|
||||||
|
var flashvars = (aElement.getAttribute("flashvars") || "").replace(/(&ap=)true/gi, "$1false")
|
||||||
|
aElement.setAttribute("flashvars", flashvars);
|
||||||
|
TRACE("handleElement msnplayer - tag: %s id: %s ")(aElement.localName, aElement.id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// BBC
|
||||||
|
handlers.add(function handleBBC(aElement){
|
||||||
|
|
||||||
|
const document = aElement.ownerDocument, window = document.defaultView, jsWin = window.wrappedJSObject;
|
||||||
|
if (jsWin.embeddedMedia && jsWin.embeddedMedia.players)
|
||||||
|
for (var player of jsWin.embeddedMedia.players || []) if (player._swf && player._swf.id == aElement.id) {
|
||||||
|
TRACE("handleElement BBC - embeddedMedia.players id: %s autoplay: %s")(player._swf.id, player._settings.autoplay);
|
||||||
|
Object.defineProperty(player._settings, "autoplay", {get: () => false});
|
||||||
|
player.setData = (info) => ( info.data && (info.data.autoPlayFirstItem = false), player.__proto__.setData.call(player, info));
|
||||||
|
window.setTimeout(function(){ player._settings.autoplay = true; handlers.remove(window, handleBBC); }, 2500);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// metacafe
|
||||||
|
handlers.add(function handleMetacafe(aElement){
|
||||||
|
|
||||||
|
if (aElement.localName == "object" && (aElement.data || "").search(/s.mcstatic.com\/Flash\/.*\.swf/) != -1)
|
||||||
|
{
|
||||||
|
var param = aElement.querySelector("#" + aElement.id + ">param[name=flashvars]");
|
||||||
|
param.value = param.value.replace(/&beacons=.*(?=&)/,"");
|
||||||
|
var id = param.value.match(/itemID=([^&]*)(?=&)/)[1];
|
||||||
|
var data = aElement.data;
|
||||||
|
aElement.data = "http://www.metacafe.com/fplayer/" + id + "/.swf";
|
||||||
|
function onClick(aEvent){
|
||||||
|
aEvent.stopImmediatePropagation();
|
||||||
|
aElement.removeEventListener(aEvent.type, onClick, true);
|
||||||
|
aElement.data = data;
|
||||||
|
}
|
||||||
|
aElement.addEventListener("mouseup", onClick, true);
|
||||||
|
TRACE("handleElement metacafe - data: %s")(aElement.data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// jwplayer
|
||||||
|
handlers.add(function handleJWPlayer(aElement){ // return;
|
||||||
|
|
||||||
|
const document = aElement.ownerDocument, window = document.defaultView, jsWin = window.wrappedJSObject;
|
||||||
|
aElement.id || (aElement.id = "dummyid" + (++dummyid % 100));
|
||||||
|
if (jsWin.jwplayer && !aElement.querySelector("[id='" + aElement.id + "']>param[name=flashvars]"))
|
||||||
|
{
|
||||||
|
if (testUserInput(aElement, 5000)) return !TRACE("jwplayer released...")();
|
||||||
|
function closest(node, selector) { while(node && !node.matches(selector)) node = node.parentElement; return node};
|
||||||
|
var res, ar, player = jsWin.jwplayer(aElement).config ?
|
||||||
|
jsWin.jwplayer(aElement) : (res = closest(aElement, ".jwplayer")) ? jsWin.jwplayer(res) : null;
|
||||||
|
|
||||||
|
if (player && (player.config || (player.config = player.getConfig())) && player.config.autostart != false)
|
||||||
|
{
|
||||||
|
TRACE("handleElement jwplayer setup - id: %s autostart: %s")(player.id, player.config.autostart);
|
||||||
|
|
||||||
|
player.config.autoStart = player.config.autostart = false;
|
||||||
|
(ar = player.config.aspectratio) && ar.indexOf("%") != -1 && (player.config.aspectratio = "100:" + ar.slice(0,-1));
|
||||||
|
aElement.localName == "video" && window.setTimeout(() => aElement.src = "");
|
||||||
|
player.setup(player.config);
|
||||||
|
}
|
||||||
|
TRACE("handleElement jwplayer - id: %s config: %s")((player && player.id), !!(player && player.config));
|
||||||
|
return player && player.config;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// flowplayer
|
||||||
|
handlers.add(function handleFlowplayer(aElement){ //return;
|
||||||
|
|
||||||
|
aElement.id || (aElement.id = "dummyid" + (++dummyid % 100));
|
||||||
|
var param = aElement.querySelector("[id='" + aElement.id + "']>param[name=flashvars]")
|
||||||
|
var config, flashvars = param ? param.value : aElement.getAttribute("flashvars");
|
||||||
|
if (flashvars && flashvars.search(/^config={/) != -1)
|
||||||
|
if ((config = JSON.parse(flashvars.slice(7).replace(/'/g,'"').replace(/("autoPlay":)true/g,"$1false"))) && (config.playlist || config.clip))
|
||||||
|
{
|
||||||
|
var playlist = (config.playlist = (config.playlist || [config.clip]));
|
||||||
|
(typeof playlist[0] == 'string') && (playlist[0] = {url: playlist[0]});
|
||||||
|
playlist[0].autoPlay = (typeof playlist[0].url == 'string' && playlist[0].url.search(/(.png|.jpg)/) != -1);
|
||||||
|
(playlist[0].autoBuffering && (playlist[0].autoBuffering = false)) || (playlist[0].autoPlay && playlist[1] && (playlist[1].autoPlay = false));
|
||||||
|
flashvars = "config=" + JSON.stringify(config);
|
||||||
|
param ? param.value = flashvars : aElement.setAttribute("flashvars", flashvars);
|
||||||
|
if (aElement.data) aElement.data = aElement.data;
|
||||||
|
TRACE("handleElement flowplayer - id: %s flashvars: %s")(aElement.id, flashvars);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// aol
|
||||||
|
handlers.add(function handleAol(aElement){
|
||||||
|
|
||||||
|
if (aElement.localName == "object" && (aElement.data || "").search(/cdn(-ssl)?.vidible.tv\/.*\.swf/) != -1)
|
||||||
|
{
|
||||||
|
aElement.id || (aElement.id = "dummyid" + (++dummyid % 100));
|
||||||
|
var param = aElement.querySelector("[id='" + aElement.id + "']>param[name=flashvars]");
|
||||||
|
if (param)
|
||||||
|
{
|
||||||
|
param.value = param.value.replace(/(initialization%22%3A%22)autoplay/, "$1click");
|
||||||
|
aElement.wrappedJSObject.doPlay = function() { TRACE("doNothing - doPlay")()};
|
||||||
|
aElement.ownerDocument.defaultView.setTimeout(() => {delete aElement.wrappedJSObject.doPlay; TRACE("handleElement aol - removed doPlay")()}, 5000);
|
||||||
|
return !TRACE("handleElement aol - data: %s")(aElement.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// general
|
||||||
|
var colValues = {"true":"false", "1":"0", "yes":"no", "on":"off", "y":"n", "Y":"N"}
|
||||||
|
function replace(match,p0,p1,p2) {
|
||||||
|
var res = p0 + (!p1 && p2 && colValues[p2] ? colValues[p2] : !!p1);
|
||||||
|
TRACE(">>> handleElement replace - match: %s p0: %s p1: %s p2: %s res: %s <<<")(match, p0, p1, p2, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
function modifyParams(str) { return (str || "").replace(/((no)?auto_?(?:play|start|run)\w*(?:["']?\s?[=:]\s?["']?|%22%3A(?!\W)))(true|1|yes|y|on|null|)(?=\W|$)/gi, replace)};
|
||||||
|
|
||||||
|
function handleGeneral(aElement){
|
||||||
|
|
||||||
|
if (aElement.localName != "object" && aElement.localName != "embed")
|
||||||
|
return;
|
||||||
|
|
||||||
|
var data = modifyParams(aElement.getAttribute("data"));
|
||||||
|
if (data != aElement.getAttribute("data") && data != "")
|
||||||
|
{
|
||||||
|
aElement.setAttribute("data", data);
|
||||||
|
TRACE("handleElement - %s.data: %s")(aElement.localName, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
var flashvars = modifyParams(aElement.getAttribute("flashvars")); // cnn | (remove) neulion nhl embed
|
||||||
|
if (aElement.localName == "embed" )
|
||||||
|
{
|
||||||
|
aElement.setAttribute("menu","true");
|
||||||
|
|
||||||
|
if (flashvars == aElement.getAttribute("flashvars") || flashvars == "" )
|
||||||
|
{
|
||||||
|
flashvars += "&autoplay=false&autostart=false&autoPlay=0"; // youtube(autoplay) | ustream live
|
||||||
|
aElement.setAttribute("play","false"); // basic flash
|
||||||
|
}
|
||||||
|
aElement.setAttribute("flashvars", flashvars);
|
||||||
|
if (aElement.src)
|
||||||
|
{
|
||||||
|
var src = modifyParams(aElement.src); // embed dailymotion
|
||||||
|
if (src != aElement.src) {
|
||||||
|
aElement.src = src;
|
||||||
|
var parent = aElement.parentNode, next = aElement.nextSibling; // workaround for chrome embed.src =
|
||||||
|
if (aElement.src && parent) { aElement.remove(); parent.insertBefore(aElement.wrappedJSObject, next); };
|
||||||
|
TRACE("handleElement embed.src: %s")(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aElement.id || (aElement.id = "dummyid" + (++dummyid % 100)); // [id =''] works with numeric ids!!!
|
||||||
|
var param = aElement.querySelector("[id='" + aElement.id + "']>param[name=flashvars], [id='" + aElement.id + "']>param[name=FlashVars], [id='" + aElement.id + "']>param[name=flashVars]");
|
||||||
|
if (param)
|
||||||
|
{
|
||||||
|
flashvars = modifyParams(param.value); // ustream(autoplay=false) | bbc / metacafe.embed(no) / tv.com(vid)
|
||||||
|
if (flashvars == param.value) {
|
||||||
|
if (flashvars.search(/auto(_?play(vid)?|start|run)["']?\s?[=:]/i) != -1) return; // false already exists...
|
||||||
|
flashvars += "&autoplay=false&autoPlay=0&autoStart=0&_autoPlay=no&auto_start=off"; // justin.tv(autoPlay=0)|nba.com(autostart)|espn(!autoplay)|discovery(_autoPlay=no)|56.com(auto_start)
|
||||||
|
}
|
||||||
|
param.value = flashvars;
|
||||||
|
if (aElement.data) aElement.data = aElement.data;
|
||||||
|
}
|
||||||
|
(param = aElement.querySelector("[id='" + aElement.id + "']>param[name=play]")) && (param.value = false);
|
||||||
|
if (param && aElement.data) aElement.data = aElement.data;
|
||||||
|
TRACE("handleElement - id: %s %s.flashvars: %s")(aElement.id, aElement.localName, flashvars);
|
||||||
|
};
|
||||||
|
|
||||||
|
handlers.add(handleGeneral);
|
||||||
|
};
|
24
AutoplayStopper/script/selector.css
Normal file
24
AutoplayStopper/script/selector.css
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
object[classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"]:not([flashstopped]),
|
||||||
|
object[classid*=":d27cdb6e-ae6d-11cf-96b8-444553540000"]:not([flashstopped]),
|
||||||
|
object[codebase*="swflash.cab"]:not([flashstopped]),
|
||||||
|
object[data*=".swf"]:not([flashstopped]),
|
||||||
|
object[type="application/x-shockwave-flash"]:not([flashstopped]),
|
||||||
|
object[src*=".swf"]:not([flashstopped]),
|
||||||
|
embed[type="application/x-shockwave-flash"]:not([flashstopped]),
|
||||||
|
embed[src*=".swf"]:not([flashstopped]),
|
||||||
|
embed[allowscriptaccess]:not([flashstopped]),
|
||||||
|
embed[flashvars]:not([flashstopped]),
|
||||||
|
embed[wmode]:not([flashstopped]),
|
||||||
|
lima-video:not([flashstopped]),
|
||||||
|
/*--------- !(html5media) ---------*/
|
||||||
|
*:not([flashstopped_p]) > video,
|
||||||
|
video:not([flashstopped]),
|
||||||
|
audio:not([flashstopped]) {
|
||||||
|
border: 5px red solid !important;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
*[flashstopped] {
|
||||||
|
border: 3px blue solid !important;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
9
AutoplayStopper/script/userhandler.js
Normal file
9
AutoplayStopper/script/userhandler.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
// userhandler.js - handler that doesn't get overwritten by new versions
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function registerUserHandlers(handlers, TRACE)
|
||||||
|
{
|
||||||
|
// add your handlers here...
|
||||||
|
};
|
BIN
AutoplayStopper/skin/IDR_CLOSE_DIALOG
Normal file
BIN
AutoplayStopper/skin/IDR_CLOSE_DIALOG
Normal file
Binary file not shown.
After Width: | Height: | Size: 139 B |
BIN
AutoplayStopper/skin/IDR_CLOSE_DIALOG_H
Normal file
BIN
AutoplayStopper/skin/IDR_CLOSE_DIALOG_H
Normal file
Binary file not shown.
After Width: | Height: | Size: 214 B |
1
AutoplayStopper/skin/arrow_down.svg
Normal file
1
AutoplayStopper/skin/arrow_down.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="12px" viewBox="0 0 24 12" fill="#757575"><g><path d="M 0 0 L 24 0 L 12 12 z"/></g></svg>
|
After Width: | Height: | Size: 150 B |
157
AutoplayStopper/skin/devtools.html
Normal file
157
AutoplayStopper/skin/devtools.html
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src="/utils.js"></script>
|
||||||
|
<script src="/devtools.js"></script>
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
body {
|
||||||
|
margin: 0.5% 10%;
|
||||||
|
font-family: "Segoe UI", Tahoma, sans-serif;
|
||||||
|
color: #4c4c4c;
|
||||||
|
}
|
||||||
|
|
||||||
|
label.settings-label {
|
||||||
|
min-width: 80px;
|
||||||
|
font-size: initial;
|
||||||
|
font-weight: lighter;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.settings-row {
|
||||||
|
margin: 6px 18px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.settings-checkbox {
|
||||||
|
align-self: flex-end;
|
||||||
|
-webkit-margin-start: 0px;
|
||||||
|
-webkit-margin-end: 10px;
|
||||||
|
margin-inline-start: 0px;
|
||||||
|
margin-inline-end: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
-webkit-margin-end: 3px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:disabled {
|
||||||
|
color: #a0a0a0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:not([disabled]) {
|
||||||
|
color: #4c4c4c;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.input {
|
||||||
|
min-width: 450px;
|
||||||
|
max-width: 85%;
|
||||||
|
border: 1px solid rgb(170, 170, 170);
|
||||||
|
padding: 1px 2px;
|
||||||
|
-webkit-appearance: textfield;
|
||||||
|
font-size: 13.3333px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 17px; /* fff */
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border-color: rgb(210, 210, 210);
|
||||||
|
border-top-width: 0px;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
margin-top: .9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-weight: 400;
|
||||||
|
margin-top: 15px; /* fff */
|
||||||
|
}
|
||||||
|
|
||||||
|
#splitter {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 0;
|
||||||
|
min-height: calc(40px + 6.5em);
|
||||||
|
max-height: calc(100vh - 10px);
|
||||||
|
margin-bottom: 1px;
|
||||||
|
resize: vertical;
|
||||||
|
background: linear-gradient(to right bottom, transparent 50%,
|
||||||
|
rgba(0, 0, 0, 0.1) 50%) 100% 100% / 16px 15px no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
#selector {
|
||||||
|
height: 100%;
|
||||||
|
width: 800px;
|
||||||
|
color: darkslateblue;
|
||||||
|
border: 1px solid rgb(170, 170, 170);
|
||||||
|
resize: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
:focus {
|
||||||
|
outline: rgb(170, 170, 170) auto 1px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="splitter">
|
||||||
|
<div class="settings-row" style="margin:0 0px;">
|
||||||
|
<img src="../icons/icon48.png" style="margin: 10px; height: 32px;" />
|
||||||
|
<h2>AutoplayStopper</h2>
|
||||||
|
<h2 id="ver" style="font-weight: 200; -webkit-margin-start: 10px; margin-inline-start: 10px;">1.0.0</h2>
|
||||||
|
</div>
|
||||||
|
<hr style="width: calc(100% - 2px); margin-top: 6px; margin-bottom: 0px"/>
|
||||||
|
<h2 i18n-content="selector">Selector</h2>
|
||||||
|
<div class="settings-row" style="height: 100%;">
|
||||||
|
<label class="settings-label" i18n-content="text" style="margin-bottom: auto;">Text</label>
|
||||||
|
<textarea id="selector" spellcheck="false"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="settings-row" style="margin-bottom: calc(.9em - 1px);">
|
||||||
|
<label class="settings-label" i18n-content="actions">Actions</label>
|
||||||
|
<button id="reset" i18n-content="reset">Reset</button>
|
||||||
|
<button id="apply" disabled="" i18n-content="apply"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr style="margin-top:0px"/>
|
||||||
|
<h2 i18n-content="script">Script</h2>
|
||||||
|
<div class="settings-row">
|
||||||
|
<label class="settings-label" i18n-content="path">Path:</label>
|
||||||
|
<span id="path-input" class="input" contenteditable="true" spellcheck="false"></span>
|
||||||
|
</div>
|
||||||
|
<div class="settings-row">
|
||||||
|
<label class="settings-label" i18n-content="actions">Actions:</label>
|
||||||
|
<button id="edit-button" i18n-content="edit">Edit</button>
|
||||||
|
<button id="load-button" i18n-content="load">Load</button>
|
||||||
|
<button id="export-button" i18n-content="export">Export...</button>
|
||||||
|
<button id="path-button" i18n-content="setPath" disabled>Set Path</button>
|
||||||
|
<button id="select-button" i18n-content="selectFile" >File...</button>
|
||||||
|
<label id="filename" class="settings-label" style="-webkit-margin-start:10px;margin-inline-start:10px;"/>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<h2 i18n-content="userScript">User Script</h2>
|
||||||
|
<div class="settings-row">
|
||||||
|
<label class="settings-label" i18n-content="path">Path:</label>
|
||||||
|
<span id="upath-input" class="input" contenteditable="true" spellcheck="false"></span>
|
||||||
|
</div>
|
||||||
|
<div class="settings-row">
|
||||||
|
<label class="settings-label" i18n-content="actions">Actions:</label>
|
||||||
|
<button id="uedit-button" i18n-content="edit">Edit</button>
|
||||||
|
<button id="uload-button" i18n-content="load">Load</button>
|
||||||
|
<button id="uexport-button" i18n-content="export">Export...</button>
|
||||||
|
<button id="upath-button" i18n-content="setPath" disabled>Set Path</button>
|
||||||
|
<button id="uselect-button" i18n-content="selectFile">File...</button>
|
||||||
|
<label id="ufilename" class="settings-label" style="-webkit-margin-start:10px;margin-inline-start:10px;"/>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div class="settings-row">
|
||||||
|
<input id="overwrite" class="settings-checkbox" type="checkbox" />
|
||||||
|
<label class="settings-label" i18n-content="overwrite">Disable overwrite on update</label>
|
||||||
|
</div>
|
||||||
|
<div class="settings-row">
|
||||||
|
<input id="debug" class="settings-checkbox" type="checkbox" />
|
||||||
|
<label class="settings-label" i18n-content="debug">Log debug info</label>
|
||||||
|
</div>
|
||||||
|
<a id="export-link" hidden="true"></a>
|
||||||
|
</body>
|
||||||
|
</html>
|
615
AutoplayStopper/skin/options.css
Normal file
615
AutoplayStopper/skin/options.css
Normal file
|
@ -0,0 +1,615 @@
|
||||||
|
|
||||||
|
/* chrome://resources/css/list.css */
|
||||||
|
|
||||||
|
list,
|
||||||
|
grid {
|
||||||
|
display: block;
|
||||||
|
outline: none;
|
||||||
|
overflow: auto;
|
||||||
|
position: relative; /* Make sure that item offsets are relative to the
|
||||||
|
list. */
|
||||||
|
}
|
||||||
|
|
||||||
|
list > *,
|
||||||
|
grid > * {
|
||||||
|
-webkit-user-select: none;
|
||||||
|
background-color: rgba(255, 255, 255, 0);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0); /* transparent white */
|
||||||
|
border-radius: 2px;
|
||||||
|
cursor: default;
|
||||||
|
line-height: 20px;
|
||||||
|
margin: -1px 0;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0 3px;
|
||||||
|
position: relative; /* to allow overlap */
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
|
||||||
|
list > * {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
grid > * {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
list > [lead],
|
||||||
|
grid > [lead] {
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
list:focus > [lead],
|
||||||
|
grid:focus > [lead] {
|
||||||
|
border-color: hsl(214, 91%, 65%);
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
list > [anchor],
|
||||||
|
grid > [anchor] {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
list:not([disabled]) > :hover,
|
||||||
|
grid:not([disabled]) > :hover {
|
||||||
|
background-color: hsl(214, 91%, 97%);
|
||||||
|
border-color: hsl(214, 91%, 85%);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
list > [selected],
|
||||||
|
grid > [selected] {
|
||||||
|
background-color: hsl(0, 0%, 90%);
|
||||||
|
background-image: -webkit-linear-gradient(rgba(255, 255, 255, 0.8),
|
||||||
|
rgba(255, 255, 255, 0));
|
||||||
|
border-color: hsl(0, 0%, 85%);
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
list:focus > [selected],
|
||||||
|
grid:focus > [selected] {
|
||||||
|
background-color: hsl(214, 91%, 89%);
|
||||||
|
border-color: hsl(214, 91%, 65%);
|
||||||
|
}
|
||||||
|
|
||||||
|
list:focus > [lead][selected],
|
||||||
|
list > [selected]:hover,
|
||||||
|
grid:focus > [lead][selected],
|
||||||
|
grid > [selected]:hover {
|
||||||
|
background-color: hsl(214, 91%, 87%);
|
||||||
|
border-color: hsl(214, 91%, 65%);
|
||||||
|
}
|
||||||
|
|
||||||
|
list > .spacer,
|
||||||
|
grid > .spacer {
|
||||||
|
border: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: block;
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
list :-webkit-any(
|
||||||
|
input[type='input'],
|
||||||
|
input[type='password'],
|
||||||
|
input[type='search'],
|
||||||
|
input[type='text'],
|
||||||
|
input[type='url']),
|
||||||
|
list :-webkit-any(
|
||||||
|
button,
|
||||||
|
input[type='button'],
|
||||||
|
input[type='submit'],
|
||||||
|
select):not(.custom-appearance) {
|
||||||
|
line-height: normal;
|
||||||
|
margin: 0;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
list input[type='text'] {
|
||||||
|
margin-left: -4px;
|
||||||
|
padding: 3px;
|
||||||
|
width: 190px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* chrome://resources/css/overlay.css */
|
||||||
|
|
||||||
|
[hidden] {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay {
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-box-pack: center;
|
||||||
|
-webkit-perspective: 1px;
|
||||||
|
-webkit-transition: 200ms opacity;
|
||||||
|
background-color: rgba(255, 255, 255, 0.75);
|
||||||
|
/* bottom: 50px; */
|
||||||
|
display: -webkit-box;
|
||||||
|
left: 0;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 20px;
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay.transparent .page {
|
||||||
|
transform: scale(0.99) translateY(-20px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.transparent {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay .page {
|
||||||
|
max-height: 335.5px;
|
||||||
|
/* display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
*/
|
||||||
|
-webkit-border-radius: 3px;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-transition: 200ms transform;
|
||||||
|
background: white;
|
||||||
|
box-shadow: 0 4px 23px 5px rgba(0, 0, 0, 0.2), 0 2px 6px rgba(0,0,0,0.15);
|
||||||
|
color: #333;
|
||||||
|
display: -webkit-box;
|
||||||
|
min-width: 400px;
|
||||||
|
padding: 0px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay .page .content-area {
|
||||||
|
-webkit-box-flex: 1;
|
||||||
|
overflow: auto;
|
||||||
|
overflow: overlay; /* auto */
|
||||||
|
padding: 0px 20px 0px; /* 0px 17px 6px */
|
||||||
|
position: relative;
|
||||||
|
min-height: 226px;
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay .page > .close-button {
|
||||||
|
background-image: url(IDR_CLOSE_DIALOG);
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
height: 14px;
|
||||||
|
position: absolute;
|
||||||
|
right: 7px;
|
||||||
|
top: 7px;
|
||||||
|
width: 14px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay .page > .close-button:hover {
|
||||||
|
background-image: url(IDR_CLOSE_DIALOG_H);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay .page > .close-button:focus:not(:hover) {
|
||||||
|
background-image: url(IDR_CLOSE_DIALOG_H);
|
||||||
|
filter: opacity(75%);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.settings-row {
|
||||||
|
margin: 2px 18px;
|
||||||
|
display: flex;
|
||||||
|
padding: 2px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
label.settings-label {
|
||||||
|
width: 130px;
|
||||||
|
display: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay .page h2 {
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* chrome://settings/contentExceptions#... */
|
||||||
|
|
||||||
|
body {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hbox {
|
||||||
|
-webkit-box-orient: horizontal;
|
||||||
|
display: -webkit-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vbox {
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
display: -webkit-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box-align-center {
|
||||||
|
-webkit-box-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stretch {
|
||||||
|
-webkit-box-flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.raw-button,
|
||||||
|
.raw-button:hover,
|
||||||
|
.raw-button:active {
|
||||||
|
background-color: transparent;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
border: none;
|
||||||
|
box-shadow: none !important;
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 0;
|
||||||
|
padding: 1px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page list {
|
||||||
|
/* Min height is a multiple of the list item height (32) */
|
||||||
|
box-sizing: content-box;
|
||||||
|
min-height: 192px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-list,
|
||||||
|
.settings-list-empty {
|
||||||
|
border: 1px solid #d9d9d9;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Editable List properties */
|
||||||
|
list > * {
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-webkit-transition: 150ms background-color;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0; /* TODO(dbeam): Is this necessary? */
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: -webkit-box;
|
||||||
|
height: 32px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
list > .spacer {
|
||||||
|
/* The above height rule should not apply to spacers. When redraw is called
|
||||||
|
on the list they will be given an explicit element height but this ensures
|
||||||
|
they have 0 height to begin with. */
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
list:not([disabled]) > :hover {
|
||||||
|
background-color: rgb(228, 236, 247);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note: If this becomes the list style for other WebUI pages these rules can be
|
||||||
|
* simplified (since they wont need to override other rules). */
|
||||||
|
|
||||||
|
list:not([has-element-focus]) > [selected],
|
||||||
|
list:not([has-element-focus]) > [lead][selected] {
|
||||||
|
background-color: #d0d0d0;
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
list[has-element-focus] > [selected],
|
||||||
|
list[has-element-focus] > [lead][selected],
|
||||||
|
list:not([has-element-focus]) > [selected]:hover,
|
||||||
|
list:not([has-element-focus]) > [selected][lead]:hover {
|
||||||
|
background-color: rgb(187, 206, 233);
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-list[has-element-focus] > [lead],
|
||||||
|
.settings-list[has-element-focus] > [lead][selected] {
|
||||||
|
border-bottom: 1px solid rgb(120, 146, 180);
|
||||||
|
border-top: 1px solid rgb(120, 146, 180);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-list[has-element-focus] > [lead]:nth-child(2),
|
||||||
|
.settings-list[has-element-focus] > [lead][selected]:nth-child(2) {
|
||||||
|
border-top: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-list[has-element-focus] > [lead]:nth-last-child(2),
|
||||||
|
.settings-list[has-element-focus] > [lead][selected]:nth-last-child(2) {
|
||||||
|
border-bottom: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-list[disabled] > [lead][selected],
|
||||||
|
.settings-list[disabled]:focus > [lead][selected] {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
list .deletable-item {
|
||||||
|
-webkit-box-align: center;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
list .deletable-item > :first-child {
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-webkit-box-flex: 1;
|
||||||
|
-webkit-padding-end: 5px;
|
||||||
|
-moz-padding-end: 5px;
|
||||||
|
display: -webkit-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
list .row-delete-button {
|
||||||
|
-webkit-transition: 150ms opacity;
|
||||||
|
background-color: transparent;
|
||||||
|
background-image:
|
||||||
|
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAAiElEQVR42r2RsQrDMAxEBRdl8SDcX8lQPGg1GBI6lvz/h7QyRRXV0qUULwfvwZ1tenw5PxToRPWMC52eA9+WDnlh3HFQ/xBQl86NFYJqeGflkiogrOvVlIFhqURFVho3x1moGAa3deMs+LS30CAhBN5nNxeT5hbJ1zwmji2k+aF6NENIPf/hs54f0sZFUVAMigAAAABJRU5ErkJggg==);
|
||||||
|
border: none;
|
||||||
|
display: block;
|
||||||
|
height: 16px;
|
||||||
|
opacity: 1;
|
||||||
|
width: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
list > *:not(:hover):not([selected]):not([lead]) .row-delete-button,
|
||||||
|
list:not([has-element-focus]) > *:not(:hover):not([selected])
|
||||||
|
.row-delete-button,
|
||||||
|
list[disabled] .row-delete-button,
|
||||||
|
list .row-delete-button[disabled] {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
list .row-delete-button:hover {
|
||||||
|
background-image:
|
||||||
|
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAAqUlEQVR4XqWRMQqEMBBF/1E8Ra6x6V3FRnS9QbCxtJg6Z7CzE9lTiIXXyUb3C8EULixDIMM8Zt4kcDfxM5A45U+cgeXnC1tREgkzAgob3hiq3CUHvGLG4FTQoSgxQGDrzN8WTLBGnx2IVDksen9GH7Z9hA5E6uxABMJyCHDMCEGHzugLQPPlBCBNGq+5YtpnGw1Bv+te15ypljTpVzdak5Opy+z+qf//zQ+Lg+07ay5KsgAAAABJRU5ErkJggg==) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
list .row-delete-button:active {
|
||||||
|
background-image:
|
||||||
|
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAAQklEQVR4AWP4TwBSTQGDHcMZIIYAKA9VwRkwtINJgyCaCTAlCBaKAoQ+hFmoCqBKENKkK8C0gpAjCXuTyICiQ2QBAPSwyG3ByZlCAAAAAElFTkSuQmCC)
|
||||||
|
,
|
||||||
|
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAA/ElEQVR4Xu3UsWrCUBiG4efGlIBoIMFbcnYolYJ3pg4iKGrGYFTRwaUFhYAekiDt0EG++X2W83N8/3J/DbwBMJJSsdQItcDY1VlCOImzq3Ed8OmicHASB3ns5KBw8VUNpDJrW7uAiJ3sbK1l0mqArpmFTUlQ5jYWZrrUAUSmT0SZm4qoA56JvVhs/5g3A7RLolA85A1ASOTye65NMxASK6syfxGITMzvMxG9CvRkliWwlOm9AsSOcitzU1NzK7mjuBkQvHtLK7iLBiB5PhttJSGpB8I8vM6kDuiHeUjoVwMfYR4SRtUAw1veIZzOjRhSBzCoyKFjgH/3K7+BHzg+Cgw0eSW3AAAAAElFTkSuQmCC)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
list .static-text {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
/* outline: none; bYO! inner rect on selection*/
|
||||||
|
}
|
||||||
|
|
||||||
|
list[type='text'][inlineeditable] input {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
list > :not([editing]) [displaymode='edit'] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
list > [editing] [displaymode='static'] {
|
||||||
|
/* Don't use display:none or visibility:hidden because we need to keep an
|
||||||
|
* element focusable.
|
||||||
|
* We shrink only height. We don't shrink width to avoid to change the size
|
||||||
|
* of containing boxes. */
|
||||||
|
border-bottom: 0 !important;
|
||||||
|
border-top: 0 !important;
|
||||||
|
height: 0 !important;
|
||||||
|
width: auto;
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
margin-top: 0 !important;
|
||||||
|
overflow: hidden;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
list > [editing] input:invalid {
|
||||||
|
background-color: pink;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* UI Controls */
|
||||||
|
|
||||||
|
/* LIST */ /* bYO! top level outline... */
|
||||||
|
.settings-list[has-element-focus]:after {
|
||||||
|
outline: 1px solid rgba(0, 128, 256, 0.5);
|
||||||
|
outline-offset: -1px;
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
right: 0px;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* chrome://settings/contentExceptions#... */
|
||||||
|
|
||||||
|
#content-settings-exceptions-area {
|
||||||
|
min-width: 540px;
|
||||||
|
width: 540px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.exception-pattern {
|
||||||
|
-webkit-box-flex: 1;
|
||||||
|
-webkit-margin-end: 10px;
|
||||||
|
-moz-margin-end: 10px;
|
||||||
|
-webkit-margin-start: 14px;
|
||||||
|
-moz-margin-start: 14px;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.exception-setting {
|
||||||
|
display: inline-block;
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
select.exception-setting {
|
||||||
|
vertical-align: middle;
|
||||||
|
-webkit-padding-start: 3px;
|
||||||
|
width: calc(120px + 4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overruled .exception-setting {
|
||||||
|
width: calc(120px - 24px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overruled .overruleable:focus {
|
||||||
|
outline:auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overruled .overruleable {
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
|
#exception-column-headers {
|
||||||
|
margin-left: 17px;
|
||||||
|
-webkit-margin-start: 17px;
|
||||||
|
display: -webkit-box;
|
||||||
|
margin-top: 10px; /* bYO! 6 lines on FF */
|
||||||
|
line-height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#exception-column-headers > div {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
#exception-pattern-column {
|
||||||
|
-webkit-box-flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.exception-value-column-header {
|
||||||
|
width: 145px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content-settings-exceptions-area list {
|
||||||
|
/*margin-bottom: 10px; bYO! keep list area consistent with scrolling */
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
/****** new ui compat... ******/
|
||||||
|
button:not(.custom-appearance) {
|
||||||
|
--google-blue-500: #528de0; /* #3b72ce #4285f4 #0a84ff */
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 100%; /* 154% */
|
||||||
|
padding: 8px 10px;
|
||||||
|
color: white !important;
|
||||||
|
border: 1px solid var(--google-blue-500);
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: none !important;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:enabled:not(.custom-appearance) {
|
||||||
|
background: var(--google-blue-500) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:enabled:not(.custom-appearance):focus {
|
||||||
|
background: rgb(58, 117, 215) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
--md-arrow-width: 0.9em;
|
||||||
|
--md-arrow-offset: 0%;
|
||||||
|
--md-select-side-padding: 3px;
|
||||||
|
--md-select-width: 110px;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
/* -webkit-margin-end: calc(-1 * var(--md-select-side-padding)); */
|
||||||
|
/* -moz-margin-end: var(--md-select-side-padding); */
|
||||||
|
/* -webkit-padding-end: calc(var(--md-select-side-padding) + var(--md-arrow-offset) + var(--md-arrow-width) + 3px); */
|
||||||
|
-webkit-padding-start: var(--md-select-side-padding);
|
||||||
|
-moz-padding-start: calc(var(--md-select-side-padding) - 1px);
|
||||||
|
background: url(arrow_down.svg) calc(100% - var(--md-arrow-offset) - var(--md-select-side-padding)) center no-repeat !important;
|
||||||
|
background-image: url(arrow_down.svg) !important;
|
||||||
|
background-size: var(--md-arrow-width) !important;
|
||||||
|
border: none;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
outline: none;
|
||||||
|
padding-bottom: 2px;
|
||||||
|
padding-top: 3px;
|
||||||
|
border-bottom: 1px solid rgb(224, 224, 224);
|
||||||
|
width: var(--md-select-width);
|
||||||
|
/* width: calc(var(--md-select-width, 200px) + 2 * var(--md-select-side-padding)); */
|
||||||
|
box-shadow: none !important;
|
||||||
|
text-shadow: none;
|
||||||
|
margin: 3px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
select:focus {
|
||||||
|
border-color: rgb(77, 144, 254);
|
||||||
|
}
|
||||||
|
|
||||||
|
select.exception-setting {
|
||||||
|
-webkit-padding-start: var(--md-select-side-padding);
|
||||||
|
width: calc(120px + var(--md-select-side-padding));
|
||||||
|
}
|
||||||
|
|
||||||
|
html > body {
|
||||||
|
height: 376px;
|
||||||
|
width: 500px;
|
||||||
|
margin: 16px 40px 14px 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay {
|
||||||
|
background-color: rgba(255, 255, 255,.5);
|
||||||
|
bottom: 0px;
|
||||||
|
padding-top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay .page {
|
||||||
|
max-height: 341.5px;
|
||||||
|
box-shadow: 0 0px 1px 0px rgba(0, 0, 0, 0.2), 0 1px 6px rgba(0,0,0,0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
body > div:first-child {
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-area {
|
||||||
|
padding-top: .3em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
label.settings-label {
|
||||||
|
width: 80px;
|
||||||
|
margin: 7px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.settings-checkbox ~ label.settings-label {
|
||||||
|
-webkit-margin-start: 3px;
|
||||||
|
-moz-margin-start: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
select ~ button.exceptions-list-button{
|
||||||
|
-webkit-margin-start: auto;
|
||||||
|
-moz-margin-start: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.settings-checkbox {
|
||||||
|
display: -moz-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:enabled:not(.custom-appearance):not(:focus):hover {
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.1); /* #3b72ce */
|
||||||
|
}
|
||||||
|
|
||||||
|
button:disabled:not(.custom-appearance) {
|
||||||
|
border-color: rgba(80, 80, 80, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
list input[type="text"] {
|
||||||
|
font-size: inherit;
|
||||||
|
font-family: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
#perms-type {
|
||||||
|
-moz-padding-start: 3px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button::-moz-focus-inner {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
select:-moz-focusring {
|
||||||
|
color: transparent;
|
||||||
|
text-shadow: 0 0 0 #000;
|
||||||
|
}
|
124
AutoplayStopper/skin/options.html
Normal file
124
AutoplayStopper/skin/options.html
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link href="options.css" rel="stylesheet" type="text/css" />
|
||||||
|
<script src="/options.js"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: "Segoe UI", Tahoma, sans-serif;
|
||||||
|
width: 560px;
|
||||||
|
height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 1em 17px;
|
||||||
|
font-size: 1.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3 {
|
||||||
|
user-select: none;
|
||||||
|
font-weight: normal;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border-style: solid;
|
||||||
|
color: #dddddd;
|
||||||
|
border-top-width: 0px;
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
margin-inline-start: initial;
|
||||||
|
margin-inline-end: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.settings-checkbox {
|
||||||
|
margin: auto 1px;
|
||||||
|
-webkit-margin-start: 0px;
|
||||||
|
margin-inline-start: 0px;
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div style="text-align: center; display: block;">
|
||||||
|
<span i18n-content="version">Version</span>
|
||||||
|
<span id="extension-version"></span>
|
||||||
|
</div>
|
||||||
|
<h1> <span i18n-content="settings" style="position: relative; top: -.7em">Settings</span></h1>
|
||||||
|
<h2 i18n-content="autoplayTabLabel">Autoplay</h2>
|
||||||
|
|
||||||
|
<div class="settings-row">
|
||||||
|
<label for="autoplay-default" class="settings-label" i18n-content="defaultMode">Default Mode:</label>
|
||||||
|
<select id="autoplay-default">
|
||||||
|
<option i18n-content="disableAutoplay" value="2">Disable Autoplay</option>
|
||||||
|
<option i18n-content="allowAutoplay" value="1">Allow Autoplay</option>
|
||||||
|
</select>
|
||||||
|
<button class="exceptions-list-button" contenttype="autoplay" i18n-content="manageExceptions">Exceptions...</button>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<h2 i18n-content="flashTabLabel">Flash</h2>
|
||||||
|
<div class="settings-row">
|
||||||
|
<label class="settings-label" for="flash-default" i18n-content="defaultMode">Default Mode:</label>
|
||||||
|
<select id="flash-default">
|
||||||
|
<option i18n-content="allowFlash" value="1">Allow Flash</option>
|
||||||
|
<option i18n-content="disableFlash" value="2">Disable Flash</option>
|
||||||
|
</select>
|
||||||
|
<button class="exceptions-list-button" contenttype="flash" i18n-content="manageExceptions">Exceptions...</button>
|
||||||
|
</div>
|
||||||
|
<div class="overlay transparent" hidden>
|
||||||
|
<div id="content-settings-exceptions-area" class="page">
|
||||||
|
<button class="close-button raw-button custom-appearance"></button>
|
||||||
|
<h2 contenttype="autoplay" i18n-content="autoplayExceptions">Autoplay exceptions</h2>
|
||||||
|
<h2 contenttype="flash" i18n-content="flashExceptions" hidden>Flash exceptions</h2>
|
||||||
|
<div class="content-area" tabindex="-1">
|
||||||
|
<div id="exception-column-headers">
|
||||||
|
<div id="exception-pattern-column" i18n-content="exceptionHostnameHeader">
|
||||||
|
Hostname</div>
|
||||||
|
<div id="exception-behavior-column" class="exception-value-column-header" i18n-content="exceptionBehaviorHeader">
|
||||||
|
Behavior</div>
|
||||||
|
</div>
|
||||||
|
<div contenttype="autoplay">
|
||||||
|
<list id="autoplay-list" aria-activedescendant="listitem-27" class="settings-list" inlineeditable="" mode="normal" role="list" tabindex="-1">
|
||||||
|
<div class="spacer" style="height: 0px;"></div>
|
||||||
|
<div role="listitem" id="listitem" class="deletable-item" aria-posinset="1" aria-setsize="3"><div><div class="exception-pattern weakrtl"><div id="perms-host" class="static-text overruleable" displaymode="static" tabindex="-1"></div><input id="perms-host-input" type="text" displaymode="edit" tabindex="0"></div><span id="perms-type" class="exception-setting overruleable" displaymode="static" tabindex="-1"></span><select id="perms-type-select" tabindex="0" class="exception-setting" aria-labelledby="exception-behavior-column" displaymode="edit"><option value="1" i18n-content="exceptionAllow">Allow</option><option value="2" i18n-content="exceptionBlock">Block</option><option value="3" i18n-content="exceptionPrompt">Block (strict)</option><option value="8" i18n-content="exceptionSession">Session</option><option value="0" i18n-content="exceptionUndefined">Undefined</option></select></div><button class="raw-button row-delete-button custom-appearance" tabindex="-1" title="Delete this item"></button></div>
|
||||||
|
<div role="listitem" id="inputitem" selected="selected" lead="lead" class="deletable-item"><div><div class="exception-pattern weakrtl"><input id="perms-host-input" type="text" tabindex="0" placeholder="http://example.com"></div><select id="perms-type-select" tabindex="0" class="exception-setting" aria-labelledby="exception-behavior-column"><option value="1" i18n-content="exceptionAllow">Allow</option><option value="2" i18n-content="exceptionBlock">Block</option><option value="3" i18n-content="exceptionPrompt">Block (strict)</option><option value="8" i18n-content="exceptionSession">Session</option><option value="0" i18n-content="exceptionUndefined">Undefined</option></select></div><button class="raw-button row-delete-button custom-appearance" tabindex="-1" title="Delete this item" disabled=""></button></div>
|
||||||
|
<div class="spacer" style="height: 0px;"></div>
|
||||||
|
</list>
|
||||||
|
</div>
|
||||||
|
<div contenttype="flash" hidden>
|
||||||
|
<list id="flash-list" aria-activedescendant="listitem-27" class="settings-list" inlineeditable="" mode="normal" role="list" tabindex="-1">
|
||||||
|
<div class="spacer" style="height: 0px;"></div>
|
||||||
|
<div role="listitem" id="listitem" class="deletable-item" aria-posinset="1" aria-setsize="3"><div><div class="exception-pattern weakrtl"><div id="perms-host" class="static-text overruleable" displaymode="static" tabindex="-1"></div><input id="perms-host-input" type="text" displaymode="edit" tabindex="0"></div><span id="perms-type" class="exception-setting overruleable" displaymode="static" tabindex="-1"></span><select id="perms-type-select" tabindex="0" class="exception-setting" aria-labelledby="exception-behavior-column" displaymode="edit"><option value="1" i18n-content="exceptionAllow">Allow</option><option value="2" i18n-content="exceptionBlock">Block</option><option value="0" i18n-content="exceptionUndefined">Undefined</option></select></div><button class="raw-button row-delete-button custom-appearance" tabindex="-1" title="Delete this item"></button></div>
|
||||||
|
<div role="listitem" id="inputitem" selected="selected" lead="lead" class="deletable-item"><div><div class="exception-pattern weakrtl"><input id="perms-host-input" type="text" tabindex="0" placeholder="http://example.com"></div><select id="perms-type-select" tabindex="0" class="exception-setting" aria-labelledby="exception-behavior-column"><option value="1" i18n-content="exceptionAllow">Allow</option><option value="2" i18n-content="exceptionBlock">Block</option><option value="0" i18n-content="exceptionUndefined">Undefined</option></select></div><button class="raw-button row-delete-button custom-appearance" tabindex="-1" title="Delete this item" disabled=""></button></div>
|
||||||
|
<div class="spacer" style="height: 0px;"></div>
|
||||||
|
</list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="action-area" style="padding-top: .5em">
|
||||||
|
<div class="hbox stretch">
|
||||||
|
</div>
|
||||||
|
<button id="exceptions-clear" style="margin-left: 20px;" i18n-content="removeAll">Remove All</button>
|
||||||
|
<div class="action-area-right" style="-webkit-box-pack: end; display: -webkit-box;">
|
||||||
|
<div class="button-strip" reversed="" style="position:relative; top: -1.5em; right: 19px">
|
||||||
|
<button id="exceptions-apply" disabled i18n-content="apply">Apply</button>
|
||||||
|
<button id="exceptions-confirm" class="default-button" i18n-content="done">Done</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<h2 i18n-content="advanced">Advanced</h2>
|
||||||
|
<div class="settings-row">
|
||||||
|
<input id="devtools" class="settings-checkbox" type="checkbox" />
|
||||||
|
<label class="settings-label" i18n-content="devtools">Devtools Panel</label>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
53
AutoplayStopper/skin/popup.css
Normal file
53
AutoplayStopper/skin/popup.css
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
body {
|
||||||
|
margin: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popupmenu {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
color: #303942;
|
||||||
|
background: #f9fafb;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popupmenu .popupitem {
|
||||||
|
cursor: pointer;
|
||||||
|
display: block;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popupmenu .popupitem:hover {
|
||||||
|
background: rgb(235, 235, 235); /*#565a63;
|
||||||
|
color: white;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.popupmenu .popupitem.separator {
|
||||||
|
background-color: rgba(0,0,0,0.15);
|
||||||
|
height: 1px;
|
||||||
|
pointer-events: none;
|
||||||
|
margin: 2px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popupmenu .popupitem:not(.separator) {
|
||||||
|
padding: 7px 10px;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popupmenu .popupitem[checked] {
|
||||||
|
background: rgb(80, 135, 90); /*#54975f;*/
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popupmenu .popupitem[checked="2"], .popupmenu .popupitem[checked="3"] {
|
||||||
|
background: rgb(135, 80, 90); /*#54975f;*/
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popupmenu.restricted #allow_site, .popupmenu.restricted #allow_session, .popupmenu.restricted #disable_site {
|
||||||
|
opacity: 0.5;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popupmenu #allow_all[checked] {
|
||||||
|
background: darkgray;
|
||||||
|
}
|
24
AutoplayStopper/skin/popup.html
Normal file
24
AutoplayStopper/skin/popup.html
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link href="popup.css" rel="stylesheet" />
|
||||||
|
<script src="/popup.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="popupmenu" class="popupmenu">
|
||||||
|
<section>
|
||||||
|
<div id="disable_site" class="popupitem" i18n-content="disableSite" >Disable flash for %S</div>
|
||||||
|
<div id="allow_site" class="popupitem" i18n-content="allowSite" >Allow autoplay for %S</div>
|
||||||
|
<div id="allow_session" class="popupitem" i18n-content="allowSession" >Allow session autoplay for %S</div>
|
||||||
|
</section>
|
||||||
|
<div class="popupitem separator"></div>
|
||||||
|
<section>
|
||||||
|
<!-- <popup-item id="script">Edit script...</popup-item> -->
|
||||||
|
<div id="allow_all" class="popupitem" i18n-content="allowAll" >Allow everywhere</div>
|
||||||
|
<div id="settings" class="popupitem" i18n-content="settings" >Settings</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
103
AutoplayStopper/utils.js
Normal file
103
AutoplayStopper/utils.js
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const i18n = new function(){
|
||||||
|
|
||||||
|
return {
|
||||||
|
process: function (doc) {
|
||||||
|
var elements = doc.querySelectorAll("[i18n-content]");
|
||||||
|
for (var i = 0; i < elements.length; ++i) {
|
||||||
|
var element = elements[i];
|
||||||
|
var message = chrome.i18n.getMessage(element.getAttribute("i18n-content"));
|
||||||
|
if (message) element.textContent = message;
|
||||||
|
else
|
||||||
|
console.warn("i18n: no message for " + element.getAttribute("i18n-content"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const Storage = function Storage(keys, areaname){
|
||||||
|
|
||||||
|
var listeners = [];
|
||||||
|
var data = {};
|
||||||
|
var ready = new Promise(function (resolve, reject) {
|
||||||
|
chrome.storage[areaname].get(keys, function(items){
|
||||||
|
Object.assign(data, items);
|
||||||
|
if (!chrome.runtime.lastError) resolve();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
chrome.storage.onChanged.addListener(function(changes, area) {
|
||||||
|
if (area == areaname) {
|
||||||
|
var updated = [];
|
||||||
|
for (var key of Object.keys(changes))
|
||||||
|
if (keys.indexOf(key) != -1) { data[key] = changes[key].newValue; updated.push(key); };
|
||||||
|
fireChanged(updated);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
get ready() { return ready; },
|
||||||
|
get data() { return data; },
|
||||||
|
addChangeListener: function(listener) { listeners.push(listener); return listener; },
|
||||||
|
removeChangeListener: function(listener) { var idx = listeners.indexOf(listener); if (idx != -1) listeners.splice(idx); },
|
||||||
|
commit: function commit(keys, callback) {
|
||||||
|
var items = {};
|
||||||
|
for (var key of keys) items[key] = data[key];
|
||||||
|
chrome.storage[areaname].set(items, function(){
|
||||||
|
if (callback) callback(chrome.runtime.lastError);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function fireChanged(updated) { for (var listener of listeners) listener(updated); };
|
||||||
|
};
|
||||||
|
|
||||||
|
const Permission = {
|
||||||
|
UNKNOWN_ACTION: 0,
|
||||||
|
ALLOW_ACTION: 1,
|
||||||
|
DENY_ACTION: 2,
|
||||||
|
PROMPT_ACTION: 3,
|
||||||
|
ACCESS_SESSION: 8
|
||||||
|
};
|
||||||
|
|
||||||
|
const Permissions = class Permissions {
|
||||||
|
|
||||||
|
constructor(data) {
|
||||||
|
|
||||||
|
function getData(type){ return data[Permissions.key(type)] || (data[Permissions.key(type)] = {}); };
|
||||||
|
function getDefault(type){ return data[Permissions.defaultKey(type)]; };
|
||||||
|
|
||||||
|
Object.assign(this, {
|
||||||
|
testPermission: function testPermission(type, uri) {
|
||||||
|
var origin, url = new window.URL(uri);
|
||||||
|
var hostTokens = url.host.split(".");
|
||||||
|
do {
|
||||||
|
var permission = getData(type)[origin = url.protocol + "//" + hostTokens.join(".")];
|
||||||
|
if (permission != undefined && permission != Permission.UNKNOWN_ACTION)
|
||||||
|
return Object.assign(Number(permission), {origin});
|
||||||
|
} while (hostTokens.shift());
|
||||||
|
return getDefault(type);
|
||||||
|
},
|
||||||
|
clear: function clear(type) { data[Permissions.key(type)] = {}; },
|
||||||
|
set: function set(type, url, perm) { getData(type)[new window.URL(url).origin] = perm; },
|
||||||
|
remove: function remove(type, url) { delete getData(type)[new window.URL(url).origin]; },
|
||||||
|
get: function get(type, url) { return getData(type)[new window.URL(url).origin]; },
|
||||||
|
setDefault: function setDefault(type, perm) { data[Permissions.defaultKey(type)] = perm; },
|
||||||
|
default: function _default(type) { return getDefault(type); },
|
||||||
|
entries: function entries(type) { return Object.entries(getData(type)); },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
key(type) { return Permissions.key(type); };
|
||||||
|
defaultKey(type) { return Permissions.defaultKey(type); };
|
||||||
|
|
||||||
|
static key(type) { return `perms:${type}`; };
|
||||||
|
static defaultKey(type) { return `perms:${type}Default`; };
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.assign(Permissions.prototype, Permission);
|
||||||
|
|
||||||
|
//</>
|
Loading…
Reference in New Issue
Block a user