ImageFAQs

Converts image and webm URLs into their embedded form

当前为 2016-05-03 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name ImageFAQs
  3. // @namespace FightingGames@gfaqs
  4. // @include http://www.gamefaqs.com
  5. // @include http://www.gamefaqs.com*
  6. // @icon http://fightinggames.bitbucket.org/imagefaqs/icon.png
  7. // @description Converts image and webm URLs into their embedded form
  8. // @version 1.18.5
  9. // @grant GM_addStyle
  10. // @grant GM_getResourceText
  11. // @grant GM_log
  12. // @grant GM_xmlhttpRequest
  13. // @require http://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js
  14. // @require https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/jquery-ui.min.js
  15. // @resource jqueryuibaseCSS https://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery.ui.base.css
  16. // @resource jqueryuithemeCSS https://code.jquery.com/ui/1.11.4/themes/cupertino/jquery-ui.css
  17. // ==/UserScript==
  18.  
  19.  
  20.  
  21. /*
  22. The MIT License (MIT)
  23.  
  24. This greasemonkey script for GameFAQs converts image and webm
  25. links into their embedded form. It can be considered as a spiritual successor
  26. to text-to-image for GameFAQs. Many of its features are inspired from appchan x
  27. by zixaphir at http://zixaphir.github.io/appchan-x/.
  28. Copyright (c) 2015 FightingGames@gamefaqs <adrenalinebionicarm@gmail.com>
  29. Copyright (c) 2015 FeaturingDante@gamefaqs <featuringDante@gmail.com>
  30.  
  31. Permission is hereby granted, free of charge, to any person obtaining a copy
  32. of this software and associated documentation files (the "Software"), to deal
  33. in the Software without restriction, including without limitation the rights
  34. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  35. copies of the Software, and to permit persons to whom the Software is
  36. furnished to do so, subject to the following conditions:
  37.  
  38. The above copyright notice and this permission notice shall be included in
  39. all copies or substantial portions of the Software.
  40.  
  41. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  42. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  43. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  44. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  45. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  46. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  47. THE SOFTWARE.
  48.  
  49. */
  50.  
  51. /*
  52. Get number of keys in a primitive java object
  53. */
  54. Object.size = function(obj) {
  55. var size = 0
  56. var key;
  57. for (key in obj) {
  58. if (obj.hasOwnProperty(key))
  59. size++;
  60. }
  61. return size;
  62. };
  63.  
  64.  
  65. /*
  66. Below is a collection of functions to iterate through HTML objects (e.g. step from <b></b> to <img/>)
  67. https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Whitespace_in_the_DOM
  68. */
  69.  
  70.  
  71. /*
  72. * Determine whether a node's text content is entirely whitespace.
  73. *
  74. * @param nod A node implementing the |CharacterData| interface (i.e.,
  75. * a |Text|, |Comment|, or |CDATASection| node
  76. * @return True if all of the text content of |nod| is whitespace,
  77. * otherwise false.
  78. */
  79. function is_all_ws( nod )
  80. {
  81. // Use ECMA-262 Edition 3 String and RegExp features
  82. return !(/[^\t\n\r ]/.test(nod.textContent));
  83. }
  84.  
  85.  
  86. /*
  87. * Determine if a node should be ignored by the iterator functions.
  88. *
  89. * @param nod An object implementing the DOM1 |Node| interface.
  90. * @return true if the node is:
  91. * 1) A |Text| node that is all whitespace
  92. * 2) A |Comment| node
  93. * and otherwise false.
  94. */
  95.  
  96. function is_ignorable( nod )
  97. {
  98. return ( nod.nodeType == 8) || // A comment node
  99. ( (nod.nodeType == 3) && is_all_ws(nod) ); // a text node, all ws
  100. }
  101.  
  102. /*
  103. * Version of |previousSibling| that skips nodes that are entirely
  104. * whitespace or comments. (Normally |previousSibling| is a property
  105. * of all DOM nodes that gives the sibling node, the node that is
  106. * a child of the same parent, that occurs immediately before the
  107. * reference node.)
  108. *
  109. * @param sib The reference node.
  110. * @return Either:
  111. * 1) The closest previous sibling to |sib| that is not
  112. * ignorable according to |is_ignorable|, or
  113. * 2) null if no such node exists.
  114. */
  115. function node_before( sib )
  116. {
  117. while ((sib = sib.previousSibling)) {
  118. if (!is_ignorable(sib)) return sib;
  119. }
  120. return null;
  121. }
  122.  
  123. /*
  124. * Version of |nextSibling| that skips nodes that are entirely
  125. * whitespace or comments.
  126. *
  127. * @param sib The reference node.
  128. * @return Either:
  129. * 1) The closest next sibling to |sib| that is not
  130. * ignorable according to |is_ignorable|, or
  131. * 2) null if no such node exists.
  132. */
  133. function node_after( sib )
  134. {
  135. while ((sib = sib.nextSibling)) {
  136. if (!is_ignorable(sib)) return sib;
  137. }
  138. return null;
  139. }
  140.  
  141. /*
  142. * Version of |lastChild| that skips nodes that are entirely
  143. * whitespace or comments. (Normally |lastChild| is a property
  144. * of all DOM nodes that gives the last of the nodes contained
  145. * directly in the reference node.)
  146. *
  147. * @param sib The reference node.
  148. * @return Either:
  149. * 1) The last child of |sib| that is not
  150. * ignorable according to |is_ignorable|, or
  151. * 2) null if no such node exists.
  152. */
  153. function last_child( par )
  154. {
  155. var res=par.lastChild;
  156. while (res) {
  157. if (!is_ignorable(res)) return res;
  158. res = res.previousSibling;
  159. }
  160. return null;
  161. }
  162.  
  163. /*
  164. * Version of |firstChild| that skips nodes that are entirely
  165. * whitespace and comments.
  166. *
  167. * @param sib The reference node.
  168. * @return Either:
  169. * 1) The first child of |sib| that is not
  170. * ignorable according to |is_ignorable|, or
  171. * 2) null if no such node exists.
  172. */
  173. function first_child( par )
  174. {
  175. var res=par.firstChild;
  176. while (res) {
  177. if (!is_ignorable(res)) return res;
  178. res = res.nextSibling;
  179. }
  180. return null;
  181. }
  182.  
  183. /*
  184. * Version of |data| that doesn't include whitespace at the beginning
  185. * and end and normalizes all whitespace to a single space. (Normally
  186. * |data| is a property of text nodes that gives the text of the node.)
  187. *
  188. * @param txt The text node whose data should be returned
  189. * @return A string giving the contents of the text node with
  190. * whitespace collapsed.
  191. */
  192. function data_of( txt )
  193. {
  194. var data = txt.textContent;
  195. // Use ECMA-262 Edition 3 String and RegExp features
  196. data = data.replace(/[\t\n\r ]+/g, " ");
  197. if (data.charAt(0) == " ")
  198. data = data.substring(1, data.length);
  199. if (data.charAt(data.length - 1) == " ")
  200. data = data.substring(0, data.length - 1);
  201. return data;
  202. }
  203.  
  204. /*End of HTML object iterator functions*/
  205.  
  206.  
  207.  
  208.  
  209.  
  210.  
  211.  
  212. /*Get our own unique jQuery library instance*/
  213. this.$ = this.jQuery = jQuery.noConflict(true);
  214.  
  215.  
  216.  
  217.  
  218.  
  219.  
  220. /*
  221. Display a notification on the bottom-right of the browser.
  222.  
  223. @param msg :: string to put between <span></span>
  224. @param duration :: number of milliseconds to display message before it disappears. Default 1000
  225. */
  226. function showNotification(msg, duration)
  227. {
  228. var notificationBox = $("#imagefaqs_notificationBox");
  229. notificationBox.remove();
  230. $("body").append(
  231. "<div id='imagefaqs_notificationBox'>" +
  232. "<span style='color: black'>" +
  233. msg +
  234. "</span>" +
  235. "</div>"
  236. );
  237. notificationBox = $("#imagefaqs_notificationBox");
  238.  
  239. notificationBox.css({
  240. "position": "absolute",
  241. "top": ($(window).scrollTop() + $(window).height() - notificationBox.height())+"px",
  242. "left": ($(window).scrollLeft() + $(window).width() - notificationBox.find("span").width())+"px",
  243. "background": "white",
  244. });
  245.  
  246. if (duration === undefined)
  247. duration = 1000;
  248. notificationBox.effect("highlight").delay(duration).fadeOut(500);
  249. }
  250.  
  251.  
  252.  
  253.  
  254.  
  255.  
  256. /*This top portion of the script handles the settings box and local storage*/
  257.  
  258. var thumbnailImgWidth = 150;
  259. var thumbnailImgHeight = 150;
  260. var thumbnailImgWidthSig = 75;
  261. var thumbnailImgHeightSig = 75;
  262. var settingsJSON = localStorage.getItem("imagefaqs");
  263. var settings; /*key-value array of JSON*/
  264. var sessionResizeHotkey;
  265. var sessionHideToggleHotkey;
  266. var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; /*osdep*/
  267.  
  268. function setSettingsToDefault() {
  269. settings = {
  270. enable_sigs: true,
  271. enable_floatingImg: true,
  272. includeSigWhenExpanding: false,
  273. hideSigsWhenHideMode: false,
  274. show_imgURLspan: true,
  275. show_imgResolutionSpan: true,
  276. show_imgFilesizeSpan: false,
  277. show_imgGoogle: true,
  278. show_imgIqdb: true,
  279. show_blacklistToggle: true,
  280. show_imgAllResizeToggles: true,
  281. show_hideToggle: true,
  282. show_hideAllToggle: true,
  283. imgContainerStyle: "sideBySideSig",
  284. auto_scroll_when_thumbnail_clicked: true,
  285. thumbnailWidth: thumbnailImgWidth,
  286. thumbnailHeight: thumbnailImgHeight,
  287. thumbnailWidthSig: thumbnailImgWidthSig,
  288. thumbnailHeightSig: thumbnailImgHeightSig,
  289. expandedWidth: 0,
  290. expandedHeight: 0,
  291. imgContainerBackgroundColor: "#DFE6F7",
  292. isHideMode: false,
  293. hideToggleHotkey: {115: 115}, /*F4*/
  294. resizeHotkey: {113: 113}, /*F2*/
  295. blacklistStr: ""
  296. };
  297. }
  298.  
  299. /*if imageFAQs was freshly installed*/
  300. if (settingsJSON === null)
  301. {
  302. setSettingsToDefault();
  303. localStorage.setItem("imagefaqs", JSON.stringify(settings)); /*save default settings*/
  304. /*gfaqsdep for URL*/
  305. showNotification("ImageFAQs "+GM_info.script.version+" has successfully been installed.<br/><br/>Settings can be accessed under 'Quick Links' at <a target='_blank' href='http://www.gamefaqs.com/user'>http://www.gamefaqs.com/user</a>", 10000);
  306. }
  307. else
  308. {
  309. settings = $.parseJSON(settingsJSON);
  310. if (settings.expandedWidth === undefined)
  311. settings.expandedWidth = 0;
  312. if (settings.expandedHeight === undefined)
  313. settings.expandedHeight = 0;
  314. if (settings.show_imgURLspan === undefined)
  315. settings.show_imgURLspan = true;
  316. if (settings.show_imgResolutionSpan === undefined)
  317. settings.show_imgResolutionSpan = true;
  318. if (settings.show_imgFilesizeSpan === undefined)
  319. settings.show_imgFilesizeSpan = true;
  320. if (settings.show_imgGoogle === undefined)
  321. settings.show_imgGoogle = true;
  322. if (settings.show_imgIqdb === undefined)
  323. settings.show_imgIqdb = true;
  324. if (settings.show_blacklistToggle === undefined)
  325. settings.show_blacklistToggle = true;
  326. if (settings.show_imgAllResizeToggles === undefined)
  327. settings.show_imgAllResizeToggles = true;
  328. if (settings.show_hideToggle === undefined)
  329. settings.show_hideToggle = true;
  330. if (settings.show_hideAllToggle === undefined)
  331. settings.show_hideAllToggle = true;
  332. if (settings.isHideMode === undefined)
  333. settings.isHideMode = false;
  334. if (settings.enable_floatingImg === undefined)
  335. settings.enable_floatingImg = true;
  336. if (settings.imgContainerStyle === undefined)
  337. settings.imgContainerStyle = "sideBySideSig";
  338. if (settings.auto_scroll_when_thumbnail_clicked === undefined)
  339. settings.auto_scroll_when_thumbnail_clicked = true;
  340. if (settings.resizeHotkey === undefined || $.isEmptyObject(settings.resizeHotkey))
  341. settings.resizeHotkey = {113: 113};
  342. if (settings.hideToggleHotkey === undefined || $.isEmptyObject(settings.hideToggleHotkey))
  343. settings.hideToggleHotkey = {115: 115};
  344. if (settings.includeSigWhenExpanding === undefined)
  345. settings.includeSigWhenExpanding = false;
  346. if (settings.hideSigsWhenHideMode === undefined)
  347. settings.hideSigsWhenHideMode = false;
  348. if (settings.thumbnailWidth === undefined)
  349. settings.thumbnailWidth = thumbnailImgWidth;
  350. if (settings.thumbnailHeight === undefined)
  351. settings.thumbnailHeight = thumbnailImgHeight;
  352. if (settings.thumbnailWidthSig === undefined)
  353. settings.thumbnailWidthSig = thumbnailImgWidthSig;
  354. if (settings.thumbnailHeightSig === undefined)
  355. settings.thumbnailHeightSig = thumbnailImgHeightSig;
  356. localStorage.setItem("imagefaqs", JSON.stringify(settings));
  357. }
  358.  
  359.  
  360.  
  361. /*
  362. Convert an ASCII numeric representation of a keyboard character to its full string name
  363.  
  364. e.g. keyCodeToString(16) === "shift"
  365. */
  366. function keyCodeToString(keyCode)
  367. {
  368. keyCode = parseInt(keyCode);
  369. if (keyCode === 16)
  370. {
  371. return "shift";
  372. }
  373. else if (keyCode === 17)
  374. {
  375. return "ctrl";
  376. }
  377. else if (keyCode === 18)
  378. {
  379. return "alt";
  380. }
  381. else if (keyCode >= 112 && keyCode <= 123) /*F keys*/
  382. {
  383. return "F" + (keyCode - 111);
  384. }
  385. else
  386. {
  387. return String.fromCharCode(keyCode);
  388. }
  389. }
  390.  
  391.  
  392. /*
  393. Convert an array of KV ASCII numeric representation of keyboard characters to its
  394. full string representation
  395.  
  396. e,g, keyCodeKVArrayToString([{68:68},{77:77}]) === "DM"
  397. */
  398. function keyCodeKVArrayToString(array)
  399. {
  400. var string = "";
  401. for (var key in array)
  402. {
  403. string += keyCodeToString(key) + " ";
  404. }
  405. return string;
  406. }
  407.  
  408.  
  409. /*
  410. Get a copy of an array of KV's using 1-level deep cloning.
  411. */
  412. function cloneKVArray(KVArray)
  413. {
  414. var newKVArray = {};
  415. for (var key in KVArray)
  416. {
  417. newKVArray[key] = KVArray[key];
  418. }
  419. return newKVArray;
  420. }
  421.  
  422.  
  423.  
  424. sessionHideToggleHotkey = cloneKVArray(settings.hideToggleHotkey);
  425. sessionResizeHotkey = cloneKVArray(settings.resizeHotkey);
  426.  
  427.  
  428.  
  429. /*Event where user opens up settings menu*/
  430. $("body").on("click", "#imagefaqs_settings_but", function(event) {
  431.  
  432. var popupBox = $("#imagefaqs_settings_popup");
  433. event.preventDefault();
  434. if (popupBox.length === 0)
  435. {
  436. $("body").append(
  437. "<div id='imagefaqs_settings_popup' title='ImageFAQs Settings. Version "+GM_info.script.version+"'>" +
  438. "Update history: <a target='_blank' href='http://fightinggames.bitbucket.org/imagefaqs/' style='outline: 0'>http://fightinggames.bitbucket.org/imagefaqs/</a>" +
  439. "<br/>" +
  440. "<span id='feedback_bugreport_info'>" +
  441. "Feedback and bug reporting: <a target='_blank' href='http://www.gamefaqs.com/boards/565885-blood-money'>http://www.gamefaqs.com/boards/565885-blood-money</a>" +
  442. "<br/>" +
  443. "</span>" +
  444. "<fieldset>" +
  445. "<legend>Main</legend>" +
  446. "<label><input id='enable_floatingImg' type='checkbox'>Enable floating expanded image upon cursor hover</label>" +
  447. "<br/>" +
  448. "<label><input id='auto_scroll_when_thumbnail_clicked_checkbox' type='checkbox'>Auto-scroll to top of image after toggling visibility or size</label>" +
  449. "</fieldset>" +
  450. "<fieldset>" +
  451. "<legend>Signature-specific</legend>" +
  452. "<label><input id='enable_sigs_checkbox' type='checkbox'>Embed signature images</label>" +
  453. "<br/>" +
  454. "<label><input id='includeSigWhenExpanding_checkbox' type='checkbox'>Affect signature images when expanding and contracting all images</label>" +
  455. "<br/>" +
  456. "<label><input id='hideSigsWhenHideMode_checkbox' type='checkbox'>Affect signature images when toggling hide mode</label>" +
  457. "</fieldset>" +
  458. "<fieldset>" +
  459. "<legend>Image Container Toggles and Information Visibility</legend>" +
  460. "<label><input id='show_ImgURLspan_checkbox' type='checkbox'>Show image URL</label>" +
  461. "<br/>" +
  462. "<label><input id='show_ImgResolutionSpan_checkbox' type='checkbox'>Show image resolution</label>" +
  463. "<br/>" +
  464. "<label><input id='show_imgFilesizeSpan_checkbox' type='checkbox'>Show image filesize (Currently slow for Chrome)</label>" +
  465. "<br/>" +
  466. "<label><input id='show_imgGoogle_checkbox' type='checkbox'>Show google reverse image search button</label>" +
  467. "<br/>" +
  468. "<label><input id='show_imgIqdb_checkbox' type='checkbox'>Show iqdb reverse image search button</label>" +
  469. "<br/>" +
  470. "<label><input id='show_blacklistToggle_checkbox' type='checkbox'>Show blacklist toggle button</label>" +
  471. "<br/>" +
  472. "<label><input id='show_imgAllResizeToggles_checkbox' type='checkbox'>Show all-resize toggle buttons</label>" +
  473. "<br/>" +
  474. "<label><input id='show_hideAllToggle_checkbox' type='checkbox'>Show all-hide/expose toggle buttons</label>" +
  475. "<br/>" +
  476. "<label><input id='show_hideToggle_checkbox' type='checkbox'>Show individual hide/expose toggle button</label>" +
  477. "</fieldset>" +
  478. "<fieldset>" +
  479. "<legend>Image Container Style</legend>" +
  480. "<label><input type='radio' name='imgContainerStyle' value='stacked' checked='checked'>Stacked and Verbose</label>" +
  481. "<br>" +
  482. "<label><input type='radio' name='imgContainerStyle' value='sideBySide'>Side-By-Side and Succinct</label>" +
  483. "<br>" +
  484. "<label><input type='radio' name='imgContainerStyle' value='sideBySideSig'>Side-By-Side and Succinct (Signatures Only)</label>" +
  485. "</fieldset>" +
  486. "<label><input id='thumbnailImgWidth_text' type='text'>Thumbnail Max-Width (150 default)</label>" +
  487. "<br/>" +
  488. "<label><input id='thumbnailImgHeight_text' type='text'>Thumbnail Max-Height (150 default)</label>" +
  489. "<br/>" +
  490. "<label><input id='thumbnailImgWidthSig_text' type='text'>Signature Thumbnail Max-Width (75 default)</label>" +
  491. "<br/>" +
  492. "<label><input id='thumbnailImgHeightSig_text' type='text'>Signature Thumbnail Max-Height (75 default)</label>" +
  493. "<br/>" +
  494. "<label><input id='expandedWidth_text' type='text'>Expanded max-width (0 default)</label>" +
  495. "<br/>" +
  496. "<label><input id='expandedHeight_text' type='text'>Expanded max-height (0 default)</label>" +
  497. "<br/ style='margin-bottom: 5px'>" +
  498. "<span>Tip: Use 0 to specify no length restriction.</span>" +
  499. "<br/><br/>" +
  500. "<input id='imgContainerBackgroundColor_color' type='color' value='#DFE6F7' size=4 ><label>Image container background color (RGB={223,230,247} default)</label>" +
  501. "<br/ style='margin-bottom: 5px'>" +
  502. "<span>Tip: Use RGB={0,0,0} for no background color.</span>" +
  503. "<br/><br/>" +
  504. "<label>Newline separated list of blacklisted image URLs</label>" +
  505. "<br/>" +
  506. "<textarea id='blacklist_text'></textarea>" +
  507. "<br/ style='margin-bottom: 5px'>" +
  508. "<span>Tip: You can blacklist an entire domain (e.g. pbsrc.com).</span>" +
  509. "<br/><br/>" +
  510. "<label><input id='resizeHotkey_text' class='hotkeyInput' type='text'>Toggle image size hotkey (F2 default)</label>" +
  511. "<br/>" +
  512. "<label><input id='hideToggleHotkey_text' class='hotkeyInput' type='text'>Toggle hide mode hotkey (F4 default)</label>" +
  513. "<br/ style='margin-bottom: 5px'>" +
  514. "<span>Tip: You can disable a hotkey with the backspace.</span>" +
  515. "<br/><br/>" +
  516. "<button id='saveImagefaqsSettingsBut' type='button'>Save</button> " +
  517. "<button id='cancelImagefaqsSettingsBut' type='button'>Cancel</button> " +
  518. "<span id='responseSpan'>&nbsp;&nbsp;</span>" + /*for reporting success or failure*/
  519. "<button id='defaultSettingsBut' type='button' style='float: right'>Reset Settings</button> " +
  520. "</div>"
  521. );
  522. popupBox = $("#imagefaqs_settings_popup");
  523. }
  524.  
  525. /*Show user's custom settings*/
  526. popupBox.find("#enable_sigs_checkbox").prop("checked", settings.enable_sigs);
  527. popupBox.find("#enable_floatingImg").prop("checked", settings.enable_floatingImg);
  528. popupBox.find("#includeSigWhenExpanding_checkbox").prop("checked", settings.includeSigWhenExpanding);
  529. popupBox.find("#hideSigsWhenHideMode_checkbox").prop("checked", settings.hideSigsWhenHideMode);
  530. popupBox.find("#show_ImgURLspan_checkbox").prop("checked", settings.show_imgURLspan);
  531. popupBox.find("#show_ImgResolutionSpan_checkbox").prop("checked", settings.show_imgResolutionSpan);
  532. popupBox.find("#show_imgFilesizeSpan_checkbox").prop("checked", settings.show_imgFilesizeSpan);
  533. popupBox.find("#show_imgGoogle_checkbox").prop("checked", settings.show_imgGoogle);
  534. popupBox.find("#show_blacklistToggle_checkbox").prop("checked", settings.show_blacklistToggle);
  535. popupBox.find("#show_imgIqdb_checkbox").prop("checked", settings.show_imgIqdb);
  536. popupBox.find("#show_imgAllResizeToggles_checkbox").prop("checked", settings.show_imgAllResizeToggles);
  537. popupBox.find("#show_hideToggle_checkbox").prop("checked", settings.show_hideToggle);
  538. popupBox.find("#show_hideAllToggle_checkbox").prop("checked", settings.show_hideAllToggle);
  539. popupBox.find("input[value="+settings.imgContainerStyle+"]").prop("checked", true);
  540. popupBox.find("#auto_scroll_when_thumbnail_clicked_checkbox").prop("checked", settings.auto_scroll_when_thumbnail_clicked);
  541. popupBox.find("#thumbnailImgWidth_text").val(settings.thumbnailWidth);
  542. popupBox.find("#thumbnailImgHeight_text").val(settings.thumbnailHeight);
  543. popupBox.find("#thumbnailImgWidthSig_text").val(settings.thumbnailWidthSig);
  544. popupBox.find("#thumbnailImgHeightSig_text").val(settings.thumbnailHeightSig);
  545. popupBox.find("#expandedWidth_text").val(settings.expandedWidth);
  546. popupBox.find("#expandedHeight_text").val(settings.expandedHeight);
  547. /*"#000000" will be changed to "0" for transparency in the imgContainerBackgroundColor global var*/
  548. popupBox.find("#imgContainerBackgroundColor_color").val(settings.imgContainerBackgroundColor);
  549. popupBox.find("#resizeHotkey_text").val( keyCodeKVArrayToString(settings.resizeHotkey) );
  550. popupBox.find("#hideToggleHotkey_text").val( keyCodeKVArrayToString(settings.hideToggleHotkey) );
  551. popupBox.find("#blacklist_text").val( settings.blacklistStr );
  552. $("#imagefaqs_settings_popup").children("#responseSpan").html("&nbsp;");
  553. popupBox.dialog({
  554. width: 630,
  555. height: 800 /*adds a scrollbar*/
  556. });
  557. popupBox.find("#blacklist_text").width(popupBox.width());
  558. });
  559.  
  560.  
  561.  
  562.  
  563. $("body").on("click", "#defaultSettingsBut", function(event) {
  564. event.preventDefault();
  565. var settingsPopup = $("#imagefaqs_settings_popup");
  566. setSettingsToDefault();
  567. settingsPopup.find("#enable_sigs_checkbox").prop("checked", settings.enable_sigs);
  568. settingsPopup.find("#enable_floatingImg").prop("checked", settings.enable_floatingImg);
  569. settingsPopup.find("#includeSigWhenExpanding_checkbox").prop("checked", settings.includeSigWhenExpanding);
  570. settingsPopup.find("#hideSigsWhenHideMode_checkbox").prop("checked", settings.hideSigsWhenHideMode);
  571. settingsPopup.find("#show_ImgURLspan_checkbox").prop("checked", settings.show_imgURLspan);
  572. settingsPopup.find("#show_ImgResolutionSpan_checkbox").prop("checked", settings.show_imgResolutionSpan);
  573. settingsPopup.find("#show_imgFilesizeSpan_checkbox").prop("checked", settings.show_imgFilesizeSpan);
  574. settingsPopup.find("#show_imgGoogle_checkbox").prop("checked", settings.show_imgGoogle);
  575. settingsPopup.find("#show_blacklistToggle_checkbox").prop("checked", settings.show_blacklistToggle);
  576. settingsPopup.find("#show_imgIqdb_checkbox").prop("checked", settings.show_imgIqdb);
  577. settingsPopup.find("#show_imgAllResizeToggles_checkbox").prop("checked", settings.show_imgAllResizeToggles);
  578. settingsPopup.find("#show_hideToggle_checkbox").prop("checked", settings.show_hideToggle);
  579. settingsPopup.find("#show_hideAllToggle_checkbox").prop("checked", settings.show_hideAllToggle);
  580. settingsPopup.find("input[value="+settings.imgContainerStyle+"]").prop("checked", true);
  581. settingsPopup.find("#auto_scroll_when_thumbnail_clicked_checkbox").prop("checked", settings.auto_scroll_when_thumbnail_clicked);
  582. settingsPopup.find("#thumbnailImgWidth_text").val(settings.thumbnailWidth);
  583. settingsPopup.find("#thumbnailImgHeight_text").val(settings.thumbnailHeight);
  584. settingsPopup.find("#thumbnailImgWidthSig_text").val(settings.thumbnailWidthSig);
  585. settingsPopup.find("#thumbnailImgHeightSig_text").val(settings.thumbnailHeightSig);
  586. settingsPopup.find("#expandedWidth_text").val(settings.expandedWidth);
  587. settingsPopup.find("#expandedHeight_text").val(settings.expandedHeight);
  588. settingsPopup.find("#imgContainerBackgroundColor_color").val(settings.imgContainerBackgroundColor);
  589. settingsPopup.find("#resizeHotkey_text").val( keyCodeKVArrayToString(settings.resizeHotkey) );
  590. settingsPopup.find("#hideToggleHotkey_text").val( keyCodeKVArrayToString(settings.hideToggleHotkey) );
  591. settingsPopup.find("#blacklist_text").val( settings.blacklistStr );
  592. $("#imagefaqs_settings_popup").children("#responseSpan").html("&nbsp;");
  593. localStorage.setItem("imagefaqs", JSON.stringify(settings));
  594. reportResponseMsgInImagefaqsSettingsPopupBox("Default settings saved.", settingsPopup);
  595. });
  596.  
  597.  
  598.  
  599. /*Event where users clicks on the "Save Settings" button*/
  600. $("body").on("click", "#saveImagefaqsSettingsBut", function(event) {
  601.  
  602. event.preventDefault();
  603. var settingsPopup = $("#imagefaqs_settings_popup");
  604. /*if valid thumbnail dimensions*/
  605. if (
  606. !isNaN($("#thumbnailImgWidth_text").val()) && $("#thumbnailImgWidth_text").val() >= 0 &&
  607. !isNaN($("#thumbnailImgHeight_text").val()) && $("#thumbnailImgHeight_text").val() >= 0 &&
  608. !isNaN($("#thumbnailImgWidthSig_text").val()) && $("#thumbnailImgWidthSig_text").val() >= 0 &&
  609. !isNaN($("#thumbnailImgHeightSig_text").val()) && $("#thumbnailImgHeightSig_text").val() >= 0)
  610. {
  611. settings.thumbnailWidth = $("#thumbnailImgWidth_text").val();
  612. settings.thumbnailHeight = $("#thumbnailImgHeight_text").val();
  613. settings.thumbnailWidthSig = $("#thumbnailImgWidthSig_text").val();
  614. settings.thumbnailHeightSig = $("#thumbnailImgHeightSig_text").val();
  615. }
  616. else
  617. {
  618. reportResponseMsgInImagefaqsSettingsPopupBox("Error: Invalid thumbnail dimensions. Use non-negative integers only.", settingsPopup);
  619. return;
  620. }
  621. /*if valid expanded dimensions*/
  622. if (
  623. !isNaN($("#expandedWidth_text").val()) && $("#expandedWidth_text").val() >= 0 &&
  624. !isNaN($("#expandedHeight_text").val()) && $("#expandedHeight_text").val() >= 0)
  625. {
  626. settings.expandedWidth = $("#expandedWidth_text").val();
  627. settings.expandedHeight = $("#expandedHeight_text").val();
  628. }
  629. else
  630. {
  631. reportResponseMsgInImagefaqsSettingsPopupBox("Error: Invalid expanded dimensions. Use non-negative integers only.", settingsPopup);
  632. return;
  633. }
  634. /*if valid image container background color*/
  635. if (settingsPopup.find("#imgContainerBackgroundColor_color").val().search(/^(#[a-zA-Z0-9]{6})|0$/i) >= 0)
  636. {
  637. settings.imgContainerBackgroundColor = settingsPopup.find("#imgContainerBackgroundColor_color").val();
  638. }
  639. else
  640. {
  641. reportResponseMsgInImagefaqsSettingsPopupBox("Error: Invalid image container background color.", settingsPopup);
  642. return;
  643. }
  644. settings.enable_sigs = settingsPopup.find("#enable_sigs_checkbox").prop("checked");
  645. settings.enable_floatingImg = settingsPopup.find("#enable_floatingImg").prop("checked");
  646. settings.includeSigWhenExpanding = settingsPopup.find("#includeSigWhenExpanding_checkbox").prop("checked");
  647. settings.hideSigsWhenHideMode = settingsPopup.find("#hideSigsWhenHideMode_checkbox").prop("checked");
  648. settings.show_imgURLspan = settingsPopup.find("#show_ImgURLspan_checkbox").prop("checked");
  649. settings.show_imgResolutionSpan = settingsPopup.find("#show_ImgResolutionSpan_checkbox").prop("checked");
  650. settings.show_imgFilesizeSpan = settingsPopup.find("#show_imgFilesizeSpan_checkbox").prop("checked");
  651. settings.show_imgGoogle = settingsPopup.find("#show_imgGoogle_checkbox").prop("checked");
  652. settings.show_imgIqdb = settingsPopup.find("#show_imgIqdb_checkbox").prop("checked");
  653. settings.show_blacklistToggle = settingsPopup.find("#show_blacklistToggle_checkbox").prop("checked");
  654. settings.show_imgAllResizeToggles = settingsPopup.find("#show_imgAllResizeToggles_checkbox").prop("checked");
  655. settings.show_hideToggle = settingsPopup.find("#show_hideToggle_checkbox").prop("checked");
  656. settings.show_hideAllToggle = settingsPopup.find("#show_hideAllToggle_checkbox").prop("checked");
  657. settings.imgContainerStyle = settingsPopup.find("input[name=imgContainerStyle]:checked").val();
  658. settings.auto_scroll_when_thumbnail_clicked = settingsPopup.find("#auto_scroll_when_thumbnail_clicked_checkbox").prop("checked");
  659. settings.resizeHotkey = cloneKVArray(sessionResizeHotkey);
  660. settings.hideToggleHotkey = cloneKVArray(sessionHideToggleHotkey);
  661. settings.blacklistStr = settingsPopup.find("#blacklist_text").val();
  662. localStorage.setItem("imagefaqs", JSON.stringify(settings));
  663. reportResponseMsgInImagefaqsSettingsPopupBox("Settings saved.", settingsPopup);
  664. });
  665.  
  666.  
  667.  
  668. /*
  669. Display a notification in the settings window
  670.  
  671. @param msg :: message string to show to the user
  672. @param box :: $("#imagefaqs_settings_popup")
  673. */
  674. function reportResponseMsgInImagefaqsSettingsPopupBox(msg, box)
  675. {
  676. var msgBox = box.children("#responseSpan");
  677. msgBox.html(msg);
  678. msgBox.effect("highlight");
  679. }
  680.  
  681.  
  682. /*Event when users clicks on the "Cancel" button the settings window.*/
  683. $("body").on("click", "#cancelImagefaqsSettingsBut", function(event) {
  684.  
  685. event.preventDefault();
  686. $("#imagefaqs_settings_popup").dialog("close");
  687. });
  688.  
  689.  
  690.  
  691.  
  692.  
  693.  
  694. /*Begin main scripting*/
  695. (function(){
  696.  
  697. var isHideMode = settings.isHideMode;
  698. var enable_floatingImg = settings.enable_floatingImg;
  699.  
  700. var includeSigWhenExpanding = settings.includeSigWhenExpanding;
  701. var hideSigsWhenHideMode = settings.hideSigsWhenHideMode;
  702.  
  703. var show_imgURLspan = settings.show_imgURLspan;
  704. var show_imgResolutionSpan = settings.show_imgResolutionSpan;
  705. var show_imgFilesizeSpan = settings.show_imgFilesizeSpan;
  706. var show_imgGoogle = settings.show_imgGoogle;
  707. var show_imgIqdb = settings.show_imgIqdb;
  708. var show_blacklistToggle = settings.show_blacklistToggle;
  709. var show_imgResizeToggles = settings.show_imgAllResizeToggles;
  710. var show_hideToggle = settings.show_hideToggle;
  711. var show_hideAllToggle = settings.show_hideAllToggle;
  712.  
  713. var imgContainerStyle = settings.imgContainerStyle;
  714. var autoScrollWhenThumbnailClicked = settings.auto_scroll_when_thumbnail_clicked;
  715.  
  716. var thumbnailImgWidth = settings.thumbnailWidth;
  717. var thumbnailImgHeight = settings.thumbnailHeight;
  718. var thumbnailImgWidthSig = settings.thumbnailWidthSig;
  719. var thumbnailImgHeightSig = settings.thumbnailHeightSig;
  720. var expandedImgWidth = settings.expandedWidth;
  721. var expandedImgHeight = settings.expandedHeight;
  722.  
  723. var imgContainerBackgroundColor = settings.imgContainerBackgroundColor;
  724. if (imgContainerBackgroundColor === "#000000") {
  725. imgContainerBackgroundColor = 0;
  726. }
  727.  
  728. var blacklist = settings.blacklistStr.split("\n"); /*array of URLs to block*/
  729. var currentURL;
  730. var pageType; /* "topic" or "postPreview" or "other" */
  731. var allowImgInSig = settings.enable_sigs;
  732. var floatingImgWidth;
  733. var floatingImgRightOffset = 50;
  734. var floatingImgBorder = 10;
  735. var currentHoveredThumbnail = null;
  736. var imgAnchorTags = [];
  737.  
  738. var expandedImgWidth_css = expandedImgWidth == 0 ? "" : expandedImgWidth+"px";
  739. var expandedImgHeight_css = expandedImgHeight == 0 ? "" : expandedImgHeight+"px";
  740.  
  741.  
  742. var heldDownKeys = {};
  743. $("body").on("keydown", "#imagefaqs_settings_popup #hideToggleHotkey_text", function(event){
  744. heldDownKeys[event.which] = event.which;
  745. sessionHideToggleHotkey = cloneKVArray(heldDownKeys);
  746. $(this).val(
  747. keyCodeKVArrayToString(sessionHideToggleHotkey)
  748. );
  749.  
  750. return false;
  751. });
  752.  
  753. $("body").on("keydown", "#imagefaqs_settings_popup #resizeHotkey_text", function(event){
  754. heldDownKeys[event.which] = event.which;
  755. sessionResizeHotkey = cloneKVArray(heldDownKeys);
  756. $(this).val(
  757. keyCodeKVArrayToString(sessionResizeHotkey)
  758. );
  759.  
  760. return false;
  761. });
  762.  
  763.  
  764. $("body").on("keyup", "#imagefaqs_settings_popup .hotkeyInput", function(event){
  765. delete heldDownKeys[event.which];
  766. return false;
  767. });
  768.  
  769. $("body").on("keypress", "#imagefaqs_settings_popup .hotkeyInput", function(event){
  770. event.preventDefault();
  771. });
  772.  
  773.  
  774.  
  775. /*
  776. Toggle between "display" and "hide" images.
  777. */
  778. function toggleImageVisiblity(embeddedImgContainers, via)
  779. {
  780. if (via === "hotkey")
  781. isHideMode = !isHideMode;
  782.  
  783. /*If set images to be hidden...*/
  784. if ((via === "hotkey" && isHideMode) ||
  785. via === "closeAnchor")
  786. {
  787. if (pageType !== "other")
  788. {
  789. embeddedImgContainers.each(function(index, element) {
  790. if ($(this).hasClass("isHidable") && !$(this).hasClass("hidden")) {
  791. hideMedia($(this), false);
  792. }
  793. });
  794.  
  795. if (via === "hotkey")
  796. showNotification("ImageFAQs: All images hidden.");
  797. }
  798. else
  799. {
  800. if (via === "hotkey")
  801. showNotification("ImageFAQs: Images will be hidden.");
  802. }
  803. }
  804. else
  805. {
  806. if (pageType !== "other")
  807. {
  808. embeddedImgContainers.each(function(index, element) {
  809. if ($(this).hasClass("hidden")) {
  810. showMedia($(this), false);
  811. }
  812. });
  813. if (via === "hotkey")
  814. showNotification("ImageFAQs: All images exposed.");
  815. }
  816. else
  817. {
  818. if (via === "hotkey")
  819. showNotification("ImageFAQs: Images will be exposed.");
  820. }
  821. }
  822. settings.isHideMode = isHideMode;
  823. localStorage.setItem("imagefaqs", JSON.stringify(settings));
  824. }
  825.  
  826.  
  827.  
  828.  
  829.  
  830. var nextImageSize = "expanded";
  831. $("body").keydown(function(event){
  832.  
  833. var key;
  834. var numMatchingPressedHotkeys;
  835. var desiredAction = "";
  836. heldDownKeys[event.which] = event.which;
  837.  
  838. /*if backspace, ignore*/
  839. if (heldDownKeys[8] === 8)
  840. {
  841. return;
  842. }
  843.  
  844. /*are every hide mode hotkey pressed?*/
  845. numMatchingPressedHotkeys = 0;
  846. for (key in settings.hideToggleHotkey)
  847. {
  848. if (settings.hideToggleHotkey[key] !== heldDownKeys[key])
  849. {
  850. break;
  851. }
  852. numMatchingPressedHotkeys++;
  853. }
  854. if (numMatchingPressedHotkeys === Object.size(settings.hideToggleHotkey) && numMatchingPressedHotkeys > 0)
  855. {
  856. desiredAction = "toggleHideMode";
  857. }
  858.  
  859. /*is every resize hotkey pressed?*/
  860. if (desiredAction === "")
  861. {
  862. numMatchingPressedHotkeys = 0;
  863. for (key in settings.resizeHotkey)
  864. {
  865. if (settings.resizeHotkey[key] !== heldDownKeys[key])
  866. {
  867. break;
  868. }
  869. numMatchingPressedHotkeys++;
  870. }
  871. if (numMatchingPressedHotkeys === Object.size(settings.resizeHotkey) && numMatchingPressedHotkeys > 0)
  872. {
  873. desiredAction = "toggleImageResize";
  874. }
  875. }
  876. if (desiredAction === "toggleHideMode")
  877. {
  878. toggleImageVisiblity($(".embeddedImgContainer"), "hotkey");
  879. }
  880. else if (desiredAction === "toggleImageResize")
  881. {
  882. if (nextImageSize === "expanded")
  883. {
  884. toggleSizesOfImages($(".embeddedImg"), true);
  885. nextImageSize = "thumbnail";
  886. showNotification("ImageFAQs: Expanded all images.");
  887. }
  888. else
  889. {
  890. toggleSizesOfImages($(".embeddedImg.expandedImg"), false);
  891. nextImageSize = "expanded";
  892. showNotification("ImageFAQs: Shrunk all images.");
  893. }
  894. }
  895. });
  896.  
  897.  
  898.  
  899.  
  900. $("body").keyup(function(event){
  901. delete heldDownKeys[event.which];
  902. });
  903.  
  904.  
  905.  
  906.  
  907.  
  908.  
  909.  
  910. if (blacklist.length === 1 && blacklist[0] === "")
  911. {
  912. blacklist = [];
  913. }
  914. else
  915. {
  916. /*trim white space*/
  917. for (var i = 0; i < blacklist.length; i++)
  918. {
  919. blacklist[i].trim();
  920. }
  921. }
  922.  
  923.  
  924.  
  925.  
  926.  
  927.  
  928.  
  929. function isURLmatchBlacklistedURL(url, blacklistedURL)
  930. {
  931. blacklistedURL = blacklistedURL.trim();
  932. /*escape everything*/
  933. var blacklistedURLregex =
  934. new RegExp( blacklistedURL.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") );
  935.  
  936. if (blacklistedURLregex.exec(url) !== null)
  937. {
  938. return true;
  939. }
  940. else
  941. {
  942. return false;
  943. }
  944. }
  945.  
  946.  
  947. /*
  948. Is the url string in the blacklist?
  949.  
  950. @url :: string of the url to check
  951. @blacklist :: array of blacklisted urls
  952.  
  953. Returns true or false
  954. */
  955. function isURLinBlacklist(url, blacklist)
  956. {
  957. for (var i = 0; i < blacklist.length; i++)
  958. {
  959. if (isURLmatchBlacklistedURL(url, blacklist[i]))
  960. {
  961. return true;
  962. }
  963. }
  964. return false;
  965. }
  966.  
  967.  
  968.  
  969.  
  970. $(window).scroll(function() {
  971. var notificationBoxes = $("body").children("#imagefaqs_notificationBox");
  972. notificationBoxes.each(function(index, element) {
  973. $(this).css({
  974. "top": ($(window).scrollTop() + $(window).height() - $(this).height())+"px",
  975. "left": ($(window).scrollLeft() + $(window).width() - $(this).find("span").width())+"px"
  976. });
  977. });
  978. });
  979.  
  980.  
  981.  
  982.  
  983.  
  984. currentURL = window.location.href;
  985. pageType = currentURL.search(/.*gamefaqs\.com\/boards\/.*\/.*/i); /*gfaqsdep*/
  986. if (currentURL.search(/.*gamefaqs\.com\/boards\/.*\/.*/i) >= 0) /*gfaqsdep*/
  987. {
  988. pageType = "topic";
  989. }
  990. else if (currentURL.search(/.*gamefaqs\.com\/boards\/post/i) >= 0) /*gfaqsdep*/
  991. {
  992. pageType = "postPreview";
  993. }
  994. else if (currentURL.search(/.*gamefaqs\.com\/user[^\/]*$/i) >= 0) /*gfaqsdep*/
  995. {
  996. /*add settings link*/ /*gfaqsdep*/
  997. $("div.body tbody:eq(2)").append("<tr><td colspan='2'><a id='imagefaqs_settings_but' href='#'>ImageFAQs Options</a> - Change thumbnail size, enable signature embedding, and more.</td></tr>");
  998. }
  999. else
  1000. {
  1001. pageType = "other";
  1002. }
  1003.  
  1004.  
  1005.  
  1006.  
  1007. if (pageType === "other")
  1008. {
  1009. return;
  1010. }
  1011.  
  1012.  
  1013.  
  1014. GM_addStyle (GM_getResourceText("jqueryuibaseCSS"));
  1015. GM_addStyle (GM_getResourceText("jqueryuithemeCSS"));
  1016.  
  1017.  
  1018.  
  1019.  
  1020.  
  1021. GM_addStyle (
  1022. ".embeddedImgContainer {" +
  1023. "background: "+imgContainerBackgroundColor+";" +
  1024. "}" +
  1025. ".embeddedImgAnchor {"+
  1026. "display: inline-block;"+
  1027. "}" +
  1028. ".thumbnailImg {"+
  1029. "display: inline-block;"+ /*prevents parent anchor from stretching horizontally*/
  1030. "vertical-align: bottom;"+ /*eliminates small gap between bottom of image and parent div*/
  1031. "}" +
  1032. ".expandedImg {" +
  1033. "display: inline-block;" +
  1034. "vertical-align: bottom;" +
  1035. "}" +
  1036. ".imgMenuButton {" +
  1037. "overflow: hidden;" +
  1038. "position: absolute;" +
  1039. "text-align: center;" +
  1040. "z-index: 90;" +
  1041. "background-color: #99FFCC;" +
  1042. "opacity: 0.5;" +
  1043. "pointer-events: none;" +
  1044. "}" +
  1045. ".imgMenuButton_symbol {" +
  1046. "display: table-cell;" +
  1047. "vertical-align: middle;" +
  1048. "}" +
  1049. ".imgMenuItem {" +
  1050. "display: block;" +
  1051. "}" +
  1052. ".imgMenuItemAnchor {" +
  1053. "display: block;" +
  1054. "}" +
  1055. ".imgMenu {" +
  1056. "background-color: #CCFFFF;" +
  1057. "opacity: 0.9;" +
  1058. "border-style: solid;" +
  1059. "border-width: 1px;" +
  1060. "}" +
  1061. ".ui-widget { " + /*shrink font size in the settings menu*/
  1062. "font-size:96%;" +
  1063. "}" +
  1064. "#imagefaqs_settings_popup input { " +
  1065. "margin-right: 5px;" +
  1066. "}" +
  1067. "#imagefaqs_settings_popup a { " +
  1068. "color: blue;" +
  1069. "}"
  1070. );
  1071.  
  1072.  
  1073.  
  1074.  
  1075.  
  1076. $("body").css("position", "relative");
  1077. var posts = null;
  1078.  
  1079. posts = $("div.msg_body"); /*gfaqsdep*/
  1080.  
  1081.  
  1082.  
  1083.  
  1084. /*for each user post*/
  1085. posts.each(function(index, element) {
  1086.  
  1087. var postHtml;
  1088. var unanchoredImgURLMatches;
  1089. var sigStrIdx;
  1090. var anchorTags;
  1091. var idxAfterAnchorTagInPostHtml = 0;
  1092. postHtml = $(this).html();
  1093. /*if in post preview mode, need to manually parse through the preview message body and
  1094. replace every plain-text image URL in its anchor form*/
  1095. if (pageType === "postPreview")
  1096. {
  1097. postHtml = postHtml.replace(/https?:\/\/[^<>\s]*?\.(?:png|jpg|gif|jpeg|webm|gifv)[^<>\s]*/ig, "<a href='$&'>$&</a>");
  1098. $(this).html(postHtml);
  1099. }
  1100. /*get all anchor tags*/
  1101. anchorTags = $(this).find("a");
  1102.  
  1103. /*filter in anchor tags that refer to images*/
  1104. anchorTags.each(function(index, element) {
  1105. var anchorURL = $(this).attr("href");
  1106. var anchorTagStrIdx = postHtml.indexOf(anchorURL + "</a>", idxAfterAnchorTagInPostHtml);
  1107. idxAfterAnchorTagInPostHtml = anchorTagStrIdx + anchorURL.length + 4;
  1108. if (anchorURL.search(/https?:\/\/[^<>\s]*?\.(?:png|jpg|gif|jpeg|webm|gifv)/i) >= 0)
  1109. {
  1110. /*if anchor is within of sig*/
  1111. if ($(this).parent().hasClass("sig_text")) /*gfaqsdep*/
  1112. {
  1113. if (allowImgInSig)
  1114. $(this).addClass("withinSig");
  1115. else
  1116. return;
  1117. }
  1118. $(this).addClass("imgAnchor");
  1119. imgAnchorTags.push($(this));
  1120. }
  1121. });
  1122. });
  1123.  
  1124.  
  1125.  
  1126.  
  1127.  
  1128. var imgAnchorIdx = 0;
  1129.  
  1130. /*for each valid image URL anchor tag, replace with template div for embedded image*/
  1131. for (var imgAnchor of imgAnchorTags)
  1132. {
  1133. var imgURL = imgAnchor.html();
  1134. var imageType = imgURL.split(".").pop();
  1135. var imgWithinSig_class = imgAnchor.hasClass("withinSig") ? "withinSig" : "";
  1136. var imgIsHidable_class = allowImgInSig && imgAnchor.hasClass("withinSig") && !hideSigsWhenHideMode ? "" : "isHidable";
  1137. var imgInitiallyBlacklisted_class = "";
  1138. var imgSpoilersTagged_class = imgAnchor.closest("s").length > 0 ? "spoilersTagged" : "";
  1139. var imgSize;
  1140. var imgInfoEleStr;
  1141. var postID;
  1142. var isBlacklisted;
  1143. var imgContainerStyle_attr;
  1144. isBlacklisted = isURLinBlacklist(imgURL, blacklist);
  1145. if (isBlacklisted)
  1146. imgInitiallyBlacklisted_class = "initiallyBlacklisted";
  1147. imgContainerStyle_attr = imgContainerStyle;
  1148. if (imgContainerStyle_attr === "sideBySideSig")
  1149. {
  1150. if (imgWithinSig_class === "withinSig")
  1151. imgContainerStyle_attr = "sideBySide";
  1152. else
  1153. imgContainerStyle_attr = "stacked";
  1154. }
  1155. if (imageType === "gifv")
  1156. imgURL = imgURL.replace(/gifv$/i, "webm");
  1157.  
  1158. if (pageType === "topic")
  1159. {
  1160. postID = imgAnchor.closest(".msg_body_box").siblings(".msg_infobox").children("a").attr("name"); /*gfaqsdep*/
  1161. }
  1162. else /*if in post preview mode, need to provide missing message ID*/
  1163. {
  1164. imgAnchor.closest("td").addClass("msg_body"); /*gfaqsdep*/
  1165. imgAnchor.closest(".msg_body").attr("name", 0); /*gfaqsdep*/
  1166. postID = 0;
  1167. }
  1168. var imgURLspan = "";
  1169. var imgResolutionSpan = "";
  1170. var imgFilesizeSpan = "";
  1171. var imgGoogleReverse = "";
  1172. var imgIQDBreverse = "";
  1173. var imgBlacklistToggle = "";
  1174. var imgCloseAll = "";
  1175. var imgClosePost = "";
  1176. var imgExpandPost = "";
  1177. var imgExpandAll = "";
  1178. var imgHideToggle = "";
  1179. var imgHideAllToggles = "";
  1180. if (imgContainerStyle_attr === "stacked")
  1181. {
  1182. if (show_imgURLspan)
  1183. {
  1184. imgURLspan =
  1185. "<span style='margin-right: 5px'>" +
  1186. "<a target='_blank' href="+imgURL+">"+imgURL+"</a>" +
  1187. "</span>";
  1188. }
  1189. if (show_imgResolutionSpan)
  1190. {
  1191. imgResolutionSpan =
  1192. "<span class='imgResolution' style='margin-right: 5px'>" +
  1193. "</span>";
  1194. }
  1195. if (show_imgFilesizeSpan)
  1196. {
  1197. imgFilesizeSpan =
  1198. "<span class='imgFilesize' style='margin-right: 5px'>" +
  1199. "</span>";
  1200. }
  1201. if (show_imgGoogle)
  1202. {
  1203. imgGoogleReverse =
  1204. "<a target='_blank' title='Reverse image search on general images' style='margin-right: 5px' href='https://www.google.com/searchbyimage?image_url="+imgURL+"'>" +
  1205. "google" +
  1206. "</a>";
  1207. }
  1208.  
  1209. if (show_imgIqdb)
  1210. {
  1211. imgIQDBreverse =
  1212. "<a target='_blank' title='Reverse image search on weeb images' style='margin-right: 5px' href='http://iqdb.org/?url="+imgURL+"'>" +
  1213. "iqdb" +
  1214. "</a>";
  1215. }
  1216. if (show_blacklistToggle)
  1217. {
  1218. if (isBlacklisted)
  1219. {
  1220. imgBlacklistToggle =
  1221. "<a class='imgBlacklistToggle' href='#' title='Whitelist image' style='margin-right: 5px'>whitelist</a>";
  1222. }
  1223. else
  1224. {
  1225. imgBlacklistToggle =
  1226. "<a class='imgBlacklistToggle' href='#' title='Blacklist image' style='margin-right: 5px'>blacklist</a>";
  1227. }
  1228. }
  1229. if (show_imgResizeToggles)
  1230. {
  1231. imgCloseAll =
  1232. "<a class='imgCloseAll' href='#' title='Close all images in page' style='margin-right: 5px'>&lt;&lt;</a>";
  1233. imgClosePost =
  1234. "<a class='imgClosePost' href='#' data-postID='"+postID+"' title='Close all images in post' style='margin-right: 5px'>&lt;</a>";
  1235. imgExpandPost =
  1236. "<a class='imgExpandPost' href='#' data-postID='"+postID+"' title='Expand all images in post' style='margin-right: 5px'>&gt;</a>";
  1237. imgExpandAll =
  1238. "<a class='imgExpandAll' href='#' title='Expand all images in page' style='margin-right: 5px'>&gt;&gt;</a>";
  1239. }
  1240.  
  1241. if (show_hideAllToggle)
  1242. {
  1243. imgHideAllToggles =
  1244. "<a class='imgHideAll' href='#' title='Hide all images in page' style='margin-right: 5px'>--</a>" +
  1245. "<a class='imgHidePost' href='#' data-postID='"+postID+"' title='Hide all images in post' style='margin-right: 5px'>-</a>" +
  1246. "<a class='imgShowPost' href='#' data-postID='"+postID+"' title='Show all images in post' style='margin-right: 5px'>+</a>" +
  1247. "<a class='imgShowAll' href='#' title='Show all images in page' style='margin-right: 5px'>++</a>";
  1248. }
  1249. if (show_hideToggle)
  1250. {
  1251. if (isBlacklisted || imgSpoilersTagged_class === "spoilersTagged" || (isHideMode && imgIsHidable_class))
  1252. {
  1253. imgHideToggle =
  1254. "<a class='imgHideToggle' href='#' title='Show image' style='margin-right: 5px'>show</a>";
  1255. }
  1256. else
  1257. {
  1258. imgHideToggle =
  1259. "<a class='imgHideToggle' href='#' title='Hide image' style='margin-right: 5px'>hide</a>";
  1260. }
  1261. }
  1262. }
  1263. var optionalBreakAfterImgHeader;
  1264. if ((!show_imgURLspan && !show_imgResolutionSpan && !show_imgFilesizeSpan && !show_imgGoogle && !show_imgIqdb && !show_blacklistToggle && !show_imgResizeToggles && !show_hideToggle && !show_hideAllToggle)
  1265. ||
  1266. imgContainerStyle_attr === "sideBySide")
  1267. {
  1268. optionalBreakAfterImgHeader = "";
  1269. }
  1270. else
  1271. {
  1272. optionalBreakAfterImgHeader = "<br/>";
  1273. }
  1274. imgAnchor.replaceWith(
  1275. "<div class='embeddedImgContainer "+imgWithinSig_class+" "+imgIsHidable_class+" "+imgInitiallyBlacklisted_class+" "+imgSpoilersTagged_class+"' data-postID='"+postID+"' data-style='"+imgContainerStyle_attr+"'>" +
  1276. imgURLspan +
  1277. imgResolutionSpan +
  1278. imgFilesizeSpan +
  1279. imgGoogleReverse +
  1280. imgIQDBreverse +
  1281. imgBlacklistToggle +
  1282. imgCloseAll +
  1283. imgClosePost +
  1284. imgExpandPost +
  1285. imgExpandAll +
  1286. imgHideAllToggles +
  1287. imgHideToggle +
  1288. optionalBreakAfterImgHeader +
  1289. "<a class='embeddedImgAnchor' href='" + imgURL + "' data-backup-href='" + imgURL + "' data-idx='"+imgAnchorIdx+"'>" +
  1290. "</a>" +
  1291. "</div>"
  1292. );
  1293. var embeddedImgAnchor = $(".embeddedImgAnchor[data-idx='"+imgAnchorIdx+"']");
  1294. var embeddedImgContainer = embeddedImgAnchor.parent();
  1295. imgAnchorIdx++;
  1296.  
  1297. /*keep iterating through the next sibling elements until find an element that's
  1298. not whitespace*/
  1299. var curNextEleJS = embeddedImgContainer[0].nextSibling;
  1300. while (curNextEleJS !== null &&
  1301. ($(curNextEleJS).is("br") || is_ignorable(curNextEleJS)))
  1302. {
  1303. curNextEleJS = curNextEleJS.nextSibling;
  1304. }
  1305. /*now do the same thing, but iterating through the previous siblings*/
  1306. var curPrevEleJS = embeddedImgContainer[0].previousSibling;
  1307. while (curPrevEleJS !== null &&
  1308. is_ignorable(curPrevEleJS))
  1309. {
  1310. curPrevEleJS = curPrevEleJS.previousSibling;
  1311. }
  1312. /*remove the next br elements if next non-whitespace sibling is a going-to-be image*/
  1313. var curNextEle;
  1314. if (curNextEleJS !== null && $(curNextEleJS).hasClass("imgAnchor"))
  1315. {
  1316. curNextEle = embeddedImgContainer.next();
  1317. while (curNextEle.length !== 0 && curNextEle.is("br"))
  1318. {
  1319. if (curNextEle.next().length === 0)
  1320. {
  1321. curNextEle.remove();
  1322. break;
  1323. }
  1324. else
  1325. {
  1326. curNextEle = curNextEle.next();
  1327. curNextEle.prev().remove();
  1328. }
  1329. }
  1330. }
  1331. /*if sig separator after image, remove <br> in between*/
  1332. else if (curNextEleJS !== null && curNextEleJS.nodeType === 3 && curNextEleJS.nodeValue === "---")
  1333. {
  1334. curNextEle = embeddedImgContainer.next();
  1335. if (curNextEle.is("br"))
  1336. curNextEle.remove();
  1337. }
  1338. /*if text after image*/
  1339. else if (curNextEleJS !== null && curNextEleJS.nodeType === 3 && curNextEleJS.nodeValue !== "---")
  1340. {
  1341. curNextEle = embeddedImgContainer.next();
  1342. if (curNextEle.is("br"))
  1343. curNextEle.remove();
  1344. }
  1345. if (imgContainerStyle_attr === "sideBySide")
  1346. {
  1347. /*if the next non-whitespace sibling not going to be an image, create a newline to
  1348. set the cursor below this image*/
  1349. if (curNextEleJS !== null && !$(curNextEleJS).hasClass("imgAnchor"))
  1350. {
  1351. $(curNextEleJS).before(
  1352. "<div style='display: block;'></div>"
  1353. );
  1354. }
  1355. /*do same with previous non-whitespace sibling*/
  1356. if (curPrevEleJS !== null && !$(curPrevEleJS).hasClass("embeddedImgContainer"))
  1357. {
  1358. $(curPrevEleJS).after(
  1359. "<div style='display: block;'></div>"
  1360. );
  1361. }
  1362. /*set container to float*/
  1363. embeddedImgContainer.css("display", "inline-block");
  1364. embeddedImgContainer.css("vertical-align", "top");
  1365. embeddedImgContainer.css("margin-right", "5px");
  1366. embeddedImgContainer.css("margin-bottom", "5px");
  1367. }
  1368. else
  1369. {
  1370. embeddedImgContainer.css("margin-bottom", "10px");
  1371. }
  1372. }
  1373.  
  1374.  
  1375.  
  1376. function getFileSize(url, span)
  1377. {
  1378. GM_xmlhttpRequest({
  1379. method: "GET",
  1380. url: url,
  1381. onload: function(response) {
  1382. var contentLengthStr = response.responseHeaders.match(/Content-Length: \d+/)[0];
  1383. var fileSizeBytes = parseInt(contentLengthStr.substring(16));
  1384. var fileSizeDisplayStr;
  1385. if (fileSizeBytes < 1000000) /*if less than 1.0MB*/
  1386. {
  1387. fileSizeDisplayStr = Math.round(fileSizeBytes / 1000) + "KB";
  1388. }
  1389. else
  1390. {
  1391. fileSizeDisplayStr = (fileSizeBytes / 1000000).toFixed(2) + "MB";
  1392. }
  1393.  
  1394. span.html("("+fileSizeDisplayStr+")");
  1395. }
  1396. });
  1397. }
  1398.  
  1399.  
  1400.  
  1401. function showMedia(mediaContainer, isToWhitelist)
  1402. {
  1403. var mediaAnchor = mediaContainer.children(".embeddedImgAnchor");
  1404. var mediaURL = mediaAnchor.attr("href");
  1405. var mediaContainerStyle = mediaContainer.attr("data-style");
  1406. if (!mediaContainer.hasClass("loaded"))
  1407. loadMedia(mediaContainer);
  1408. mediaContainer.removeClass("hidden");
  1409. /*remove url from blacklist*/
  1410. var urlIdx = blacklist.indexOf(mediaURL);
  1411. if (urlIdx > -1)
  1412. {
  1413. blacklist.splice(urlIdx, 1);
  1414. }
  1415. if (isToWhitelist)
  1416. {
  1417. mediaAnchor.removeClass("blacklisted");
  1418. if (mediaContainerStyle === "stacked" && show_blacklistToggle)
  1419. {
  1420. mediaAnchor.siblings(".imgBlacklistToggle").html("blacklist");
  1421. mediaAnchor.siblings(".imgBlacklistToggle").attr("title", "Blacklist image");
  1422. }
  1423. }
  1424. mediaAnchor.show();
  1425. if (mediaContainerStyle === "sideBySide")
  1426. {
  1427. mediaAnchor.siblings("a.imgMenuItem").remove();
  1428. mediaAnchor.siblings("div.imgMenuItem").remove();
  1429. mediaAnchor.attr("style", "");
  1430. mediaAnchor.parent().css("max-width", "");
  1431. }
  1432. else
  1433. {
  1434. if (show_hideToggle)
  1435. {
  1436. var imgHideToggle = mediaAnchor.siblings(".imgHideToggle");
  1437. imgHideToggle.html("hide");
  1438. imgHideToggle.attr("title", "Hide image");
  1439. }
  1440. }
  1441. settings.blacklistStr = blacklist.join("\n");
  1442. localStorage.setItem("imagefaqs", JSON.stringify(settings));
  1443. }
  1444.  
  1445.  
  1446.  
  1447. function hideMedia(mediaContainer, isToBlacklist)
  1448. {
  1449. var mediaAnchor = mediaContainer.children(".embeddedImgAnchor");
  1450. var media = mediaAnchor.children(".embeddedImg");
  1451. var mediaURL = mediaAnchor.attr("href");
  1452. var postID = mediaContainer.attr("data-postID");
  1453. var mediaContainerStyle = mediaContainer.attr("data-style");
  1454. var isSig = mediaContainer.hasClass("withinSig");
  1455. var mediaThumbnailImgWidth = isSig ? thumbnailImgWidthSig : thumbnailImgWidth;
  1456. var mediaThumbnailImgHeight = isSig ? thumbnailImgHeightSig : thumbnailImgHeight;
  1457. var mediaThumbnailImgWidth_css = mediaThumbnailImgWidth == 0 ? "" : mediaThumbnailImgWidth+"px";
  1458. var mediaThumbnailImgHeight_css = mediaThumbnailImgHeight == 0 ? "" : mediaThumbnailImgHeight+"px";
  1459. /*shrink image*/
  1460. if (media.hasClass("expandedImg"))
  1461. toggleSizesOfImages(media, false);
  1462. mediaContainer.addClass("hidden");
  1463. mediaAnchor.hide();
  1464. if (isToBlacklist)
  1465. {
  1466. mediaAnchor.addClass("blacklisted");
  1467. if (blacklist.indexOf(mediaURL) === -1)
  1468. blacklist.push(mediaURL);
  1469. }
  1470. if (mediaContainerStyle === "sideBySide")
  1471. {
  1472. mediaContainer.css("max-width", mediaThumbnailImgWidth_css);
  1473. mediaContainer.append("<a target='_blank' class='imgMenuItem' href="+mediaURL+">"+mediaURL+"</a>");
  1474. if (mediaAnchor.hasClass("blacklisted"))
  1475. {
  1476. if (show_blacklistToggle)
  1477. {
  1478. mediaContainer.append(
  1479. "<div class='imgMenuItem'><a class='imgBlacklistToggle' href='#' title='Whitelist image'>whitelist</a></div>"
  1480. );
  1481. }
  1482. }
  1483. if (show_hideAllToggle)
  1484. {
  1485. mediaContainer.append(
  1486. "<div class='imgMenuItem'>" +
  1487. "<a class='imgHideAll' href='#' title='Hide all images in page' style='margin-right: 5px'>--</a>" +
  1488. "<a class='imgHidePost' href='#' data-postID='"+postID+"' title='Hide all images in post' style='margin-right: 5px'>-</a>" +
  1489. "<a class='imgShowPost' href='#' data-postID='"+postID+"' title='Show all images in post' style='margin-right: 5px'>+</a>" +
  1490. "<a class='imgShowAll' href='#' title='Show all images in page' style='margin-right: 5px'>++</a>" +
  1491. "</div>"
  1492. );
  1493. }
  1494. if (show_hideToggle)
  1495. {
  1496. mediaContainer.append(
  1497. "<div class='imgMenuItem'><a class='imgHideToggle' href='#' title='Show image'>show</a></div>"
  1498. );
  1499. }
  1500.  
  1501. hideImgMenu();
  1502. }
  1503. else
  1504. {
  1505. if (show_blacklistToggle && isToBlacklist)
  1506. {
  1507. mediaAnchor.siblings(".imgBlacklistToggle").html("whitelist");
  1508. mediaAnchor.siblings(".imgBlacklistToggle").attr("title", "Whitelist image");
  1509. }
  1510. }
  1511. if (mediaContainerStyle === "sideBySide")
  1512. {
  1513. }
  1514. else
  1515. {
  1516. if (show_hideToggle)
  1517. {
  1518. var imgHideToggle = mediaAnchor.siblings(".imgHideToggle");
  1519. imgHideToggle.html("show");
  1520. imgHideToggle.attr("title", "Show image");
  1521. }
  1522. }
  1523. settings.blacklistStr = blacklist.join("\n");
  1524. localStorage.setItem("imagefaqs", JSON.stringify(settings));
  1525. }
  1526.  
  1527.  
  1528.  
  1529.  
  1530.  
  1531. function loadMedia(mediaContainer)
  1532. {
  1533. var mediaAnchor = mediaContainer.children(".embeddedImgAnchor");
  1534. var mediaResolutionSpan = mediaContainer.children(".imgResolution");
  1535. var imgFilesize = mediaContainer.children(".imgFilesize");
  1536. var mediaURL = mediaAnchor.attr("href");
  1537. var postID = mediaContainer.attr("data-postID");
  1538. var mediaIdx = mediaContainer.attr("data-idx");
  1539. var isSig = mediaContainer.hasClass("withinSig");
  1540. var mediaThumbnailImgWidth = isSig ? thumbnailImgWidthSig : thumbnailImgWidth;
  1541. var mediaThumbnailImgHeight = isSig ? thumbnailImgHeightSig : thumbnailImgHeight;
  1542. var mediaThumbnailImgWidth_css = mediaThumbnailImgWidth == 0 ? "" : mediaThumbnailImgWidth+"px";
  1543. var mediaThumbnailImgHeight_css = mediaThumbnailImgHeight == 0 ? "" : mediaThumbnailImgHeight+"px";
  1544. mediaContainer.addClass("loaded");
  1545. if (imgFilesize.length > 0)
  1546. getFileSize(mediaURL, imgFilesize);
  1547. var mediaType = mediaURL.split(".").pop();
  1548. if (mediaType.search(/(webm)/i) == -1) /*if image, and not a video*/
  1549. {
  1550. var image = new Image();
  1551. /*on event that image cannot be loaded, post the error*/
  1552. image.onerror = function() {
  1553. mediaAnchor.html("Image cannot be loaded.");
  1554. };
  1555. /*on event that image loaded successfully in memory*/
  1556. $(image).load(function() {
  1557. /*write down image's natural dimensions*/
  1558. if (mediaResolutionSpan.length > 0)
  1559. {
  1560. mediaResolutionSpan.html(
  1561. "(" + image.naturalWidth + "x" + image.naturalHeight + ")"
  1562. );
  1563. }
  1564. });
  1565. image.src = mediaURL;
  1566. $(image).addClass("embeddedImg thumbnailImg");
  1567. $(image).attr("data-postID", postID);
  1568. $(image).attr("alt", "");
  1569. $(image).attr("display", "none");
  1570. mediaAnchor.html(image);
  1571. $(image).css("max-width", getOptimalImgMaxWidth($(image), mediaThumbnailImgWidth) + "px");
  1572. $(image).css("max-height", mediaThumbnailImgHeight_css);
  1573. $(image).attr("display", "");
  1574. }
  1575. else
  1576. {
  1577. var htmlVideoSrcTag =
  1578. "<video id='embeddedImg_"+mediaIdx+"' data-postID='"+postID+"' " +
  1579. "class='embeddedImg webmExt thumbnailImg' " +
  1580. "style=''>" +
  1581. "<source src='" + mediaURL + "' type='video/webm'>" +
  1582. "</video>";
  1583. mediaAnchor.html(htmlVideoSrcTag);
  1584. var video = $("#embeddedImg_"+mediaIdx);
  1585.  
  1586. video.css("max-width", getOptimalImgMaxWidth(video, mediaThumbnailImgWidth) + "px");
  1587. video.css("max-height", mediaThumbnailImgHeight_css);
  1588. video.attr("display", "");
  1589.  
  1590. /*when video's metadata has been loaded, record its natural width and resolution*/
  1591. $("#embeddedImg_"+mediaIdx+"")[0].onloadedmetadata = function() {
  1592. var video = this;
  1593. if (mediaResolutionSpan.length > 0)
  1594. {
  1595. mediaResolutionSpan.html(
  1596. "(" + video.videoWidth + "x" + video.videoHeight + ")"
  1597. );
  1598. }
  1599. };
  1600. $("#embeddedImg_"+mediaIdx+"")[0].addEventListener('error', function(event) {
  1601. mediaAnchor.html("Video cannot be loaded.");
  1602. }, true);
  1603. }
  1604. if (mediaContainer.hasClass("withinSig"))
  1605. mediaContainer.find(".embeddedImg").addClass("withinSig");
  1606. }
  1607.  
  1608.  
  1609. /*for each template div, insert an embedded image*/
  1610. $(".embeddedImgContainer").each(function(index, element) {
  1611. var curEmbeddedImgContainer = $(this);
  1612. curEmbeddedImgContainer.attr("data-idx", index);
  1613. if (isHideMode)
  1614. {
  1615. if (curEmbeddedImgContainer.hasClass("isHidable"))
  1616. hideMedia(curEmbeddedImgContainer, false);
  1617. else
  1618. loadMedia(curEmbeddedImgContainer, false);
  1619. }
  1620. else
  1621. {
  1622. var isBlacklisted = curEmbeddedImgContainer.hasClass("initiallyBlacklisted");
  1623. var isSpoilersTagged = curEmbeddedImgContainer.hasClass("spoilersTagged");
  1624. if (isBlacklisted)
  1625. hideMedia(curEmbeddedImgContainer, true);
  1626. else if (isSpoilersTagged)
  1627. hideMedia(curEmbeddedImgContainer, false);
  1628. else
  1629. loadMedia(curEmbeddedImgContainer, false);
  1630. }
  1631. });
  1632.  
  1633.  
  1634. /*
  1635. Get the natural width of an embedded image.
  1636.  
  1637. @image :: jQuery object with the class "embeddedImg"
  1638. */
  1639. function getNatWidthOfEmbeddedImg(image)
  1640. {
  1641. if (image.hasClass("webmExt"))
  1642. {
  1643. return image[0].videoWidth;
  1644. }
  1645. else
  1646. {
  1647. return image[0].naturalWidth;
  1648. }
  1649. }
  1650.  
  1651.  
  1652.  
  1653. /*
  1654. Get the natural width of an embedded image.
  1655.  
  1656. @image :: jQuery object with the class "embeddedImg"
  1657. */
  1658. function getNatHeightOfEmbeddedImg(image)
  1659. {
  1660. if (image.hasClass("webmExt"))
  1661. {
  1662. return image[0].videoHeight;
  1663. }
  1664. else
  1665. {
  1666. return image[0].naturalHeight;
  1667. }
  1668. }
  1669.  
  1670.  
  1671.  
  1672.  
  1673.  
  1674. $("body").append(
  1675. "<div class='imgMenuButton' style='display: none'>" +
  1676. "<div class='imgMenuButton_symbol'>" +
  1677. "+" +
  1678. "</div>" +
  1679. "</div>"
  1680. );
  1681. var imgMenuButton = $("body div.imgMenuButton");
  1682.  
  1683.  
  1684. /*
  1685. Show a transparent button in the top-right corner of a thumbnail image.
  1686.  
  1687. @param thumbnail :: embedded thumbnail image
  1688. @param isShow :: true if the button should appear
  1689. */
  1690. function showImgMenuButton(thumbnail, isShow)
  1691. {
  1692. if (!show_imgURLspan && !show_imgResolutionSpan && !show_imgFilesizeSpan && !show_imgGoogle && !show_imgIqdb &&
  1693. !show_blacklistToggle && !show_imgResizeToggles)
  1694. {
  1695. return;
  1696. }
  1697.  
  1698. if (isShow)
  1699. {
  1700. if (imgMenu !== null &&
  1701. thumbnail.parent().attr("data-idx") === imgMenu.attr("data-idx"))
  1702. {
  1703. imgMenuButton.children().html("-");
  1704. }
  1705. else
  1706. {
  1707. imgMenuButton.children().html("+");
  1708. }
  1709. imgMenuButton.css("display", "table");
  1710. imgMenuButton.css("left", (thumbnail.offset().left + thumbnail.width() - 18) + "px");
  1711. imgMenuButton.css("top", thumbnail.offset().top - 1 + "px");
  1712. imgMenuButton.css("width", imgMenuButton.height());
  1713. }
  1714. else
  1715. {
  1716. imgMenuButton.css("display", "none");
  1717. }
  1718. }
  1719.  
  1720. function isHoverOverImgMenuButton(clickEvent)
  1721. {
  1722. if (!show_imgURLspan && !show_imgResolutionSpan && !show_imgFilesizeSpan && !show_imgGoogle && !show_imgIqdb &&
  1723. !show_blacklistToggle && !show_imgResizeToggles)
  1724. {
  1725. return false;
  1726. }
  1727. var isCursorInButton =
  1728. imgMenuButton.css("display") === "table" &&
  1729. clickEvent.pageX > imgMenuButton.offset().left &&
  1730. clickEvent.pageX < imgMenuButton.offset().left + imgMenuButton.width() &&
  1731. clickEvent.pageY > imgMenuButton.offset().top &&
  1732. clickEvent.pageY < imgMenuButton.offset().top + imgMenuButton.height();
  1733. return isCursorInButton;
  1734. }
  1735.  
  1736.  
  1737.  
  1738.  
  1739.  
  1740.  
  1741.  
  1742. var imgMenu = null;
  1743. function showImgMenu(image)
  1744. {
  1745. var imgURL = image.parent().attr("data-backup-href");
  1746. var imgURL_menuItem = "";
  1747. var imgResolution_span = "";
  1748. var imgFilesize_span = "";
  1749. var imgResolutionAndFilesize_menuItem = "";
  1750. var imgGoogleReverse_menuItem = "";
  1751. var imgIQDBreverse_menuItem = "";
  1752. var imgBlacklistToggle_menuItem = "";
  1753. var imgResizeToggles_menuItem = "";
  1754. var imgHideToggle_menuItem = "";
  1755. var imgHideAllToggle_menuItem = "";
  1756. var postID = image.attr("data-postID");
  1757. if (show_imgURLspan)
  1758. {
  1759. imgURL_menuItem =
  1760. "<div class='imgMenuItem'><span>" +
  1761. "<a target='_blank' class='imgMenuItemAnchor_url' href="+imgURL+">"+imgURL+"</a>" +
  1762. "</span></div>";
  1763. }
  1764. if (show_imgResolutionSpan)
  1765. {
  1766. imgResolution_span =
  1767. "<span class='imgResolution' style='margin-right: 5px'>" +
  1768. "</span>";
  1769. }
  1770. if (show_imgFilesizeSpan)
  1771. {
  1772. imgFilesize_span =
  1773. "<span class='imgFilesize'>" +
  1774. "</span>";
  1775. }
  1776. imgResolutionAndFilesize_menuItem = imgResolution_span + imgFilesize_span;
  1777. if (imgResolutionAndFilesize_menuItem !== "")
  1778. {
  1779. imgResolutionAndFilesize_menuItem =
  1780. "<div class='imgMenuItem'>" +
  1781. imgResolutionAndFilesize_menuItem +
  1782. "</div>";
  1783. }
  1784. if (show_imgGoogle)
  1785. {
  1786. imgGoogleReverse_menuItem =
  1787. "<div class='imgMenuItem'><a target='_blank' class='imgMenuItemAnchor_google' title='Reverse image search on general images' href='https://www.google.com/searchbyimage?image_url="+imgURL+"'>" +
  1788. "google" +
  1789. "</a></div>";
  1790. }
  1791.  
  1792. if (show_imgIqdb)
  1793. {
  1794. imgIQDBreverse_menuItem =
  1795. "<div class='imgMenuItem'><a target='_blank' class='imgMenuItemAnchor_iqdb' title='Reverse image search on weeb images' href='http://iqdb.org/?url="+imgURL+"'>" +
  1796. "iqdb" +
  1797. "</a></div>";
  1798. }
  1799. if (show_blacklistToggle)
  1800. {
  1801. if (isBlacklisted)
  1802. {
  1803. imgBlacklistToggle_menuItem =
  1804. "<div class='imgMenuItem'><a class='imgBlacklistToggle' href='#' title='Whitelist image'>whitelist</a></div>";
  1805. }
  1806. else
  1807. {
  1808. imgBlacklistToggle_menuItem =
  1809. "<div class='imgMenuItem'><a class='imgBlacklistToggle' href='#' title='Blacklist image'>blacklist</a></div>";
  1810. }
  1811. }
  1812. if (show_imgResizeToggles)
  1813. {
  1814. imgResizeToggles_menuItem =
  1815. "<div class='imgMenuItem'>" +
  1816. "<a class='imgCloseAll' href='#' title='Close all images in page'>&lt;&lt;&nbsp;</a>" +
  1817. "<a class='imgClosePost' href='#' data-postID='"+postID+"' title='Close all images in post'>&lt;&nbsp;</a>" +
  1818. "<a class='imgExpandPost' href='#' data-postID='"+postID+"' title='Expand all images in post'>&gt;&nbsp;</a>" +
  1819. "<a class='imgExpandAll' href='#' title='Expand all images in page'>&gt;&gt;</a>" +
  1820. "</div>";
  1821. }
  1822. if (show_hideAllToggle)
  1823. {
  1824. imgHideAllToggle_menuItem =
  1825. "<div class='imgMenuItem'>" +
  1826. "<a class='imgHideAll' href='#' title='Hide all images in page' style='margin-right: 5px'>--</a>" +
  1827. "<a class='imgHidePost' href='#' data-postID='"+postID+"' title='Hide all images in post' style='margin-right: 5px'>-</a>" +
  1828. "<a class='imgShowPost' href='#' data-postID='"+postID+"' title='Show all images in post' style='margin-right: 5px'>+</a>" +
  1829. "<a class='imgShowAll' href='#' title='Show all images in page' style='margin-right: 5px'>++</a>" +
  1830. "</div>";
  1831. }
  1832. if (show_hideToggle)
  1833. {
  1834. imgHideToggle_menuItem =
  1835. "<div class='imgMenuItem'><a class='imgHideToggle' href='#' title='Hide image'>hide</a></div>";
  1836. }
  1837. if (imgMenu !== null)
  1838. imgMenu.remove();
  1839. $("body").append(
  1840. "<div class='imgMenu' data-idx='"+image.parent().attr("data-idx")+"' style='display: none; position: absolute; z-index: 90;'>" +
  1841. imgURL_menuItem +
  1842. imgResolutionAndFilesize_menuItem +
  1843. imgGoogleReverse_menuItem +
  1844. imgIQDBreverse_menuItem +
  1845. imgBlacklistToggle_menuItem +
  1846. imgResizeToggles_menuItem +
  1847. imgHideAllToggle_menuItem +
  1848. imgHideToggle_menuItem +
  1849. "</div>"
  1850. );
  1851. imgMenu = $("body > .imgMenu");
  1852. var imgFilesizeSpan = imgMenu.find(".imgFilesize");
  1853. var imgResolutionSpan = imgMenu.find(".imgResolution");
  1854. getFileSize(imgURL, imgFilesizeSpan);
  1855.  
  1856. /*if plain image (i.e. not a webm video)*/
  1857. if (! image.hasClass("webmExt"))
  1858. {
  1859. image.load(function() {
  1860. if (imgResolutionSpan.length > 0)
  1861. {
  1862. imgResolutionSpan.html(
  1863. "(" + image[0].naturalWidth + "x" + image[0].naturalHeight + ")"
  1864. );
  1865. }
  1866. });
  1867. /*if image already loaded*/
  1868. if (image[0].naturalWidth !== 0)
  1869. {
  1870. if (imgResolutionSpan.length > 0)
  1871. {
  1872. imgResolutionSpan.html(
  1873. "(" + image[0].naturalWidth + "x" + image[0].naturalHeight + ")"
  1874. );
  1875. }
  1876. }
  1877. }
  1878. else /*if webm*/
  1879. {
  1880. /*when video's metadata has been loaded, record its natural width and resolution*/
  1881. image[0].onloadedmetadata = function() {
  1882. var video = this;
  1883. if (imgResolutionSpan.length > 0)
  1884. {
  1885. imgResolutionSpan.html(
  1886. "(" + video.videoWidth + "x" + video.videoHeight + ")"
  1887. );
  1888. }
  1889. };
  1890. if (image[0].videoWidth !== 0)
  1891. {
  1892. imgResolutionSpan.html(
  1893. "(" + image[0].videoWidth + "x" + image[0].videoHeight + ")"
  1894. );
  1895. }
  1896. }
  1897. var img_rightOffset = image.offset().left + image.width();
  1898. var imgMenu_rightOffset = img_rightOffset + imgMenu.width();
  1899. /*if imgMenu right offset exceeds beyond window's right offset*/
  1900. if (imgMenu_rightOffset > $(window).scrollLeft() + $(window).width())
  1901. imgMenu.css("left", ($(window).scrollLeft() + $(window).width() - imgMenu.width()) + "px");
  1902. else
  1903. imgMenu.css("left", img_rightOffset + "px");
  1904. imgMenu.css("top", image.offset().top + "px");
  1905. imgMenu.css("display", "inline");
  1906. imgMenuButton.children().html("-");
  1907. }
  1908.  
  1909. function hideImgMenu()
  1910. {
  1911. if (imgMenu !== undefined && imgMenu !== null)
  1912. {
  1913. imgMenu.remove();
  1914. imgMenu = null;
  1915. }
  1916. }
  1917.  
  1918. function getImageAnchorOfImgMenu()
  1919. {
  1920. var imgIdx = $("body > .imgMenu").attr("data-idx");
  1921. return $(".embeddedImgAnchor[data-idx='"+imgIdx+"']");
  1922. }
  1923.  
  1924. function isHovered(jQueryObj)
  1925. {
  1926. return !!$(jQueryObj).filter(function() { return $(this).is(":hover"); }).length;
  1927. }
  1928.  
  1929.  
  1930.  
  1931. $(document).on("click", function(event) {
  1932. if (imgMenu !== null &&
  1933. !isHovered(imgMenu) ||
  1934. isHovered($(".imgMenuItemAnchor_url")) ||
  1935. isHovered($(".imgMenuItemAnchor_google")) ||
  1936. isHovered($(".imgMenuItemAnchor_iqdb")) ||
  1937. isHovered($(".imgBlacklistToggle")) ||
  1938. isHovered($(".imgCloseAll")) ||
  1939. isHovered($(".imgClosePost")) ||
  1940. isHovered($(".imgExpandPost"))||
  1941. isHovered($(".imgExpandAll")) ||
  1942. isHovered($(".imgHideAll")) ||
  1943. isHovered($(".imgHidePost")) ||
  1944. isHovered($(".imgShowPost"))||
  1945. isHovered($(".imgShowAll")) ||
  1946. isHovered($(".imgHideToggle"))
  1947. )
  1948. {
  1949. hideImgMenu();
  1950. }
  1951. });
  1952.  
  1953.  
  1954.  
  1955. function handleFloatingImage(event)
  1956. {
  1957. if (!enable_floatingImg)
  1958. return;
  1959. var floatingImgLeft;
  1960. var floatingImgTop;
  1961. var floatingImgWidth;
  1962. var floatingImgHeight;
  1963. var floatingImgStyleStr;
  1964. /*if user is hovering over thumbnail, prepare floating image size and position*/
  1965. if (currentHoveredThumbnail !== null)
  1966. {
  1967. floatingImgWidth = parseInt(getNatWidthOfEmbeddedImg(currentHoveredThumbnail));
  1968.  
  1969. floatingImgLeft = event.pageX + floatingImgRightOffset;
  1970. /*if right of image exceeds beyond right of window, restrict max width*/
  1971. if (floatingImgLeft + floatingImgWidth > $(window).scrollLeft() + $(window).width() - floatingImgBorder)
  1972. {
  1973. floatingImgWidth = $(window).scrollLeft() + $(window).width() - floatingImgBorder - floatingImgLeft;
  1974. }
  1975. if (floatingImgWidth < 0)
  1976. floatingImgWidth = 0;
  1977. floatingImgHeight = Math.round(getNatHeightOfEmbeddedImg(currentHoveredThumbnail) * (floatingImgWidth / getNatWidthOfEmbeddedImg(currentHoveredThumbnail)));
  1978. floatingImgTop = event.pageY - (floatingImgHeight / 2);
  1979. /*if bottom of image exceeds beyond the window, shift top upwards*/
  1980. if (floatingImgTop + floatingImgHeight > $(window).scrollTop() + $(window).height() - floatingImgBorder)
  1981. {
  1982. floatingImgTop = $(window).scrollTop() + $(window).height() - floatingImgBorder - floatingImgHeight;
  1983. }
  1984. /*if top of image expands beyond top of window, lower top of image*/
  1985. if (floatingImgTop < $(window).scrollTop() + floatingImgBorder)
  1986. {
  1987. floatingImgTop = $(window).scrollTop() + floatingImgBorder;
  1988. }
  1989. /*if bottom of image exceeds beyond the window, restrict max height*/
  1990. if (floatingImgTop + floatingImgHeight > $(window).scrollTop() + $(window).height() - floatingImgBorder)
  1991. {
  1992. floatingImgHeight = $(window).scrollTop() + $(window).height() - floatingImgBorder - floatingImgTop;
  1993. }
  1994. if (curFloatingImg !== null &&
  1995. curFloatingImg.attr("data-idx") !== currentHoveredThumbnail.parent().attr("data-idx"))
  1996. {
  1997. curFloatingImg.attr("data-href", "");
  1998. if (curFloatingImg.prop("tagName") === "video")
  1999. curFloatingImg.children("source").attr("src", "");
  2000. else
  2001. curFloatingImg.attr("src", "");
  2002. }
  2003. /*if floating image doesn't exist or doesn't have an image yet...*/
  2004. if (curFloatingImg === null || curFloatingImg.attr("data-href") === "")
  2005. {
  2006. var floatingImgStyleStr =
  2007. "position: absolute;" +
  2008. "left: " + floatingImgLeft + "px;" +
  2009. "top: " + floatingImgTop + "px;" +
  2010. "max-width: " + floatingImgWidth + "px;" +
  2011. "max-height: " + floatingImgHeight + "px;" +
  2012. "z-index: 100;";
  2013. var imgIdx = currentHoveredThumbnail.parent().attr("data-idx");
  2014. var imgContainerStyle_this = currentHoveredThumbnail.closest(".embeddedImgContainer").attr("data-style");
  2015. /*if webm video*/
  2016. if (currentHoveredThumbnail.hasClass("webmExt"))
  2017. {
  2018. srcURL = currentHoveredThumbnail.children("source").attr("src");
  2019. floatingImgSrc =
  2020. "<video id='floatingImg' data-idx='"+imgIdx+"' data-href='"+srcURL+"' style='" + floatingImgStyleStr + "'>" +
  2021. "<source src='"+srcURL+"' type='video/webm'>" +
  2022. "</video>";
  2023. }
  2024. else
  2025. {
  2026. srcURL = currentHoveredThumbnail.attr("src");
  2027. floatingImgSrc =
  2028. "<img id='floatingImg' data-idx='"+imgIdx+"' data-href='"+srcURL+"' style='" + floatingImgStyleStr + "' src='"+srcURL+"'>";
  2029. }
  2030. /*create the floating image element if haven't so*/
  2031. if (curFloatingImg === null)
  2032. {
  2033. $("body").append(
  2034. floatingImgSrc
  2035. );
  2036. curFloatingImg = $("body").children("#floatingImg");
  2037. }
  2038. else
  2039. {
  2040. curFloatingImg.attr("data-href", srcURL);
  2041. curFloatingImg.attr("data-idx", imgIdx);
  2042. curFloatingImg.attr("style", floatingImgStyleStr);
  2043. if (curFloatingImg.prop("tagName") === "video")
  2044. curFloatingImg.children("source").attr("src", srcURL);
  2045. else
  2046. curFloatingImg.attr("src", srcURL);
  2047. }
  2048.  
  2049. /*if webm video*/
  2050. if (currentHoveredThumbnail.hasClass("webmExt"))
  2051. {
  2052. var video = curFloatingImg;
  2053.  
  2054. video.attr("loop", "");
  2055. video[0].play();
  2056. }
  2057. if (imgContainerStyle_this === "sideBySide")
  2058. showImgMenuButton(currentHoveredThumbnail, true);
  2059. }
  2060. else /*if floating image already exists, update its size and position*/
  2061. {
  2062. $("body").children("#floatingImg").css({
  2063. "left": floatingImgLeft + "px",
  2064. "top": floatingImgTop + "px",
  2065. "max-width": floatingImgWidth + "px",
  2066. "max-height": floatingImgHeight + "px",
  2067. });
  2068. }
  2069. }
  2070. /*if user is not hovering over thumbnail and floating image still exists*/
  2071. else if (currentHoveredThumbnail === null && curFloatingImg !== null)
  2072. {
  2073. showImgMenuButton(null, false);
  2074. curFloatingImg.remove();
  2075. curFloatingImg = null;
  2076. }
  2077. }
  2078.  
  2079.  
  2080.  
  2081. var curFloatingImg = null;
  2082. /*if cursor is hovering inside a thumbnail image, display expanded image as floating div
  2083. Also show a transparent button to expand the image menu (side-by-side image view only)
  2084. */
  2085. $(document).on("mousemove", function(event) {
  2086. handleFloatingImage(event);
  2087. });
  2088.  
  2089.  
  2090.  
  2091.  
  2092. /*if mouse hovers inside the image, change cursor to pointer*/
  2093. $(document).on("mouseover", ".embeddedImg", function(event){
  2094. $("html").css("cursor", "pointer");
  2095. if (! $(this).hasClass("expandedImg"))
  2096. {
  2097. currentHoveredThumbnail = $(event.target);
  2098. }
  2099. });
  2100.  
  2101. /*if mouse hovers outside the image, restore cursor to default graphic*/
  2102. $(document).on("mouseout", ".embeddedImg", function(){
  2103. $("html").css("cursor", "default");
  2104. currentHoveredThumbnail = null;
  2105. });
  2106.  
  2107.  
  2108.  
  2109. /*if clicked on the image URL anchor that's surrounding the embedded image, prevent default
  2110. behaviour of anchor, unless it's a middle click*/
  2111. $("body").on("click", ".embeddedImgAnchor", function(event){
  2112. /*left-click*/
  2113. if (event.which === 1)
  2114. {
  2115. }
  2116. else
  2117. {
  2118. $(this).attr("href", $(this).attr("data-backup-href"));
  2119. }
  2120. });
  2121.  
  2122. $("body").on("mousedown", ".embeddedImgAnchor", function(event){
  2123. /*left-click*/
  2124. if (event.which === 1)
  2125. {
  2126. event.preventDefault();
  2127. }
  2128. else
  2129. {
  2130. $(this).attr("href", $(this).attr("data-backup-href"));
  2131. }
  2132. });
  2133.  
  2134. /* jshint -W107 */
  2135. /*toggle image size on left-click*/
  2136. $("body").on("click", ".embeddedImg", function(event){
  2137. /*left-click*/
  2138. if (event.which === 1)
  2139. {
  2140. if (isHoverOverImgMenuButton(event) && imgMenu === null)
  2141. {
  2142. showImgMenu($(this));
  2143. return false;
  2144. }
  2145. else if (isHoverOverImgMenuButton(event) && imgMenu !== null)
  2146. {
  2147. /*if referring to same thumbnail*/
  2148. if (imgMenu.attr("data-idx") === $(this).parent().attr("data-idx"))
  2149. {
  2150. hideImgMenu();
  2151. }
  2152. else
  2153. {
  2154. showImgMenu($(this));
  2155. }
  2156. showImgMenuButton($(this), true);
  2157. return false;
  2158. }
  2159. else if (imgMenu !== null)
  2160. {
  2161. hideImgMenu();
  2162. }
  2163.  
  2164. showImgMenuButton($(this), false);
  2165.  
  2166. var mouseRelativeY = event.pageY - $(this).offset().top;
  2167. /*if expanded webm file, don't shrink to thumbnail if clicked on its controls*/
  2168. if ($(this).hasClass("webmExt") && $(this).hasClass("expandedImg") &&
  2169. (mouseRelativeY > ($(this).height() - 28)))
  2170. {
  2171. $(this).parent().attr("href", "javascript:void(0);");
  2172. }
  2173. else
  2174. {
  2175. toggleEmbeddedImgSize($(this), false);
  2176.  
  2177. if (autoScrollWhenThumbnailClicked)
  2178. $(window).scrollTop( $(this).parent().parent().offset().top );
  2179. return false;
  2180. }
  2181. }
  2182. });
  2183.  
  2184.  
  2185.  
  2186.  
  2187.  
  2188.  
  2189. /*
  2190. @param isAll :: true if your intention is to expand/shrink all images
  2191. */
  2192. function toggleEmbeddedImgSize(embeddedImg, isAll)
  2193. {
  2194. var embeddedImgContainer = embeddedImg.closest(".embeddedImgContainer");
  2195. var isSig = embeddedImgContainer.hasClass("withinSig");
  2196. var thumbnailImgWidth_this = isSig ? thumbnailImgWidthSig : thumbnailImgWidth;
  2197. var thumbnailImgHeight_this = isSig ? thumbnailImgHeightSig : thumbnailImgHeight;
  2198. var thumbnailImgWidth_this_css = thumbnailImgWidth_this == 0 ? "" : thumbnailImgWidth_this+"px";
  2199. var thumbnailImgHeight_this_css = thumbnailImgHeight_this == 0 ? "" : thumbnailImgHeight_this+"px";
  2200. if (!includeSigWhenExpanding && embeddedImg.hasClass("withinSig") && isAll)
  2201. {
  2202. }
  2203. else
  2204. {
  2205. embeddedImg.toggleClass("thumbnailImg expandedImg");
  2206. }
  2207. /*if going to expand image*/
  2208. if (embeddedImg.hasClass("expandedImg"))
  2209. {
  2210. if (!includeSigWhenExpanding && embeddedImg.hasClass("withinSig") && isAll)
  2211. {
  2212. return;
  2213. }
  2214. currentHoveredThumbnail = null;
  2215. $("#floatingImg").remove();
  2216.  
  2217. embeddedImg.css("max-width", getOptimalImgMaxWidth(embeddedImg, expandedImgWidth) + "px");
  2218. embeddedImg.css("max-height", expandedImgHeight_css);
  2219. /*if webm file, start playing it*/
  2220. if (embeddedImg.hasClass("webmExt"))
  2221. {
  2222. embeddedImg[0].play();
  2223. embeddedImg.attr("controls", "");
  2224. }
  2225. }
  2226. else /*if shrinking image back to thumbnail*/
  2227. {
  2228. embeddedImg.css("max-width", getOptimalImgMaxWidth(embeddedImg, thumbnailImgWidth_this) + "px");
  2229. embeddedImg.css("max-height", thumbnailImgHeight_this_css);
  2230. /*if webm file, stop playing it*/
  2231. if (embeddedImg.hasClass("webmExt"))
  2232. {
  2233. embeddedImg[0].pause();
  2234. embeddedImg.removeAttr("controls");
  2235. }
  2236. if (isHovered(embeddedImg) && !isFirefox) /*osdep*/
  2237. {
  2238. currentHoveredThumbnail = embeddedImg;
  2239. }
  2240. else
  2241. {
  2242. $("html").css("cursor", "default"); /*osdep for firefox*/
  2243. currentHoveredThumbnail = null;
  2244. }
  2245. }
  2246. }
  2247.  
  2248.  
  2249. /*
  2250. Get the optimal max-width for an image.
  2251.  
  2252. The width will be one of the following:
  2253. - until the right of the browser windows border
  2254. - until the right of the parent container of the image container
  2255. - until the user-defined width limit
  2256.  
  2257. The smallest of the 3 will be chosen.
  2258.  
  2259. @param embeddedImg :: jQuery object of the image
  2260. @param userDefinedWidthLimit :: use 0 if no limit
  2261.  
  2262. The returned width will be the smaller of the three.
  2263. */
  2264. function getOptimalImgMaxWidth(embeddedImg, userDefinedWidthLimit)
  2265. {
  2266. var optimalWidth;
  2267. var toContainerWidth;
  2268. var toWindowWidth;
  2269. toContainerWidth =
  2270. embeddedImg.closest(".msg_body, blockquote").width(); /*gfaqsdep*/
  2271. toWindowWidth =
  2272. $(window).width() - embeddedImg.closest(".msg_body, blockquote").offset().left; /*gfaqsdep*/
  2273. if (toContainerWidth > toWindowWidth)
  2274. optimalWidth = toWindowWidth;
  2275. else
  2276. optimalWidth = toContainerWidth;
  2277.  
  2278. /*if no user-defined limit on the width*/
  2279. if (userDefinedWidthLimit == 0)
  2280. {
  2281. return optimalWidth;
  2282. }
  2283. else
  2284. {
  2285. if (optimalWidth > userDefinedWidthLimit)
  2286. return userDefinedWidthLimit;
  2287. else
  2288. return optimalWidth;
  2289. }
  2290. }
  2291.  
  2292.  
  2293.  
  2294.  
  2295.  
  2296.  
  2297.  
  2298.  
  2299.  
  2300.  
  2301. function toggleSizesOfImages(embeddedImages, isExpanding) {
  2302.  
  2303. embeddedImages.each(function(index, element) {
  2304. if ($(this).closest(".embeddedImgContainer").hasClass("hidden")) {
  2305. return false;
  2306. }
  2307. if (isExpanding && $(this).hasClass("expandedImg"))
  2308. {
  2309. /*update its max-width*/
  2310. $(this).css("max-width", getOptimalImgMaxWidth($(this)));
  2311. }
  2312. else
  2313. {
  2314. toggleEmbeddedImgSize($(this), true);
  2315. }
  2316. });
  2317. }
  2318.  
  2319. $("body").on("click", ".imgCloseAll", function(event) {
  2320. event.preventDefault();
  2321. toggleSizesOfImages($(".embeddedImg.expandedImg"), false);
  2322. nextImageSize = "expanded";
  2323. var isContainerStacked = $(this).parent().attr("data-style");
  2324. if (autoScrollWhenThumbnailClicked) {
  2325. if (isContainerStacked)
  2326. $(window).scrollTop( $(this).parent().offset().top );
  2327. else
  2328. $(window).scrollTop( getImageAnchorOfImgMenu().parent().offset().top );
  2329. }
  2330. });
  2331.  
  2332. $("body").on("click", ".imgClosePost", function(event) {
  2333. var postID = $(this).attr("data-postID");
  2334. event.preventDefault();
  2335. toggleSizesOfImages($(".embeddedImg[data-postID="+postID+"].expandedImg"), false);
  2336.  
  2337. var isContainerStacked = $(this).parent().attr("data-style");
  2338. if (autoScrollWhenThumbnailClicked) {
  2339. if (isContainerStacked)
  2340. $(window).scrollTop( $(this).parent().offset().top );
  2341. else
  2342. $(window).scrollTop( getImageAnchorOfImgMenu().parent().offset().top );
  2343. }
  2344. });
  2345.  
  2346. $("body").on("click", ".imgExpandPost", function(event) {
  2347. var postID = $(this).attr("data-postID");
  2348.  
  2349. event.preventDefault();
  2350. toggleSizesOfImages($(".embeddedImg[data-postID='"+postID+"']"), true);
  2351.  
  2352. var isContainerStacked = $(this).parent().attr("data-style");
  2353. if (autoScrollWhenThumbnailClicked) {
  2354. if (isContainerStacked)
  2355. $(window).scrollTop( $(this).parent().offset().top );
  2356. else
  2357. $(window).scrollTop( getImageAnchorOfImgMenu().parent().offset().top );
  2358. }
  2359. });
  2360.  
  2361. $("body").on("click", ".imgExpandAll", function(event) {
  2362. event.preventDefault();
  2363. toggleSizesOfImages($(".embeddedImg"), true);
  2364. nextImageSize = "thumbnail";
  2365. var isContainerStacked = $(this).parent().attr("data-style");
  2366. if (autoScrollWhenThumbnailClicked) {
  2367. if (isContainerStacked)
  2368. $(window).scrollTop( $(this).parent().offset().top );
  2369. else
  2370. $(window).scrollTop( getImageAnchorOfImgMenu().parent().offset().top );
  2371. }
  2372. });
  2373.  
  2374.  
  2375.  
  2376.  
  2377.  
  2378.  
  2379.  
  2380.  
  2381.  
  2382.  
  2383. $("body").on("click", ".imgBlacklistToggle", function(event) {
  2384. event.preventDefault();
  2385. var imgURL;
  2386. var imgAnchor;
  2387. var isContainerStacked = $(this).parent().attr("data-style");
  2388. if (!isContainerStacked)
  2389. {
  2390. if ($(this).html() === "blacklist")
  2391. imgAnchor = getImageAnchorOfImgMenu();
  2392. else
  2393. imgAnchor = $(this).parent().siblings(".embeddedImgAnchor");
  2394. }
  2395. else
  2396. {
  2397. imgAnchor = $(this).siblings(".embeddedImgAnchor");
  2398. }
  2399. imgURL = imgAnchor.attr("data-backup-href");
  2400. imgURL.trim();
  2401. /*if image isn't blacklisted (but going to blacklist)*/
  2402. if (! imgAnchor.hasClass("blacklisted"))
  2403. {
  2404. /*for every embedded image anchor*/
  2405. $(".embeddedImgAnchor").each(function(index, element) {
  2406. /*if has URL that was just blacklisted, hide it*/
  2407. if (isURLmatchBlacklistedURL(imgURL, $(this).attr("data-backup-href")))
  2408. {
  2409. hideMedia($(this).parent(), true);
  2410. }
  2411. });
  2412. }
  2413. else /*if image is blacklisted (but going to whitelist)*/
  2414. {
  2415. /*for every embedded image anchor*/
  2416. $(".embeddedImgAnchor").each(function(index, element) {
  2417.  
  2418. /*if has URL that was just whitelisted, show it*/
  2419. if ($(this).attr("data-backup-href") === imgURL)
  2420. {
  2421. showMedia($(this).parent(), true);
  2422. }
  2423. });
  2424. }
  2425. });
  2426.  
  2427.  
  2428.  
  2429. $("body").on("click", "a.imgHideToggle", function(event) {
  2430. event.preventDefault();
  2431.  
  2432. var curEmbeddedImgContainer;
  2433. var isContainerStacked = $(this).parent().attr("data-style");
  2434. /*if image is going to be hidden*/
  2435. if ($(this).html() === "hide")
  2436. {
  2437. if (!isContainerStacked)
  2438. curEmbeddedImgContainer = getImageAnchorOfImgMenu().parent();
  2439. else
  2440. curEmbeddedImgContainer = $(this).parent();
  2441. hideMedia(curEmbeddedImgContainer, false);
  2442. }
  2443. else /*if image is going to be shown*/
  2444. {
  2445. if (!isContainerStacked)
  2446. curEmbeddedImgContainer = $(this).closest(".embeddedImgContainer");
  2447. else
  2448. curEmbeddedImgContainer = $(this).parent();
  2449.  
  2450. showMedia(curEmbeddedImgContainer, false);
  2451. }
  2452. });
  2453.  
  2454.  
  2455.  
  2456. $("body").on("click", "a.imgHideAll", function(event) {
  2457. event.preventDefault();
  2458. toggleImageVisiblity($(".embeddedImgContainer"), "closeAnchor");
  2459. var isContainerStacked = $(this).parent().attr("data-style");
  2460. if (autoScrollWhenThumbnailClicked) {
  2461. if (isContainerStacked)
  2462. $(window).scrollTop( $(this).parent().offset().top );
  2463. else
  2464. $(window).scrollTop( getImageAnchorOfImgMenu().parent().offset().top );
  2465. }
  2466. });
  2467. $("body").on("click", "a.imgHidePost", function(event) {
  2468. event.preventDefault();
  2469. var postID = $(this).attr("data-postID");
  2470. var isContainerStacked = $(this).parent().attr("data-style");
  2471. toggleImageVisiblity($(".embeddedImgContainer[data-postID="+postID+"]"), "closeAnchor");
  2472.  
  2473. if (autoScrollWhenThumbnailClicked) {
  2474. if (isContainerStacked)
  2475. $(window).scrollTop( $(this).parent().offset().top );
  2476. else
  2477. $(window).scrollTop( getImageAnchorOfImgMenu().parent().offset().top );
  2478. }
  2479. });
  2480. $("body").on("click", "a.imgShowPost", function(event) {
  2481. event.preventDefault();
  2482.  
  2483. var postID = $(this).attr("data-postID");
  2484. var isContainerStacked = $(this).parent().attr("data-style");
  2485. toggleImageVisiblity($(".embeddedImgContainer[data-postID="+postID+"]"), "showAnchor");
  2486. if (autoScrollWhenThumbnailClicked) {
  2487. if (isContainerStacked)
  2488. $(window).scrollTop( $(this).parent().offset().top );
  2489. else
  2490. $(window).scrollTop( getImageAnchorOfImgMenu().parent().offset().top );
  2491. }
  2492. });
  2493. $("body").on("click", "a.imgShowAll", function(event) {
  2494. event.preventDefault();
  2495. var isContainerStacked = $(this).parent().attr("data-style");
  2496. toggleImageVisiblity($(".embeddedImgContainer"), "showAnchor");
  2497. if (autoScrollWhenThumbnailClicked) {
  2498. if (isContainerStacked)
  2499. $(window).scrollTop( $(this).parent().offset().top );
  2500. else
  2501. $(window).scrollTop( getImageAnchorOfImgMenu().parent().offset().top );
  2502. }
  2503. });
  2504.  
  2505.  
  2506. })(); /*end of greasemonkey script*/