// ==UserScript== // @name X-links Extension - Nyaa Torrents // @namespace dnsev-h // @author dnsev-h // @version 1.0.0.9 // @description Linkify and format nyaa.se links // @include http://boards.4chan.org/* // @include https://boards.4chan.org/* // @include http://boards.4channel.org/* // @include https://boards.4channel.org/* // @include http://8ch.net/* // @include https://8ch.net/* // @include https://archived.moe/* // @include https://boards.fireden.net/* // @include http://desuarchive.org/* // @include https://desuarchive.org/* // @include http://fgts.jp/* // @include https://fgts.jp/* // @include http://boards.38chan.net/* // @include http://forums.e-hentai.org/* // @include https://forums.e-hentai.org/* // @include https://meguca.org/* // @homepage https://dnsev-h.github.io/x-links/ // @supportURL https://github.com/dnsev-h/x-links/issues // @updateURL https://raw.githubusercontent.com/dnsev-h/x-links/stable/builds/x-links-ext-nyaa.meta.js // @downloadURL https://raw.githubusercontent.com/dnsev-h/x-links/stable/builds/x-links-ext-nyaa.user.js // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAA4klEQVR4Ae2ZoQ7CMBRF+VIMBjGDwSAwmImZGcQUYoYPq32fAPK8LCSleZCmzb3JcUtzD+ndBDslHuVVQr0zJdCAQHoaQEggTQYj9C8ggRVCAqPBDfoUkMBq8HAs4J8vLZ2uEH/VSqC6QEZmMbg7ZgiWzu2wJQEJZGRmgwn+cNf9jxXcRn0BCZA/33VKb848OfbQioAEikqni+MMpRugdGADFQQkEL7rlN7c3QG+2EZgrPUEJPD7V+RgcHQcoGAXDQlIoLx0/kxKhwbahoAEPn5ZYwKU7ldAAvqLSQLNRlEU5Q1O5fOjZV4u4AAAAABJRU5ErkJggg== // @icon64 data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAOVBMVEUBAAAAAADmce/ml+/mje/mku/mhO/mY+/mbO/mdu/me+/mie/mXu/mm+/mpe/mf+/mqu/maO/moe9+hYmYAAAAAXRSTlMAQObYZgAAAJRJREFUeF7t1zkOAzEMBEFRe9+2//9YtzOCIOR8oEoX7GCgZEtXigWtb8qBF36ywIgD8gHcyAIHZqgHbnxwwRCPH1igEvCRCwMmZMd+cKVAjEwY0RpvgDkKAe/feANmVJxQC8TjHRssqDBHI5CPt6FihR8zjicQaD6eFW8sMEcxEI99fEG2vFrgwY4scEI/0P8X0HVf06IrwbJZHiwAAAAASUVORK5CYII= // @grant none // @run-at document-start // ==/UserScript== (function () { "use strict"; /*#{begin_debug:timing=true}#*/ var xlinks_api = (function () { "use strict"; // Private var ready = (function () { var callbacks = [], check_interval = null, check_interval_time = 250; var callback_check = function () { if ( (document.readyState === "interactive" || document.readyState === "complete") && callbacks !== null ) { var cbs = callbacks, cb_count = cbs.length, i; callbacks = null; for (i = 0; i < cb_count; ++i) { cbs[i].call(null); } window.removeEventListener("load", callback_check, false); window.removeEventListener("DOMContentLoaded", callback_check, false); document.removeEventListener("readystatechange", callback_check, false); if (check_interval !== null) { clearInterval(check_interval); check_interval = null; } return true; } return false; }; window.addEventListener("load", callback_check, false); window.addEventListener("DOMContentLoaded", callback_check, false); document.addEventListener("readystatechange", callback_check, false); return function (cb) { if (callbacks === null) { cb.call(null); } else { callbacks.push(cb); if (check_interval === null && callback_check() !== true) { check_interval = setInterval(callback_check, check_interval_time); } } }; })(); var ttl_1_hour = 60 * 60 * 1000; var ttl_1_day = 24 * ttl_1_hour; var ttl_1_year = 365 * ttl_1_day; var cache_prefix = ""; var cache_storage = window.localStorage; var cache_set = function (key, data, ttl) { cache_storage.setItem(cache_prefix + "ext-" + key, JSON.stringify({ expires: Date.now() + ttl, data: data })); }; var cache_get = function (key) { var json = parse_json(cache_storage.getItem(cache_prefix + "ext-" + key), null); if ( json !== null && typeof(json) === "object" && Date.now() < json.expires && typeof(json.data) === "object" ) { return json.data; } cache_storage.removeItem(key); return null; }; var random_string_alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; var random_string = function (count) { var alpha_len = random_string_alphabet.length, s = "", i; for (i = 0; i < count; ++i) { s += random_string_alphabet[Math.floor(Math.random() * alpha_len)]; } return s; }; var is_object = function (obj) { return (obj !== null && typeof(obj) === "object"); }; var get_regex_flags = function (regex) { var s = ""; if (regex.global) s += "g"; if (regex.ignoreCase) s += "i"; if (regex.multiline) s += "m"; return s; }; var create_temp_storage = function () { var data = {}; var fn = { length: 0, key: function (index) { return Object.keys(data)[index]; }, getItem: function (key) { if (Object.prototype.hasOwnProperty.call(data, key)) { return data[key]; } return null; }, setItem: function (key, value) { if (!Object.prototype.hasOwnProperty.call(data, key)) { ++fn.length; } data[key] = value; }, removeItem: function (key) { if (Object.prototype.hasOwnProperty.call(data, key)) { delete data[key]; --fn.length; } }, clear: function () { data = {}; fn.length = 0; } }; return fn; }; var set_shared_node = function (node) { var par = document.querySelector(".xl-extension-sharing-elements"), id = random_string(32); if (par === null) { par = document.createElement("div"); par.className = "xl-extension-sharing-elements"; par.style.setProperty("display", "none", "important"); document.body.appendChild(par); } try { node.setAttribute("data-xl-sharing-id", id); par.appendChild(node); } catch (e) { return null; } return id; }; var settings_descriptor_info_normalize = function (input) { var info = {}, opt, label, desc, a, i, ii, v; if (typeof(input.type) === "string") { info.type = input.type; } if (Array.isArray((a = input.options))) { info.options = []; for (i = 0, ii = a.length; i < ii; ++i) { v = a[i]; if ( Array.isArray(v) && v.length >= 2 && typeof((label = v[1])) === "string" ) { opt = [ v[0], v[1] ]; if (typeof((desc = v[2])) === "string") { opt.push(desc); } info.options.push(opt); } } } return info; }; var config = {}; var CommunicationChannel = function (name, key, is_extension, channel, callback) { var self = this; this.port = null; this.port_other = null; this.post = null; this.on_message = null; this.origin = null; this.name_key = null; this.is_extension = is_extension; this.name = name; this.key = key; this.callback = callback; if (channel === null) { this.name_key = name; if (key !== null) { this.name_key += "_"; this.name_key += key; } this.origin = window.location.protocol + "//" + window.location.host; this.post = this.post_window; this.on_message = function (event) { self.on_window_message(event); }; window.addEventListener("message", this.on_message, false); } else { this.port = channel.port1; this.port_other = channel.port2; this.post = this.post_channel; this.on_message = function (event) { self.on_port_message(event); }; this.port.addEventListener("message", this.on_message, false); this.port.start(); } }; CommunicationChannel.prototype.post_window = function (message, transfer) { var msg = { ext: this.is_extension, key: this.name_key, data: message }; try { window.postMessage(msg, this.origin, transfer); } catch (e) { // Tampermonkey bug try { unsafeWindow.postMessage(msg, this.origin, transfer); } catch (e2) {} } }; CommunicationChannel.prototype.post_channel = function (message, transfer) { this.port.postMessage(message, transfer); }; CommunicationChannel.prototype.post_null = function () { }; CommunicationChannel.prototype.on_window_message = function (event) { var data = event.data; if ( event.origin === this.origin && is_object(data) && data.ext === (!this.is_extension) && // jshint ignore:line data.key === this.name_key && is_object((data = data.data)) ) { this.callback(event, data, this); } }; CommunicationChannel.prototype.on_port_message = function (event) { var data = event.data; if (is_object(data)) { this.callback(event, data, this); } }; CommunicationChannel.prototype.close = function () { if (this.on_message !== null) { if (this.port === null) { window.removeEventListener("message", this.on_message, false); } else { this.port.removeEventListener("message", this.on_message, false); this.port.close(); this.port = null; } this.on_message = null; this.post = this.post_null; } }; var api = null; var API = function () { this.event = null; this.reply_callbacks = {}; this.init_state = 0; this.handlers = API.handlers_init; this.functions = {}; this.url_info_functions = {}; this.url_info_to_data_functions = {}; this.details_functions = {}; this.actions_functions = {}; var self = this; this.channel = new CommunicationChannel( "xlinks_broadcast", null, true, null, function (event, data, channel) { self.on_message(event, data, channel, {}); } ); }; API.prototype.on_message = function (event, data, channel, handlers) { var action = data.xlinks_action, action_is_null = (action === null), action_data, reply, fn, err; if ( (action_is_null || typeof(action) === "string") && is_object((action_data = data.data)) ) { reply = data.reply; if (typeof(reply) === "string") { if (Object.prototype.hasOwnProperty.call(this.reply_callbacks, reply)) { fn = this.reply_callbacks[reply]; delete this.reply_callbacks[reply]; this.event = event; fn.call(this, null, action_data); this.event = null; } else { err = "Cannot reply to extension"; } } else if (action_is_null) { err = "Missing extension action"; } else if (Object.prototype.hasOwnProperty.call(handlers, action)) { handlers[action].call(this, action_data, channel, data.id); } else { err = "Invalid extension call"; } if (err !== undefined && typeof((reply = data.id)) === "string") { this.send( channel, null, reply, { err: "Invalid extension call" } ); } } }; API.prototype.send = function (channel, action, reply_to, data, timeout_delay, on_reply) { var self = this, id = null, timeout = null, cb, i; if (on_reply !== undefined) { for (i = 0; i < 10; ++i) { id = random_string(32); if (!Object.prototype.hasOwnProperty.call(this.reply_callbacks)) break; } cb = function () { if (timeout !== null) { clearTimeout(timeout); timeout = null; } on_reply.apply(this, arguments); }; this.reply_callbacks[id] = cb; cb = null; if (timeout_delay >= 0) { timeout = setTimeout(function () { timeout = null; delete self.reply_callbacks[id]; on_reply.call(self, "Response timeout"); }, timeout_delay); } } channel.post({ xlinks_action: action, data: data, id: id, reply: reply_to }); }; API.prototype.reply_error = function (channel, reply_to, err) { channel.post({ xlinks_action: null, data: { err: err }, id: null, reply: reply_to }); }; API.prototype.post_message = function (msg) { try { window.postMessage(msg, this.origin); } catch (e) { // Tampermonkey bug try { unsafeWindow.postMessage(msg, this.origin); } catch (e2) { console.log("window.postMessage failed! Your userscript manager may need to be updated!"); console.log("window.postMessage exception:", e, e2); } } }; API.prototype.init = function (info, callback) { if (this.init_state !== 0) { if (typeof(callback) === "function") callback.call(null, this.init_state === 1 ? "Init active" : "Already started"); return; } this.init_state = 1; var self = this, de = document.documentElement, count = info.registrations, namespace = info.namespace || "", send_info = { namespace: namespace }, a, v, i; if (typeof((v = info.name)) === "string") send_info.name = v; if (typeof((v = info.author)) === "string") send_info.author = v; if (typeof((v = info.description)) === "string") send_info.description = v; if (Array.isArray((v = info.version))) { for (i = 0; i < v.length; ++i) { if (typeof(v[i]) !== "number") break; } if (i === v.length) send_info.version = v.slice(0); } if (typeof(count) !== "number" || count < 0) { count = 1; } send_info.registrations = count; send_info.main = (typeof(info.main) === "function") ? info.main.toString() : null; if (de) { a = de.getAttribute("data-xlinks-extensions-waiting"); a = (a ? (parseInt(a, 10) || 0) : 0) + count; de.setAttribute("data-xlinks-extensions-waiting", a); de = null; } ready(function () { self.send( self.channel, "init", null, send_info, 10000, function (err, data) { err = self.on_init(err, data, namespace); if (err === "Internal") { self.channel.close(); this.init_state = 3; } if (typeof(callback) === "function") callback.call(null, err); } ); }); }; API.prototype.on_init = function (err, data, namespace) { var self = this, api_key, ch, v; if (err === null) { if (!is_object(data)) { err = "Could not generate extension key"; } else if (typeof((err = data.err)) !== "string") { if (typeof((api_key = data.key)) !== "string") { err = "Could not generate extension key"; } else { // Valid err = null; if (typeof((v = data.cache_prefix)) === "string") { cache_prefix = v; } if (typeof((v = data.cache_mode)) === "string") { if (v === "session") { cache_storage = window.sessionStorage; } else if (v === "none") { cache_storage = create_temp_storage(); } } // New channel ch = (this.event.ports && this.event.ports.length === 1) ? { port1: this.event.ports[0], port2: null } : null; this.channel.close(); this.channel = new CommunicationChannel( namespace, api_key, true, ch, function (event, data, channel) { self.on_message(event, data, channel, API.handlers); } ); } } } this.init_state = (err === null) ? 2 : 0; return err; }; API.prototype.register = function (data, callback) { if (this.init_state !== 2) { if (typeof(callback) === "function") callback.call(null, "API not init'd", 0); return; } // Data var send_data = { settings: {}, request_apis: [], linkifiers: [], commands: [], create_url: null }; var request_apis_response = [], command_fns = [], array, entry, fn_map, a_data, a, i, ii, k, o, v; // Settings o = data.settings; if (is_object(o)) { for (k in o) { a = o[k]; if (Array.isArray(a)) { send_data.settings[k] = a_data = []; for (i = 0, ii = a.length; i < ii; ++i) { v = a[i]; if (Array.isArray(v) && typeof(v[0]) === "string") { entry = [ v[0] ]; if (v.length > 1) { entry.push( (v[1] === undefined ? null : v[1]), "" + (v[2] || ""), "" + (v[3] || "") ); if (v.length > 4 && is_object(v[4])) { entry.push(settings_descriptor_info_normalize(v[4])); } } a_data.push(entry); } } } } } // Request APIs array = data.request_apis; if (Array.isArray(array)) { for (i = 0, ii = array.length; i < ii; ++i) { a = array[i]; fn_map = {}; a_data = { group: "other", namespace: "other", type: "other", count: 1, concurrent: 1, delays: { okay: 200, error: 5000 }, functions: [] }; if (typeof((v = a.group)) === "string") a_data.group = v; if (typeof((v = a.namespace)) === "string") a_data.namespace = v; if (typeof((v = a.type)) === "string") a_data.type = v; if (typeof((v = a.count)) === "number") a_data.count = Math.max(1, v); if (typeof((v = a.concurrent)) === "number") a_data.concurrent = Math.max(1, v); if (typeof((v = a.delay_okay)) === "number") a_data.delay_okay = Math.max(0, v); if (typeof((v = a.delay_error)) === "number") a_data.delay_error = Math.max(0, v); if (is_object((o = a.functions))) { for (k in o) { v = o[k]; if (typeof(v) === "function") { a_data.functions.push(k); fn_map[k] = v; } } } request_apis_response.push({ functions: fn_map }); send_data.request_apis.push(a_data); } } // Linkifiers array = data.linkifiers; if (Array.isArray(array)) { for (i = 0, ii = array.length; i < ii; ++i) { a = array[i]; a_data = { regex: null, prefix_group: 0, prefix: "" }; v = a.regex; if (typeof(v) === "string") { a_data.regex = [ v ]; } else if (v instanceof RegExp) { a_data.regex = [ v.source, get_regex_flags(v) ]; } else if (Array.isArray(v)) { if (typeof(v[0]) === "string") { if (typeof(v[1]) === "string") { a_data.regex = [ v[0], v[1] ]; } else { a_data.regex = [ v[0] ]; } } } if (typeof((v = a.prefix_group)) === "number") a_data.prefix_group = v; if (typeof((v = a.prefix)) === "string") a_data.prefix = v; send_data.linkifiers.push(a_data); } } // URL info functions array = data.commands; if (Array.isArray(array)) { for (i = 0, ii = array.length; i < ii; ++i) { a = array[i]; a_data = { url_info: false, to_data: false, actions: false, details: false }; o = { url_info: null, to_data: null, actions: null, details: null }; if (typeof((v = a.url_info)) === "function") { a_data.url_info = true; o.url_info = v; } if (typeof((v = a.to_data)) === "function") { a_data.to_data = true; o.to_data = v; } if (typeof((v = a.actions)) === "function") { a_data.actions = true; o.actions = v; } if (typeof((v = a.details)) === "function") { a_data.details = true; o.details = v; } command_fns.push(o); send_data.commands.push(a_data); } } // URL create functions o = data.create_url; if (is_object(o)) { send_data.create_url = o; } // Send this.send( this.channel, "register", null, send_data, 10000, function (err, data) { var o; if (err !== null || (err = data.err) !== null) { if (typeof(callback) === "function") callback.call(null, err, 0); } else if (!is_object((o = data.response))) { if (typeof(callback) === "function") callback.call(null, "Invalid extension response", 0); } else { var okay = this.register_complete(o, request_apis_response, command_fns, send_data.settings); if (typeof(callback) === "function") callback.call(null, null, okay); } } ); }; API.prototype.register_complete = function (data, request_apis, command_fns, settings) { var reg_count = 0, setting_ns, errors, name, fn, e, o, i, ii, k, v; // Request APIs errors = []; i = 0; if (Array.isArray((o = data.request_apis))) { for (ii = o.length; i < ii; ++i) { e = o[i]; if (i >= request_apis.length) { errors.push("Invalid"); } else if (typeof(e) === "string") { errors.push(e); } else if (!is_object(e)) { errors.push("Invalid"); } else { ++reg_count; for (k in e) { if (Object.prototype.hasOwnProperty.call(e, k) && Object.prototype.hasOwnProperty.call(request_apis[i].functions, k)) { fn = request_apis[i].functions[k]; this.functions[e[k]] = fn; } } } } } for (ii = request_apis.length; i < ii; ++i) { errors.push("Invalid"); } // URL infos errors = []; i = 0; if (Array.isArray((o = data.commands))) { for (ii = o.length; i < ii; ++i) { e = o[i]; if (i >= command_fns.length) { errors.push("Invalid"); } else if (typeof(e) === "string") { errors.push(e); } else if (!is_object(e) || typeof((k = e.id)) !== "string") { errors.push("Invalid"); } else { ++reg_count; this.url_info_functions[k] = command_fns[i].url_info; this.url_info_to_data_functions[k] = command_fns[i].to_data; if (command_fns[i].actions !== null) this.actions_functions[k] = command_fns[i].actions; if (command_fns[i].details !== null) this.details_functions[k] = command_fns[i].details; } } } for (ii = command_fns.length; i < ii; ++i) { errors.push("Invalid"); } // Settings for (k in settings) { setting_ns = settings[k]; for (i = 0, ii = setting_ns.length; i < ii; ++i) { name = setting_ns[i][0]; if ( !is_object(data.settings) || !is_object((o = data.settings[k])) || (v = o[name]) === undefined ) { v = (setting_ns[i].length > 1) ? setting_ns[i][1] : false; } o = config[k]; if (o === undefined) config[k] = o = {}; o[name] = v; } } return reg_count; }; API.handlers_init = {}; API.handlers = { request_end: function (data) { var id = data.id; if (typeof(id) === "string") { // Remove request delete requests_active[id]; } }, api_function: function (data, channel, reply) { var self = this, req = null, state, id, args, fn, ret; if ( typeof((id = data.id)) !== "string" || !Array.isArray((args = data.args)) ) { // Error this.reply_error(channel, reply, "Invalid extension data"); return; } // Exists if (!Array.prototype.hasOwnProperty.call(this.functions, id)) { // Error this.reply_error(channel, reply, "Invalid extension function"); return; } fn = this.functions[id]; // State if (is_object((state = data.state))) { id = state.id; req = requests_active[id]; if (req === undefined) { requests_active[id] = req = new Request(); } load_request_state(req, state); } // Callback args = Array.prototype.slice.call(args); args.push(function () { // Err var i = 0, ii = arguments.length, arguments_copy = new Array(ii); for (; i < ii; ++i) arguments_copy[i] = arguments[i]; self.send( channel, null, reply, { err: null, args: arguments_copy } ); }); // Call ret = fn.apply(req, args); }, url_info: function (data, channel, reply) { var self = this, id, url, fn; if ( typeof((id = data.id)) !== "string" || typeof((url = data.url)) !== "string" ) { // Error this.reply_error(channel, reply, "Invalid extension data"); return; } // Exists if (!Array.prototype.hasOwnProperty.call(this.url_info_functions, id)) { // Error this.reply_error(channel, reply, "Invalid extension function"); return; } fn = this.url_info_functions[id]; // Call fn(url, function (err, data) { self.send( channel, null, reply, { err: err, data: data } ); }); }, url_info_to_data: function (data, channel, reply) { var self = this, id, url_info; if ( typeof((id = data.id)) !== "string" || !is_object((url_info = data.url)) ) { // Error this.reply_error(channel, reply, "Invalid extension data"); return; } // Exists if (!Array.prototype.hasOwnProperty.call(this.url_info_to_data_functions, id)) { // Error this.reply_error(channel, reply, "Invalid extension function"); return; } // Call this.url_info_to_data_functions[id](url_info, function (err, data) { self.send( channel, null, reply, { err: err, data: data } ); }); }, create_actions: function (data, channel, reply) { var self = this, id, fn_data, fn_info; if ( typeof((id = data.id)) !== "string" || !is_object((fn_data = data.data)) || !is_object((fn_info = data.info)) ) { // Error this.reply_error(channel, reply, "Invalid extension data"); return; } // Exists if (!Array.prototype.hasOwnProperty.call(this.actions_functions, id)) { // Error this.reply_error(channel, reply, "Invalid extension function"); return; } // Call this.actions_functions[id](fn_data, fn_info, function (err, data) { self.send( channel, null, reply, { err: err, data: data } ); }); }, create_details: function (data, channel, reply) { var self = this, id, fn_data, fn_info; if ( typeof((id = data.id)) !== "string" || !is_object((fn_data = data.data)) || !is_object((fn_info = data.info)) ) { // Error this.reply_error(channel, reply, "Invalid extension data"); return; } // Exists if (!Array.prototype.hasOwnProperty.call(this.details_functions, id)) { // Error this.reply_error(channel, reply, "Invalid extension function"); return; } // Call this.details_functions[id](fn_data, fn_info, function (err, data) { self.send( channel, null, reply, { err: err, data: set_shared_node(data) } ); }); }, }; var RequestErrorMode = { None: 0, NoCache: 1, Save: 2 }; var ImageFlags = { None: 0x0, NoLeech: 0x1 }; var requests_active = {}; var Request = function () { }; var load_request_state = function (request, state) { for (var k in state) { request[k] = state[k]; } }; // Public var init = function (info, callback) { if (api === null) api = new API(); api.init(info, callback); }; var register = function (data, callback) { if (api === null) { callback.call(null, "API not init'd", 0); return; } api.register(data, callback); }; var request = function (namespace, type, unique_id, info, callback) { if (api === null || api.init_state !== 2) { callback.call(null, "API not init'd", null); return; } api.send( api.channel, "request", null, { namespace: namespace, type: type, id: unique_id, info: info }, -1, function (err, data) { if (err !== null || (err = data.err) !== null) { data = null; } else if ((data = data.data) === null) { err = "Invalid extension data"; } callback.call(null, err, data); } ); }; var insert_styles = function (styles) { var head = document.head, n; if (head) { n = document.createElement("style"); n.textContent = styles; head.appendChild(n); } }; var parse_json = function (text, def) { try { return JSON.parse(text); } catch (e) {} return def; }; var parse_html = function (text, def) { try { return new DOMParser().parseFromString(text, "text/html"); } catch (e) {} return def; }; var parse_xml = function (text, def) { try { return new DOMParser().parseFromString(text, "text/xml"); } catch (e) {} return def; }; var get_domain = function (url) { var m = /^(?:[\w\-]+):\/*((?:[\w\-]+\.)*)([\w\-]+\.[\w\-]+)/i.exec(url); return (m === null) ? [ "", "" ] : [ m[1].toLowerCase(), m[2].toLowerCase() ]; }; var get_image = function (url, flags, callback) { if (api === null || api.init_state !== 2) { callback.call(null, "API not init'd", null); return; } // Send api.send( api.channel, "get_image", null, { url: url, flags: flags }, 10000, function (err, data) { if (err !== null) { data = null; } else if (!is_object(data)) { err = "Invalid data"; } else if (typeof((err = data.err)) !== "string" && typeof((data = data.url)) !== "string") { data = null; err = "Invalid data"; } callback.call(null, err, data); } ); }; // Exports return { RequestErrorMode: RequestErrorMode, ImageFlags: ImageFlags, init: init, config: config, register: register, request: request, get_image: get_image, insert_styles: insert_styles, parse_json: parse_json, parse_html: parse_html, parse_xml: parse_xml, get_domain: get_domain, random_string: random_string, is_object: is_object, ttl_1_hour: ttl_1_hour, ttl_1_day: ttl_1_day, ttl_1_year: ttl_1_year, cache_set: cache_set, cache_get: cache_get }; })(); var main = function main_fn(xlinks_api) { var $$ = function (selector, root) { return (root || document).querySelectorAll(selector); }; var $ = (function () { var d = document; var Module = function (selector, root) { return (root || d).querySelector(selector); }; Module.add = function (parent, child) { return parent.appendChild(child); }; Module.tnode = function (text) { return d.createTextNode(text); }; Module.node = function (tag, class_name, text) { var elem = d.createElement(tag); elem.className = class_name; if (text !== undefined) { elem.textContent = text; } return elem; }; Module.node_ns = function (namespace, tag, class_name) { var elem = d.createElementNS(namespace, tag); elem.setAttribute("class", class_name); return elem; }; Module.node_simple = function (tag) { return d.createElement(tag); }; return Module; })(); var re_html = /[<>&]/g, re_html_full = /[<>&'"]/g, html_replace_map = { "<": "<", ">": ">", "&": "&", "'": "'", "\"": """ }; var escape_html = function (text, regex) { return text.replace(regex, function (m) { return html_replace_map[m]; }); }; var innerhtml_to_safe_text = function (node) { var text = "", tag_stack = [], children, par, next, n, t; par = node; n = par.firstChild; if (n === null) return text; done: while (true) { if (n.nodeType === Node.ELEMENT_NODE) { // Format tags children = false; if (n.tagName === "DIV" || n.tagName === "SPAN") { children = true; } else if (n.tagName === "B" || n.tagName === "I") { t = n.tagName.toLowerCase(); text += "<" + t + ">"; tag_stack.push(n, ""); children = true; } else if (n.tagName === "BR") { text += "
"; } else if (n.tagName === "A") { text += ""; tag_stack.push(n, ""); children = true; } else if (n.tagName === "INPUT") { if (n.getAttribute("type") === "button") { text += ""; } } else if (n.tagName === "IMG") { text += "[Image] "; } // Visit children if (children) { par = n; n = n.firstChild; } else { n = n.nextSibling; } } else { // Text node or other next = n.nextSibling; if (n.nodeType === Node.TEXT_NODE) { // Update text text += escape_html(n.nodeValue, re_html); } n = next; } // Next node while (n === null) { n = par; if (n === node) break done; if (tag_stack.length > 0) { if (n === tag_stack[tag_stack.length - 2]) { text += tag_stack[tag_stack.length - 1]; tag_stack.splice(tag_stack.length - 2, 2); } } par = n.parentNode; n = n.nextSibling; } } return text; }; var apply_safe_text_to_node = function (node, safe_text) { // Safe version of: node.innerHTML = safe_text; // Cannot inject any