The version of vichan running on lainchan.org
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

451 lignes
13KB

  1. /*
  2. * quick-reply.js
  3. * https://github.com/savetheinternet/Tinyboard/blob/master/js/quick-reply.js
  4. *
  5. * Released under the MIT license
  6. * Copyright (c) 2013 Michael Save <savetheinternet@tinyboard.org>
  7. * Copyright (c) 2013-2014 Marcin Łabanowski <marcin@6irc.net>
  8. *
  9. * Usage:
  10. * $config['additional_javascript'][] = 'js/jquery.min.js';
  11. * $config['additional_javascript'][] = 'js/jquery-ui.custom.min.js'; // Optional; if you want the form to be draggable.
  12. * $config['additional_javascript'][] = 'js/quick-reply.js';
  13. *
  14. */
  15. (function() {
  16. var settings = new script_settings('quick-reply');
  17. var do_css = function() {
  18. $('#quick-reply-css').remove();
  19. // Find background of reply posts
  20. var dummy_reply = $('<div class="post reply"></div>').appendTo($('body'));
  21. var reply_background = dummy_reply.css('backgroundColor');
  22. var reply_border_style = dummy_reply.css('borderStyle');
  23. var reply_border_color = dummy_reply.css('borderColor');
  24. var reply_border_width = dummy_reply.css('borderWidth');
  25. dummy_reply.remove();
  26. $('<style type="text/css" id="quick-reply-css">\
  27. #quick-reply {\
  28. position: fixed;\
  29. right: 5%;\
  30. top: 5%;\
  31. float: right;\
  32. display: block;\
  33. padding: 0 0 0 0;\
  34. width: 300px;\
  35. z-index: 100;\
  36. }\
  37. #quick-reply table {\
  38. border-collapse: collapse;\
  39. background: ' + reply_background + ';\
  40. border-style: ' + reply_border_style + ';\
  41. border-width: ' + reply_border_width + ';\
  42. border-color: ' + reply_border_color + ';\
  43. margin: 0;\
  44. width: 100%;\
  45. }\
  46. #quick-reply tr td:nth-child(2) {\
  47. white-space: nowrap;\
  48. text-align: right;\
  49. padding-right: 4px;\
  50. }\
  51. #quick-reply tr td:nth-child(2) input[type="submit"] {\
  52. width: 100%;\
  53. }\
  54. #quick-reply th, #quick-reply td {\
  55. margin: 0;\
  56. padding: 0;\
  57. }\
  58. #quick-reply th {\
  59. text-align: center;\
  60. padding: 2px 0;\
  61. border: 1px solid #222;\
  62. }\
  63. #quick-reply th .handle {\
  64. float: left;\
  65. width: 100%;\
  66. display: inline-block;\
  67. }\
  68. #quick-reply th .close-btn {\
  69. float: right;\
  70. padding: 0 5px;\
  71. }\
  72. #quick-reply input[type="text"], #quick-reply select {\
  73. width: 100%;\
  74. padding: 2px;\
  75. font-size: 10pt;\
  76. box-sizing: border-box;\
  77. -webkit-box-sizing:border-box;\
  78. -moz-box-sizing: border-box;\
  79. }\
  80. #quick-reply textarea {\
  81. width: 100%;\
  82. min-width: 100%;\
  83. box-sizing: border-box;\
  84. -webkit-box-sizing:border-box;\
  85. -moz-box-sizing: border-box;\
  86. font-size: 10pt;\
  87. resize: vertical horizontal;\
  88. }\
  89. #quick-reply input, #quick-reply select, #quick-reply textarea {\
  90. margin: 0 0 1px 0;\
  91. }\
  92. #quick-reply input[type="file"] {\
  93. padding: 5px 2px;\
  94. }\
  95. #quick-reply .nonsense {\
  96. display: none;\
  97. }\
  98. #quick-reply td.recaptcha {\
  99. text-align: center;\
  100. padding: 0 0 1px 0;\
  101. }\
  102. #quick-reply td.recaptcha span {\
  103. display: inline-block;\
  104. width: 100%;\
  105. background: white;\
  106. border: 1px solid #ccc;\
  107. cursor: pointer;\
  108. }\
  109. #quick-reply td.recaptcha-response {\
  110. padding: 0 0 1px 0;\
  111. }\
  112. @media screen and (max-width: 400px) {\
  113. #quick-reply {\
  114. display: none !important;\
  115. }\
  116. }\
  117. </style>').appendTo($('head'));
  118. };
  119. var show_quick_reply = function(){
  120. if($('div.banner').length == 0)
  121. return;
  122. if($('#quick-reply').length != 0)
  123. return;
  124. do_css();
  125. var $postForm = $('form[name="post"]').clone();
  126. $postForm.clone();
  127. $dummyStuff = $('<div class="nonsense"></div>').appendTo($postForm);
  128. $postForm.find('table tr').each(function() {
  129. var $th = $(this).children('th:first');
  130. var $td = $(this).children('td:first');
  131. if ($th.length && $td.length) {
  132. $td.attr('colspan', 2);
  133. if ($td.find('input[type="text"]').length) {
  134. // Replace <th> with input placeholders
  135. $td.find('input[type="text"]')
  136. .removeAttr('size')
  137. .attr('placeholder', $th.clone().children().remove().end().text());
  138. }
  139. // Move anti-spam nonsense and remove <th>
  140. $th.contents().filter(function() {
  141. return this.nodeType == 3; // Node.TEXT_NODE
  142. }).remove();
  143. $th.contents().appendTo($dummyStuff);
  144. $th.remove();
  145. if ($td.find('input[name="password"]').length) {
  146. // Hide password field
  147. $(this).hide();
  148. }
  149. // Fix submit button
  150. if ($td.find('input[type="submit"]').length) {
  151. $td.removeAttr('colspan');
  152. $('<td class="submit"></td>').append($td.find('input[type="submit"]')).insertAfter($td);
  153. }
  154. // reCAPTCHA
  155. if ($td.find('#recaptcha_widget_div').length) {
  156. // Just show the image, and have it interact with the real form.
  157. var $captchaimg = $td.find('#recaptcha_image img');
  158. $captchaimg
  159. .removeAttr('id')
  160. .removeAttr('style')
  161. .addClass('recaptcha_image')
  162. .click(function() {
  163. $('#recaptcha_reload').click();
  164. });
  165. // When we get a new captcha...
  166. $('#recaptcha_response_field').focus(function() {
  167. if ($captchaimg.attr('src') != $('#recaptcha_image img').attr('src')) {
  168. $captchaimg.attr('src', $('#recaptcha_image img').attr('src'));
  169. $postForm.find('input[name="recaptcha_challenge_field"]').val($('#recaptcha_challenge_field').val());
  170. $postForm.find('input[name="recaptcha_response_field"]').val('').focus();
  171. }
  172. });
  173. $postForm.submit(function() {
  174. setTimeout(function() {
  175. $('#recaptcha_reload').click();
  176. }, 200);
  177. });
  178. // Make a new row for the response text
  179. var $newRow = $('<tr><td class="recaptcha-response" colspan="2"></td></tr>');
  180. $newRow.children().first().append(
  181. $td.find('input').removeAttr('style')
  182. );
  183. $newRow.find('#recaptcha_response_field')
  184. .removeAttr('id')
  185. .addClass('recaptcha_response_field')
  186. .attr('placeholder', $('#recaptcha_response_field').attr('placeholder'));
  187. $('#recaptcha_response_field').addClass('recaptcha_response_field')
  188. $td.replaceWith($('<td class="recaptcha" colspan="2"></td>').append($('<span></span>').append($captchaimg)));
  189. $newRow.insertAfter(this);
  190. }
  191. // Upload section
  192. if ($td.find('input[type="file"]').length) {
  193. if ($td.find('input[name="file_url"]').length) {
  194. $file_url = $td.find('input[name="file_url"]');
  195. if (settings.get('show_remote', false)) {
  196. // Make a new row for it
  197. var $newRow = $('<tr><td colspan="2"></td></tr>');
  198. $file_url.clone().attr('placeholder', _('Upload URL')).appendTo($newRow.find('td'));
  199. $newRow.insertBefore(this);
  200. }
  201. $file_url.parent().remove();
  202. $td.find('label').remove();
  203. $td.contents().filter(function() {
  204. return this.nodeType == 3; // Node.TEXT_NODE
  205. }).remove();
  206. $td.find('input[name="file_url"]').removeAttr('id');
  207. }
  208. if ($(this).find('input[name="spoiler"]').length) {
  209. $td.removeAttr('colspan');
  210. }
  211. }
  212. // Disable embedding if configured so
  213. if (!settings.get('show_embed', false) && $td.find('input[name="embed"]').length) {
  214. $(this).remove();
  215. }
  216. // Remove oekaki if existent
  217. if ($(this).is('#oekaki')) {
  218. $(this).remove();
  219. }
  220. // Remove upload selection
  221. if ($td.is('#upload_selection')) {
  222. $(this).remove();
  223. }
  224. // Remove mod controls, because it looks shit.
  225. if ($td.find('input[type="checkbox"]').length) {
  226. var tr = this;
  227. $td.find('input[type="checkbox"]').each(function() {
  228. if ($(this).attr('name') == 'spoiler') {
  229. $td.find('label').remove();
  230. $(this).attr('id', 'q-spoiler-image');
  231. $postForm.find('input[type="file"]').parent()
  232. .removeAttr('colspan')
  233. .after($('<td class="spoiler"></td>').append(this, ' ', $('<label for="q-spoiler-image">').text(_('Spoiler Image'))));
  234. } else if ($(this).attr('name') == 'no_country') {
  235. $td.find('label,input[type="checkbox"]').remove();
  236. } else {
  237. $(tr).remove();
  238. }
  239. });
  240. }
  241. $td.find('small').hide();
  242. }
  243. });
  244. $postForm.find('textarea[name="body"]').removeAttr('id').removeAttr('cols').attr('placeholder', _('Comment'));
  245. $postForm.find('textarea:not([name="body"]),input[type="hidden"]').removeAttr('id').appendTo($dummyStuff);
  246. $postForm.find('br').remove();
  247. $postForm.find('table').prepend('<tr><th colspan="2">\
  248. <span class="handle">\
  249. <a class="close-btn" href="javascript:void(0)">×</a>\
  250. ' + _('Quick Reply') + '\
  251. </span>\
  252. </th></tr>');
  253. $postForm.attr('id', 'quick-reply');
  254. $postForm.appendTo($('body')).hide();
  255. $origPostForm = $('form[name="post"]:first');
  256. // Synchronise body text with original post form
  257. $origPostForm.find('textarea[name="body"]').on('change input propertychange', function() {
  258. $postForm.find('textarea[name="body"]').val($(this).val());
  259. });
  260. $postForm.find('textarea[name="body"]').on('change input propertychange', function() {
  261. $origPostForm.find('textarea[name="body"]').val($(this).val());
  262. });
  263. $postForm.find('textarea[name="body"]').focus(function() {
  264. $origPostForm.find('textarea[name="body"]').removeAttr('id');
  265. $(this).attr('id', 'body');
  266. });
  267. $origPostForm.find('textarea[name="body"]').focus(function() {
  268. $postForm.find('textarea[name="body"]').removeAttr('id');
  269. $(this).attr('id', 'body');
  270. });
  271. // Synchronise other inputs
  272. $origPostForm.find('input[type="text"],select').on('change input propertychange', function() {
  273. $postForm.find('[name="' + $(this).attr('name') + '"]').val($(this).val());
  274. });
  275. $postForm.find('input[type="text"],select').on('change input propertychange', function() {
  276. $origPostForm.find('[name="' + $(this).attr('name') + '"]').val($(this).val());
  277. });
  278. if (typeof $postForm.draggable != 'undefined') {
  279. if (localStorage.quickReplyPosition) {
  280. var offset = JSON.parse(localStorage.quickReplyPosition);
  281. if (offset.top < 0)
  282. offset.top = 0;
  283. if (offset.right > $(window).width() - $postForm.width())
  284. offset.right = $(window).width() - $postForm.width();
  285. if (offset.top > $(window).height() - $postForm.height())
  286. offset.top = $(window).height() - $postForm.height();
  287. $postForm.css('right', offset.right).css('top', offset.top);
  288. }
  289. $postForm.draggable({
  290. handle: 'th .handle',
  291. containment: 'window',
  292. distance: 10,
  293. scroll: false,
  294. stop: function() {
  295. var offset = {
  296. top: $(this).offset().top - $(window).scrollTop(),
  297. right: $(window).width() - $(this).offset().left - $(this).width(),
  298. };
  299. localStorage.quickReplyPosition = JSON.stringify(offset);
  300. $postForm.css('right', offset.right).css('top', offset.top).css('left', 'auto');
  301. }
  302. });
  303. $postForm.find('th .handle').css('cursor', 'move');
  304. }
  305. $postForm.find('th .close-btn').click(function() {
  306. $origPostForm.find('textarea[name="body"]').attr('id', 'body');
  307. $postForm.remove();
  308. floating_link();
  309. });
  310. // Fix bug when table gets too big for form. Shouldn't exist, but crappy CSS etc.
  311. $postForm.show();
  312. $postForm.width($postForm.find('table').width());
  313. $postForm.hide();
  314. $(window).trigger('quick-reply');
  315. $(window).ready(function() {
  316. if (settings.get('hide_at_top', true)) {
  317. $(window).scroll(function() {
  318. if ($(this).width() <= 400)
  319. return;
  320. if ($(this).scrollTop() < $origPostForm.offset().top + $origPostForm.height() - 100)
  321. $postForm.fadeOut(100);
  322. else
  323. $postForm.fadeIn(100);
  324. }).scroll();
  325. } else {
  326. $postForm.show();
  327. }
  328. $(window).on('stylesheet', function() {
  329. do_css();
  330. if ($('link#stylesheet').attr('href')) {
  331. $('link#stylesheet')[0].onload = do_css;
  332. }
  333. });
  334. });
  335. };
  336. $(window).on('cite', function(e, id, with_link) {
  337. if ($(this).width() <= 400)
  338. return;
  339. show_quick_reply();
  340. if (with_link) {
  341. $(document).ready(function() {
  342. if ($('#' + id).length) {
  343. highlightReply(id);
  344. $(document).scrollTop($('#' + id).offset().top);
  345. }
  346. // Honestly, I'm not sure why we need setTimeout() here, but it seems to work.
  347. // Same for the "tmp" variable stuff you see inside here:
  348. setTimeout(function() {
  349. var tmp = $('#quick-reply textarea[name="body"]').val();
  350. $('#quick-reply textarea[name="body"]').val('').focus().val(tmp);
  351. }, 1);
  352. });
  353. }
  354. });
  355. var floating_link = function() {
  356. if (!settings.get('floating_link', false))
  357. return;
  358. $('<a href="javascript:void(0)" class="quick-reply-btn">'+_('Quick Reply')+'</a>')
  359. .click(function() {
  360. show_quick_reply();
  361. $(this).remove();
  362. }).appendTo($('body'));
  363. $(window).on('quick-reply', function() {
  364. $('.quick-reply-btn').remove();
  365. });
  366. };
  367. if (settings.get('floating_link', false)) {
  368. $(window).ready(function() {
  369. if($('div.banner').length == 0)
  370. return;
  371. $('<style type="text/css">\
  372. a.quick-reply-btn {\
  373. position: fixed;\
  374. right: 0;\
  375. bottom: 0;\
  376. display: block;\
  377. padding: 5px 13px;\
  378. text-decoration: none;\
  379. }\
  380. </style>').appendTo($('head'));
  381. floating_link();
  382. if (settings.get('hide_at_top', true)) {
  383. $('.quick-reply-btn').hide();
  384. $(window).scroll(function() {
  385. if ($(this).width() <= 400)
  386. return;
  387. if ($(this).scrollTop() < $('form[name="post"]:first').offset().top + $('form[name="post"]:first').height() - 100)
  388. $('.quick-reply-btn').fadeOut(100);
  389. else
  390. $('.quick-reply-btn').fadeIn(100);
  391. }).scroll();
  392. }
  393. });
  394. }
  395. })();