您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a few quality of life improvements on Sankaku Channel: 'Choose/Set Parent' mode, automatic image scaling, duplicate tagging/flagging, muting videos. Fully configurable using localStorage.
当前为
// ==UserScript== // @name SankakuAddon // @namespace SankakuAddon // @description Adds a few quality of life improvements on Sankaku Channel: 'Choose/Set Parent' mode, automatic image scaling, duplicate tagging/flagging, muting videos. Fully configurable using localStorage. // @include http://chan.sankakucomplex.com/* // @include https://chan.sankakucomplex.com/* // @include http://idol.sankakucomplex.com/* // @include https://idol.sankakucomplex.com/* // @run-at document-start // @version 0.97.7 // @grant none // ==/UserScript== var version = "v0.97.7"; if (!String.prototype.startsWith) { String.prototype.startsWith = function(searchString, position) { return this.substr(position || 0, searchString.length) === searchString; }; } /***************************/ /* configuration functions */ /***************************/ var default_config = { scroll_to_image:true, scale_image:true, //and video scale_only_downscale:false, scale_flash:false, scale_mode:0, scale_on_resize:false, video_mute:true, video_controls:true, setparent_deletepotentialduplicate:false, hide_headerlogo:false, tag_search_buttons:false, //experimental common_tags:"1girl 2girls 3girls 4girls 5girls 6+girls 1boy 2boys 3boys 4boys 5boys 6+boys" //experimental }; var config_value_types = ["scale_mode", "common_tags"]; var use_local_storage = (typeof(Storage) !== "undefined"); var key_prefix = "config."; var config = JSON.parse(JSON.stringify(default_config)); //calls f(cfg_elem, key, get_value) for each existing config element function foreach_config_element(f) { for (var key in config) { if (config.hasOwnProperty(key)) { var cfg_key = key_prefix + key; var cfg_elem = document.getElementById(cfg_key); if (cfg_elem === null) continue; (function(cfg_elem) { if (config_value_types.indexOf(key) != -1) { f(cfg_elem, key, function() { return cfg_elem.value; }); } else { f(cfg_elem, key, function() { return cfg_elem.checked; }); } })(cfg_elem); } } } function save_config(key, value) { if (!use_local_storage) { notice("addon: couldn't save setting \"" + key + " = " + value + "\" to local storage. check permissions."); return; } var cfg_key = key_prefix + key; localStorage.setItem(cfg_key, JSON.stringify(value)); } function load_config() { for (var key in config) { if (config.hasOwnProperty(key)) { var value = config[key]; //default already loaded if (use_local_storage) { var cfg_key = key_prefix + key; var stored_value = localStorage.getItem(cfg_key); if (stored_value) value = JSON.parse(stored_value); } config_changed(key, value); //fire regardless } } } function local_storage_changed(e) { if (e.key.startsWith(key_prefix)) { var key = e.key.substring(key_prefix.length); var value = JSON.parse(e.newValue); config_changed(key, value); } } //event that is fired whenever a setting changes in the config dialog or the local storage function config_changed(key, value) { config[key] = value; //update config dialog var cfg_key = key_prefix + key; var cfg_elem = document.getElementById(cfg_key); if (cfg_elem === null) { notice("addon error: couldn't find config element " + cfg_key + "!"); } else { if (config_value_types.indexOf(key) != -1) { cfg_elem.value = config[key]; } else { cfg_elem.checked = config[key]; } } //currently the only dynamic change if (key === "hide_headerlogo") hide_headerlogo(value); } function reset_config() { //clear local storage if (use_local_storage) { for (var key in config) { if (config.hasOwnProperty(key)) { var cfg_key = key_prefix + key; localStorage.removeItem(cfg_key); } } } for (var key in config) { if (config.hasOwnProperty(key)) { config_changed(key, default_config[key]); } } } function show_config_overlay(bool) { document.getElementById("cfg_overlay").style.display = (bool ? "" : "none"); } /********************/ /* helper functions */ /********************/ function getScrollbarWidth() { //from Stack Overflow var outer = document.createElement("div"); outer.style.visibility = "hidden"; outer.style.width = "100px"; outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps document.body.appendChild(outer); var widthNoScroll = outer.offsetWidth; // force scrollbars outer.style.overflow = "scroll"; // add innerdiv var inner = document.createElement("div"); inner.style.width = "100%"; outer.appendChild(inner); var widthWithScroll = inner.offsetWidth; // remove divs outer.parentNode.removeChild(outer); return widthNoScroll - widthWithScroll; } //helper function to modify nodes on creation function register_observer(node_id, node_modifier) { var observer = new MutationObserver(function(mutations) { for (var i = 0; i < mutations.length; i++) { var mutationAddedNodes = mutations[i].addedNodes; for (var j = 0; j < mutationAddedNodes.length; j++) { var node = mutationAddedNodes[j]; if (node.id && node.id == node_id) { node_modifier(node); observer.disconnect(); return; } } } }); observer.observe(document, {childList: true, subtree: true}); } /*********************/ /* general functions */ /*********************/ var header_offset_height = null; //distance needed to scroll if headerlogo is hidden/shown function hide_headerlogo(hide) { var headerlogo = document.getElementById("headerlogo"); var visible = (headerlogo.style.display != "none"); headerlogo.style.display = (hide ? "none" : ""); //scroll if needed if (visible === !!hide) window.scrollBy(0, (visible && hide ? -1 : 1) * header_offset_height); } function add_config_overlay() { var cfg_overlay = document.createElement("div"); cfg_overlay.id = "cfg_overlay"; cfg_overlay.style.display = "none"; cfg_overlay.style.border = "1px solid #DDD"; cfg_overlay.style.top = "300px"; cfg_overlay.style.width = "400px"; cfg_overlay.style.height = "330px"; cfg_overlay.style.position = "fixed"; cfg_overlay.style.left = "0"; cfg_overlay.style.right = "0"; cfg_overlay.style.margin = "0 auto"; cfg_overlay.style.overflow = "auto"; cfg_overlay.style.backgroundColor = "white"; cfg_overlay.style.zIndex = 10002; cfg_overlay.innerHTML = "" + "<div style='display: table; position: absolute; height: 100%; width: 100%'>" + "<div style='display: table-cell; vertical-align: middle'>" + "<div style='padding: 8px; margin-left: auto; margin-right: auto;'>" + "<b>Sankaku Addon "+version+"</b><br>" + "<hr style='margin-top: 0; margin-bottom: 2px; border:1px solid #DDD;'>" + "<span>" + "<input id='" + key_prefix + "scroll_to_image' type='checkbox'>" + "<span>Scroll to image/video when opening post</span><br>" + "</span>" + "<span>" + "<input id='" + key_prefix + "scale_image' type='checkbox'>" + "<span>Scale image/video when opening post</span><br>" + "</span>" + "<span>" + "<input id='" + key_prefix + "scale_only_downscale' type='checkbox'>" + "<span>Only downscale</span><br>" + "</span>" + "<span>" + "<input id='" + key_prefix + "scale_flash' type='checkbox'>" + "<span>Also scale flash videos</span><br>" + "</span>" + "<span>" + "<input id='" + key_prefix + "scale_on_resize' type='checkbox'>" + "<span title=\"This uses the 'scale image mode' setting, so it doesn't work well when using the manual scaling actions.\" style='cursor:help'>Scale image on window resize</span><br>" + "</span>" + "<span>" + "<span>Scale image/video mode: </span>" + "<select id='" + key_prefix + "scale_mode'>" + "<option value=0>Fit to window</option>" + "<option value=1>Fit horizontally</option>" + "<option value=2>Fit vertically</option>" + "</select>" + "<br>" + "</span>" + "<span>" + "<input id='" + key_prefix + "video_mute' type='checkbox'>" + "<span>Mute (non-flash) videos*</span><br>" + "</span>" + "<span>" + "<input id='" + key_prefix + "video_controls' type='checkbox'>" + "<span>Show video controls*</span><br>" + "</span>" + "<span>" + "<input id='" + key_prefix + "setparent_deletepotentialduplicate' type='checkbox'>" + "<span>Delete potential_duplicate tag when using \"Set Parent\"</span><br>" + "</span>" + "<span>" + "<input id='" + key_prefix + "hide_headerlogo' type='checkbox'>" + "<span>Hide header logo</span><br>" + "</span>" + "<span>" + "<input id='" + key_prefix + "tag_search_buttons' type='checkbox'>" + "<span>Experimental + - tag search buttons*</span><br>" + "</span>" + "<span>" + "<input id='" + key_prefix + "common_tags'>" + "<span> Experimental common tags list*</span><br>" + "</span>" + "<button id='config_close'>Close</button>" + "<button id='config_reset'>Reset settings</button>" + "<span> *requires a page reload.</span>" + "</div>" + ""; document.body.appendChild(cfg_overlay); //add events document.getElementById("config_close").onclick = function() { show_config_overlay(false); return false; }; document.getElementById("config_reset").onclick = function() { reset_config(); return false; }; foreach_config_element(function(cfg_elem, key, get_value) { cfg_elem.addEventListener("change", function() { config_changed(key, get_value()); save_config(key, get_value()); }); }); } function add_config_button() { var navbar = document.getElementById("navbar"); if (!navbar) { notice("addon error: couldn't find \"navbar\" element! Config dialog disabled."); return } navbar.style.whiteSpace = "nowrap"; //hack to fit config button var a = document.createElement("A"); a.href = "#"; a.onclick = function() { show_config_overlay(true); return false; }; a.innerHTML = "Addon config"; a.style.fontSize = "110%"; var li = document.createElement("LI"); li.className = "lang-select"; //match style of top bar li.appendChild(a); navbar.appendChild(li); } function add_tag_search_buttons() { var tagsidebar = document.getElementById("tag-sidebar"); if (!tagsidebar) return; var items = tagsidebar.getElementsByTagName("LI"); for (var i = 0; i < items.length; ++i) { var taglink = items[i].getElementsByTagName("A")[0]; var tagname = taglink.innerHTML.replace(/ /g, "_"); // " " -> "_" hopefully this is the only edgecase //generates onclick events var tag_search_button_func = function(tagname, add) { return function() { var search_field = document.getElementById("tags"); if (add) { search_field.value = (search_field.value + " " + tagname).trim(); } else { search_field.value = search_field.value.replace(new RegExp(tagname, "g"), "").replace(new RegExp(" ", "g"), " ").trim(); } //focus but don't scroll var x = window.scrollX, y = window.scrollY; search_field.focus(); window.scrollTo(x, y); return false; } }; var a = document.createElement("A"); a.href = "#"; a.innerHTML = "+ "; a.onclick = tag_search_button_func(tagname, true); items[i].insertBefore(a, taglink); a = document.createElement("A"); a.href = "#"; a.innerHTML = "- "; a.onclick = tag_search_button_func(tagname, false); items[i].insertBefore(a, taglink); } } /***********************************************/ /* main page / visually similar page functions */ /***********************************************/ function add_mode_options(modeDropdown) { var option; if (modeDropdown.options.namedItem("choose-parent") === null) { option = document.createElement("option"); option.text = "Choose Parent"; option.value = "choose-parent"; modeDropdown.add(option); } if (modeDropdown.options.namedItem("set-parent") === null) { option = document.createElement("option"); option.text = "Set Parent"; option.value = "set-parent"; modeDropdown.add(option); } } /***********************/ /* post page functions */ /***********************/ //original post/parent ids var post_id = null; var parent_id = null; //original image size var img_width = null; var img_height = null; var img_aspect_ratio = null; var resize_timer; var tag_update_timer; function add_tag_menu() { var tag_menu = document.createElement("DIV"); tag_menu.id = "tag_menu"; tag_menu.style.display = "none"; tag_menu.style.border = "1px solid #DDD"; tag_menu.style.width = "100%"; tag_menu.style.height = "30%"; //TODO variable height tag_menu.style.position = "fixed"; tag_menu.style.bottom = "0"; tag_menu.style.overflow = "auto"; tag_menu.style.backgroundColor = "white"; tag_menu.style.zIndex = 10001; document.body.appendChild(tag_menu); //the inner div ensures tag_menu_close button doesn't scroll with the content tag_menu.innerHTML = "<div style='width: 100%; height: 100%; overflow: auto;'>common tags:<br>" + "<span id='common_tags'></span>" + "<br>current tags:<br>" + "<span id='current_tags'></span></div>"; var generate_tag_menu_button = function(id, text) { var button = document.createElement("DIV"); button.id = id; button.style.border = "1px solid #DDD"; button.style.width = "24px"; button.style.height = "24px"; button.style.position = "absolute"; button.style.backgroundColor = "#EEE"; button.innerHTML = "<span style='position: absolute; top: 50%; left: 50%; transform: translateX(-50%) translateY(-50%);'>" + text + "</span>"; button.style.zIndex = 10001; return button; }; var tag_menu_close = generate_tag_menu_button("tag_menu_close", "X"); tag_menu_close.style.right = "0"; tag_menu_close.style.top = "0"; tag_menu_close.onclick = function() { show_tag_menu(false); return false; }; tag_menu.appendChild(tag_menu_close); var tag_menu_open = generate_tag_menu_button("tag_menu_open", "«"); tag_menu_open.style.position = "fixed"; tag_menu_open.style.right = "0"; tag_menu_open.style.bottom = "0"; tag_menu_open.onclick = function() { show_tag_menu(true); update_tag_menu(); return false; }; document.body.appendChild(tag_menu_open); } function update_tag_menu() { var generate_tag_button = function(tag) { var a = document.createElement("A"); a.href = "#"; a.style.paddingLeft = "5px"; a.style.paddingRight = "5px"; a.style.borderStyle = "solid"; a.style.borderWidth = "1px"; a.className = (tag_is_present(tag) ? "" : "tag_nonexistent"); a.onclick = function(tag, a) { return function() { if (tag_is_present(tag)) { remove_tag(tag); a.className = "tag_nonexistent"; } else { add_tag(tag); a.className = ""; } return false; }; }(tag, a); a.innerHTML = tag; return a; }; var generate_tag_button_li = function(tag) { var li = document.createElement("LI"); li.style.paddingTop = "3px"; li.style.paddingBottom = "3px"; li.style.float = "left"; li.appendChild(generate_tag_button(tag)); return li; }; var create_tag_list = function() { var ul = document.createElement("UL"); ul.style.listStyleType = "none"; ul.style.margin = "0"; ul.style.padding = "0"; ul.style.display = "inline-block"; return ul; }; var ul1 = create_tag_list(); var ul2 = create_tag_list(); var common_tags_array = config.common_tags.trim().split(/\s+/); for (var i = 0; i < common_tags_array.length; i++) { ul1.appendChild(generate_tag_button_li(common_tags_array[i])); } var tags = get_tags_array(); for (var i = 0; i < tags.length; i++) { ul2.appendChild(generate_tag_button_li(tags[i])); } var common_tags = document.getElementById("common_tags"); var current_tags = document.getElementById("current_tags"); //TODO check for issues while (common_tags.hasChildNodes()) { common_tags.removeChild(common_tags.lastChild); } while (current_tags.hasChildNodes()) { current_tags.removeChild(current_tags.lastChild); } common_tags.appendChild(ul1); current_tags.appendChild(ul2); } function show_tag_menu(bool) { document.getElementById("tag_menu").style.display = (bool ? "" : "none"); document.getElementById("tag_menu_open").style.display = (!bool ? "" : "none"); } function add_addon_actions() { var li = document.getElementById("add-to-pool"); if (li === null) { notice("addon error: couldn't find \"add-to-pool\" element! Addon actions disabled."); return; } if (document.getElementById("flag-duplicate") === null) { var actions_ul = li.parentElement; var separator = document.createElement("H5"); separator.innerHTML = "Addon actions"; var newli = document.createElement("LI"); newli.appendChild(separator); actions_ul.appendChild(newli); var add_action = function(func, name, id) { var a = document.createElement("A"); a.href = "#"; a.onclick = function() {func(); return false;}; a.innerHTML = name; var newli = document.createElement("LI"); newli.id = id; newli.appendChild(a); actions_ul.appendChild(newli); }; add_action(function() { scale_image(0, false); scroll_to_image(); }, "Fit image", "scale-image-fit"); add_action(function() { scale_image(1, false); scroll_to_image(); }, "Fit image (Horizontal)", "scale-image-hor"); add_action(function() { scale_image(2, false); scroll_to_image(); }, "Fit image (Vertical)", "scale-image-ver"); add_action(function() { scale_image(-1, false); scroll_to_image(); }, "Reset image size", "reset-image"); if (post_id !== null) { add_action(function() { flag_duplicate(post_id, ""); }, "Flag duplicate", "flag-duplicate"); add_action(function() { flag_duplicate(post_id, ", visually identical"); }, "Flag duplicate (identical)", "flag-duplicate-identical"); add_action(function() { flag_duplicate(post_id, " with worse quality"); }, "Flag duplicate (quality)", "flag-duplicate-quality"); add_action(function() { flag_duplicate(post_id, " with worse resolution"); }, "Flag duplicate (resolution)", "flag-duplicate-resolution"); } } } function add_tag_buttons() { var edit_form = document.getElementById("edit-form"); if (edit_form === null) { notice("couldn't find \"edit-form\" element, tag buttons disabled!"); return; } var button_place = edit_form.children[1].children[0].children[0].children[0]; button_place.setAttribute("nowrap", "nowrap"); //hack to keep buttons from wrapping (not HTML5 conform, should use CSS) var el = document.createElement("BUTTON"); el.id = "clear_parent_id_button"; el.style.margin = "0 3px 0 6px"; el.innerHTML = "Clear"; el.onclick = function() { post_parent_id.clear(); return false;}; post_parent_id.parentNode.appendChild(el); el = document.createElement("BUTTON"); el.id = "reset_parent_id_button"; el.style.margin = "0 3px"; el.innerHTML = "Reset"; el.onclick = function() { reset_parent_id(); return false;}; post_parent_id.parentNode.appendChild(el); el = document.createElement("BUTTON"); el.id = "tag_reset_button"; el.style.margin = "0 3px 0 6px"; el.innerHTML = "Reset"; el.onclick = function() { reset_tags(); return false; }; button_place.appendChild(el); el = document.createElement("BUTTON"); el.id = "tag_dup_button"; el.style.margin = "0 3px"; button_place.appendChild(el); el = document.createElement("BUTTON"); el.id = "tag_var_button"; el.style.margin = "0 3px"; button_place.appendChild(el); el = document.createElement("BUTTON"); el.id = "tag_pot_button"; el.style.margin = "0 3px"; button_place.appendChild(el); } function update_tag_buttons() { var taglist = document.getElementById("post_tags"); var dup_button = document.getElementById("tag_dup_button"); var var_button = document.getElementById("tag_var_button"); var pot_button = document.getElementById("tag_pot_button"); if (!taglist || !dup_button || !var_button || !pot_button) { notice("addon error: couldn't find tag buttons."); return; } var tags = get_tags_array(); if (tags.indexOf("duplicate") == -1) { dup_button.onclick = function() {add_tag("duplicate"); return false;}; dup_button.innerHTML = "Tag duplicate"; } else { dup_button.onclick = function() {remove_tag("duplicate"); return false;}; dup_button.innerHTML = "Untag duplicate"; } if (tags.indexOf("legitimate_variation") == -1) { var_button.onclick = function() {add_tag("legitimate_variation"); return false;}; var_button.innerHTML = "Tag legitimate_variation"; } else { var_button.onclick = function() {remove_tag("legitimate_variation"); return false;}; var_button.innerHTML = "Untag legitimate_variation"; } pot_button.innerHTML = "Untag potential_duplicate"; if (tags.indexOf("potential_duplicate") == -1) { pot_button.disabled = true; } else { pot_button.onclick = function() {remove_tag("potential_duplicate"); return false;}; pot_button.disabled = false; } } function reset_parent_id() { document.getElementById("post_parent_id").value = parent_id; } function get_old_tags_array() { return document.getElementById("post_old_tags").value.trim().split(/\s+/); } function get_tags_array() { return document.getElementById("post_tags").value.trim().split(/\s+/); } function add_tag(tag) { var tags = get_tags_array(); if ((tag == "duplicate" && tags.indexOf("legitimate_variation") != -1) || (tag == "legitimate_variation" && tags.indexOf("duplicate") != -1)) { notice("addon: cannot tag as duplicate and legitimate_variation at the same time."); return; } if (tags.indexOf(tag) != -1) { notice("addon: tag already present."); return; } document.getElementById("post_tags").value += " " + tag; updated_tags(); } function remove_tag(tag) { var tags = get_tags_array(); for (var i = 0; i < tags.length; i++) { if (tags[i] == tag) { tags[i] = ""; } } document.getElementById("post_tags").value = tags.join(" ").trim(); updated_tags(); } function tag_is_present(tag) { return get_tags_array().indexOf(tag) != -1; } function reset_tags() { document.getElementById("post_tags").value = document.getElementById("post_old_tags").value; updated_tags(); } //event that gets called whenever post_tags changes function updated_tags() { update_tag_buttons(); update_tag_menu(); } //flag option with default text function flag_duplicate(id, reason_suffix) { var current_parent_id = document.getElementById("post_parent_id").value; if (current_parent_id != parent_id) { notice("addon: parent id was changed but not saved!"); return false; } if (!current_parent_id || current_parent_id.length === 0) { notice("addon: no parent id set!"); return false; } var tags = get_tags_array(); var old_tags = get_old_tags_array(); if (tags.indexOf("duplicate") == -1 && old_tags.indexOf("duplicate") != -1) { notice("addon: duplicate tag set but not saved!"); return false; } if (old_tags.indexOf("duplicate") == -1) { notice("addon: not tagged as duplicate!"); return false; } if (old_tags.indexOf("legitimate_variation") != -1) { notice("addon: tagged as legitimate_variation, are you sure it is a duplicate?"); return false; } var reason = prompt("Why should this post be reconsidered for moderation?", "duplicate of " + parent_id + reason_suffix); if (reason === null) { return false; } new Ajax.Request("/post/flag.json", { parameters: { "id": id, "reason": reason }, onComplete: function(response) { var resp = response.responseJSON; if (resp.success) { notice("Post was resent to moderation queue"); } else { notice("Error: " + resp.reason); } } }); } //stretch image/video/flash function scale_image(mode, only_downscale) { mode = Number(mode); if (isNaN(mode)) { notice("addon error: scaling mode wasn't a number?"); return; } var flash = false; var emb; var img = document.getElementById("image"); //image or video if (!img) { var non_image_content = document.getElementById("non-image-content"); img = non_image_content.getElementsByTagName("OBJECT")[0]; emb = non_image_content.getElementsByTagName("EMBED")[0]; flash = img && emb; if (!flash || !config.scale_flash) return; } //save original image size if (img_width === null) img_width = img.width; if (img_height === null) img_height = img.height; if (img_aspect_ratio === null) img_aspect_ratio = img.width / img.height; //reset image size if (mode === -1) { if (!flash) { img.style.width = null; img.style.height = null; } else { img.width = img_width; img.height = img_height; emb.width = img_width; emb.height = img_height; } return; } var scale = function(obj, mode, only_downscale) { //target rect var img_rect_w = Math.max(window.innerWidth - img.getBoundingClientRect().left - getScrollbarWidth() - 1, 1); var img_rect_h = Math.max(window.innerHeight - 1, 1); var img_rect_aspect_ratio = img_rect_w / img_rect_h; //fit into window if (mode === 0) { mode = (img_aspect_ratio > img_rect_aspect_ratio ? 1 : 2); } var new_width, new_height; //horizontal if (mode === 1) { new_width = Math.floor(img_rect_w); new_height = Math.floor(img_rect_w / img_aspect_ratio); //vertical } else if (mode === 2) { new_width = Math.floor(img_rect_h * img_aspect_ratio); new_height = Math.floor(img_rect_h); } if (only_downscale && (new_width > img_width || new_height > img_height)) return; obj.width = new_width + "px"; obj.height = new_height + "px"; }; if (!flash) { scale(img.style, mode, only_downscale); } else { scale(img, mode, only_downscale); scale(emb, mode, only_downscale); } } function scroll_to_image() { var img = document.getElementById("image"); if (!img) img = document.getElementById("non-image-content"); if (!img) return; img.scrollIntoView(); } /******************/ /* document-start */ /******************/ /*************************************/ /* main page / visually similar page */ /*************************************/ if (location.pathname === "/" || location.pathname.startsWith("/post/similar")) { // add new modes right when dropdown is added to prevent it being reset to "view post" on page reloads register_observer("mode", function(node) { add_mode_options(node); }); /*************/ /* post page */ /*************/ } else if (location.pathname.startsWith("/post/show/")) { var mute_video = function(node) { if (node.nodeType !== Node.ELEMENT_NODE) return; if (node.tagName !== "VIDEO") return; if (config.video_mute) node.muted = true; if (config.video_controls) node.controls = true; }; register_observer("image", mute_video); } /******************/ /* content-loaded */ /******************/ document.addEventListener("DOMContentLoaded", function() { header_offset_height = document.getElementById("headerlogo").offsetHeight; //fix for flagged posts not always showing red border //problem: "flagged" style is defined before "has-parent" and "has-children" CSS styles, so these two take priority //fix: just add another copy of the "flagged" style at the end var sheet = document.createElement("style"); sheet.innerHTML = "img.has-children {padding:0px;border:2px solid #A7DF38;} img.has-parent {padding:0px;border:2px solid #CCCC00;} img.flagged {padding: 0px; border: 2px solid #F00;}"; sheet.innerHTML += " a.tag_nonexistent { color: #D00; }"; //custom style document.body.appendChild(sheet); add_config_overlay(); add_config_button(); //listen for config changes in other windows window.addEventListener("storage", local_storage_changed); load_config(); /*************************************/ /* main page / visually similar page */ /*************************************/ if (location.pathname === "/" || location.pathname.startsWith("/post/similar")) { if (config.tag_search_buttons) add_tag_search_buttons(); if (!PostModeMenu.old_change) PostModeMenu.old_change = PostModeMenu.change; if (!PostModeMenu.old_click) PostModeMenu.old_click = PostModeMenu.click; //add change events PostModeMenu.change = function() { var s = $F("mode"); PostModeMenu.old_change(); if (s == "apply-tag-script") { document.body.setStyle({ backgroundColor: "#FDF" //weaken color intensity }); } else if (s == "choose-parent") { document.body.setStyle({ backgroundColor: "#FFD" }); } else if (s == "set-parent") { if (Cookie.get("chosen-parent") === null) { notice("addon: Choose parent first!"); $("mode").value = "choose-parent"; PostModeMenu.change(); } else { document.body.setStyle({ backgroundColor: "#DFF" }); } } }; //add click events PostModeMenu.click = function(post_id) { if (PostModeMenu.old_click(post_id)) { return true; } var s = $("mode"); if (s.value == "choose-parent") { Cookie.put("chosen-parent", post_id); $("mode").value = "set-parent"; PostModeMenu.change(); } else if (s.value == "set-parent") { var parent_id = Cookie.get("chosen-parent"); TagScript.run(post_id, "parent:" + parent_id + (config.setparent_deletepotentialduplicate ? " -potential_duplicate" : "")); } return false; }; //guarantee that 'mode' variable correctly changes to new modes when loading page PostModeMenu.change(); /*************/ /* post page */ /*************/ } else if (location.pathname.startsWith("/post/show/")) { var hidden_post_id = document.getElementById("hidden_post_id"); if (hidden_post_id) { post_id = hidden_post_id.innerHTML; } var post_parent_id = document.getElementById("post_parent_id"); if (post_parent_id) { parent_id = post_parent_id.value; } add_addon_actions(); add_tag_buttons(); add_tag_menu(); updated_tags(); if (config.tag_search_buttons) add_tag_search_buttons(); if (config.scale_image) scale_image(config.scale_mode, config.scale_only_downscale); if (config.scroll_to_image) scroll_to_image(); window.addEventListener("resize", function() { clearTimeout(resize_timer); resize_timer = setTimeout(function() { if (config.scale_on_resize) scale_image(config.scale_mode, config.scale_only_downscale); }, 100); }); var post_tags_area = document.getElementById("post_tags"); if (post_tags_area.addEventListener) post_tags_area.addEventListener("change", function() { //TODO "change" should always fire, needs testing clearTimeout(tag_update_timer); tag_update_timer = setTimeout(function() { updated_tags(); }, 500); }); /*************/ /* pool page */ /*************/ } else if (location.pathname.startsWith("/pool/index")) { //fix to show pool links even if missing english translation (they could not be clicked on otherwise) var pool_entries = document.getElementById("pool-index").getElementsByTagName("TABLE")[0].getElementsByTagName("TBODY")[0].getElementsByTagName("TR"); for (var i = 0; i < pool_entries.length; i++) { var pool_name = pool_entries[i].getElementsByTagName("TD")[0].getElementsByTagName("A")[0]; if (pool_name.innerHTML.trim().length == 0) pool_name.innerHTML = "<missing English translation>"; } } }, false);