fork(1) download
  1. // ==UserScript==
  2. // @name shitaraba_option_2
  3. // @namespace john1851
  4. // @description shitaraba_option_2
  5. // @include http://c...content-available-to-author-only...a.net/internet/21154/config/data/thread_delete*
  6. // @exclude http://c...content-available-to-author-only...a.net/internet/21154/config/data/thread_delete_confirm
  7. // @exclude http://c...content-available-to-author-only...a.net/internet/21154/config/data/thread_delete_finish
  8. // @grant none
  9. // @version 0.5.0.00
  10. // ==/UserScript==
  11.  
  12.  
  13. (function (_, count) {
  14. _('content', function (board, threads) {
  15. console.log('今日は' + count + '回目の起動の日です。おめでとうございます。');
  16.  
  17. board.click(function (type, isForward) {
  18. board.draw(sort(threads, type, isForward));
  19. });
  20. board.draw(threads);
  21. });
  22.  
  23. function align(array, name, isForward, action) {
  24. if (isForward)
  25. return array.sort(function (x, y) { return action(x[name], y[name]); });
  26. return array.sort(function (x, y) { return action(y[name], x[name]); });
  27. }
  28. function sort(threads, type, isForward) {
  29. if (['no', 'title', 'response', 'newResponse', 'vigor'].indexOf(type) < 0)
  30. throw new RangeError('not support type: ' + type);
  31.  
  32. if (type === 'title') {
  33. return align(threads, type, isForward, function (x, y) {
  34. return x < y ? -1 : x > y ? 1 : 0;
  35. });
  36. }
  37. return align(threads, type, isForward, function (x, y) {
  38. return x - y;
  39. });
  40. }
  41. })((function () {
  42. function array(str) {
  43. return new Function('return [' + str + '];')();
  44. }
  45. function project(array, name) {
  46. return array.map(function (x) { return x[name]; });
  47. }
  48. function zip() {
  49. var results = [],
  50. arrays = [].slice.call(arguments, 0),
  51. length = Math.max.apply(null, project(arrays, 'length'));
  52. for (var i = 0; i < length; i++) {
  53. results.push(project(arrays, i));
  54. }
  55. return results;
  56. };
  57. function format(date) {
  58. var m = (date.getMonth() + 1) + '/',
  59. d = date.getDate() + '/',
  60. h = date.getHours() + ':',
  61. min = date.getMinutes();
  62. return m + d + h + min;
  63. };
  64. function interval(date) {
  65. var sec = Math.floor(new Date() / 1000 - date / 1000),
  66. min, hour, day, mon, times, unit, result;
  67. min = Math.floor(sec / 60);
  68. sec = sec % 60;
  69. hour = Math.floor(min / 60);
  70. min = min % 60;
  71. day = Math.floor(hour / 24);
  72. hour = hour % 24;
  73. mon = Math.floor(day / 30);
  74. day = day % 30;
  75.  
  76. times = [mon, day, hour, min, sec];
  77. unit = ['ヶ月', '日', '時間', '分', '秒'];
  78. result = '';
  79. for (var i = 0; i < times.length; i++) if (times[i] != 0) {
  80. result += times[i] + unit[i];
  81. if (i != times.length - 1)
  82. result += times[i + 1] + unit[i + 1];
  83. break;
  84. }
  85. return result + '前';
  86. };
  87.  
  88. function $(tag, option) {
  89. var children = [].slice.call(arguments, 2),
  90. element = document.createElement(tag);
  91. $.option(element, option || {});
  92. children.forEach(function (x) { element.appendChild(x); });
  93. return element;
  94. }
  95. $.attribute = function (element, attributes) {
  96. Object.keys(attributes).filter(function (x) {
  97. return ['klass', 'text'].indexOf(x) < 0;
  98. }).forEach(function (x) {
  99. element.setAttribute(x, attributes[x]);
  100. });
  101. };
  102. $.option = function (element, option) {
  103. if (option.klass)
  104. element.classList.add(option.klass);
  105. if (option.text)
  106. element.textContent = option.text;
  107. $.attribute(element, option);
  108. return element;
  109. }
  110. $.find = function (id, child) {
  111. if (child)
  112. return document.getElementById(id).getElementsByTagName(child)[0];
  113. return document.getElementById(id);
  114. }
  115. $.clone = function (node, option) {
  116. var element = node.cloneNode(true);
  117. return $.option(element, option || {});
  118. };
  119. $.prepend = function (node, child) {
  120. node.insertBefore(child, node.firstElementChild);
  121. };
  122.  
  123. function threads(id) {
  124. var table = $.find(id).getElementsByTagName('table')[0],
  125. tr = table.getElementsByTagName('tr'),
  126. th = tr[0].children;
  127.  
  128. return [].slice.call(tr, 1).map(function (x) {
  129. return x.children;
  130. }).map(function (x, i) {
  131. var date = new Date(),
  132. response = parseInt(x[3].textContent, 10),
  133. url = x[2].children[1].textContent.split('/').pop();
  134. date.setTime(parseInt(url, 10) * 1000);
  135. return {
  136. check: x[0].children[0].checked,
  137. no: parseInt(x[1].textContent, 10),
  138. title: x[2].children[0].textContent,
  139. url: url,
  140. date: date,
  141. response: response,
  142. vigor: (function () {
  143. var timestamp = new Date() / 1000 - date / 1000,
  144. vigor = response / (timestamp / (60 * 60 * 24));
  145. if (response <= 1)
  146. return 0;
  147. else if (response <= 10)
  148. return vigor * response / 10;
  149. return vigor;
  150. })()
  151. };
  152. });
  153. }
  154.  
  155. function view() {
  156. return $('tbody', {},
  157. $('tr', {},
  158. $('th', { klass: 'checkbox', text: '削除' }),
  159. $('th', { klass: 'no', 'data-type': 'no', text: 'No.', style: 'cursor: pointer;' }),
  160. $('th', { klass: 'title', 'data-type': 'title', text: 'タイトル', style: 'cursor: pointer;' }),
  161. $('th', { klass: 'resNumber', 'data-type': 'response', text: 'レス数', style: 'cursor: pointer;' }),
  162. $('th', { klass: 'resNumber', 'data-type': 'newResponse', text: '新レス数', style: 'cursor: pointer;' }),
  163. $('th', { klass: 'resNumber', 'data-type': 'vigor', text: '勢い', style: 'cursor: pointer;' }),
  164. $('th', { klass: 'individualDeletion' }),
  165. $('th', { klass: 'infectionDeletion' })
  166. )
  167. );
  168. }
  169. view.row = function (thread, i) {
  170. function checkbox(url) {
  171. return $('td', { klass: 'checkbox' },
  172. $('input', {
  173. type: 'checkbox', name: 'key_' + url
  174. })
  175. );
  176. }
  177. function no(no) {
  178. return $('td', { klass: 'no', text: no });
  179. }
  180. function title(title, url, date, isNew) {
  181. var element = $('td', { klass: 'title' },
  182. $('a', {
  183. target: '_blank', text: title,
  184. href: 'http://j...content-available-to-author-only...a.net/bbs/read.cgi/internet/' + url + '/1405372778/l50'
  185. }),
  186. $('p', {
  187. klass: 'searchURL', text: format(date) + ' '
  188. }, $('b', { text: interval(date) }))
  189. );
  190. if (isNew)
  191. $.prepend(element, $('span', { text: '(New) ', style: 'color: #eb6101;' }));
  192. return element;
  193. }
  194. function response(response) {
  195. return $('td', { klass: 'resNumber', text: response });
  196. }
  197. function newResponse(newResponse, isNew) {
  198. var element = $('td', { klass: 'resNumber' },
  199. $('i', { text: '(' + newResponse + ')' })
  200. );
  201. if (isNew)
  202. $.option(element.firstElementChild, { style: 'color: red;' });
  203. else
  204. $.option(element.firstElementChild, { style: 'color: blue;' });
  205. return element;
  206. }
  207. function vigor(vigor) {
  208. return $('td', { klass: 'resNumber', style: 'overflow: hidden;' },
  209. $('b', {
  210. text: (function () {
  211. if (vigor < 1)
  212. return vigor.toFixed(2);
  213. else if (vigor < 100)
  214. return vigor.toFixed(1);
  215. else if (vigor < 1000)
  216. return vigor.toFixed(0);
  217. return '999+';
  218. })()
  219. })
  220. );
  221. }
  222. function save(url) {
  223. return $('td', { klass: 'individualDeletion' },
  224. $('a', {
  225. text: '倉庫へ送る',
  226. href: './thread_delete_confirm?key=' + url + '&subcommand=save'
  227. })
  228. );
  229. }
  230. function remove(url) {
  231. return $('td', { klass: 'infectionDeletion' },
  232. $('a', {
  233. text: '完全削除',
  234. href: './thread_delete_confirm?key=' + url + '&subcommand=remove'
  235. })
  236. );
  237. }
  238.  
  239. return $('tr', { klass: i % 2 === 0 ? 'even' : 'odd' },
  240. checkbox(thread.url),
  241. no(thread.no),
  242. title(thread.title, thread.url, thread.date, thread.isNew),
  243. response(thread.response),
  244. newResponse(thread.newResponse, thread.isNew),
  245. vigor(thread.vigor),
  246. save(thread.url),
  247. remove(thread.url)
  248. );
  249. };
  250.  
  251. function board(id) {
  252. var table = $.find(id, 'table');
  253. table.replaceChild(view(), table.firstElementChild);
  254. return {
  255. draw: function (threads) {
  256. [].slice.call(table.firstElementChild.children, 1).forEach(function (x) {
  257. table.firstElementChild.removeChild(x);
  258. });
  259. threads.forEach(function (x, i) {
  260. table.firstElementChild.appendChild(view.row(x, i));
  261. });
  262. },
  263. click: function (callback) {
  264. [].slice.call(table.firstElementChild.firstElementChild.children, 1, -2).forEach(function (x) {
  265. x.addEventListener('click', function () {
  266. var type = x.dataset['type'],
  267. value = sessionStorage[type],
  268. isForward = typeof value === 'undefined' ? true : value === 'true';
  269. callback(type, isForward);
  270. sessionStorage[type] = !isForward;
  271. }, false);
  272. });
  273. }
  274. };
  275. }
  276.  
  277. function autoCheck(id) {
  278. var form = $.find(id, 'table').parentNode,
  279. button = $('input', { type: 'button', value: '自動チェック' }),
  280. tip = $('b', { text: '現在の総スレ数: ' + threads(id).length });
  281.  
  282. button.addEventListener('click', function () {
  283. var elements = document.forms[0].elements,
  284. value = sessionStorage['autoCheck'],
  285. toggle = typeof value === 'undefined' ? true : value === 'true';
  286. if (toggle)
  287. {
  288. zip(threads(id), elements).filter(function (x) {
  289. return typeof x[0] !== 'undefined';
  290. }).sort(function (x, y) {
  291. return x[0].vigor - y[0].vigor;
  292. }).slice(0, 30).forEach(function (x) {
  293. x[1].checked = true;
  294. });
  295. }
  296. else
  297. {
  298. for (var i = 0, length = elements.length; i < length; i++) {
  299. elements[i].checked = false;
  300. }
  301. }
  302. sessionStorage['autoCheck'] = !toggle;
  303. }, false);
  304. form.parentNode.insertBefore(button, form);
  305. form.parentNode.insertBefore(tip, form);
  306. }
  307.  
  308. return function (id, callback) {
  309. var _threads = threads(id),
  310. responses = array(localStorage['responses'] || project(_threads, 'response'));
  311. responses = new Array(_threads.length - responses.length).concat(responses);
  312.  
  313. zip(_threads, responses).forEach(function (x) {
  314. x[0].newResponse = x[0].response - (x[1] || 0);
  315. x[0].isNew = typeof x[1] === 'undefined';
  316. });
  317.  
  318. autoCheck(id);
  319. callback(board(id), _threads);
  320.  
  321. localStorage['responses'] = project(_threads, 'response').toString();
  322. localStorage['count'] = (parseInt(localStorage['count'], 10) || 1) + 1;
  323. };
  324. })(), parseInt(localStorage['count'], 10) || 1);
  325.  
Runtime error #stdin #stdout #stderr 0.02s 5112KB
stdin
Standard input is empty
stdout
Standard output is empty
stderr
prog.js:324: ReferenceError: localStorage is not defined