mx pak1Vmbackground.html6wI css\options.css ֚def.json`$)x defaults.jsonu''xZ icon-18.pngQ+s icon.png6/r&"icons\icon_16.pngHI#Jicons\icon_32.pngBM'Uicons\icon_48.pngiT- ^includes\app.js]ڃ includes\opener.jsLlkkzincludes\viewer.js|50 js\app_bg.jscIwpjs\background.js+c js\frames.js&LJM js\options.jss~1n%o locales.json ƿ options.html{ ::-moz-selection { background: #adf; } ::selection { background: #adf; } html { min-height: 100%; background-color: #f3f3f5; cursor: default; } body { display: none; position: relative; max-width: 700px; min-height: 300px; margin: 0 auto; padding: 6px 15px 15px; border-top: 0; box-shadow: 0 0 6px #666; -webkit-box-shadow: 0 0 6px #666; background-color: #fff; font: 13px "Lucida Grande", "Lucida Sans Unicode", "Tahoma", sans-serif; } a { text-decoration: none; color: #1155ef; } a:hover { color: #000; } :focus { outline: none; } .fn { float: none; } /* http://nicolasgallagher.com/micro-clearfix-hack/ */ .cf::after { content: ""; display: block; clear: both; } hr { border: 1px solid #eee; margin: 10px 0; } #right-panel { position: absolute; left: 100%; top: 0; } #right-panel > aside { max-width: 140px; position: fixed; top: 0; padding: 0 5px 3px 8px; box-shadow: 2px 2px 2px #aaa; -webkit-box-shadow: 2px 2px 2px #aaa; background-color: rgba(255, 255, 255, .8); overflow: hidden; text-align: center; } #right-panel > aside, section { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } aside > .app-info { font-weight: bold; } #platform-info { font: normal 8px sans-serif; color: gray; } .hidden, body.opera .opera, body.firefox .firefox, body.chrome .chrome, body.safari .safari, body.maxthon .maxthon { display: none; } .logo { display: block; width: 128px; height: 128px; margin-top: 5px; border-radius: 10px; background: url(../icon.png) no-repeat center; -webkit-transition: -webkit-box-shadow .2s; transition: box-shadow .2s; } .logo:hover { box-shadow: 0 0 10px #bef; -webkit-box-shadow: 0 0 10px #bef; } body > form > section { display: none; } nav { margin-bottom: 20px; text-align: center; } nav > a { display: inline-block; border-bottom: 3px solid transparent; padding: 5px 6px; color: #1155ef; text-decoration: none; -webkit-transition: border-bottom-color .5s; transition: border-bottom-color .5s; } nav > a:hover { -webkit-transition: border-bottom-color 0s; transition: border-bottom-color 0s; border-bottom: 3px solid #aaf; color: #000; } nav > .active { color: #000; border-bottom: 3px solid #000; } .prow { clear: both; padding-bottom: 3px; } .prow, .tiptop { position: relative; } .tip { visibility: hidden; max-width: 100%; width: 33px; height: 25px; z-index: 1; position: absolute; left: -48px; top: -5px; border: 1px solid transparent; padding: 5px 7px; overflow: hidden; opacity: 0; font: 12px/150% Verdana, sans-serif; white-space: pre-wrap; color: rgba(0, 0, 0, 0); -webkit-transition: visibility 0s 0.5s, opacity 0.5s, color .7s; transition: visibility 0s 0.5s, opacity 0.5s, color .7s; } .tiptop:hover > .tip:not(:empty) { visibility: visible; opacity: 1; -webkit-transition-delay: 0s; transition-delay: 0s; } .tip:hover { width: auto; height: auto; left: -45px; border: 1px solid #ddd; border-left: none; border-radius: 6px; padding: 10px; padding-left: 40px; box-shadow: 0 0 10px #666; -webkit-box-shadow: 0 0 10px #666; background-color: rgba(245, 245, 255, .9); background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #fff), color-stop(100%, rgba(245, 245, 255, 0))); background-image: linear-gradient(to bottom, #fff, rgba(245, 245, 255, 0)); overflow: visible; color: #000; } .tip::before { display: inline-block; margin-right: 20px; border: 3px solid #aaa; border-right: none; border-radius: 10px 6px 6px 10px; padding: 0 6px 2px; text-align: center; text-shadow: 0 0 3px #000, 0 0 3px #000; font: 700 17px Verdana, sans-serif; color: #fff; content: "?"; } .tip:hover::before { position: absolute; left: 5px; top: 5px; } .prow > label, .prow > span:not(.clean) { display: inline-block; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; width: 49.6%; } .prow > label { padding-top: 8px; } .prow:hover label:not(.checkbox), label:not(.checkbox):hover { color: #45f; } .prow > span:not(.clean) { float: right; max-width: 50%; margin-top: 4px; text-align: right; } .prow input[type="text"] { width: 300px; } .prow select { max-width: 308px; } .prow input[type="color"] + input[type="text"], .shorter-input { width: 242px; vertical-align: middle; } .prowone > label, .prowone > span { width: auto !important; padding: 2px 0; } .sub-opt { padding-left: 20px; } input, textarea, select, code, .checkbox, .pager > a { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; margin: 2px; border: 1px solid #ddd; border-radius: 3px; padding: 3px; background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #fff), color-stop(100%, #f5f5f5)); background-image: linear-gradient(to bottom, #fff, #f5f5f5); background-color: rgba(242, 242, 242, 0); font: 13px Verdana, sans-serif; -webkit-transition: color .2s, border-color .2s; transition: color .2s, border-color .2s; } pre, code, textarea { font: 13px Consolas, Monaco, monospace; transition: all 0s; } code { display: inline-block; border: 1px solid silver; padding: 3px 5px; background-image: linear-gradient(to bottom, #FFFFFF, #F5F5F5); } select { max-width: 100%; } textarea { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; width: 100%; overflow-x: hidden; resize: none; -webkit-tab-size: 4; -moz-tab-size: 4; -o-tab-size: 4; tab-size: 4; } select:focus, textarea:focus, input[type="text"]:focus, input:hover, select:hover, textarea:hover, .prow:hover input, .prow:hover select, label:hover input, .pager > a:hover, .prow:hover .checkbox, label:hover > .checkbox, .checkbox:hover { border: 1px solid #888; } input[type="checkbox"] { display: none; } .checkbox { display: inline-block; width: 20px; height: 20px; position: relative; padding: 0; vertical-align: middle; color: transparent; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .checkbox::after { position: absolute; left: 3px; top: 0; font-weight: 700; content: "✔"; } input[type="checkbox"]:checked + .checkbox { color: #616161; } input[type="number"], input[type="color"] { width: 50px; text-align: center; } input[type="color"] { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; padding: 2px; background: none; vertical-align: middle; } input[type="number"] { width: 60px; box-shadow: none; /* Firefox marks "invalid" inputs */ } input[type="range"] { height: 24px; vertical-align: middle; } output { display: inline-block; min-width: 24px; } h3 { clear: left; } .color-helper { float: right; opacity: 0.3; transition: opacity .3s; } .color-helper:hover { opacity: 1; } .color-helper > input[type="text"] { width: 80px !important; } .shortcuts > label { display: block; } .shortcuts > label:hover input { border: 1px solid #aaa; } .shortcuts input, .sub-shortcuts input { width: 35px; margin: 5px; text-align: center; } .sub-shortcuts input { margin: 0; } .sub-shortcuts li { line-height: 200%; } .op-buttons > button, .action-buttons > span { position: relative; border-radius: 3px; border: 1px solid #ddd; background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #fff), color-stop(100%, #f5f5f5)); background-image: linear-gradient(to bottom, #fff, #f5f5f5); font-weight: 700; font-size: 14px; color: #000; cursor: pointer; } .op-buttons > button { width: 95%; margin-bottom: 10px; padding: 10px 0; box-shadow: 0 1px 2px rgba(0, 0, 0, .5); -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .5); font: 700 14px Arial; -webkit-transition: border-color .3s, color .3s; transition: border-color .3s, color .3s; } .op-buttons > button:hover { border: 1px solid #999; } .container-info { text-align: center; } #info-sec > pre { white-space: pre-line; } #locales-table { margin: 0 auto; border-collapse: separate; border-spacing: 25px 2px; font: 13px Consolas, Monaco; } #locales-table > tr:hover { margin: 0 auto; border-collapse: separate; border-spacing: 25px 2px; font: 13px Consolas, Monaco; } #locales-table th:first-child { text-align: left; } #locales-table td:last-child { text-align: center; } [{ "type": "extension", "frameworkVersion": "1.0.1", "guid": "{000008f5-8a32-4389-a7da-2daa0e9d7760}", "version": "1.0.0", "title": {"en": "Viewhance"}, "description": {"_t": "APP_DESCRIPTION"}, "author": { "name": "Deathamns", "email": "deathamns@gmail.com" }, "permissions": {"httpRequest": ["*"]}, "config": "options.html", "service": { "main": "background.html#Viewhance,1.0.0" }, "actions": [ { "type": "script", "entryPoints": ["doc_start"], "exclude": ["res"], "js": [ "includes/app.js", "includes/viewer.js" ], "includeFrames": true }, { "type": "script", "entryPoints": ["doc_end"], "exclude": ["res"], "js": [ "includes/opener.js" ], "includeFrames": true } ] }] // Wed, 06 May 2015 19:58:00 GMT { "mode": 1, "minUpscale": 0, "mediaInfo": "%ow\u00d7%oh | %name (%perc%)", "favicon": "", "customCSS": "", "center": true, "wheelZoom": false, "video": true, "vidattrs": "autoplay controls", "lpDelay": 350, "lpLeft": 1, "lpRight": 0, "sendTo": [ "TinEye|https://www.tineye.com/search?sort=size&order=desc&url=%url", "Google|https://images.google.com/searchbyimage?image_url=%url", "Bing|https://www.bing.com/images/searchbyimage?cbir=sbi&imgurl=%url", "Yandex|https://images.yandex.ru/yandsearch?rpt=imagecbir&img_url=%url", "KarmaDecay|http://karmadecay.com/%url", "ZXing QRCode|http://zxing.org/w/decode?full=true&u=%url", "ImgOps|https://imgops.com/%url", "Pixlr|https://apps.pixlr.com/editor/?image=%url", "PicMonkey|https://www.picmonkey.com/service?_import=%url" ], "key_mOrig": "0", "key_mFit": "1", "key_mFitW": "2", "key_mFitH": "3", "key_rotL": "E", "key_rotR": "R", "key_flipH": "Q", "key_flipV": "W", "key_cycle": "C", "opener": 0 } PNG  IHDRVΎWIDAT8oTU3Ngj -!Z0jq>\r^]pmA6IiJC;;y9~>n%R %"ԍsxywy?RRh0ZhEV_7b]1rlXg)QR?o]k@1es˫K\ѣ/D!pej38Ȑo}gNҡYzuH70Q184XYhr ,.&YO,ZE&^%Ĭ%s'dU1³cc䝘c:1//'ZOk[zTOxLf<WJ+r9HC{k/MnmDŽZ]#BCLYY@`+P*/lw"wIDATx^}\y{oL!"aB CJfM ;ة-QFF&6 ,JZvx7"Ļ|H`&,rbhFf43=}ϻ;ۭAVܹV?yޏVrAE0- $ @9BNLO%2P''`L(}yD!8Ao'^TU4JS@+CyAބ.~'{U5TQ* hO0mʊ>^9УLV9䑲"NEmY; iN_?+A%l aWB:V01EK1>7W 8YP-2W%=ƔdWR_9J>b' Z'QP,Ok'ӬF#SB#>· wAB'VP ,;_M& <8Iޛ +bi}y pն,LE,?I!%arrYc/N^R9(XNPa`gloV)y&"]fz\VL ? !,K'p"~Y;YKؒ\^HOz@Y)X~f.{G$[@j$(81I!]/Jo!TqNkTpdoOSs_Q@8C0t.лٯ鍴uGVTC1>~7NhCR>|ƚ@o pe Y#,Ƒ 4k.'=OlOUƝyOؚ@Qa IDI+9<9]H < u[MEXCJ 8%Lr\`9 pP#lO2pGDu'#hIbGNqHWTp1(Fѫ!(VH^o茂/E3XMfJfb%8pD}Eq2 {ŮGYNYeMvu)`yǂw5$EZ̒P$@mHiΤ>,i; F~DpBOe(Y9+E1P~ {m>& 㰮 Vvnd@ ¾@)#{U( ?Bf >~=C7\ h("{zt'ɳ nBN7\Dҳbƻ{&BoOVSčk4sU #iǚX8S*#E`2cMcLM QmBi,8fʖ _~n߽{LdD8Xa`S$m34]λ~ {GENHV P_pMH7j^v+u`h ;lpv2VBy&!`8@rH;C避xw1>?% i׌Ǐv݀ˊNˉ ,7atXI$.xkHnչWuXpoٞm;Wv\u0p9xL<+Q"WZRIcɲ1$!/3ː=#+/;p^ᤁv@T5XpW :fw92(܀2/ o3",F,qJG[>8{7TPgR2?'=9K۹ARE:et6&>yu]^D%1$= gO8p~;Aё^/kҀdlPyPˁݺ8g&"ZCu,+ 9B038~- 㴂CNxx׌ .Vގi;]x<`G[Rъj)椠 CI( kĕ{vYBv(vxi?AQj d9ۂAj/\noR( x;R!rCv%;lㅀytz`‹f?]>vզ}lE$\_cZp,?@$p໮֦<@{1{uGú)ǸQHQc͉'r5C x c< .Q7t#@υ7@[Ӑ~\vٺuTLj@b]pIgC\24fJo)g8.v˜*+OdX%,~El]}яͳOѫH'ޔ@A]>)tFv\^Qk'>xstN9p@MPE%N`GgϭɊ.R塆0J^@8 LՐeUhUV} <^nW 53to&˝+ \NZD^2!E~TIBPgk\*WGgPm:)_2JpH_qb 1@vHr z!t,Z-e&aΩQBxޓi_KODsZ*()-Sc:@]o%?67waL,ZSO ɫ02U~Uk?hC_RoBHJ7ح ߕӑ#i jODHVt I(laS`DtVh/挗0&I1/: 8###x5󟭶Xn{E?ъUg<3SӐ> \^^l=3fDpI_Aӿ(N[JyH`]lh3Pi+R#SPձN9BvҾ;Ib7(7\MXSSY8[ٰ[B`t$\cB@&p)*uy|ݭ'?kS+3dž9rJ&r*74~]@{iZC FTƐ#p>BGzY?ҬQUS6qp2W&зRjdZ3G3)SOj:G,xJPo2Y [FDgϋ{.8 94R͏wj~Dbmt~dՈ p%%ڋ 9:Sq倫4(H_I:!}چ KN"(o=]u GN\G"m Xno X;-ʃX Gj|BiLQYm0 o6γI#,_p^ܙOYX0rDP_@VFK̉Sqp\8xTj8ʷL.oE` . 9/9u? 2(־9;)Vlv{ҥ_$\2A’k.Tj="=,? yߨEoB<}A蟟8οs$P`p rMSC A,S}3X»ܩ/8;pAsh%k@0ȋ8 n|c7́I3tǔ4:ہ`R၍3Q_>>)Li,}eblVZkCz@X[Ṕj( /ŝȡ].>;"s4S䮸@[9Yq;sG[?g;ز|0#_ȁC?5 2^p>%78vkjǥ 6>{r`LJ+ |Ng,]q;ՂAD~d@y;G ;pO?>Efas q7F1P 0qd3̱! 9c|vӓAB2_󡒘6|{;+>q>qX Ld!P8hC}ɂDhpON:tqgI*zŤzǐ<'9 A,.-A /d^36wu; '#ä~++s΃&0"zfQXxKib|X߼AAOG`EꄽfqHh *J(*z\  2!w^1 y̿ mT^ <\O4zt R"@8@'2priE:o8H`~U@? Uc[tR %qq/ZE3SS @GD71%[1h肜J~A`pcoe* b5RxQDdP*$Ah Ϋ eE߷&]8qL;=F2D1 lD|h*Sj?:L!n g0y V~y[}ndlfuJ\ ](! 1'\eJ_~jHnqB/.IrԄnIENDB`PNG  IHDRasRGBgAMA a pHYsodtEXtSoftwarepaint.net 4.0;imIDAT8O-Ogg-zv%[nD3c&u )ȀЁRhK-WGKKm)-`2~{J<;s]ܒTy[ǁx#PLm#HCIO|/cQ9K^ex)`UxUJ&Dps 7vrᵋ̆"K#ĥlNd<;q5,]J6}/d&'IrB ͨYEaG.G[ G+GS5cIQtk M?!.!OCR9*\<`iSbMZ Uzp-@SG>@f(%7R4xtv)e|] wpoZ x@#͗C>jܚKro]t,'(LIFW;Ẓ^'< qFb1M=EXjwtyDq *=.bk[vNiԌopJ,:g#\jRP?9CBl:~vɯln3F~kf8U9Li<:*tV:3 q /7Ňl}{{\OsM^f?UkLs;3?(yN >R=J6`r&^I.?n(%-xﺞ_aa+U[LwYYiz3M׊Jz(}sa:*wE:ߋ2OMiLE2 ~эyh 0Q4K{]9ߟ4nd KF?֌r﹋ujcqGW+aIENDB`PNG  IHDR DPLTEֱԭԣϝԝˍЊ҇ч҇ӋՍԌҐ֔Քڙڔ֑Շ΃͂Ђ̅}urrk|ۄޅ}uruvzrnpswx~ܑܛޡߠݩݮ۳ڮ֚ڙ̍ЅȒÌʷyzrĴsqfgc^TNI}Bw:t>p9f2e5_;Z8T1W3N2I1F8B@IEMCXHbJdPoWwVvbjkukxj|lor|}{}jph{nj[_Q_F~EB8ӌ+fH؀ D fl8{sM8 ]#r;c=ht!Z!֋ay|[u߽7nˆe [of_-vb.@|yҐ,o~AX4/ޓh.8?є4*KvGC,Fo?װXBSez+QLő #L'֛፣CNڪ?EC,e䋭`nj~L&kӓBteL}08!$5J('U~^ja4(v)0~@T+nH "h%@K3 ^#UQ MT@9_ zĚ^'[IENDB`PNG  IHDR00` PLTEms$v(z084:?H~EzBw?q;k3i9c3`2Z:[:T2S9N7J0J4C;EBLCXASNZHaPfPn^hm`TT2;1rMVQX\dblluqkox~}ل܇҇ыӑ֌ԍѐՌדٔ՘טܕےݗٛߵݦוӖztwvsmmg`V^bhqy~}ysouqɃЂ~̂̇φЍӉɅ̝ʤΗ٤ܵ٥ɠqlxY\cSSrJKA@S`lzeqZ{b}jϴ֖omyqidyъޠűǣܧިץ̟s8itRNS0>I|IDATx]ole img#img_elem:first-child, ' + 'body > ' + 'video[name=media][controls][autoplay]:first-child:not([src]) >' + 'source[src]:only-child' ); if ( !media ) { return this._mediaType; } if ( media.src !== location.href && media.currentSrc !== location.href ) { return this._mediaType; } if ( media.parentNode !== document.body ) { media = document.body.firstElementChild; } return this._mediaType = media.nodeName.toLowerCase(); }, set: function(type) { this._mediaType = type; }}); vAPI.messaging = { listenerId: Math.random().toString(36).slice(2), emptyListener: function() {}, listen: function(listener, once) { if ( this.listener ) { vAPI.runtime.listen(this.listenerId, this.emptyListener); } if ( typeof listener !== 'function' ) { this.listener = null; return; } this.listener = function(e) { listener(e); if ( once ) { vAPI.messaging.listen(null); } }; vAPI.runtime.listen(this.listenerId, this.listener); }, send: function(message, callback) { if ( typeof callback === 'function' ) { this.listen(callback, true); } vAPI.runtime.post('service', { message: message, listenerId: this.listenerId, origin: location.href }); } }; if ( location.protocol === 'mxaddon-pkg:' ) { vAPI.i18n = function(s) { var t = vAPI.runtime.locale.t(s) || s; return t[0] === '"' ? JSON.parse(t) : t; }; vAPI.insertHTML = function(n, html) { n.innerHTML = html; }; } 'use strict'; (function() { if ( document instanceof window.HTMLDocument === false ) { return; } // Should not run on media documents if ( vAPI.mediaType ) { return; } if ( vAPI.safari && location.protocol === 'safari-extension:' ) { return; } vAPI.messaging.send({cmd: 'loadPrefs', property: 'opener'}, function(response) { var opener = response && response.prefs; if ( !opener ) { return; } var lastMouseDownTime, lastMouseDownX, lastMouseDownY; var checkBG = function(cs) { // ("...\"") - Gecko // (...) or ('...)') - WebKit // ("..."") - Presto var rgxCssUrl = /\burl\(([^'"\)][^\)]*|"[^"\\]+(?:\\.[^"\\]*)*|'[^'\\]+(?:\\.[^'\\]*)*)(?=['"]?\))/g; var imgs = cs.backgroundImage + cs.content + cs.listStyleImage; imgs = imgs.match(rgxCssUrl); if ( imgs === null ) { return imgs; } for ( var i = 0, pos; i < imgs.length; ++i ) { pos = imgs[i][4]; pos = pos === '"' || pos === "'" ? 5 : 4; imgs[i] = imgs[i].slice(pos); } return imgs; }; var checkIMG = function(node) { var nname = node.nodeName.toUpperCase(); if ( nname === 'IMG' || nname === 'EMBED' || node.type === 'image' ) { return node.src; } else if ( nname === 'CANVAS' ) { return node.toDataURL(); } else if ( nname === 'OBJECT' ) { if ( node.data ) { return node.data; } } else if ( nname === 'AREA' ) { var img = document.querySelector( 'img[usemap="#' + node.parentNode.name + '"]' ); if ( img && img.src ) { return img.src; } } else if ( nname === 'VIDEO' ) { nname = document.createElement('canvas'); nname.width = node.clientWidth; nname.height = node.clientHeight; nname.getContext('2d').drawImage( node, 0, 0, nname.width, nname.height ); return nname.toDataURL('image/jpeg'); } else if ( /^\[object SVG/.test(node.toString()) ) { var svgString = (new window.XMLSerializer).serializeToString( node.ownerSVGElement === null ? node : node.ownerSVGElement ); if ( typeof svgString === 'string' ) { return 'data:image/svg+xml,' + encodeURIComponent( svgString ); } } else if ( node.poster ) { return node.poster; } return null; }; window.addEventListener('mousedown', function(e) { if ( e.button !== 2 ) { return; } lastMouseDownTime = e.timeStamp; // context menu should work where the mousedown happened (Chrome...) lastMouseDownX = e.clientX; lastMouseDownY = e.clientY; }, true); window.addEventListener('contextmenu', function(e) { if ( e.button !== 2 || !lastMouseDownTime ) { return; } if ( lastMouseDownX !== e.clientX || lastMouseDownY !== e.clientY ) { return; } var elapsed = e.timeStamp - lastMouseDownTime >= 300; if ( !(e.ctrlKey && e.altKey && !e.shiftKey && !elapsed && opener > 1 || elapsed && (opener === 1 || opener === 3) && !e.ctrlKey && !e.shiftKey && !e.altKey) ) { return; } var url, r; var urls = []; var el = 30; var rgxIgnore = /^(html|body)$/i; // not exactly what we want var xpath = document.evaluate([ '.', './ancestor::*[position()<' + el + ']', './preceding::*[position()<' + el + '][not(head) and not(ancestor::head)]', './descendant::*[position()<' + el + ']', './following::*[position()<' + el + ']' ].join(' | '), e.target, null, 4, null ); while ( el = xpath.iterateNext() ) { if ( rgxIgnore.test(el.nodeName) && !rgxIgnore.test(e.target.nodeName) ) { continue; } r = el.getBoundingClientRect(); if ( !r ) { continue; } if ( e.clientX < r.left || e.clientX > r.left + r.width || e.clientY < r.top || e.clientY > r.top + r.height ) { continue; } if ( url = checkIMG(el) ) { urls.push(url); } if ( url = checkBG(window.getComputedStyle(el)) ) { urls = urls.concat(url); } } if ( !urls || !urls.length ) { return; } e.stopImmediatePropagation(); e.preventDefault(); var i; var filter = {}; for ( i = 0; i < urls.length; ++i ) { if ( urls[i] === 'about:blank' ) { continue; } filter[urls[i]] = true; } vAPI.messaging.send({ cmd: 'open', url: Object.keys(filter).reverse() }); }, true); }); })(); 'use strict'; var init = function(win, doc, response) { if ( !doc || !doc.body || !response || !response.prefs ) { init = null; return; } var cfg = response.prefs; var media = doc.body.querySelector('img' + (cfg.video ? ', video' : '')); if ( !media ) { init = null; return; } var pdsp = function(e, d, p) { if ( !e || !e.preventDefault || !e.stopPropagation ) { return; } if ( d === void 0 || d === true ) { e.preventDefault(); } if ( p !== false ) { e.stopImmediatePropagation(); } }; var shortcut = { specKeys: { 8: 'Backspace', 9: 'Tab', 13: 'Enter', 16: 'Shift', 17: 'Ctrl', 18: 'Alt', 27: 'Esc', 32: 'Space', 33: 'PgUp', 34: 'PgDn', 35: 'End', 36: 'Home', 37: 'Left', 38: 'Up', 39: 'Right', 40: 'Down', 45: 'Ins', 46: 'Del', 96: '0', 97: '1', 98: '2', 99: '3', 100: '4', 101: '5', 102: '6', 103: '7', 104: '8', 105: '9', 106: '*', 107: '+', 109: '-', 110: '.', 111: '/', 186: ';', 187: '=', 188: ',', 189: '-', 190: '.', 191: '/', 192: '`', 219: '[', 220: '\\', 221: ']', 222: "'", 112: 'F1', 113: 'F2', 114: 'F3', 115: 'F4', 116: 'F5', 117: 'F6', 118: 'F7', 119: 'F8', 120: 'F9', 121: 'F10', 122: 'F11', 123: 'F12' }, isModifier: function(e) { return e.which > 15 && e.which < 19; }, key: function(e) { return this.specKeys[e.which] || String.fromCharCode(e.which).toUpperCase(); } }; var root, head, initParams, panning, winW, winH, sX, sY; var noFit = {cur: false, real: false}; var lastEvent = {}; var progress = null; var cancelAction = false; var freeZoom = null; var dragSlide = []; var borderSize = 0; var MAXSIZE = 0x7fff; media.style.display = 'none'; ['class', 'style', 'name'].forEach(function(attr) { doc.documentElement.removeAttribute(attr); doc.body.removeAttribute(attr); media.removeAttribute(attr); }); if ( head = doc.querySelector('head') ) { doc.documentElement.removeChild(head); } head = doc.createElement('head'); if ( cfg.favicon ) { root = doc.createElement('link'); root.rel = 'shortcut icon'; root.href = cfg.favicon === '%url' && vAPI.mediaType === 'img' ? win.location.href : cfg.favicon.replace('%url', encodeURIComponent(win.location.href)); head.appendChild(root); } head.appendChild(doc.createElement('style')).textContent = [ 'html, body {', 'width: 100%;', 'height: 100%;', '-webkit-user-select: none;', '-moz-user-select: none;', '-ms-user-select: none;', '}', 'body {', 'margin: 0;', 'padding: 0;', 'font: 12px "Trebuchet MS", sans-serif;', 'cursor: default;', '}', '#main-media {', vAPI.browser['box-sizing-css'], ': border-box;', 'position: absolute;', 'margin: 0;', 'background-clip: padding-box;', '}', 'html.audio #main-media {', 'width: 50%;', 'height: 40px !important;', 'min-width: 300px;', 'max-width: 1000px;', 'position: absolute;', 'top: 0;', 'right: 0;', 'bottom: 0;', 'left: 0;', 'margin: auto;', 'box-shadow: none;', 'background: transparent;', '}', 'html.load-failed #main-media {', 'margin: auto', 'box-shadow: 0 0 10px red;', '}', 'html.fullscreen #main-media {', 'background: black !important;', '}', '#main-media:-moz-full-screen {', 'background: black !important;', '}', 'html.load-failed > body > h2 {', 'text-shadow: 1px 1px 15px firebrick;', '}', '#main-media.m-1 {', 'width: auto;', 'height: auto;', 'max-width: 100%;', 'max-height: 100%;', '}', '#main-media.m-2 {', 'width: 100%;', 'height:auto;', '}', '#main-media.m-3 {', 'height: 100%;', 'width: auto;', '}', 'h2 {', 'margin: 0;', 'padding-top: 15%;', 'text-align: center;', 'text-shadow: 1px 1px 15px #000;', 'font: 700 30px "Trebuchet MS", sans-serif;', 'color: #fff;', '}', 'a {', 'text-decoration: none;', '}', ':focus {', 'outline: 0;', '}', ':invalid {', 'box-shadow: none;', '}', '#menu {', 'width: 50px;', 'height: 33.33%;', 'position: fixed;', 'top: 0;', 'opacity: 0;', vAPI.browser['transition-css'], ': opacity .25s, left .2s;', '}', 'ul {', 'display: inline-block;', 'margin: 0;', 'padding: 5px 15px;', 'background: rgba(0, 0, 0, .6); color: #fff;', 'font-size: 25px; font-weight: 700;', 'text-align: center;', 'list-style: none;', '}', 'li {', 'display: block;', 'position: relative;', '}', 'li[data-cmd] {', 'cursor: pointer;', '}', 'li[data-cmd=cycle], li[data-cmd=rotate] {', 'position: relative;', '}', 'li[data-cmd=cycle]::after {', 'position: absolute;', 'left: 25%;', 'content: "\u2195";', '}', 'li[data-cmd=rotate]::after {', 'position: absolute;', 'left: 2px;', 'content: "\u21BB";', '}', 'li ul {', 'visibility: hidden;', 'position: absolute;', 'left: 100%;', 'top: 0;', 'text-align: left;', 'opacity: 0;', vAPI.browser['transition-css'], ': visibility .4s, opacity .2s .3s;', '}', 'li:hover ul {', 'display: block;', 'visibility: visible;', 'opacity: 1;', '}', 'li ul > li {', 'display: block !important;', 'padding: 3px 0;', 'font-size: 15px;', '}', '.send-hosts li > a {', 'padding-left: 25px;', 'background-size: 16px 16px;', 'background-repeat: no-repeat;', 'background-position: 0 3px;', 'color: #fff;', '}', '#menu > ul > li:hover, .send-hosts li > a:hover {', 'color: silver;', '}', 'li ul > li {', 'white-space: nowrap;', '}', '.filters > ul {', 'font-size: 15px;', '}', '.filters > form {', 'margin: 0;', 'padding: 0;', '}', 'body.frames {', 'overflow-y: scroll !important;', 'text-align: center;', '}', 'body.frames * {', 'margin: 2px;', '}', '#frames > canvas, #frames > img {', 'display: none;', '}', '#current-frame + output {', 'display: inline-block;', 'width: 65px;', 'font-family: Conoslas, monospace;', 'text-align: right;', '}', '.back {', 'font-size: 150%;', 'text-decoration: none;', 'color: black;', '}', '#frames.showall > img, #frames.showall > canvas {', 'display: inline-block !important;', '}', // Custom or default styling cfg.customCSS || 'body {background: silver; overflow: hidden;}' + '#main-media {background: white; box-shadow: 0 0 5px grey;}' ].join(''); doc.documentElement.insertBefore(head, doc.body); init = function() { if ( !(media.naturalWidth || media.width || media.videoWidth || vAPI.mediaType === 'audio' || initParams === null) ) { if ( initParams && ++initParams.loop >= initParams.maxLoop && progress ) { clearInterval(progress); } return; } if ( progress ) { clearInterval(progress); progress = null; } root.classList.add(vAPI.mediaType); if ( vAPI.mediaType === 'img' ) { doc.body.replaceChild(media, doc.images[0]); } else if ( vAPI.mediaType === 'video' ) { media.naturalWidth = media.videoWidth; media.naturalHeight = media.videoHeight; } [].forEach.call(doc.body.childNodes, function(node) { if ( media !== node ) { node.parentNode.removeChild(node); } }); media.style.display = 'block'; if ( vAPI.mediaType === 'audio' ) { return; } head.appendChild(doc.createElement('style')).textContent = '#main-media {max-width:' + Math.min( MAXSIZE, Math.floor(media.naturalWidth * MAXSIZE / media.naturalHeight) ) + 'px;max-height:' + Math.min( MAXSIZE, Math.floor(media.naturalHeight * MAXSIZE / media.naturalWidth) ) + 'px}'; if ( !cfg.mediaInfo ) { cfg.mediaInfo = false; } cfg.hiddenScrollbars = win.getComputedStyle(root).overflow === 'hidden' || win.getComputedStyle(doc.body).overflow === 'hidden'; var menu = doc.body.appendChild(doc.createElement('div')); menu.id = 'menu'; if ( win.getComputedStyle(menu).display === 'none' ) { doc.body.removeChild(menu); menu = null; } else { menu.style.cssText = '-webkit-filter: blur(0px); filter: blur(0px)'; if ( menu.style.filter || menu.style.webkitFilter ) { media.filters = Object.create(null); menu.onchange = function(e) { var t = e.target; var filterCSS = ''; var filterName; if ( !t.value ) { media.style.filter = media.style.webkitFilter = filterCSS; return; } if ( t.value === t.defaultValue ) { delete media.filters[t.parentNode.textContent.trim()]; } else { filterName = t.parentNode.textContent.trim(); media.filters[filterName] = t.value + t.getAttribute('unit'); } for ( filterName in media.filters ) { filterCSS += filterName + '(' + media.filters[filterName] + ') '; } media.style.filter = media.style.webkitFilter = filterCSS; }; } vAPI.buildNodes(menu.appendChild(doc.createElement('ul')), [ {tag: 'li', attrs: {'data-cmd': 'cycle'}, text: '\u2194'}, {tag: 'li', attrs: {'data-cmd': 'zoom'}, nodes: [ {tag: 'span', attrs: {style: 'visibility: hidden'}, text: '.'}, {tag: 'span', attrs: {style: 'transform: rotate(-45deg); position: absolute; left: 20%; font-size: 125%'}, text: '\u26B2'} ]}, {tag: 'li', attrs: {'data-cmd': 'flip'}, text: '\u21CB'}, {tag: 'li', attrs: {'data-cmd': 'rotate'}, text: '\u21BA'}, media.filters ? {tag: 'li', attrs: {'class': 'filters'}, nodes: [ '\u2261', {tag: 'form', nodes: [{tag: 'ul', nodes: [ {tag: 'li', nodes: [{tag: 'input', attrs: { type: 'range', min: 0, max: 250, step: 10, value: 100, unit: '%'} }, ' brightness']}, {tag: 'li', nodes: [{tag: 'input', attrs: { type: 'range', min: 0, max: 300, step: 25, value: 100, unit: '%'} }, ' contrast']}, {tag: 'li', nodes: [{tag: 'input', attrs: { type: 'range', min: 0, max: 1000, step: 50, value: 100, unit: '%'} }, ' saturate']}, {tag: 'li', nodes: [{tag: 'input', attrs: { type: 'range', min: 0, max: 100, step: 25, value: 0, unit: '%'} }, ' grayscale']}, {tag: 'li', nodes: [{tag: 'input', attrs: { type: 'range', min: 0, max: 100, step: 100, value: 0, unit: '%'} }, ' invert']}, {tag: 'li', nodes: [{tag: 'input', attrs: { type: 'range', min: 0, max: 100, step: 20, value: 0, unit: '%'} }, ' sepia']}, {tag: 'li', nodes: [{tag: 'input', attrs: { type: 'range', min: 0, max: 360, step: 36, value: 0, unit: 'deg'} }, ' hue-rotate']}, {tag: 'li', nodes: [{tag: 'input', attrs: { type: 'range', min: 0, max: 20, step: 1, value: 0, unit: 'px'}}, ' blur']} ]}]} ]} : '', {tag: 'li', attrs: {'data-cmd': 'reset'}, text: '\u2715'}, /^https?:$/.test(win.location.protocol) && cfg.sendTo.length ? {tag: 'li', attrs: {'class': 'send-hosts'}, nodes: [ '\u2197', {tag: 'ul', nodes: cfg.sendTo.map(function(item) { var host = item.split('|'); return {tag: 'li', nodes: [{ tag: 'a', attrs: { href: host.slice(1).join('|') }, text: host[0] }]}; })} ]} : null, vAPI.mediaType === 'img' ? {tag: 'li', attrs: {'data-cmd': 'frames'}, text: '\u22EF'} : '', {tag: 'li', attrs: {'data-cmd': 'options'}, text: '\u2713'} ]); menu.style.cssText = 'display: none; left: -' + menu.offsetWidth + 'px'; menu.addEventListener('mousedown', function(e) { var t = e.target; if ( t.href && t.href.indexOf('%', t.host.length) > -1 ) { t.href = t.href.replace(/%url/, encodeURIComponent(media.src)); } pdsp(e, !!t.textContent); }, false); // Load favicons only when the menu item is hovered the first time if ( /^https?:$/.test(win.location.protocol) && cfg.sendTo.length ) { menu.querySelector('.send-hosts').onmouseover = function() { this.onmouseover = null; var links = this.querySelectorAll('.send-hosts > ul > li > a'); [].forEach.call(links, function(a) { var url = a.getAttribute('data-favicon') || a.host + '/favicon.ico'; a.style.backgroundImage = 'url(' + a.protocol + '//' + url + ')'; }); }; } var handleCommand = function(cmd, e) { if ( e.button === 1 ) { return; } var p = e.type.indexOf('wheel') > -1 && (-e.wheelDelta || e.deltaY) > 0 || e.button === 2 ? 1 : 0; if ( cmd === 'cycle' ) { media.cycle(!p); } else if ( cmd === 'flip' ) { media.flip(media, p); } else if ( cmd === 'rotate' ) { media.rotate(!p, e.ctrlKey); } else if ( cmd === 'zoom' ) { pdsp(e); media.zoomToCenter({wheelDelta: p ? -1 : 1}); } else if ( cmd === 'reset' && e.button === 0 ) { media.reset(); } else if ( cmd === 'frames' ) { vAPI.messaging.send({cmd: 'frames.js'}, function(data) { var errorHandler = function(msg) { // Success if ( msg !== null ) { alert(msg); // eslint-disable-line var frms = menu.querySelector('li[data-cmd="frames"]'); frms.removeAttribute('data-cmd'); frms.style.opacity = '0.2'; return; } if ( vAPI.maxthon ) { win.addEventListener('mousedown', function(ev) { pdsp(ev, false); }, true); } }; Function( 'win', 'drawFullFrame', 'errorHandler', data['frames.js'] )(win, e.button === 0, errorHandler); }); } else if ( cmd === 'options' && e.button === 0 ) { vAPI.messaging.send({cmd: 'open', url: 'options.html'}); } else { p = null; } if ( p !== null ) { pdsp(e); } }; menu.addEventListener(vAPI.browser.wheel, function(e) { var t = e.target; if ( t.nodeType === 3 ) { t = t.parentNode; } if ( t.type === 'range' ) { t.value = Math.max( t.getAttribute('min'), Math.min( parseInt(t.value, 10) + t.getAttribute('step') * ((-e.wheelDelta || e.deltaY) > 0 ? -1 : 1), t.getAttribute('max') ) ); menu.onchange(e); pdsp(e); } else if ( !/reset|frames|options/.test(t.getAttribute('data-cmd') || (t = t.parentNode) && t.getAttribute('data-cmd')) ) { handleCommand(t.getAttribute('data-cmd'), e); } }, false); menu.onclick = function(e) { var target = e.target; if ( !target.hasAttribute('data-cmd') ) { target = target.parentNode; } if ( target.hasAttribute('data-cmd') ) { handleCommand(target.getAttribute('data-cmd'), e); } }; menu.oncontextmenu = function(e) { var target = e.target; if ( target.type === 'range' ) { target.value = target.defaultValue; menu.onchange(e); pdsp(e); return; } this.onclick(e); }; menu.addEventListener(vAPI.browser.transitionend, function(e) { if ( e.propertyName === 'left' && this.style.left[0] === '-' ) { menu.style.display = 'none'; } }, false); if ( win.Node.prototype && !win.Node.prototype.contains ) { win.Node.prototype.contains = function(n) { if ( n instanceof Node === false ) { return false; } return this === n || !!(this.compareDocumentPosition(n) & 16); }; } menu.onmouseover = function() { if ( !menu.mtimer ) { return; } clearTimeout(menu.mtimer); menu.mtimer = null; menu.style.left = '0'; menu.style.opacity = '1'; }; menu.onmouseout = function(e) { if ( this.contains(e.relatedTarget) ) { return; } doc.addEventListener('mousemove', menuTrigger, false); // eslint-disable-line menu.mtimer = setTimeout(function() { menu.style.left = '-' + menu.offsetWidth + 'px'; menu.style.opacity = '0'; menu.mtimer = null; }, 800); }; var menuTrigger = function(e) { if ( panning || freeZoom ) { return; } if ( e.clientX > 40 || e.clientY > win.innerHeight / 3 ) { return; } if ( menu.style.display === 'block' ) { return; } menu.style.display = 'block'; setTimeout(function() { menu.style.left = '0'; menu.style.opacity = '1'; }, 50); doc.removeEventListener('mousemove', menuTrigger, false); }; // Safari showed the menu even if the cursor wasn't at the edge setTimeout(function() { doc.addEventListener('mousemove', menuTrigger, false); }, 500); } var convertInfoParameter = function(a, param) { var m = media; switch ( param ) { case 'w': return m.clientWidth; case 'h': return m.clientHeight; case 'ow': return m.naturalWidth; case 'oh': return m.naturalHeight; case 'url': return win.location.href; case 'name': return m.alt; case 'ratio': return Math.round(m.clientWidth / m.clientHeight * 100) / 100; case 'perc': return Math.round(m.clientWidth * 100 / m.naturalWidth); } }; var afterCalcCallback = function() { // Gecko and WebKit/Blink render scrollbars for a split of a second, // even if the image fits into the view-port winH = doc.compatMode[0] === 'B' ? doc.body : root; winW = winH.clientWidth; winH = winH.clientHeight; var m = media; m.calcFit(); // Change curosr according to sizing if ( m.clientWidth > winW || m.clientHeight > winH ) { m.style.cursor = 'move'; } else if ( winH >= m.clientHeight && winW >= m.clientWidth && winH < m.naturalHeight || winW < m.naturalWidth ) { m.style.cursor = vAPI.browser['zoom-in']; } else if ( noFit.cur && noFit.real && (m.clientHeight < m.naturalHeight || m.clientWidth < m.naturalWidth) ) { m.style.cursor = vAPI.browser['zoom-in']; } else { m.style.cursor = 'default'; } if ( !cfg.mediaInfo || !(m.naturalWidth && m.naturalHeight) ) { return; } doc.title = cfg.mediaInfo.replace( /%(o?[wh]|url|name|ratio|perc)/g, convertInfoParameter ); }; var afterCalc = function() { if ( !media.calcFit ) { return; } winH = doc.compatMode[0] === 'B' ? doc.body : root; winW = winH.clientWidth; winH = winH.clientHeight; media.setPos(); setTimeout(afterCalcCallback, 0xf); }; media.resize = function(m, w) { var mode = m === void 0 ? 1 : m; if ( mode === -1 ) { if ( w ) { this.style.width = w; } } else if ( this.mode === -1 ) { this.style.width = ''; this.style.height = ''; } this.mode = mode; this.className = 'm-' + mode; if ( this.naturalWidth ) { afterCalc(); } }; media.setPos = function() { var s = this.style; if ( cfg.center ) { s.top = Math.max(0, (winH - this.offsetHeight) / 2) + 'px'; s.left = Math.max(0, (winW - this.offsetWidth) / 2) + 'px'; } else { s.top = s.left = '0'; } var box = this.getBoundingClientRect(); this.box = box; if ( box.left < 0 ) { s.left = (parseInt(s.left, 10) - box.left - win.pageXOffset) + 'px'; } if ( box.top < 0 ) { s.top = (parseInt(s.top, 10) - box.top - win.pageYOffset) + 'px'; } }; media.calcFit = function() { var box = this.box || this.getBoundingClientRect(); noFit = { cur: box.width <= winW && box.height <= winH, real: this.naturalWidth <= winW && this.naturalHeight <= winH }; }; media.wheelZoom = function(e) { stopScroll(); // eslint-disable-line pdsp(e); var w = media.offsetWidth; var h = media.offsetHeight; if ( (-e.wheelDelta || e.deltaY) > 0 ) { media.resize(-1, Math.max(1, w * 0.75) + 'px'); } else { var width = w * (4 / 3); media.resize(-1, (width > 10 ? width : width + 3) + 'px'); } if ( !e.keypress && e.target.nodeName.toUpperCase() !== 'IMG' ) { return; } var layerX = e.offsetX || e.layerX || 0; var layerY = e.offsetY || e.layerY || 0; win.scrollTo( layerX * media.offsetWidth / w - e.clientX + borderSize, layerY * media.offsetHeight / h - e.clientY + borderSize ); }; media.zoomToCenter = function(e) { pdsp(e); this.wheelZoom({ keypress: true, wheelDelta: e.wheelDelta, clientX: winW / 2, clientY: winH / 2, offsetX: win.pageXOffset + media.offsetLeft + winW / 2, offsetY: win.pageYOffset + media.offsetTop + winH / 2 }); }; media.cycle = function(back) { var mode = (this.mode === 1 ? 0 : this.mode) - (back ? 1 : -1); if ( mode === 1 ) { mode -= back ? 1 : -1; } else if ( mode < 0 ) { mode = 3; } else if ( mode > 3 ) { mode = 0; } this.resize(mode); }; media.reset = function() { if ( freeZoom ) { doc.removeEventListener('mousemove', drawMask, false); doc.body.removeChild(media.mask); freeZoom = null; cancelAction = false; return; } // Firefox document readyState stucks in 'interactive' for videos, // but videos don't need to be loaded anyway if ( vAPI.mediaType === 'img' && doc.readyState !== 'complete' ) { return; } var filters = doc.body.querySelector('#menu li.filters > form'); var style = this.style; if ( filters ) { style.filter = style.webkitFilter = ''; media.filters = {}; filters.reset(); } delete this.curdeg; delete this.scale; style[vAPI.browser.transform] = ''; style.width = ''; style.height = ''; this.resize(0); }; media.flip = function(el, horizontal) { if ( !this.scale ) { this.scale = {h: 1, v: 1}; } this.scale[horizontal ? 'h' : 'v'] *= -1; var transformCss = this.scale.h !== 1 || this.scale.v !== 1 ? 'scale(' + this.scale.h + ',' + this.scale.v + ')' : ''; if ( this.curdeg ) { transformCss += ' rotate(' + this.curdeg + 'deg)'; } this.style[vAPI.browser.transform] = transformCss; }; media.rotate = function(deg, fine) { var rot; if ( !this.curdeg ) { this.curdeg = 0; } if ( deg ) { this.curdeg += fine ? 10 : 90; } else { this.curdeg -= fine ? 10 : 90; } win.status = this.curdeg + '°'; rot = 'rotate(' + this.curdeg + 'deg)'; if ( this.scale ) { rot += ' scale(' + this.scale.h + ', ' + this.scale.v + ')'; } this.style[vAPI.browser.transform] = rot; this.setPos(); }; if ( cfg.wheelZoom ) { doc.addEventListener(vAPI.browser.wheel, media.wheelZoom, false); } else { doc.addEventListener(vAPI.browser.wheel, function(e) { if ( media.clientWidth <= winW && media.clientHeight <= winH ) { return; } stopScroll(); // eslint-disable-line var x = 0; var y = ((-e.wheelDelta || e.deltaY) > 0 ? winH : -winH) / 5; if ( media.clientWidth <= winW && media.clientHeight > winH ) { if ( !cfg.hiddenScrollbars ) { return; } } else if ( media.clientHeight <= winH && media.clientWidth > winW || e.clientX < winW / 2 && e.clientY > winH - 100 ) { x = (y < 0 ? -winW : winW) / 5; y = 0; } else if ( !cfg.hiddenScrollbars ) { return; } win.scrollBy(x, y); pdsp(e); }, false); } win.addEventListener('resize', afterCalc, false); doc.addEventListener('contextmenu', function(e) { doc.removeEventListener('mousemove', onMove, true); // eslint-disable-line if ( progress ) { clearTimeout(progress); progress = null; } if ( cancelAction ) { e.preventDefault(); } }, false); var lastMoveX, lastMoveY; var onMove = function(e) { lastMoveX = e.clientX; lastMoveY = e.clientY; if ( lastMoveX === lastEvent.clientX && lastMoveY === lastEvent.clientY ) { return; } if ( progress ) { clearTimeout(progress); progress = lastEvent.button = null; } if ( sX === true || noFit.cur ) { doc.removeEventListener('mousemove', onMove, true); return; } if ( !panning ) { panning = win.requestAnimationFrame(onMoveFrame); } if ( dragSlide.length !== 3 ) { dragSlide = [ [lastMoveX, lastMoveY], [lastMoveX, lastMoveY], [lastMoveX, lastMoveY] ]; return; } // Opera fires move event before mouseup if ( dragSlide[2][0] === lastMoveX && dragSlide[2][1] === lastMoveY ) { return; } dragSlide[0] = [dragSlide[1][0], dragSlide[1][1]]; dragSlide[1] = [dragSlide[2][0], dragSlide[2][1]]; dragSlide[2] = [lastMoveX, lastMoveY]; media.dragSlideTime = Date.now(); }; var pan = function() { win.scrollBy(sX - lastMoveX, sY - lastMoveY); sX = lastMoveX; sY = lastMoveY; }; var onMoveFrame = function() { pan(); panning = null; }; var startScroll = function() { progress = setInterval(function() { win.scrollBy(dragSlide[0], dragSlide[1]); if ( dragSlide[0] ) { if ( Math.abs(dragSlide[0]) < 1 ) { dragSlide[0] = 0; } dragSlide[0] /= 1.11; } if ( dragSlide[1] ) { if ( Math.abs(dragSlide[1]) < 1 ) { dragSlide[1] = 0; } dragSlide[1] /= 1.11; } var atRight = root.scrollWidth - win.pageXOffset === winW; var atBottom = root.scrollHeight - win.pageYOffset === winH; if ( !(dragSlide[0] && dragSlide[1]) || !win.pageYOffset && !win.pageXOffset || !win.pageYOffset && atRight || atBottom && !win.pageXOffset || atBottom && atRight ) { stopScroll(); } }, 25); }; var stopScroll = function(e) { if ( e ) { doc.removeEventListener(e.type, stopScroll); } if ( !dragSlide.length ) { return; } clearInterval(progress); progress = null; cancelAction = false; dragSlide.length = 0; media.dragSlideTime = false; }; var drawMask = function(e) { if ( ++freeZoom.counter % 3 ) { return; } var x = e.clientX - freeZoom.left; var y = e.clientY - freeZoom.top; if ( e.ctrlKey ) { var rx = freeZoom.prevX ? x - freeZoom.prevX : 0; var ry = freeZoom.prevY ? y - freeZoom.prevY : 0; freeZoom.prevX = x; freeZoom.prevY = y; freeZoom.x += rx; freeZoom.y += ry; freeZoom.X += rx; freeZoom.Y += ry; } else { if ( freeZoom.prevX ) { delete freeZoom.prevX; delete freeZoom.prevY; } freeZoom.w = Math.abs(freeZoom.X - x); freeZoom.h = Math.abs(freeZoom.Y - y); freeZoom.x = freeZoom.X < x ? freeZoom.X : freeZoom.X - freeZoom.w; freeZoom.y = freeZoom.Y < y ? freeZoom.Y : freeZoom.Y - freeZoom.h; } media.mctx.clearRect(0, 0, media.mask.width, media.mask.height); media.mctx.fillRect(0, 0, media.mask.width, media.mask.height); media.mctx.clearRect(freeZoom.x, freeZoom.y, freeZoom.w, freeZoom.h); }; var longpressHandler = function() { cancelAction = true; progress = null; var action = cfg[lastEvent.button === 2 ? 'lpRight' : 'lpLeft']; if ( action === 1 ) { var x, y; var b = doc.body; if ( media.mode === 2 || media.clientWidth === b.clientWidth || b.clientHeight > media.clientHeight && winW < b.clientWidth ) { x = media.clientWidth; media.resize(3); x = lastEvent.layerX * media.clientWidth / x - winW / 2; y = 0; } else { y = media.clientHeight; media.resize(2); x = 0; y = lastEvent.layerY * media.clientHeight / y - winH / 2; } win.scrollTo(x, y); } }; media.addEventListener('mousedown', function(e) { pdsp(e, false); if ( e.button === 1 || e.ctrlKey || e.altKey ) { return; } if ( vAPI.fullScreenElement === media && vAPI.mediaType === 'video' ) { return; } if ( !e.shiftKey && vAPI.mediaType === 'video' ) { var topPart = Math.min( this.clientHeight - 40, this.clientHeight / 2 ); if ( (e.offsetY || e.layerY || 0) > topPart ) { return; } } if ( e.button === 0 && this.mode < 4 || e.button === 2 ) { if ( e.button === 2 ) { sX = true; } else { if ( !e.shiftKey && noFit.cur && this.clientWidth >= 60 ) { if ( this.clientWidth - (e.offsetX || e.layerX || 0) <= 30 ) { lastEvent.clientX = e.clientX; lastEvent.clientY = e.clientY; return; } } e.preventDefault(); win.focus(); sX = e.clientX; sY = e.clientY; } if ( !e.shiftKey ) { doc.addEventListener('mousemove', onMove, true); } } if ( !cfg.lpDelay ) { return; } // For fine move and free zoom if ( e.shiftKey ) { cancelAction = true; if ( e.button === 0 ) { freeZoom = { counter: 0, left: parseInt(this.style.left, 10), top: parseInt(this.style.top, 10) }; freeZoom.X = e.clientX - freeZoom.left; freeZoom.Y = e.clientY - freeZoom.top; if ( !this.mask ) { this.mask = doc.createElement('canvas'); this.mask.className = 'mask'; this.mask.style.cssText = [ 'display: block', 'position: fixed', 'left: 0', 'top: 0' ].join(';'); this.mctx = this.mask.getContext('2d'); } doc.addEventListener('mousemove', drawMask, false); var h = this.curdeg && Math.sin(this.curdeg) ? true : false; var w = h ? this.offsetHeight : this.offsetWidth; h = h ? this.offsetWidth : this.offsetHeight; this.mask.width = Math.min(winW, w); this.mask.height = Math.min(winH, h); this.mask.style.left = this.style.left; this.mask.style.top = this.style.top; this.mctx.clearRect(0, 0, this.mask.width, this.mask.height); doc.body.appendChild(this.mask); w = win.getComputedStyle(this.mask).color; this.mctx.fillStyle = !w || w === 'rgb(0, 0, 0)' ? 'rgba(0,0,0,.4)' : w; } } // Is dragSlideing if ( progress ) { if ( stopScroll ) { stopScroll(); cancelAction = e.button === 0; } if ( e.button === 0 ) { return; } } if ( e.shiftKey || e.button === 0 && !cfg.lpLeft || e.button === 2 && !cfg.lpRight ) { return; } lastEvent.clientX = e.clientX; lastEvent.clientY = e.clientY; lastEvent.layerX = e.offsetX || e.layerX || 0; lastEvent.layerY = e.offsetY || e.layerY || 0; lastEvent.button = e.button; progress = setTimeout(longpressHandler, cfg.lpDelay); }, true); doc.addEventListener('mouseup', function(e) { if ( e.button !== 0 ) { return; } if ( vAPI.fullScreenElement === media && vAPI.mediaType === 'video' ) { return; } var x, y; if ( media.mode < 4 ) { doc.removeEventListener('mousemove', onMove, true); if ( freeZoom ) { doc.removeEventListener('mousemove', drawMask, false); doc.body.removeChild(media.mask); var w = Math.min( media.clientWidth, freeZoom.w + Math.min(freeZoom.x, 0) + (freeZoom.x + freeZoom.w > media.mask.width ? media.mask.width - freeZoom.x - freeZoom.w : 0) ); var h = Math.min( media.clientHeight, freeZoom.h + Math.min(freeZoom.y, 0) + (freeZoom.y + freeZoom.h > media.mask.height ? media.mask.height - freeZoom.y - freeZoom.h : 0) ); x = Math.max(0, freeZoom.x); y = Math.max(0, freeZoom.y); freeZoom = null; cancelAction = false; if ( !w || !h ) { return; } if ( x >= media.clientWidth || y >= media.clientHeight ) { return; } var nimgw, nimgh; var scrollbars = win.innerWidth - winW || win.innerHeight - winH; var fitW = winW < w * winH / h; fitW = e.ctrlKey ? !fitW : fitW; if ( fitW ) { nimgw = media.clientWidth * winW / w; nimgh = nimgw * media.clientHeight / media.clientWidth; } else { nimgh = media.clientHeight * winH / h; nimgw = nimgh * media.clientWidth / media.clientHeight; } if ( nimgw > MAXSIZE ) { nimgw = MAXSIZE; nimgh = media.clientHeight * MAXSIZE / media.clientWidth; } if ( nimgh > MAXSIZE ) { nimgw = media.clientWidth * MAXSIZE / media.clientHeight; nimgh = MAXSIZE; } var cx = (win.pageXOffset + x + w / 2) * nimgw / media.clientWidth - winW / 2 - scrollbars; var cy = (win.pageYOffset + y + h / 2) * nimgh / media.clientHeight - winH / 2 - scrollbars; media.resize(-1, nimgw + 'px'); win.scrollTo(cx, cy); return; } else if ( dragSlide.length === 3 ) { x = dragSlide[0][0] - dragSlide[2][0]; y = dragSlide[0][1] - dragSlide[2][1]; if ( Date.now() - media.dragSlideTime > 100 ) { cancelAction = false; dragSlide.length = 0; return; } if ( x || y ) { dragSlide.length = 2; dragSlide[0] = x; dragSlide[1] = y; startScroll(); doc.addEventListener(vAPI.browser.wheel, stopScroll); return; } } } if ( progress ) { clearTimeout(progress); progress = null; } if ( cancelAction ) { cancelAction = false; return; } if ( e.shiftKey || e.ctrlKey || e.altKey ) { return; } if ( e.target !== media || lastEvent.button === null ) { return; } if ( e.clientX !== lastEvent.clientX || e.clientY !== lastEvent.clientY ) { return; } if ( media.mode < 2 && noFit.real ) { if ( media.mode === -1 ) { media.resize(0); } else if ( winW / winH < media.naturalWidth / media.naturalHeight ) { media.resize(2); } else if ( winH === media.offsetHeight && winW > media.offsetWidth ) { media.resize(2); } else { media.resize(3); } } else if ( media.mode === 1 || noFit.cur ) { if ( media.naturalWidth === media.clientWidth && media.naturalHeight === media.clientHeight ) { return; } x = e.offsetX || e.layerX || 0; y = e.offsetY || e.layerY || 0; if ( media.scale ) { if ( media.scale.h === -1 ) { x = media.clientWidth - x; } if ( media.scale.v === -1 ) { y = media.clientHeight - y; } } x = x * media.naturalWidth / media.clientWidth - winW / 2; y = y * media.naturalHeight / media.clientHeight - winH / 2; media.resize(0); win.scrollTo(x, y); } else { media.resize(1); } }, true); doc.addEventListener('keydown', function(e) { if ( stopScroll ) { stopScroll(); } if ( shortcut.isModifier(e) ) { return; } var key = shortcut.key(e); if ( e.ctrlKey || freeZoom && key !== 'Esc' ) { return; } if ( key === '+' || key === '-' ) { e.wheelDelta = key === '+' ? 1 : -1; media.zoomToCenter(e); return; } var x, y, z; switch ( key ) { case 'Esc': media.reset(); break; case 'PgUp': x = e.shiftKey ? -winW / 2 : 0; y = e.shiftKey ? 0 : -winH / 2; break; case 'PgDn': x = e.shiftKey ? winW / 2 : 0; y = e.shiftKey ? 0 : winH / 2; break; case 'End': x = e.shiftKey ? root.scrollWidth : win.pageXOffset; y = e.shiftKey ? win.pageYOffset : root.scrollHeight; z = true; break; case 'Home': x = e.shiftKey ? 0 : win.pageXOffset; y = e.shiftKey ? win.pageYOffset : 0; z = true; break; default: x = true; } if ( x !== true ) { if ( x !== void 0 ) { win[z ? 'scrollTo' : 'scrollBy'](x, y); e.preventDefault(); } return; } switch ( key ) { case cfg.key_mOrig: media.resize(0); break; case cfg.key_mFit: media.resize(1); break; case cfg.key_mFitW: media.resize(2); break; case cfg.key_mFitH: media.resize(3); break; case cfg.key_cycle: media.cycle(e.shiftKey); break; case cfg.key_rotL: media.rotate(false, e.shiftKey); break; case cfg.key_rotR: media.rotate(true, e.shiftKey); break; case cfg.key_flipH: media.flip(media, 0); break; case cfg.key_flipV: media.flip(media, 1); break; default: x = true; } if ( vAPI.mediaType === 'video' ) { x = null; if ( key === 'Space' ) { media.togglePlay(); } else if ( key === 'Up' || key === 'Down' ) { key = media.volume + (key === 'Up' ? 0.1 : -0.1); // Must check the range manually, // otherwise browsers will throw an error media.volume = key < 0 ? 0 : key > 1 ? 1 : key; } else { x = true; } } if ( x !== true ) { pdsp(e); } }, true); if ( vAPI.mediaType === 'video' ) { media.addEventListener('click', function(e) { if ( e.button !== 0 ) { return; } var y = e.offsetY || e.layerY || 0; if ( y > media.clientHeight - 40 ) { return; } if ( vAPI.fullScreenElement === this || y > media.clientHeight / 2 ) { media.togglePlay(); } pdsp(e); }); media.addEventListener('dblclick', function(e) { if ( (e.offsetY || e.layerY || 0) < media.clientHeight / 2 ) { pdsp(e); } }); } media.mode = cfg.mode; media.calcFit(); progress = []; if ( cfg.minUpscale ) { if ( media.naturalWidth >= winW * cfg.minUpscale / 100 ) { progress[0] = 1; } if ( media.naturalHeight >= winH * cfg.minUpscale / 100 ) { progress[1] = 1; } } if ( media.mode === 4 ) { if ( media.naturalWidth / media.naturalHeight > winW / winH ) { media.mode = 3; } else { media.mode = 2; } } else if ( media.mode === 1 || media.mode === 0 && noFit.real ) { if ( progress.length ) { if ( media.naturalWidth / media.naturalHeight > winW / winH ) { media.mode = 2; } else { media.mode = 3; } } } if ( media.mode === 2 && media.naturalWidth < winW && !progress[0] ) { media.mode = 0; } else if ( media.mode === 3 && media.naturalHeight < winH && !progress[1] ) { media.mode = 0; } progress = null; media.resize(media.mode); // Some browsers (Safari, Firefox) won't position the media without this setTimeout(function() { media.setPos(); }, 30); }; if ( vAPI.mediaType === 'video' ) { root = {}; cfg.vidattrs.split(/\s+/).forEach(function(attribute) { var attr = attribute.split('='); if ( attr[0] === 'volume' ) { root[attr[0]] = Math.min( 100, Math.max(0, parseInt(attr[1], 10) / 100) ); } else { root[attr[0]] = true; } }); ['autoplay', 'loop', 'controls', 'muted', 'volume'].forEach(function(attr) { if ( attr === 'volume' ) { media[attr] = root[attr] === void 0 ? 1 : root[attr]; } else { media[attr] = root[attr] || false; } }); media.togglePlay = function() { if ( this.paused || Math.abs(this.duration - this.currentTime) < 0.01 ) { this.play(); } else { this.pause(); } }; media.addEventListener('loadedmetadata', function onLoadedMetadata(e) { this.removeEventListener(e.type, onLoadedMetadata); if ( vAPI.opera || vAPI.chrome ) { doc.addEventListener('fullscreenchange', function() { root.classList.toggle('fullscreen'); }); } if ( media.autoplay ) { setTimeout(media.play.bind(media), 50); } if ( this.videoHeight ) { return; } vAPI.mediaType = 'audio'; doc.title = media.alt; doc.onkeydown = function(ev) { var key = shortcut.key(ev); if ( key === 'Space' ) { media.togglePlay(); } else if ( key === 'Up' || key === 'Down' ) { key = media.volume + (key === 'Up' ? 0.1 : -0.1); media.volume = key < 0 ? 0 : key > 1 ? 1 : key; } else { return; } pdsp(ev); }; media.ondblclick = function(ev) { pdsp(ev); }; if ( vAPI.opera || vAPI.firefox || vAPI.chrome ) { return; } // To not show the black poster when audio restarts or if seek happends media.addEventListener('playing', function() { this.poster = 'data:image/gif;base64,R0lGODlhAQABAAAAACwAAAAAAQABAAA='; }); }); } else { media = doc.createElement('img'); media.src = win.location.href; } root = doc.documentElement; media.id = 'main-media'; media.onerror = function() { // Opera fires an error event on local video files when they're close to the end // Firefox did it a few times too, even if there was nothing wrong with the video if ( media.currentTime > 0.1 && win.location.protocol === 'file:' ) { return; } clearInterval(progress); root.classList.add('load-failed'); }; if ( win.location.protocol === 'data:' ) { media.alt = vAPI.mediaType + ' (data:)'; if ( !cfg.mediaInfo ) { doc.title = media.alt; } } else { media.alt = (win.location.href .replace(/#.*/, '') .match(/(?:[^\/]+)?$/)[0] || vAPI.mediaType ).split('?')[0]; try { // Some Unicode characters caused problems for decodeURIComponent media.alt = decodeURIComponent(media.alt); } catch ( ex ) { // } } if ( media.naturalWidth || media.videoWidth || vAPI.mediaType === 'audio' ) { initParams = null; init(); return; } initParams = {loop: 0, wait: 150, maxLoop: 900}; progress = setInterval(init, initParams.wait); setTimeout(function() { if ( root.classList.contains(vAPI.mediaType) ) { return; } // Firefox won't show the image if a site uses CSP settings, // so we should use the default image if ( (vAPI.firefox || vAPI.maxthon) && (vAPI.mediaType === 'img' ? !media.naturalWidth && doc.images[0].naturalWidth : !media.videoWidth && doc.body.querySelector('video').videoWidth) ) { // TODO: audio/video doc.images[0].style.display = 'block'; clearInterval(progress); return; } media.style.display = 'none'; var header = doc.body.appendChild(doc.createElement('h2')); header.textContent = media.alt; header.onclick = function() { doc.body.removeChild(this); media.style.display = 'block'; }; }, 1000); }; (function() { if ( vAPI.safari && location.protocol === 'safari-extension:' ) { init = null; return; } if ( vAPI.opera || vAPI.firefox ) { if ( !vAPI.mediaType ) { init = null; return; } vAPI.messaging.send({cmd: 'loadPrefs'}, function(response) { init(window, document, response); }); return; } vAPI.messaging.send({cmd: 'loadPrefs'}, function(response) { if ( !vAPI.mediaType ) { init = null; return; } init(window, document, response); }); })(); 'use strict'; var vAPI = Object.create(null); // Extension info is passed through the URL for Firefox, Safari, and Maxthon, // in order to get it synchronously if ( location.hash ) { vAPI.app = location.hash.slice(1).split(','); vAPI.app = { name: vAPI.app[0], version: vAPI.app[1] }; } vAPI.app.platform = 'Maxthon ' + external.mxVersion + ' (' + navigator.platform + ')'; vAPI.runtime = external.mxGetRuntime(); vAPI.storage = { mxStorage: vAPI.runtime.storage, get: function(key, callback) { callback(this.mxStorage.getConfig(key)); }, set: function(key, value) { return this.mxStorage.setConfig(key, value); } }; vAPI.tabs = { mxTabs: new mx.browser.tabs, // eslint-disable-line getSelected: function(callback) { callback(this.mxTabs.getCurrentTab()); }, create: function(params) { if ( /^[a-z-]{2,10}:/.test(params.url) === false ) { params.url = vAPI.runtime.getPrivateUrl() + params.url; } this.mxTabs.newTab({ url: params.url, activate: params.active }); } }; vAPI.messaging = { parseMessage: function(msg) { var listenerId = msg.listenerId; return { msg: msg.message, origin: msg.origin, postMessage: function(message) { vAPI.runtime.post(listenerId, message); } }; }, listen: function(callback, name) { vAPI.runtime.listen(name || 'service', callback); } }; 'use strict'; var cachedPrefs; vAPI.storage.get('cfg', function(prefs) { var xhr = new XMLHttpRequest; xhr.overrideMimeType('application/json;charset=utf-8'); xhr.open('GET', 'defaults.json', true); xhr.onload = function() { var needsUpdate = false; var defaltPrefs = JSON.parse(this.responseText); cachedPrefs = prefs ? JSON.parse(prefs) : {}; for ( var p in defaltPrefs ) { if ( cachedPrefs[p] === void 0 ) { cachedPrefs[p] = defaltPrefs[p]; needsUpdate = true; } } if ( needsUpdate ) { vAPI.storage.set('cfg', JSON.stringify(cachedPrefs)); } }; xhr.send(); }); vAPI.messaging.listen(function(e, origin, postMessage) { var channel = vAPI.messaging.parseMessage(e, origin, postMessage); var message = channel.msg; if ( !message.cmd ) { return; } switch ( message.cmd ) { case 'loadPrefs': var response = { prefs: message.property ? cachedPrefs[message.property] : cachedPrefs }; if ( message.getAppInfo ) { response.app = vAPI.app; } channel.postMessage(response); break; case 'save': cachedPrefs = message.prefs; vAPI.storage.set('cfg', JSON.stringify(cachedPrefs)); break; case 'open': if ( !Array.isArray(message.url) ) { message.url = [message.url]; } vAPI.tabs.getSelected(function(tab) { for ( var i = 0; i < message.url.length; ++i ) { vAPI.tabs.create({ incognito: !!tab.incognito, url: message.url[i], active: !message.nf }); } }); break; case 'frames.js': var xhr = new XMLHttpRequest; xhr.overrideMimeType('text/plain;charset=utf-8'); xhr.open('GET', 'js/frames.js', true); xhr.onload = function() { channel.postMessage({'frames.js': this.responseText}); }; xhr.send(); break; } // Chrome return true; // eslint-disable-line }); /* global win, errorHandler, drawFullFrame */ 'use strict'; var $ = function(id) { return document.getElementById(id); }; var crc32 = (function() { var c, k; var n = 0; var crcTable = []; for ( ; n < 256; ++n ) { for ( c = n, k = 0; k < 8; ++k ) { c = c & 1 ? 0xedb88320 ^ c >>> 1 : c >>> 1; } crcTable[n] = c; } return function(s) { var i = 0; var length = s.length; var crc = -1; while ( i < length ) { crc = crcTable[(crc ^ s.charCodeAt(i++)) & 0xff] ^ crc >>> 8; } return crc ^ -1; }; })(); var BinaryTools = function(data) { this.pos = 0; this.data = data; this.length = data.length; this.littleEndian = false; this.zeropad = '00000000'; this.readByte = function(position) { var pos = position === void 0 || position < 0 ? this.pos++ : position; return this.data.charCodeAt(pos) & 0xff; }; this.readString = function(length, position) { var pos; if ( position === void 0 || position < 0 ) { pos = this.pos; this.pos += length || 0; } else { pos = position; } return this.data.substr(pos, length || 0); }; this.readBits = function(length, pos) { var curbyte; var bitarray = []; var i = 0; while ( i++ < length ) { curbyte = this.readByte(pos).toString(2); bitarray.push( this.zeropad.substr(0, this.zeropad.length - curbyte.length) + curbyte ); } return (this.littleEndian ? bitarray.reverse() : bitarray).join(''); }; this.readInt = function(bytes, position) { if ( bytes < 1 ) { return null; } var pos; if ( position === void 0 || position < 0 ) { pos = this.pos; this.pos += bytes; } else { pos = position; } var i; var integer = 0; if ( this.littleEndian ) { i = bytes - 1; while ( i >= 0 ) { integer += this.readByte(pos + i) << i-- * 8; } } else { i = 0; while ( i < bytes ) { integer += this.readByte(pos + i++) << (bytes - i) * 8; } } return integer >>> 0; }; this.intToBytes = function(integer, numberOfBytes) { var i = numberOfBytes || 4; var bytes = []; while ( i-- ) { bytes.push(integer >> i * 8 & 0xff); } return String.fromCharCode.apply( null, this.littleEndian ? bytes.reverse() : bytes ); }; }; if ( !win.opera ) { // Solves utf8 problems win.btoa = function(b64str) { var b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; var c1, c2; var pos = 0; var res = ''; var mod = b64str.length % 3; var l = b64str.length - mod; while ( pos < l ) { c1 = b64str.charCodeAt(pos++) & 0xff; c2 = b64str.charCodeAt(pos++) & 0xff; res += b64chars[c1 >> 2]; res += b64chars[(c1 & 3) << 4 | c2 >> 4]; c1 = b64str.charCodeAt(pos++) & 0xff; res += b64chars[(c2 & 0x0f) << 2 | c1 >> 6]; res += b64chars[c1 & 0x3f]; } if ( mod ) { c1 = b64str.charCodeAt(pos++) & 0xff; res += b64chars[c1 >> 2]; if ( mod === 1 ) { res += b64chars[(c1 & 3) << 4]; res += '=='; } else { c2 = b64str.charCodeAt(pos++) & 0xff; res += b64chars[(c1 & 3) << 4 | c2 >> 4]; res += b64chars[(c2 & 0x0f) << 2]; res += '='; } } return res; }; } var maxSize = 20 * 1024 * 1024; var xhr = new win.XMLHttpRequest; xhr.overrideMimeType('text/plain; charset=x-user-defined'); xhr.onreadystatechange = function() { if ( this.readyState === 2 ) { var contentLength = this.getResponseHeader('Content-Length'); if ( contentLength && contentLength > maxSize ) { this.abort(); errorHandler('Image is too large...'); return; } } if ( !this.responseText ) { return; } if ( !this.imgType ) { // PNG or GIF or WEBP signature imgHead = /^(?:\x89(PNG)\r\n\x1a\n|(GIF)8[79]a|RIFF....(WEBP)VP8X)/; this.imgType = this.responseText.match(imgHead); // Seems like in some cases a character encoding is applied anyway, // however it's enough to check only the signature if ( !this.imgType && (this.responseText[1] === 'P' && (chunkSize = 8) || this.responseText[0] === 'G' && (chunkSize = 6) || this.responseText[0] === 'R' && (chunkSize = 16)) ) { this.imgType = this.responseText.slice(0, chunkSize).split(''); for ( i = 0; i < this.imgType.length; ++i ) { this.imgType[i] = this.imgType[i].charCodeAt(0) & 0xff; } this.imgType = String.fromCharCode.apply(null, this.imgType).match(imgHead); } if ( !this.imgType ) { this.abort(); this.onprogress = null; errorHandler('Not animated...'); return; } this.imgType = this.imgType[2] || this.imgType[1] || this.imgType[3]; } if ( this.readyState !== 4 ) { /* || this.status !== 200*/ return; } if ( this.responseText.length > maxSize ) { this.onprogress = null; errorHandler('Image is too large...'); return; } var i, IHDR, chunkType, chunkSize; var frames = []; var bin = new BinaryTools(this.responseText); var animation = {}; var imgHead = ''; if ( this.imgType === 'PNG' ) { // https://wiki.mozilla.org/APNG_Specification // Skip signature bin.pos = 8; while ( bin.pos < bin.length ) { // Read the chunk type chunkType = bin.readString(4, bin.pos + 4); // console.log(i, chunkType, bin.readInt(4, bin.pos)); if ( chunkType === 'IHDR' ) { // Skip chunk length and name bin.pos += 8; animation.width = bin.readInt(4); animation.height = bin.readInt(4); IHDR = bin.readString(5); // Skip crc bin.pos += 4; } else if ( !frames.length && chunkType === 'acTL' ) { animation.numFrames = bin.readInt(4, bin.pos + 8); animation.numPlays = bin.readInt(4, bin.pos + 12); bin.pos += 20; } else if ( chunkType === 'fcTL' ) { bin.pos += 12; i = frames.length; frames.push({ width: bin.readInt(4), height: bin.readInt(4), xOffset: bin.readInt(4), yOffset: bin.readInt(4), delay: 1000 * bin.readInt(2) / (bin.readInt(2) || 100), disposeOp: bin.readInt(1), blendOp: bin.readInt(1), data: 'IDAT' }); if ( i === 0 && frames[i].disposeOp === 2 ) { frames[i].disposeOp = 1; } // Skip crc bin.pos += 4; // console.log(frames[frames.length - 1]); } else if ( chunkType === 'IDAT' || chunkType === 'fdAT' ) { if ( !animation.numFrames || animation.numFrames < 2 ) { break; // IDAT without acTL chunk should be ignored } else if ( chunkType === 'IDAT' && !frames.length ) { // console.log('PNG: ignoring IDAT from animation...'); bin.pos += bin.readInt(4, bin.pos) + 12; continue; } i = chunkType === 'fdAT' ? 4 : 0; // Read the length, also skip the sequence number from fdAT chunkSize = bin.readInt(4) - i; // Skip chunk type, // also the sequence number in case of the fdAT chunk type bin.pos += 4 + i; frames[frames.length - 1].data += bin.readString(chunkSize); // Skip crc bin.pos += 4; } else if ( !frames.length ) { // Read the full chunk (length + chunk type + chunkdate + crc) imgHead += bin.readString(bin.readInt(4, bin.pos) + 12); } else { bin.pos += bin.readInt(4, bin.pos) + 12; } } } else if ( this.imgType === 'GIF' ) { // http://www.w3.org/Graphics/GIF/spec-gif89a.txt bin.littleEndian = true; bin.skipSubBlock = function() { do { this.pos += this.readInt(1, this.pos) + 1; if ( bin.pos >= bin.length ) { throw this.imgType + ': end reached...'; } } while ( this.readInt(1, this.pos) !== 0x00 ); ++this.pos; }; // Skip signature bin.pos = 6; // Logical Screen Descriptor animation.width = bin.readInt(2); animation.height = bin.readInt(2); bin.packed = bin.readBits(1, 10); bin.packed = bin.packed[0] === '1' ? 3 * 1 << parseInt(bin.packed.slice(-3), 2) + 1 : 0; imgHead += bin.readString(3 + bin.packed); // Frame index i = 0; while ( bin.pos < bin.length ) { chunkType = bin.readString(1); // console.log("sentinel: " + chunkType); // Extension block (0x21, an exclamation point '!') // optional if ( chunkType === '!' ) { chunkType = bin.readInt(1); // console.log("ext_label: " + chunkType.toString(16)); // Plain Text Extension if ( chunkType === 0x01 ) { // No support for this, so skip bin.pos += 13; bin.skipSubBlock(); // Graphics Control Extension } else if ( chunkType === 0xf9 ) { bin.packed = bin.readBits(1, bin.pos + 1); frames.push({ delay: bin.readInt(2, bin.pos + 2) * 10 || 100, // -1 in order to match PNG's indexes, also treat 0 as 1 disposeOp: Math.max(0, parseInt(bin.packed.slice(3, -2), 2) - 1), // sentinel + ext_label data: bin.readString(4, bin.pos - 2) + // with zero delay bin.intToBytes(0, 2) + // transparent color index + block terminator bin.readString(2, bin.pos + 4) }); bin.pos += 6; // Comment Block Extension } else if ( chunkType === 0xfe ) { bin.skipSubBlock(); // Application Block Extension } else if ( chunkType === 0xff ) { bin.pos += 12; bin.skipSubBlock(); // Try to skip anything else } else { bin.pos = bin.data.indexOf('\x00', bin.pos); if ( bin.pos === -1 ) { bin.pos = bin.length; } else { ++bin.pos; } } // Image (0x2C, a comma ',') } else if ( chunkType === ',' ) { if ( !frames[i] ) { frames.push({ delay: 100, disposeOp: 0, // sentinel, ext_label, block size, packed field, delay, // transparent color index, terminator data: '\x21\xf9\x04\x00\x00\x00\x00\x00' }); } frames[i].xOffset = bin.readInt(2); frames[i].yOffset = bin.readInt(2); bin._pos = bin.pos; frames[i].width = bin.readInt(2); frames[i].height = bin.readInt(2); bin.packed = bin.readBits(1); bin.pos += bin.packed[0] === '1' ? 3 * (1 << parseInt(bin.packed.slice(-3), 2) + 1) : 0; // LZW minimum code size ++bin.pos; bin.skipSubBlock(); frames[i]._data = [bin.pos - bin._pos, bin._pos]; ++i; // Trailer (0x3B, a semi-colon ';') or something else } else { break; } } } else if ( this.imgType === 'WEBP' ) { // https://developers.google.com/speed/webp/docs/riff_container bin.littleEndian = true; // WebP file header + VP8X and its chunk size bin.pos = 20; // VP8X flags bin.packed = bin.readBits(1); // Animation flag if ( bin.packed[6] === '0' ) { this.onprogress = null; errorHandler(this.imgType + ': not animated...'); return; } // Reserved 24 bits bin.pos += 3; // Canvas width animation.width = bin.readInt(3) + 1; // Canvas height animation.height = bin.readInt(3) + 1; while ( bin.pos < bin.length ) { chunkType = bin.readString(4); if ( chunkType === 'ANIM' ) { // Skip Background Color: 32 bits + Loop Count: 16 bits // chunk size + chunk payload bin.pos += 4 + bin.readInt(4); animation.ANIM = true; continue; } if ( chunkType !== 'ANMF' ) { // Skip chunk bin.pos += 4 + bin.readInt(4); continue; } if ( !animation.ANIM ) { this.onprogress = null; errorHandler(this.imgType + ': ANIM chunk not found!'); return; } i = frames.length; // Size of the Frame Data chunkSize = bin.readInt(4); // If the chunk size is odd, then a padding byte is added chunkSize += chunkSize & 1; // Remove the size of the ANMF properties listed below chunkSize -= 16; frames.push({ xOffset: bin.readInt(3) * 2, yOffset: bin.readInt(3) * 2, width: bin.readInt(3) + 1, height: bin.readInt(3) + 1, delay: bin.readInt(3), disposeOp: bin.readInt(1) & 1, data: '' }); bin._pos = bin.pos + chunkSize; while ( bin.pos < bin._pos ) { chunkType = bin.readString(4); chunkSize = bin.readInt(4); chunkSize += chunkSize & 1; // Should exist before the 'VP8 ' chunk only /* if ( chunkType === 'ALPH' ) { if ( bin.readString(4, bin.pos + chunkSize) === 'VP8 ' ) { // The whole ALPH chunk frames[i].data += bin.readString(8, bin.pos - 8); frames[i].data += bin.readString(chunkSize); } else { bin.pos += chunkSize; } } else */ if ( chunkType === 'VP8 ' || chunkType === 'VP8L' ) { // chunk type + chunk size + VP8? bitstream; frames[i].data += bin.readString(8, bin.pos - 8); frames[i].data += bin.readString(chunkSize); } else { bin.pos += chunkSize; } } // frames[i].data += bin.readString(chunkSize); } } if ( frames.length < 1 ) { this.onprogress = null; errorHandler(this.imgType + ': not animated...'); return; } var generateImageSRC, wrap, speed, currentFrame; var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); var img = new Image; canvas.width = animation.width; canvas.height = animation.height; if ( this.imgType === 'PNG' ) { chunkSize = bin.intToBytes(13); var imgEnd = bin.readString(12, bin.length - 12); generateImageSRC = function() { var frm = frames[frames.idx]; var _IHDR = 'IHDR' + bin.intToBytes(frm.width) + bin.intToBytes(frm.height) + IHDR; _IHDR += bin.intToBytes(crc32(_IHDR)); return 'data:image/png;base64,' + win.btoa( '\x89PNG\r\n\x1a\n' + chunkSize + _IHDR + imgHead + bin.intToBytes(frm.data.length - 4) + frm.data + bin.intToBytes(crc32(frm.data)) + imgEnd ); }; } else if ( this.imgType === 'GIF' ) { chunkSize = bin.intToBytes(0, 2); chunkSize = ',' + chunkSize + chunkSize; generateImageSRC = function() { var frm = frames[frames.idx]; return 'data:image/gif;base64,' + win.btoa( 'GIF89a' + bin.intToBytes(frm.width, 2) + bin.intToBytes(frm.height, 2) + imgHead + frm.data + chunkSize + bin.readString(frm._data[0], frm._data[1]) + ';' ); }; } else if ( this.imgType === 'WEBP' ) { generateImageSRC = function() { var frm = frames[frames.idx]; return 'data:image/webp;base64,' + win.btoa( 'RIFF' + bin.intToBytes(frm.data.length + 4) + 'WEBP' + frm.data ); }; } img.onerror = function() { wrap.textContent = xhr.imgType + ': frame (' + (frames.idx + 1) + ") couldn't be parsed!"; wrap.appendChild(this); }; img.onload = function() { if ( drawFullFrame ) { var frame = frames[frames.idx]; var prev = frames[frames.idx - 1]; if ( prev ) { if ( prev.disposeOp === 1 ) { ctx.clearRect( prev.xOffset, prev.yOffset, prev.width, prev.height ); } else if ( prev.disposeOp === 2 ) { ctx.putImageData( this.prevDisposeData, prev.xOffset, prev.yOffset ); } } if ( frame.disposeOp === 2 ) { this.prevDisposeData = ctx.getImageData( frame.xOffset, frame.yOffset, frame.width, frame.height ); } // only for PNG if ( frame.blendOp === 0 ) { ctx.clearRect( frame.xOffset, frame.yOffset, frame.width, frame.height ); } ctx.drawImage( this, frame.xOffset, frame.yOffset ); } var c = canvas.cloneNode(false); if ( drawFullFrame ) { c.getContext('2d').putImageData( ctx.getImageData(0, 0, canvas.width, canvas.height), 0, 0 ); } else { c.width = this.width; c.height = this.height; c.getContext('2d').drawImage(this, 0, 0); } wrap.appendChild(c); this.removeAttribute('src'); c.style.display = 'inline-block'; if ( c.previousElementSibling ) { c.previousElementSibling.style.display = ''; } ++frames.idx; currentFrame.value = frames.idx; processNextFrame(); // eslint-disable-line }; var processNextFrame = function() { if ( frames.idx < frames.length ) { img.src = generateImageSRC(); frames[frames.idx].data = null; } else { img.onload = null; img = null; done(); errorHandler(null); } }; var done = function() { wrap.current = 0; wrap.children[wrap.children.length - 1].style.display = ''; wrap.children[wrap.current].style.display = 'inline-block'; currentFrame.value = 1; currentFrame.oninput = function() { if ( parseFloat(speed.value, 10) !== 0 ) { wrap.stop(); } if ( wrap.classList.contains('showall') ) { wrap.onmouseup({button: 0}); } wrap.step(null); }; speed.oninput = function() { wrap.speedValue = parseFloat(speed.value) || 0; if ( wrap.speedValue === 0 ) { wrap.stop(); wrap.addEventListener(vAPI.browser.wheel, wrap.wheeler, false); return; } wrap.classList.remove('showall'); wrap.removeEventListener(vAPI.browser.wheel, wrap.wheeler, false); wrap.animate(); }; wrap.wheeler = function(e) { wrap.step((e.deltaY || -e.wheelDelta) > 0); wrap.sotp(); e.preventDefault(); e.stopImmediatePropagation(); }; wrap.addEventListener(vAPI.browser.wheel, wrap.wheeler, false); currentFrame.addEventListener(vAPI.browser.wheel, wrap.wheeler, false); wrap.onmouseup = function(e) { if ( e.button !== 0 ) { return; } if ( e.ctrlKey ) { if ( e.target.toDataURL && speed.value < 1 ) { var canvasImg = new Image; canvasImg.src = e.target.toDataURL(); this.replaceChild(canvasImg, e.target); wrap.step(null); } return; } this.stop(); if ( this.classList.contains('showall') ) { if ( e.target && e.target.parentNode === wrap ) { currentFrame.value = [].indexOf.call(wrap.childNodes, e.target) + 1; wrap.step(null); } this.addEventListener(vAPI.browser.wheel, this.wheeler, false); } else { this.removeEventListener(vAPI.browser.wheel, this.wheeler, false); } this.classList.toggle('showall'); }; wrap.animate = function() { clearTimeout(wrap.animationTimer); wrap.step(wrap.speedValue < 0); if ( wrap.speedValue ) { wrap.animationTimer = setTimeout( wrap.animate, frames[wrap.current].delay / Math.abs(wrap.speedValue) ); } }; wrap.stop = function() { clearTimeout(this.animationTimer); speed.value = 0; }; wrap.step = function(backward) { wrap.children[wrap.current].style.display = ''; if ( backward === null ) { wrap.current = Math.max( 1, Math.min( parseInt(currentFrame.value, 10) || 1, currentFrame.max ) ) - 1; } else if ( backward ) { --wrap.current; } else { ++wrap.current; } if ( wrap.current >= wrap.children.length ) { wrap.current = 0; } else if ( wrap.current < 0 ) { wrap.current = wrap.children.length - 1; } wrap.children[wrap.current].style.display = 'inline-block'; currentFrame.value = wrap.current + 1; currentFrame.nextElementSibling.value = currentFrame.value + ' / ' + frames.length; }; }; wrap = document.body; wrap.className = 'frames'; wrap.textContent = ''; vAPI.buildNodes(wrap, [ {tag: 'a', attrs: { 'class': 'back', href: win.location.href }, text: '\u2190'}, ' ', {tag: 'input', attrs: { type: 'number', id: 'speed', style: 'width: 55px; text-align: center;', value: 0, step: 0.5, min: -10, max: 10 }}, 'x ', {tag: 'input', attrs: { type: 'range', id: 'current-frame', style: 'width: 500px; vertical-align: middle;', size: 6, value: 1, step: 1, min: 1 }}, ' ', {tag: 'output', attrs: { 'for': 'currentFrame' }, text: '1 / ' + frames.length}, ' ', {tag: 'div', attrs: {id: 'frames'}} ]); wrap = $('frames'); speed = $('speed'); currentFrame = $('current-frame'); currentFrame.max = frames.length; frames.idx = 0; processNextFrame(); }; xhr.onerror = function() { this.onprogress = null; errorHandler('Failed to load!'); }; xhr.open('GET', win.location.href, true); xhr.send(); 'use strict'; var defaultPrefs; var inputChanges = Object.create(null); var $ = function(id) { return document.getElementById(id); }; var localizeNodes = function(nodes) { var i = nodes.length; while ( i-- ) { if ( nodes[i]._nodeLocalized ) { continue; } var els = nodes[i].querySelectorAll('[data-i18n]'); var l = els.length; while ( l-- ) { var i18nString = vAPI.i18n(els[l].dataset.i18n); var i18nAttr = els[l].dataset.i18nAttr; els[l].removeAttribute('data-i18n'); if ( !i18nAttr ) { vAPI.insertHTML(els[l], i18nString); continue; } if ( /^(title|placeholder)$/i.test(i18nAttr) ) { els[l][i18nAttr] = i18nString; } els[l].removeAttribute('data-i18n-attr'); } nodes[i]._nodeLocalized = true; } }; var changeColor = function(node, color, time) { clearTimeout(node.colorTransitionTimer); if ( typeof color !== 'string' ) { node.style.color = ''; delete node.colorTransitionTimer; return; } node.style.color = color; node.colorTransitionTimer = setTimeout(function() { changeColor(node, null); }, time || 2000); }; var fillOutput = function(node) { var op = node.previousElementSibling; op.value = node.value; op.defaultValue = defaultPrefs[node.name]; }; var colorOnInput = function(node) { var target = node.type === 'input' ? this : node; var c = /^#([\da-f]{3}){1,2}$/i.test(target.value) ? target.value : '#ffffff'; if ( c.length === 4 ) { c = '#' + c[1] + c[1] + c[2] + c[2] + c[3] + c[3]; } target.previousElementSibling.value = c; }; var colorOnChange = function() { this.nextElementSibling.value = this.value; }; var setDefault = function(selector) { if ( !selector ) { return; } var nodeList = typeof selector === 'string' ? document.querySelectorAll(selector) : [selector]; [].forEach.call(nodeList, function(el) { if ( el.type === 'checkbox' ) { el.checked = el.defaultChecked; return; } if ( /^SELECT/i.test(el.type) ) { var i = el.length; while ( i-- ) { if ( el[i].hasAttribute('selected') ) { el.selectedIndex = i; break; } } return; } el.value = el.defaultValue; if ( el.type === 'range' ) { fillOutput(el); } }); }; var load = function(prefs) { var m, field, fieldType, pref; var fields = document.querySelectorAll('[name]'); var i = fields.length; while ( i-- ) { field = fields[i]; pref = field.name; if ( field.disabled || field.readOnly || defaultPrefs[pref] === void 0 ) { continue; } fieldType = field.getAttribute('type') || 'text'; if ( field.type !== fieldType ) { fieldType = field.type; } if ( fieldType === 'checkbox' ) { field.defaultChecked = defaultPrefs[pref]; pref = !!(prefs[pref] === void 0 ? defaultPrefs : prefs)[pref]; field.checked = field.defChecked = pref; continue; } if ( pref === 'sendTo' ) { if ( !Array.isArray(prefs[pref]) ) { prefs[pref] = defaultPrefs[pref]; } field.rows = prefs[pref].length || 2; field.defaultValue = defaultPrefs[pref].join('\n'); prefs[pref] = prefs[pref].join('\n'); } else if ( fieldType.slice(0, 6) === 'select' ) { /* eslint-disable */ [].some.call(field, function(el) { if ( el.value == defaultPrefs[pref] ) { el.defaultSelected = true; return true; } }); /* eslint-enable */ } else { field.defaultValue = defaultPrefs[pref]; } pref = (prefs[pref] === void 0 ? defaultPrefs : prefs)[pref]; field.value = field.defValue = pref; if ( fieldType === 'range' ) { m = field.previousElementSibling; if ( m && m.nodeName === 'OUTPUT' ) { fillOutput(field); } m = m.previousElementSibling; if ( m && m.getAttribute('type') === 'color' ) { m.style.opacity = field.value; } field.addEventListener('change', fillOutput); } else if ( fieldType === 'text' ) { if ( !field.previousElementSibling ) { continue; } if ( field.previousElementSibling.getAttribute('type') === 'color' ) { continue; } field.addEventListener('input', colorOnInput); colorOnInput(field); field.previousElementSibling.addEventListener('change', colorOnChange); } } }; var save = function() { var i, field, fieldType, pref; var fields = document.querySelectorAll('[name]'); var prefs = Object.create(null); for ( i = 0; i < fields.length; ++i ) { field = fields[i]; pref = field.name; if ( field.disabled || field.readOnly || defaultPrefs[pref] === void 0 ) { continue; } fieldType = field.getAttribute('type'); if ( fieldType === 'checkbox' ) { prefs[pref] = field.checked; } else if ( fieldType === 'range' || fieldType === 'number' || field.classList.contains('number') ) { prefs[pref] = parseFloat(field.value); if ( field.min ) { prefs[pref] = Math.max( field.min, Math.min(field.max, prefs[pref]) ); } if ( typeof prefs[pref] !== 'number' ) { prefs[pref] = parseFloat(field.defaultValue); } field.value = prefs[pref]; } else { if ( pref === 'sendTo' ) { // eslint-disable-line prefs[pref] = field.value.trim().split(/[\r\n]+/).filter(Boolean); field.rows = prefs[pref].length || 2; } else { prefs[pref] = field.value; } } if ( prefs[pref] === void 0 ) { prefs[pref] = defaultPrefs[pref]; } } vAPI.messaging.send({cmd: 'save', prefs: prefs}); }; var onHashChange = function() { var args = []; var menu = $('nav-menu'); var prevHash = menu.activeLink && menu.activeLink.hash.slice(1) || 'general'; var hash = location.hash.slice(1) || 'general'; if ( hash.indexOf('/') > -1 ) { args = hash.split('/'); hash = args.shift(); } var section = $(hash + '-sec') || $((hash = 'general') + '-sec'); if ( hash === 'info' ) { if ( !section._nodeLocalized ) { if ( args[0] ) { args = args[0] === '0' ? 'app-installed' : 'app-updated'; $(args).style.display = 'block'; } var fillLocalesTable = function() { this.onload = null; var alpha2, td; var rows = []; var lngMap = function(el, idx) { el.name = [ el.name || el.fullname || '', el.fullname && el.name ? ' (' + el.fullname + ')' : '' ].join(''); if ( !el.name ) { el.name = el.email || el.web; } if ( idx ) { td.nodes.push(', '); } td.nodes.push(el.email || el.web ? { tag: 'a', attrs: {href: el.email ? 'mailto:' + el.email : el.web }, text: el.name } : el.name ); }; var locales = JSON.parse(this.responseText); for ( alpha2 in locales ) { // _ is the default language if ( alpha2 === '_' ) { continue; } td = {tag: 'td'}; rows.push({tag: 'tr', nodes: [ { tag: 'td', attrs: locales[alpha2]['%'] ? {title: locales[alpha2]['%'] + '%'} : null, text: alpha2 + ', ' + locales[alpha2].name }, td ]}); if ( locales[alpha2].translators ) { td.nodes = []; locales[alpha2].translators.forEach(lngMap); } else { td.text = 'anonymous'; } } vAPI.buildNodes($('locales-table'), rows); }; var xhr = new XMLHttpRequest; xhr.overrideMimeType('application/json;charset=utf-8'); xhr.open('GET', 'locales.json', true); xhr.onload = fillLocalesTable; xhr.send(); } } if ( prevHash !== hash && (prevHash = $(prevHash + '-sec')) ) { prevHash.style.display = 'none'; } if ( section ) { localizeNodes([section]); section.style.display = 'block'; } if ( menu.activeLink ) { menu.activeLink.classList.remove('active'); } if ( menu.activeLink = menu.querySelector('a[href="#' + hash + '"]') ) { menu.activeLink.classList.add('active'); } }; window.addEventListener('hashchange', onHashChange); window.addEventListener('load', function() { ['opera', 'firefox', 'chrome', 'safari', 'maxthon'].some(function(el) { if ( vAPI[el] ) { document.body.classList.add(el); return true; } return false; }); var menu = $('nav-menu'); var colorHelper = document.body.querySelector( '.color-helper > input[type=text]' ); if ( colorHelper ) { colorHelper.addEventListener('input', colorOnInput); colorOnInput(colorHelper); colorHelper.previousElementSibling.addEventListener('change', colorOnChange); } localizeNodes([menu, $('right-panel').firstElementChild]); menu.addEventListener('click', function(e) { if ( e.button === 0 && e.target.hash ) { e.preventDefault(); location.hash = e.target.hash; } }); onHashChange(); var form = document.forms[0]; var onFormChange = function(e) { if ( e.stopPropagation ) { e.stopPropagation(); } var defval; var t = e.target; if ( t.formSaved ) { delete t.formSaved; } else if ( t.parentNode.dataset.form || t.parentNode.parentNode.dataset.form ) { defval = 'default'; } else if ( t.id.indexOf('_') > 0 ) { defval = 'def'; } if ( !defval ) { return; } if ( t.type === 'checkbox' && t[defval + 'Checked'] !== t.checked ) { inputChanges[t.name] = true; } else if ( t.type !== 'checkbox' && t[defval + 'Value'] != t.value ) { // eslint-disable-line inputChanges[t.name] = true; } else { delete inputChanges[t.name]; } $('save-button').style.color = Object.keys(inputChanges).length ? '#e03c00' : ''; }; form.addEventListener('keydown', function(e) { e.stopPropagation(); if ( e.which === 13 ) { e.target.formSaved = true; } if ( e.repeat || !e.target.name || e.target.name.indexOf('key_') !== 0 || e.ctrlKey || e.altKey || e.metaKey || e.which < 47 ) { return; } e.preventDefault(); changeColor(e.target); var keys = { 96: '0', 97: '1', 98: '2', 99: '3', 100: '4', 101: '5', 102: '6', 103: '7', 104: '8', 105: '9', 106: '*', 107: '+', 109: '-', 110: '.', 111: '/', 186: ';', 187: '=', 188: ',', 189: '-', 190: '.', 191: '/', 192: '`', 219: '[', 220: '\\', 221: ']', 222: "'", 112: 'F1', 113: 'F2', 114: 'F3', 115: 'F4', 116: 'F5', 117: 'F6', 118: 'F7', 119: 'F8', 120: 'F9', 121: 'F10', 122: 'F11', 123: 'F12' }; var key = keys[e.which] || String.fromCharCode(e.which).toUpperCase(); keys = document.body.querySelectorAll('input[name^="key_"]'); for ( var i = 0; i < keys.length; ++i ) { if ( keys[i].value.toUpperCase() !== key ) { continue; } if ( e.target !== keys[i] ) { changeColor(e.target, 'red'); } return; } e.target.value = key; form.onchange(e); }); form.addEventListener('contextmenu', function(e) { e.stopPropagation(); var t = e.target; if ( t.classList.contains('checkbox') ) { t = t.previousElementSibling; } if ( !t.name ) { return; } if ( e.ctrlKey ) { e.preventDefault(); setDefault(t); onFormChange({target: t}); } }); form.addEventListener('change', onFormChange); var resetButton = $('reset-button'); resetButton.reset = function() { delete resetButton.pending; resetButton.style.color = '#000'; }; resetButton.addEventListener('click', function(e) { if ( e.button !== 0 ) { return; } if ( this.pending ) { clearTimeout(this.pending); delete this.pending; this.style.color = ''; this.nextElementSibling.style.color = '#e03c00'; inputChanges.formReset = true; if ( e.ctrlKey ) { e.preventDefault(); var sec = (location.hash || '#general') + '-sec '; setDefault(e + 'input,' + sec + 'select,' + sec + 'textarea'); this.style.color = 'lime'; } else { this.style.color = 'green'; } this.pending = setTimeout(this.reset, 2000); return; } this.style.color = 'orange'; this.pending = setTimeout(this.reset, 2000); e.preventDefault(); }); $('save-button').addEventListener('click', function(e) { e.preventDefault(); if ( e.button !== 0 ) { return; } save(); changeColor(resetButton); changeColor(this, 'green'); }); [].forEach.call(document.body.querySelectorAll('.action-buttons') || [], function(el) { el.addEventListener('mousedown', function(e) { e.preventDefault(); }); }); vAPI.messaging.send({cmd: 'loadPrefs', getAppInfo: true}, function(data) { $('app-name').textContent = data.app.name; $('app-version').textContent = data.app.version; $('platform-info').textContent = data.app.platform; document.title = ':: ' + data.app.name + ' ::'; var xhr = new XMLHttpRequest; xhr.overrideMimeType('application/json;charset=utf-8'); xhr.open('GET', 'defaults.json', true); xhr.onload = function() { defaultPrefs = JSON.parse(this.responseText); load(data.prefs); document.body.style.display = 'block'; }; xhr.send(); }); }); {"_":"en","cs":{"name":"Czech (čeština)","translators":[{"email":"jaramat@email.cz","fullname":"Jaroslav Matura","name":"jaramat"}]},"el":{"%":66.67,"name":"Greek (Ελληνικά)","translators":[{"email":"farow.the.time.traveler@gmail.com","name":"Farow"}]},"en":{"name":"English","translators":[{"email":"deathamns@gmail.com","name":"Deathamns"}]},"es":{"name":"Spanish (español)","translators":[{"email":"nightroad@mail.com","fullname":"Javier Vera","name":"DurianZheitk"}]},"fi":{"%":61.4,"name":"Finnish (suomi)","translators":[{"email":"opeeera@myopera.com","name":"Opeeera"}]},"fr":{"%":91.23,"name":"French (français)","translators":[{"email":"tmnath2@gmail.com","name":"Tmnath"}]},"hu":{"name":"Hungarian (magyar)","translators":[{"email":"deathamns@gmail.com","name":"Deathamns"}]},"ko":{"name":"Korean (한국어)","translators":[{"email":"yut951121@gmail.com","fullname":"유태종","name":"QbsidianH20"}]},"nl":{"%":70.18,"name":"Dutch (Nederlands)","translators":[{"email":"kackar@outlook.com","name":"Kaçkar"}]},"pl":{"name":"Polish (polski)","translators":[{"fullname":"Paweł Pawlak","name":"pafflick","web":"http://www.pafflick.com/"}]},"pt-BR":{"%":70.18,"name":"Portuguese (Brazil) (português (Brasil))","translators":[{"email":"romulo@brazilmail.com","fullname":"Rômulo Godoi"}]},"ru":{"name":"Russian (русский)","translators":[{"email":"rodny0@gmail.com","name":"Rodny"}]},"tr":{"%":33.33,"name":"Turkish (Türkçe)","translators":[{"email":"sanerapaydin86@gmail.com","fullname":"Saner Apaydın"}]},"uk":{"%":70.18,"name":"Ukrainian (українська)","translators":[{"email":"simofon@yandex.ru","name":"Simofon"}]},"zh-CN":{"%":70.18,"name":"Chinese (Simplified Han) (中文(简体中文))","translators":[{"email":"wlq105556@gmail.com","name":"fang5566"}]},"zh-TW":{"%":43.86,"name":"Chinese (Traditional Han) (中文 (繁體中文))","translators":[{"email":"tingyang@gmail.com","name":"TYKuo"}]}}
0%

  • + / -