您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
2ちゃんねるのスレッドビューワ
- // ==UserScript==
- // @name 2ch Thread Viewer
- // @namespace https://gf.qytechs.cn/users/1009-kengo321
- // @version 26
- // @description 2ちゃんねるのスレッドビューワ
- // @grant GM_getValue
- // @grant GM_setValue
- // @grant GM.getValue
- // @grant GM.setValue
- // @match *://*.2ch.net/test/read.cgi/*
- // @match *://*.5ch.net/test/read.cgi/*
- // @license MIT
- // @noframes
- // @run-at document-start
- // ==/UserScript==
- ;(function() {
- 'use strict'
- var find = function(predicate, array) {
- for (var i = 0; i < array.length; i++) {
- var e = array[i]
- if (predicate(e)) return e
- }
- }
- var pushIfAbsent = function(array, value) {
- if (array.indexOf(value) === -1) array.push(value)
- return array
- }
- var pushSelectedAll = function(document) {
- return function(array, selector) {
- ;[].push.apply(array, document.querySelectorAll(selector))
- return array
- }
- }
- var not = function(fn) {
- return function() { return !fn.apply(this, arguments) }
- }
- var array = Function.prototype.call.bind([].slice)
- var curry = (function() {
- var applyOrRebind = function(func, arity, args) {
- var passed = args.concat(array(arguments, 3)).slice(0, arity)
- return arity === passed.length
- ? func.apply(this, passed)
- : applyOrRebind.bind(this, func, arity, passed)
- }
- return function(func) {
- return applyOrRebind.bind(this, func, func.length, [])
- }
- })()
- var invoke = curry(function(methodName, args, obj) {
- return obj[methodName].apply(obj, args)
- })
- var equalObj = curry(function(o1, o2) {
- return Object.keys(o1)
- .concat(Object.keys(o2))
- .reduce(pushIfAbsent, [])
- .every(function(key) { return o1[key] === o2[key] })
- })
- var prop = curry(function(propName, obj) {
- return obj[propName]
- })
- var listeners = {
- set: function(eventTypes, observer) {
- eventTypes.forEach(function(t) {
- observer[`_${t}Listener`] = observer[`_${t}`].bind(observer)
- })
- },
- add: function(eventTypes, observer, observable) {
- eventTypes.forEach(function(t) {
- observable.addEventListener(t, observer[`_${t}Listener`])
- })
- },
- remove: function(eventTypes, observer, observable) {
- eventTypes.forEach(function(t) {
- observable.removeEventListener(t, observer[`_${t}Listener`])
- })
- },
- }
- var msPerDay = 86400000
- var truncTime = function(dateTime) {
- return dateTime - dateTime % msPerDay
- }
- var toDateString = function(msTime) {
- var d = new Date(msTime)
- return `${d.getUTCFullYear()}-${d.getUTCMonth() + 1}-${d.getUTCDate()}`
- }
- var Observable = (function() {
- var Observable = function() {
- this._eventTypeToListeners = Object.create(null)
- }
- Observable.prototype.addEventListener = function(eventType, listener) {
- var m = this._eventTypeToListeners
- var v = m[eventType]
- if (v) v.push(listener); else m[eventType] = [listener]
- }
- Observable.prototype.removeEventListener = function(eventType, listener) {
- var v = this._eventTypeToListeners[eventType]
- if (!v) return
- var i = v.indexOf(listener)
- if (i >= 0) v.splice(i, 1)
- }
- Observable.prototype.getEventListeners = function(eventType) {
- return this._eventTypeToListeners[eventType] || []
- }
- Observable.prototype.fireEvent = function(eventType/* , ...args */) {
- var v = this._eventTypeToListeners[eventType]
- ;(v || []).forEach(invoke('apply', [null, array(arguments, 1)]))
- }
- return Observable
- })()
- var Parser = (function() {
- var mail = function(dt) {
- var e = dt.childNodes[1]
- return e.tagName === 'FONT' ? '' : Parser._mail(e)
- }
- var id = function(dt) {
- var r = /ID:([\w+/]+)/.exec(dt.childNodes[2].textContent)
- return r ? r[1] : ''
- }
- var createResponse = function(dt, dd) {
- var num = parseInt(dt.firstChild.textContent.split(' ')[0])
- var name = dt.childNodes[1].textContent
- return {
- number: num,
- name,
- mail: mail(dt),
- jstTime: Parser._jstTime(dt.childNodes[2].textContent),
- id: id(dt),
- anchors: Parser._anchors(dd, num),
- contentNodes: Parser._contentNodes(dd.childNodes),
- korokoro: Parser._korokoro(name),
- }
- }
- var postedResShowElem = function(document) {
- return find(function(e) {
- return e.textContent === '新着レスの表示'
- }, document.getElementsByTagName('center'))
- }
- var hrAbove = function(e) {
- var p = e.previousSibling
- if (!p) return null
- var hr = p.previousSibling
- return hr && hr.tagName === 'HR' ? hr : null
- }
- var pageSizeElem = function(document) {
- return find(function(e) {
- return e.textContent.endsWith('KB')
- && e.getAttribute('color') === 'red'
- && e.getAttribute('face') === 'Arial'
- }, document.getElementsByTagName('font'))
- }
- var pushIfTruthy = function(array, value) {
- if (value) array.push(value)
- }
- var Parser = function(document) {
- this.doc = document
- }
- Parser.prototype._boardId = function() {
- if (!this.doc.location) return ''
- var r = /\/test\/read.cgi\/([^/]+)/.exec(this.doc.location.pathname)
- return r ? r[1] : ''
- }
- Parser.prototype._threadNumber = function() {
- if (!this.doc.location) return 0
- var r = /\/test\/read.cgi\/[^/]+\/(\d+)/.exec(this.doc.location.pathname)
- return r ? parseInt(r[1]) : 0
- }
- Parser.prototype._floatedSpan = function() {
- return this.doc.querySelector('body > div > span')
- }
- Parser.prototype._postForm = function() {
- return find(function(f) {
- return f.getAttribute('action').startsWith('../test/bbs.cgi')
- && f.method.toUpperCase() === 'POST'
- }, this.doc.querySelectorAll('form'))
- }
- Parser.prototype._elementsToRemove = function() {
- var result = []
- var e = postedResShowElem(this.doc)
- if (e) {
- result.push(e)
- pushIfTruthy(result, hrAbove(e))
- }
- pushIfTruthy(result, pageSizeElem(this.doc))
- return result
- }
- Parser.prototype._ads = function() {
- return ['.ad--right', '.js--ad--top', '.js--ad--bottom']
- .reduce(pushSelectedAll(this.doc), [])
- }
- Parser.prototype._hasThreadClosed = function() {
- return !postedResShowElem(this.doc)
- }
- Parser.prototype._responses = function() {
- var dl = this.doc.querySelector('.thread')
- var dt = dl.getElementsByTagName('dt')
- var dd = dl.getElementsByTagName('dd')
- var result = []
- for (var i = 0; i < dt.length; i++) {
- result.push(createResponse(dt[i], dd[i]))
- }
- return result
- }
- Parser.prototype._action = function() {
- return function() {}
- }
- Parser.prototype.parse = function() {
- return {
- responses: this._responses(),
- threadClosed: this._hasThreadClosed(),
- ads: this._ads(),
- elementsToRemove: this._elementsToRemove(),
- threadRootElement: this.doc.querySelector('.thread'),
- postForm: this._postForm(),
- boardId: this._boardId(),
- threadNumber: this._threadNumber(),
- floatedSpan: this._floatedSpan(),
- action: this._action(),
- }
- }
- Parser.of = function(document) {
- if (document.querySelector('dl.thread')) return new Parser(document)
- if (document.querySelector('div.thread')) return new Parser6(document)
- return null
- }
- Parser._mail = function(anchor) {
- var s = anchor.href.slice('mailto:'.length)
- try {
- return decodeURI(s)
- } catch (e) {
- return s
- }
- }
- Parser._jstTime = function(text) {
- var datetime = /(\d{4})\/(\d{2})\/(\d{2})\(.\)/.exec(text)
- if (!datetime) return NaN
- var year = datetime[1]
- var month = datetime[2] - 1
- var date = datetime[3]
- var time = /(\d{2}):(\d{2}):(\d{2})/.exec(text)
- var hour = time ? time[1] : 0
- var minute = time ? time[2] : 0
- var seconds = time ? time[3] : 0
- return Date.UTC(year, month, date, hour, minute, seconds)
- }
- var last = function(array) {
- return array[array.length - 1]
- }
- var isEmptyTextNode = function(node) {
- return node.nodeType === Node.TEXT_NODE && node.nodeValue.trim() === ''
- }
- var isTrimmedRightNode = function(node) {
- return node && (node.tagName === 'BR' || isEmptyTextNode(node))
- }
- Parser._contentNodes = function(childNodes) {
- var nodes = Array.from(childNodes)
- while (isTrimmedRightNode(last(nodes))) nodes.pop()
- return nodes.filter(function(n) {
- return !(n.classList && n.classList.contains('banner'))
- })
- }
- Parser._anchors = function(root, responseNumber) {
- return Array.from(root.querySelectorAll('a')).filter(function(n) {
- return n.textContent.startsWith('>>')
- }).map(function(n) {
- return parseInt(n.textContent.slice('>>'.length))
- }).filter(function(num) {
- return num < responseNumber
- }).reduce(pushIfAbsent, [])
- }
- Parser._korokoro = function(name) {
- var r = /\s(.{4}-.{4}).*?$/.exec(name)
- return r ? r[1] : ''
- }
- return Parser
- })()
- var Parser6 = (function(_super) {
- var mail = function(post) {
- var a = post.querySelector('.name a')
- return a ? Parser._mail(a) : ''
- }
- var id = function(post) {
- var userid = post.dataset.userid
- if (!(userid && userid.startsWith('ID:'))) return ''
- var val = userid.slice('ID:'.length)
- return val.startsWith('???') ? '' : val
- }
- var createResponse = function(post) {
- var num = parseInt(post.id)
- var name = post.querySelector('.name').textContent
- return {
- number: num,
- name,
- mail: mail(post),
- jstTime: Parser._jstTime(post.querySelector('.date').textContent),
- id: id(post),
- anchors: Parser._anchors(post.querySelector('.message'), num),
- contentNodes: Parser._contentNodes(post.querySelector('.message').childNodes),
- korokoro: Parser._korokoro(name),
- }
- }
- var Parser6 = function(document) {
- _super.call(this, document)
- }
- Parser6.prototype = Object.create(_super.prototype)
- Parser6.prototype._floatedSpan = function() { return null }
- Parser6.prototype._postForm = function() {
- return this.doc.querySelector('form')
- }
- Parser6.prototype._elementsToRemove = function() {
- return ['.cLength', '.newposts'].reduce(pushSelectedAll(this.doc), [])
- }
- Parser6.prototype._ads = function() {
- return ['.ad--right', '.ad--bottom', '#banner']
- .reduce(pushSelectedAll(this.doc), [])
- }
- Parser6.prototype._hasThreadClosed = function() {
- return !this.doc.querySelector('.newpostbutton')
- }
- Parser6.prototype._responses = function() {
- return Array.from(this.doc.querySelectorAll('.thread .post')
- , createResponse)
- }
- Parser6.prototype._action = function() {
- return () => {
- const e = this.doc.querySelector('.container_body')
- if (e) e.removeAttribute('style')
- }
- }
- return Parser6
- })(Parser)
- var Response = (function(_super) {
- var padZero = function(n) {
- return (n <= 9 ? '0' : '') + n
- }
- var content = function(nodes) {
- var result = ''
- for (var n of nodes)
- result += (n.tagName === 'BR' ? '\n' : n.textContent)
- return result
- }
- var Response = function(objParam) {
- _super.call(this)
- this.number = objParam.number
- this.name = objParam.name
- this.mail = objParam.mail
- this.jstTime = objParam.jstTime
- this.id = objParam.id
- this.contentNodes = objParam.contentNodes
- this.content = content(objParam.contentNodes)
- this.anchors = objParam.anchors
- this.korokoro = objParam.korokoro
- this.children = []
- this.sameIdResponses = []
- this.sameKorokoroResponses = []
- this.ngId = false
- this.ngParent = false
- this.ngWord = false
- this.ngName = false
- this.ngKorokoro = false
- this.ngIdTail = false
- this.ngSlip = false
- this.parents = new Set
- }
- Response.of = function(objParam) {
- return new Response(objParam)
- }
- Response.prototype = Object.create(_super.prototype)
- Response.prototype.getDateTimeString = function() {
- var d = new Date(this.jstTime)
- var y = d.getUTCFullYear()
- var mon = padZero(d.getUTCMonth() + 1)
- var date = padZero(d.getUTCDate())
- var h = padZero(d.getUTCHours())
- var min = padZero(d.getUTCMinutes())
- var s = padZero(d.getUTCSeconds())
- return `${y}-${mon}-${date} ${h}:${min}:${s}`
- }
- Response.prototype.getIndexOfSameIdResponses = function() {
- return this.sameIdResponses.indexOf(this)
- }
- Response.prototype.getIndexOfSameKorokoroResponses = function() {
- return this.sameKorokoroResponses.indexOf(this)
- }
- Response.prototype.addChildren = function(children) {
- if (children.length === 0) return
- ;[].push.apply(this.children, children)
- children.forEach(invoke('addParent', [this]))
- this.fireEvent('childrenAdded', children)
- }
- Response.prototype.addSameIdResponses = function(sameIdResponses) {
- if (sameIdResponses.length === 0) return
- ;[].push.apply(this.sameIdResponses, sameIdResponses)
- this.fireEvent('sameIdResponsesAdded', sameIdResponses)
- }
- Response.prototype.addSameKorokoroResponses = function(sameKorokoroResponses) {
- if (sameKorokoroResponses.length === 0) return
- ;[].push.apply(this.sameKorokoroResponses, sameKorokoroResponses)
- this.fireEvent('sameKorokoroResponsesAdded', sameKorokoroResponses)
- }
- Response.prototype.getNoNgChildren = function() {
- return this.children.filter(not(invoke('isNg', [])))
- }
- Response.prototype.isNg = function() {
- return this.ngId
- || this.ngParent
- || this.ngWord
- || this.ngName
- || this.ngKorokoro
- || this.ngIdTail
- || this.ngSlip
- }
- Response.prototype._setNg = function(propName, newVal) {
- var preNg = this.isNg()
- this[propName] = Boolean(newVal)
- if (preNg !== this.isNg()) this.fireEvent('ngChanged', this.isNg())
- }
- Response.prototype.setNgId = function(ngId) {
- this._setNg('ngId', ngId)
- }
- Response.prototype.setNgParent = function(ngParent) {
- this._setNg('ngParent', ngParent)
- }
- Response.prototype.setNgWord = function(ngWord) {
- this._setNg('ngWord', ngWord)
- }
- Response.prototype.setNgName = function(ngName) {
- this._setNg('ngName', ngName)
- }
- Response.prototype.setNgKorokoro = function(ngKorokoro) {
- this._setNg('ngKorokoro', ngKorokoro)
- }
- Response.prototype.setNgIdTail = function(ngIdTail) {
- this._setNg('ngIdTail', ngIdTail)
- }
- Response.prototype.setNgSlip = function(ngSlip) {
- this._setNg('ngSlip', ngSlip)
- }
- Response.prototype.updateNgParent = function() {
- this.setNgParent([...this.parents].some(p => p.isNg()))
- }
- Response.prototype.addParent = function(parent) {
- if (this.parents.has(parent)) return
- this.parents.add(parent)
- this.updateNgParent()
- parent.addEventListener('ngChanged', () => this.updateNgParent())
- }
- Response.prototype.hasAsciiArt = function() {
- return this.content.includes('\u3000\x20')
- }
- return Response
- })(Observable)
- var ResponseRequest = (function() {
- var HTTP_OK = 200
- var parseResponseText = function(responseText) {
- var d = new DOMParser().parseFromString(responseText, 'text/html')
- var r = Parser.of(d).parse()
- return {
- responses: r.responses.slice(1),
- threadClosed: r.threadClosed,
- }
- }
- var onload = function(xhr, resolve, reject) {
- return function() {
- if (xhr.status === HTTP_OK) {
- try {
- resolve(parseResponseText(xhr.responseText))
- } catch (e) {
- reject(e)
- }
- } else {
- reject(new Error(xhr.status + ' ' + xhr.statusText))
- }
- }
- }
- var ResponseRequest = function() {}
- ResponseRequest.prototype.send = function(basePath, startResponseNumber) {
- return new Promise(function(resolve, reject) {
- var xhr = new XMLHttpRequest()
- xhr.timeout = 10000
- xhr.onload = onload(xhr, resolve, reject)
- xhr.onerror = function() { reject(new Error('エラー')) }
- xhr.ontimeout = function() { reject(new Error('時間切れ')) }
- xhr.open('GET', `${basePath}${startResponseNumber - 1}-n`)
- xhr.overrideMimeType('text/html; charset=shift_jis')
- xhr.send()
- })
- }
- return ResponseRequest
- })()
- function NgItem() {}
- NgItem.prototype.isValidFor = function() {
- throw new Error('NgItem#isValidFor(thread) must be implemented')
- }
- NgItem.prototype.match = function() {
- throw new Error('NgItem#match(response) must be implemented')
- }
- function BoundableNgItem(boardId, threadNumber) {
- if (boardId) this.boardId = boardId
- if (threadNumber) this.threadNumber = parseInt(threadNumber)
- }
- BoundableNgItem.prototype = Object.create(NgItem.prototype)
- BoundableNgItem.prototype.constructor = BoundableNgItem
- BoundableNgItem.prototype.isValidFor = function(thread) {
- return (!this.boardId || this.boardId === thread.boardId)
- && (!this.threadNumber || this.threadNumber === thread.threadNumber)
- }
- function NgWord(ngWord, boardId, threadNumber) {
- BoundableNgItem.call(this, boardId, threadNumber)
- this.ngWord = ngWord
- }
- NgWord.of = function(objParam) {
- return new NgWord(objParam.ngWord, objParam.boardId, objParam.threadNumber)
- }
- NgWord.prototype = Object.create(BoundableNgItem.prototype)
- NgWord.prototype.constructor = NgWord
- NgWord.prototype.match = function(res) {
- return res.content.includes(this.ngWord)
- }
- function NgName(ngName, boardId, threadNumber) {
- BoundableNgItem.call(this, boardId, threadNumber)
- this.ngName = ngName
- }
- NgName.of = function(objParam) {
- return new NgName(objParam.ngName, objParam.boardId, objParam.threadNumber)
- }
- NgName.prototype = Object.create(BoundableNgItem.prototype)
- NgName.prototype.constructor = NgName
- NgName.prototype.match = function(res) {
- return res.name.includes(this.ngName)
- }
- function BoardScopeNgItem(boardId) {
- this.boardId = boardId
- }
- BoardScopeNgItem.prototype = Object.create(NgItem.prototype)
- BoardScopeNgItem.prototype.constructor = BoardScopeNgItem
- BoardScopeNgItem.prototype.isValidFor = function(thread) {
- return this.boardId === thread.boardId
- }
- var NgId = (function(_super) {
- var NgId = function(boardId, jstTime, id) {
- _super.call(this, boardId)
- this.boardId = boardId
- this.activeDate = truncTime(jstTime)
- this.id = id
- }
- NgId.of = function(objParam) {
- return new NgId(objParam.boardId, objParam.activeDate, objParam.id)
- }
- NgId.prototype = Object.create(_super.prototype)
- NgId.prototype.constructor = NgId
- NgId.prototype.match = function(response) {
- return this.id === response.id
- && this.activeDate === truncTime(response.jstTime)
- }
- NgId.prototype.getActiveDateString = function() {
- return toDateString(new Date(this.activeDate))
- }
- return NgId
- })(BoardScopeNgItem)
- function NgIdTail(ngIdTail, boardId, threadNumber) {
- BoundableNgItem.call(this, boardId, threadNumber)
- this.ngIdTail = ngIdTail
- }
- NgIdTail.of = function(objParam) {
- return new NgIdTail(objParam.ngIdTail, objParam.boardId, objParam.threadNumber)
- }
- NgIdTail.prototype = Object.create(BoundableNgItem.prototype)
- NgIdTail.prototype.constructor = NgIdTail
- NgIdTail.prototype.match = function(res) {
- return res.id.length >= 9 && res.id.charAt(8) === this.ngIdTail
- }
- var NgKorokoro = (function(_super) {
- var msForLastThu = [
- msPerDay * 3,
- msPerDay * 4,
- msPerDay * 5,
- msPerDay * 6,
- 0,
- msPerDay,
- msPerDay * 2,
- ]
- var lastThursday = function(ms) {
- return ms - msForLastThu[new Date(ms).getUTCDay()]
- }
- function NgKorokoro(boardId, jstTime, korokoro) {
- _super.call(this, boardId)
- this.startOfAvailablePeriod = lastThursday(truncTime(jstTime))
- this.korokoro = korokoro
- }
- NgKorokoro.of = function(objParam) {
- var o = objParam
- return new NgKorokoro(o.boardId, o.startOfAvailablePeriod, o.korokoro)
- }
- NgKorokoro.prototype = Object.create(_super.prototype)
- NgKorokoro.prototype.constructor = NgKorokoro
- NgKorokoro.prototype._endOfAvailablePeriod = function() {
- return this.startOfAvailablePeriod + msPerDay * 7
- }
- NgKorokoro.prototype.match = function(response) {
- return this.korokoro === response.korokoro
- && this.startOfAvailablePeriod <= response.jstTime
- && response.jstTime < this._endOfAvailablePeriod()
- }
- NgKorokoro.prototype.getAvailablePeriodString = function() {
- var start = new Date(this.startOfAvailablePeriod)
- var end = new Date(this.startOfAvailablePeriod + msPerDay * 6)
- return `${toDateString(start)}_${toDateString(end)}`
- }
- return NgKorokoro
- })(BoardScopeNgItem)
- function NgSlip(type, boardId, threadNumber) {
- BoundableNgItem.call(this, boardId, threadNumber)
- this.type = type
- }
- NgSlip.of = function(objParam) {
- return new NgSlip(objParam.type, objParam.boardId, objParam.threadNumber)
- }
- NgSlip.prototype = Object.create(BoundableNgItem.prototype)
- NgSlip.prototype.constructor = NgSlip
- NgSlip.prototype.match = function(res) {
- return (this.type === 'id' && !res.id)
- || (this.type === 'korokoro' && !res.korokoro)
- }
- var NgItems = {
- createFactoryMethod(setNgTo) {
- var filter = function() {
- return result(Array.prototype.filter.apply(this, arguments))
- }
- var concat = function() {
- return result(Array.prototype.concat.apply(this, arguments))
- }
- var result = function(ngItemArray) {
- ngItemArray.setNgTo = setNgTo
- ngItemArray.filter = filter
- ngItemArray.concat = concat
- return ngItemArray
- }
- return result
- },
- }
- var NgWords = {
- from: NgItems.createFactoryMethod(function(res) {
- res.setNgWord(this.some(function(ngWord) { return ngWord.match(res) }))
- }),
- }
- var NgNames = {
- from: NgItems.createFactoryMethod(function(res) {
- res.setNgName(this.some(function(ngName) { return ngName.match(res) }))
- }),
- }
- var NgIds = {
- from: NgItems.createFactoryMethod(function(res) {
- res.setNgId(this.some(function(ngId) { return ngId.match(res) }))
- }),
- }
- var NgKorokoros = {
- from: NgItems.createFactoryMethod(function(res) {
- res.setNgKorokoro(this.some(function(ngKorokoro) { return ngKorokoro.match(res) }))
- }),
- }
- var NgIdTails = {
- from: NgItems.createFactoryMethod(function(res) {
- res.setNgIdTail(this.some(function(ngIdTail) { return ngIdTail.match(res) }))
- }),
- }
- var NgSlips = {
- from: NgItems.createFactoryMethod(function(res) {
- res.setNgSlip(this.some(function(ngSlip) { return ngSlip.match(res) }))
- }),
- }
- function ArrayStore(objParam) {
- Observable.call(this)
- this.getValue = objParam.getValue
- this.setValue = objParam.setValue
- this.key = objParam.key
- this.valueOf = objParam.valueOf
- this.arrayFrom = objParam.arrayFrom
- this.equals = objParam.equals
- }
- ArrayStore.prototype = Object.create(Observable.prototype)
- ArrayStore.prototype.constructor = ArrayStore
- ArrayStore.prototype.get = async function() {
- var values = JSON.parse(await this.getValue(this.key, '[]'))
- return this.arrayFrom(values.map(this.valueOf))
- }
- ArrayStore.prototype._set = async function(values) {
- await this.setValue(this.key, JSON.stringify(values))
- }
- ArrayStore.prototype.set = async function(values) {
- await this._set(values)
- this.fireEvent('changed', values)
- }
- ArrayStore.prototype.add = async function(value) {
- var addedValues = (await this.get()).concat(value)
- await this._set(addedValues)
- this.fireEvent('changed', addedValues)
- }
- ArrayStore.prototype.remove = async function(removedValue) {
- var filteredValues = (await this.get()).filter(function(value) {
- return !this.equals(removedValue, value)
- }, this)
- await this._set(filteredValues)
- this.fireEvent('changed', filteredValues)
- }
- ArrayStore.prototype.removeAll = async function() {
- await this.setValue(this.key, '[]')
- this.fireEvent('changed', this.arrayFrom([]))
- }
- var Config = (function(_super) {
- var identity = function(a) { return a }
- var Config = function(getValue, setValue) {
- _super.call(this)
- this._getValue = getValue
- this._setValue = setValue
- var o = function(key, valueOf, arrayFrom) {
- return {getValue, setValue, key, valueOf, arrayFrom, equals: equalObj}
- }
- this.ngWords = new ArrayStore(o('ngWords', NgWord.of, NgWords.from))
- this.ngIds = new ArrayStore(o('ngIds', NgId.of, NgIds.from))
- this.ngNames = new ArrayStore(o('ngNames', NgName.of, NgNames.from))
- this.ngKorokoros = new ArrayStore(o('ngKorokoros', NgKorokoro.of, NgKorokoros.from))
- this.threadHistories = new ArrayStore(o('threadHistories', identity, identity))
- this.ngIdTails = new ArrayStore(o('ngIdTails', NgIdTail.of, NgIdTails.from))
- this.ngSlips = new ArrayStore(o('ngSlips', NgSlip.of, NgSlips.from))
- }
- Config.prototype = Object.create(_super.prototype)
- Config.prototype.isPageCentering = async function() {
- return await this._getValue('pageCentering', true)
- }
- Config.prototype.setPageCentering = async function(pageCentering) {
- await this._setValue('pageCentering', pageCentering)
- this.fireEvent('pageCenteringChanged', pageCentering)
- }
- Config.prototype.getPageMaxWidth = async function() {
- return await this._getValue('pageMaxWidth', 600)
- }
- Config.prototype.setPageMaxWidth = async function(pageMaxWidth) {
- await this._setValue('pageMaxWidth', pageMaxWidth)
- this.fireEvent('pageMaxWidthChanged', pageMaxWidth)
- }
- Config.prototype.isNgVisible = async function() {
- return await this._getValue('ngVisible', false)
- }
- Config.prototype.setNgVisible = async function(ngVisible) {
- await this._setValue('ngVisible', ngVisible)
- this.fireEvent('ngVisibleChanged', ngVisible)
- }
- Config.prototype.getNgItemArrayStores = function() {
- return [
- this.ngWords,
- this.ngIds,
- this.ngNames,
- this.ngKorokoros,
- this.ngIdTails,
- this.ngSlips,
- ]
- }
- return Config
- })(Observable)
- var ThreadHistory = (function() {
- var removeCopyrightWarnings = function(s) {
- return s.replace(/\[転載禁止\]/g, '')
- .replace(/\[無断転載禁止\]/g, '')
- .replace(/©2ch.net/g, '')
- .trim()
- }
- function ThreadHistory(threadHistories, location, title) {
- this.threadHistories = threadHistories
- this.location = location
- this.title = removeCopyrightWarnings(title)
- }
- ThreadHistory.prototype.isValidLocation = function() {
- return /^\/test\/read\.cgi\/\w+\/\d+\/$/.test(this.location.pathname)
- }
- ThreadHistory.prototype.exists = async function() {
- return Boolean(await this._history())
- }
- ThreadHistory.prototype._url = function() {
- var l = this.location
- return `${l.protocol}//${l.host}${l.pathname}`
- }
- ThreadHistory.prototype._history = async function() {
- var u = this._url()
- return (await this.threadHistories.get()).find(function(h) { return h.url === u })
- }
- ThreadHistory.prototype.getResNum = async function() {
- if (this.isValidLocation() && await this.exists())
- return (await this._history()).resNum
- throw new Error('must be valid location and exists')
- }
- ThreadHistory.prototype._toObj = function(resNum) {
- return {url: this._url(), title: this.title, resNum}
- }
- ThreadHistory.prototype._removeOldAndAddNew = async function(old, resNum) {
- return (await this.threadHistories.get())
- .filter(not(this.threadHistories.equals.bind(null, old)))
- .concat(this._toObj(resNum))
- }
- ThreadHistory.prototype.setResNum = async function(resNum) {
- if (!this.isValidLocation()) return
- var old = await this._history()
- if (old) {
- if (old.resNum === resNum) return
- await this.threadHistories.set(await this._removeOldAndAddNew(old, resNum))
- } else {
- await this.threadHistories.add(this._toObj(resNum))
- }
- }
- return ThreadHistory
- })()
- var Thread = (function(_super) {
- var putAsArray = function(obj, key, value) {
- var array = obj[key]
- if (array) array.push(value); else obj[key] = [value]
- return obj
- }
- var putResById = function(obj, res) {
- return res.id ? putAsArray(obj, res.id, res) : obj
- }
- var putResByPassedAnchor = curry(function(res, obj, anchor) {
- return putAsArray(obj, anchor, res)
- })
- var putResByAnchor = function(obj, res) {
- return res.anchors.reduce(putResByPassedAnchor(res), obj)
- }
- var putResByNumber = function(obj, res) {
- obj[res.number] = res
- return obj
- }
- var putResByKorokoro = function(obj, res) {
- return res.korokoro ? putAsArray(obj, res.korokoro, res) : obj
- }
- var addNewChild = function(responses, addedResponses) {
- var all = responses.concat(addedResponses)
- var resNumToRes = all.reduce(putResByNumber, {})
- var addedAnchors = addedResponses.reduce(putResByAnchor, {})
- Object.keys(addedAnchors).forEach(function(anchor) {
- var r = resNumToRes[anchor]
- if (r) r.addChildren(addedAnchors[anchor])
- })
- }
- var addSameId = curry(function(idToRes, response) {
- var sameId = idToRes[response.id]
- if (sameId) response.addSameIdResponses(sameId)
- })
- var addNewSameId = function(responses, addedResponses) {
- responses.forEach(addSameId(addedResponses.reduce(putResById, {})))
- addedResponses.forEach(
- addSameId(responses.concat(addedResponses).reduce(putResById, {})))
- }
- var addSameKorokoro = curry(function(korokoroToRes, response) {
- var sameKorokoro = korokoroToRes[response.korokoro]
- if (sameKorokoro) response.addSameKorokoroResponses(sameKorokoro)
- })
- var addNewSameKorokoro = function(responses, addedResponses) {
- responses.forEach(
- addSameKorokoro(addedResponses.reduce(putResByKorokoro, {})))
- addedResponses.forEach(
- addSameKorokoro(responses.concat(addedResponses).reduce(putResByKorokoro, {})))
- }
- var Thread = function(config, boardId, threadNumber, threadHistory) {
- _super.call(this)
- this._responses = []
- this.boardId = boardId
- this.threadNumber = threadNumber
- this.config = config
- this.threadHistory = threadHistory
- this.newResCount = 0
- this._addEventListenersToConfig()
- }
- Thread.prototype = Object.create(_super.prototype)
- Thread.prototype._addEventListenersToConfig = function() {
- var listener = this._ngItemsChanged.bind(this)
- for (var s of this.config.getNgItemArrayStores())
- s.addEventListener('changed', listener)
- }
- Thread.prototype._hasBeenAddedResponses = function() {
- return Boolean(this._responses.length)
- }
- Thread.prototype._getNewResCountBy = async function(addedResCount) {
- if (this._hasBeenAddedResponses())
- return addedResCount
- if (this.threadHistory.isValidLocation() && await this.threadHistory.exists())
- return addedResCount - await this.threadHistory.getResNum()
- return 0
- }
- Thread.prototype.addResponses = async function(responses) {
- this.newResCount = await this._getNewResCountBy(responses.length)
- this._setNgToResponsesBy(await this._getAllNgItemsArray(), responses)
- addNewChild(this._responses, responses)
- addNewSameId(this._responses, responses)
- addNewSameKorokoro(this._responses, responses)
- ;[].push.apply(this._responses, responses)
- await this.threadHistory.setResNum(this._responses.length)
- this.fireEvent('responsesAdded', responses)
- }
- Thread.prototype._getAllNgItemsArray = function() {
- return Promise.all(this.config.getNgItemArrayStores().map(function(arrayStore) {
- return arrayStore.get()
- }))
- }
- Thread.prototype._setNgToResponsesBy = function(ngItemsArray, responses) {
- responses = responses || this._responses
- for (var ngItems of ngItemsArray) {
- var filteredNgItems = ngItems.filter(invoke('isValidFor', [this]))
- for (var res of responses) filteredNgItems.setNgTo(res)
- }
- }
- Thread.prototype.getLastResponseNumber = function() {
- var r = this._responses
- var last = r[r.length - 1]
- return last ? last.number : -1
- }
- Thread.prototype.addNgId = async function(jstTime, ngId) {
- await this.config.ngIds.add(new NgId(this.boardId, jstTime, ngId))
- }
- Thread.prototype._ngItemsChanged = function(ngItems) {
- this._setNgToResponsesBy([ngItems])
- }
- Thread.prototype.hasResponse = function(responseNumber) {
- return this._responses.some(function(r) {
- return r.number === responseNumber
- })
- }
- return Thread
- })(Observable)
- var ResponseView = (function() {
- var eventTypes = [
- 'childrenAdded',
- 'sameIdResponsesAdded',
- 'sameKorokoroResponsesAdded',
- 'ngChanged',
- ]
- var ResponseView = function(document, response, root) {
- this._doc = document
- this._response = response
- this._factory = new ResponseView.Factory(document, response, root)
- this.rootElement = this._factory.createResponseElement()
- this._childResponseViews = []
- this._sameIdResponseViews = []
- this._sameKorokoroResponseViews = []
- listeners.set(eventTypes, this)
- listeners.add(eventTypes, this, this._response)
- this._childNgChangedListener = this._childNgChanged.bind(this)
- this._addListenersToChildren(response.children)
- }
- ResponseView.new = curry(function(document, response) {
- return new ResponseView(document, response)
- })
- ResponseView.prototype._childrenAdded = function(addedChildren) {
- this._addListenersToChildren(addedChildren)
- this._updateResNumElem()
- this._appendAddedChildren(addedChildren)
- }
- ResponseView.prototype._sameIdResponsesAdded = function(addedSameId) {
- this._updateIdElem()
- this._appendAddedSameId(addedSameId)
- }
- ResponseView.prototype._sameKorokoroResponsesAdded = function(addedSameKorokoro) {
- this._updateKorokoroElem()
- this._appendAddedSameKorokoro(addedSameKorokoro)
- }
- ResponseView.prototype._ngChanged = function(ng) {
- if (ng) this._destroyAllResponseViews()
- this._replaceRootWithNew()
- }
- ResponseView.prototype._isChildrenVisibleAndAllNg = function() {
- return Boolean(this.rootElement.querySelector('.children'))
- && this._response.getNoNgChildren().length === 0
- }
- ResponseView.prototype._childNgChanged = function() {
- this._updateResNumElem()
- if (this._isChildrenVisibleAndAllNg()) this._destroyChildren()
- }
- ResponseView.prototype._addListenersToChildren = function(children) {
- children.forEach(invoke('addEventListener'
- , ['ngChanged', this._childNgChangedListener]))
- }
- ResponseView.prototype._removeListenersFromChildren = function() {
- this._response.children
- .forEach(invoke('removeEventListener'
- , ['ngChanged', this._childNgChangedListener]))
- }
- ResponseView.prototype._removeListenersFromResponse = function() {
- listeners.remove(eventTypes, this, this._response)
- }
- ResponseView.prototype._updateResNumElem = function() {
- if (this._response.isNg()) return
- var numElem = this.rootElement.querySelector('header .headerNumber')
- if (numElem) this._factory.updateHeaderNumClass(numElem)
- }
- ResponseView.prototype._appendAdded = function(added, propName, selector) {
- var views = added.map(ResponseView.new(this._doc))
- ;[].push.apply(this[propName], views)
- var toggled = this.rootElement.querySelector(selector)
- views.map(prop('rootElement')).forEach(toggled.appendChild.bind(toggled))
- }
- ResponseView.prototype._appendAddedChildren = function(addedChildren) {
- if (this._childResponseViews.length) {
- this._appendAdded(addedChildren, '_childResponseViews', '.children')
- }
- }
- ResponseView.prototype._appendAddedSameId = function(addedSameId) {
- if (this._sameIdResponseViews.length) {
- this._appendAdded(addedSameId, '_sameIdResponseViews', '.sameId')
- }
- }
- ResponseView.prototype._appendAddedSameKorokoro = function(addedSameKorokoro) {
- if (this._sameKorokoroResponseViews.length) {
- this._appendAdded(addedSameKorokoro, '_sameKorokoroResponseViews', '.sameKorokoro')
- }
- }
- ResponseView.prototype._getIdValElem = function() {
- return this.rootElement.querySelector('header .id .value')
- }
- ResponseView.prototype._updateIdValueElem = function() {
- this._factory.updateIdValClass(this._getIdValElem())
- }
- ResponseView.prototype._hasIdCountElem = function() {
- return Boolean(this.rootElement.querySelector('header .id .count'))
- }
- ResponseView.prototype._insertIdCountElem = function() {
- var e = this._getIdValElem()
- e.parentNode.insertBefore(this._factory.createIdCount(), e.nextSibling)
- }
- ResponseView.prototype._updateIdTotalElem = function() {
- var e = this.rootElement.querySelector('header .id .count .total')
- e.textContent = this._response.sameIdResponses.length
- }
- ResponseView.prototype._updateIdElem = function() {
- if (this._response.isNg()) return
- this._updateIdValueElem()
- if (this._hasIdCountElem()) {
- this._updateIdTotalElem()
- } else {
- this._insertIdCountElem()
- }
- }
- ResponseView.prototype._getKorokoroValueElem = function() {
- return this.rootElement.querySelector('header .korokoro .value')
- }
- ResponseView.prototype._insertKorokoroCountElem = function() {
- var e = this._getKorokoroValueElem()
- e.parentNode.insertBefore(this._factory.createKorokoroCount(), e.nextSibling)
- }
- ResponseView.prototype._updateKorokoroValueElem = function() {
- this._factory.updateKorokoroValClass(this._getKorokoroValueElem())
- }
- ResponseView.prototype._hasKorokoroCountElem = function() {
- return Boolean(this.rootElement.querySelector('header .korokoro .count'))
- }
- ResponseView.prototype._updateKorokoroTotalElem = function() {
- var totalElem = this.rootElement.querySelector('header .korokoro .count .total')
- totalElem.textContent = this._response.sameKorokoroResponses.length
- }
- ResponseView.prototype._updateKorokoroElem = function() {
- if (this._response.isNg()) return
- this._updateKorokoroValueElem()
- if (this._hasKorokoroCountElem())
- this._updateKorokoroTotalElem()
- else
- this._insertKorokoroCountElem()
- }
- ResponseView.prototype._replaceRootWithNew = function() {
- var old = this.rootElement
- this.rootElement = this._factory.createResponseElement()
- var p = old.parentNode
- if (p) p.replaceChild(this.rootElement, old)
- }
- ResponseView.prototype._destroyResponseViews = function(propName) {
- this[propName].forEach(function(v) {
- v._removeListenersFromResponse()
- v._removeListenersFromChildren()
- v._destroyAllResponseViews()
- })
- this[propName] = []
- }
- ResponseView.prototype._destroyAllResponseViews = function() {
- var propNames = [
- '_childResponseViews',
- '_sameIdResponseViews',
- '_sameKorokoroResponseViews',
- ]
- for (var n of propNames) this._destroyResponseViews(n)
- }
- ResponseView.prototype._newSubResponseViews = function(propName) {
- return this._response[propName].map(ResponseView.new(this._doc))
- }
- ResponseView.prototype._insertAfterContent = function(views, methodName) {
- var responseElems = views.map(prop('rootElement'))
- var toggledElem = this._factory[methodName](responseElems)
- var contentElem = this.rootElement.querySelector('.content')
- this.rootElement.insertBefore(toggledElem, contentElem.nextSibling)
- }
- ResponseView.prototype._destroyChildren = function() {
- this.rootElement.querySelector('.children').remove()
- this._destroyResponseViews('_childResponseViews')
- }
- ResponseView.prototype.toggleChildren = function() {
- if (this._response.children.length === 0) return
- var e = this.rootElement.querySelector('.children')
- if (e) {
- this._destroyChildren()
- } else {
- var views = this._newSubResponseViews('children')
- this._childResponseViews = views
- this._insertAfterContent(views, 'createChildrenElement')
- }
- }
- ResponseView.prototype.toggleSameId = function() {
- if (this._response.sameIdResponses.length < 2) return
- var e = this.rootElement.querySelector('.sameId')
- if (e) {
- e.remove()
- this._destroyResponseViews('_sameIdResponseViews')
- } else {
- var views = this._newSubResponseViews('sameIdResponses')
- this._sameIdResponseViews = views
- this._insertAfterContent(views, 'createSameIdElement')
- }
- }
- ResponseView.prototype.toggleSameKorokoro = function() {
- if (this._response.sameKorokoroResponses.length < 2) return
- var e = this.rootElement.querySelector('.sameKorokoro')
- if (e) {
- e.remove()
- this._destroyResponseViews('_sameKorokoroResponseViews')
- } else {
- var views = this._newSubResponseViews('sameKorokoroResponses')
- this._sameKorokoroResponseViews = views
- this._insertAfterContent(views, 'createSameKorokoroElement')
- }
- }
- ResponseView.prototype._getResponseViewByChild = function(elem, select) {
- var resViews = this._childResponseViews
- .concat(this._sameIdResponseViews)
- .concat(this._sameKorokoroResponseViews)
- for (var i = 0; i < resViews.length; i++) {
- var v = resViews[i]._getResponseViewBy(elem, select)
- if (v) return v
- }
- return null
- }
- ResponseView.prototype._getResponseViewBy = function(elem, select) {
- return select(this.rootElement) === elem
- ? this
- : this._getResponseViewByChild(elem, select)
- }
- ResponseView.prototype.getResponseViewByNumElem = function(numElem) {
- return this._getResponseViewBy(numElem, function(rootElem) {
- return rootElem.querySelector('header .headerNumber')
- })
- }
- ResponseView.prototype.getResponseViewByIdValElem = function(idValElem) {
- return this._getResponseViewBy(idValElem, function(rootElem) {
- var h = rootElem.querySelector('header')
- return h ? h.querySelector('.id .value') : null
- })
- }
- ResponseView.prototype.getResponseViewByKorokoroValElem = function(korokoroValElem) {
- return this._getResponseViewBy(korokoroValElem, function(rootElem) {
- return rootElem.querySelector('header .korokoro .value')
- })
- }
- return ResponseView
- })()
- ResponseView.Factory = (function() {
- var replaceMatchedByCreatedElem = function(textNode, regExp, createElem) {
- var document = textNode.ownerDocument
- var result = document.createDocumentFragment()
- var begin = 0
- var text = textNode.nodeValue
- for (var r; (r = regExp.exec(text));) {
- result.appendChild(document.createTextNode(text.slice(begin, r.index)))
- result.appendChild(createElem(r[0]))
- begin = regExp.lastIndex
- }
- result.appendChild(document.createTextNode(text.slice(begin)))
- result.normalize()
- return result
- }
- const hasAnchorAncestor = node => {
- for (let p = node.parentNode; p; p = p.parentNode)
- if (p.tagName === 'A')
- return true
- return false
- }
- const allTextNodesExceptInAnchor = root => {
- const d = root.ownerDocument
- const filter = {
- acceptNode(textNode) {
- return !hasAnchorAncestor(textNode)
- },
- }
- const i = d.createNodeIterator(root, NodeFilter.SHOW_TEXT, filter)
- const result = []
- let n = i.nextNode()
- while (n) {
- // document#createNodeIterator() に NodeFilter.SHOW_TEXT を渡しているのに、
- // NodeIterator#nextNode() からテキストノード以外のノードが返されてしまう。
- // テキストノードかどうかを調べることで対処する。
- // Google Chrome 60.0.3112.90(Official Build) (64 ビット)
- // Tampermonkey 4.3.6
- if (n.nodeType === Node.TEXT_NODE)
- result.push(n)
- n = i.nextNode()
- }
- return result
- }
- var replaceTextNodeIfMatched = function(node, regExp, createElem) {
- allTextNodesExceptInAnchor(node).forEach(function(textNode) {
- var newNode = replaceMatchedByCreatedElem(textNode, regExp, createElem)
- textNode.parentNode.replaceChild(newNode, textNode)
- }, this)
- return node
- }
- var setLinkType = function(link) {
- link.rel = 'noopener noreferrer'
- }
- var replaceOutsideLinkFromCushionToDirect = function(node) {
- ;[].filter.call(node.querySelectorAll('a'), function(a) {
- var c = a.textContent
- return c.startsWith('http://') || c.startsWith('https://')
- }).forEach(function(a) {
- a.href = a.textContent
- a.target = '_blank'
- setLinkType(a)
- })
- }
- var resAnchors = function(node) {
- return [].reduce.call(node.querySelectorAll('a'), function(result, a) {
- var r = /^>>(\d+)/.exec(a.textContent)
- if (r) result.push({anchor: a, responseNumber: parseInt(r[1])})
- return result
- }, [])
- }
- var replaceResAnchorWithTextNode = function(anchor) {
- var textNode = anchor.ownerDocument.createTextNode(anchor.textContent)
- anchor.parentNode.replaceChild(textNode, anchor)
- }
- var replaceUpwardResAnchorWithTextNode = function(node, responseNumber) {
- for (var resAnchor of resAnchors(node))
- if (resAnchor.responseNumber >= responseNumber)
- replaceResAnchorWithTextNode(resAnchor.anchor)
- }
- var setupResAnchorsClassAndDataset = function(node) {
- for (var resAnchor of resAnchors(node)) {
- resAnchor.anchor.classList.add('resAnchor')
- resAnchor.anchor.dataset.resNum = resAnchor.responseNumber
- }
- }
- var createLink = curry(function(document, matchedText) {
- var result = document.createElement('a')
- result.href = matchedText[0] === 'h' ? matchedText : 'h' + matchedText
- result.target = '_blank'
- setLinkType(result)
- result.textContent = matchedText
- return result
- })
- var Factory = function(document, response, root) {
- this._doc = document
- this._response = response
- this._root = root
- }
- Factory.prototype._createTotal = function(textContent) {
- var result = this._doc.createElement('span')
- result.className = 'total'
- result.textContent = textContent
- return result
- }
- Factory.prototype._createIndex = function(index) {
- return this._doc.createTextNode(`(${index + 1}/`)
- }
- Factory.prototype.updateIdValClass = function(idValElem) {
- var n = this._response.sameIdResponses.length
- var l = idValElem.classList
- if (n >= 2) l.add('sameIdExist')
- if (n >= 5) l.add('sameIdExist5')
- }
- Factory.prototype.updateKorokoroValClass = function(korokoroValElem) {
- if (this._response.sameKorokoroResponses.length >= 2)
- korokoroValElem.classList.add('sameKorokoroExist')
- }
- Factory.prototype._createVal = function(textContent) {
- var result = this._doc.createElement('span')
- result.className = 'value'
- result.textContent = textContent
- return result
- }
- Factory.prototype._createIdVal = function() {
- var result = this._createVal(this._response.id)
- this.updateIdValClass(result)
- return result
- }
- Factory.prototype._createNgButton = function(title, dataset) {
- var result = this._doc.createElement('span')
- result.className = 'ngButton'
- result.textContent = '[×]'
- result.title = title
- Object.assign(result.dataset, dataset)
- return result
- }
- Factory.prototype._createIdNgButton = function() {
- return this._createNgButton('NGID', {
- id: this._response.id,
- jstTime: this._response.jstTime,
- })
- }
- Factory.prototype._createCount = function(len, index) {
- var result = this._doc.createDocumentFragment()
- if (len >= 2) {
- var count = this._doc.createElement('span')
- count.className = 'count'
- count.appendChild(this._createIndex(index))
- count.appendChild(this._createTotal(len))
- count.appendChild(this._doc.createTextNode(')'))
- result.appendChild(count)
- }
- return result
- }
- Factory.prototype.createIdCount = function() {
- return this._createCount(this._response.sameIdResponses.length
- , this._response.getIndexOfSameIdResponses())
- }
- Factory.prototype._createId = function() {
- var result = this._doc.createDocumentFragment()
- if (this._response.id) {
- var id = this._doc.createElement('span')
- id.className = 'id'
- id.appendChild(this._createIdVal())
- id.appendChild(this.createIdCount())
- id.appendChild(this._createIdNgButton())
- result.appendChild(id)
- }
- return result
- }
- Factory.prototype.updateHeaderNumClass = function(numElem) {
- var childNum = this._response.getNoNgChildren().length
- numElem.classList[childNum >= 1 ? 'add' : 'remove']('hasChild')
- numElem.classList[childNum >= 3 ? 'add' : 'remove']('hasChild3')
- }
- Factory.prototype._createHeaderNum = function() {
- var result = this._doc.createElement('span')
- result.className = 'headerNumber'
- this.updateHeaderNumClass(result)
- result.textContent = this._response.number
- return result
- }
- Factory.prototype.createKorokoroCount = function() {
- return this._createCount(this._response.sameKorokoroResponses.length
- , this._response.getIndexOfSameKorokoroResponses())
- }
- Factory.prototype._createKorokoroVal = function() {
- var result = this._createVal(this._response.korokoro)
- this.updateKorokoroValClass(result)
- return result
- }
- Factory.prototype._createKorokoroNgButton = function() {
- return this._createNgButton('NGID(ワッチョイ)', {
- korokoro: this._response.korokoro,
- jstTime: this._response.jstTime,
- })
- }
- Factory.prototype._createKorokoro = function() {
- var result = this._doc.createElement('span')
- result.className = 'korokoro'
- result.appendChild(this._createKorokoroVal())
- result.appendChild(this.createKorokoroCount())
- result.appendChild(this._createKorokoroNgButton())
- return result
- }
- Factory.prototype._setHeaderNameWithKorokoro = function(elem) {
- var n = this._response.name
- var k = this._response.korokoro
- var i = n.indexOf(k)
- if (i === -1) {
- elem.textContent = this._response.name
- return
- }
- elem.appendChild(this._doc.createTextNode(n.slice(0, i)))
- elem.appendChild(this._createKorokoro())
- elem.appendChild(this._doc.createTextNode(n.slice(i + k.length)))
- }
- Factory.prototype._createHeaderName = function() {
- var result = this._doc.createElement('span')
- result.className = 'name'
- if (this._response.korokoro)
- this._setHeaderNameWithKorokoro(result)
- else
- result.textContent = this._response.name
- return result
- }
- Factory.prototype._getHeaderMailText = function() {
- var m = this._response.mail
- return `[${m === 'sage' ? '↓' : m}]`
- }
- Factory.prototype._createHeaderMail = function() {
- var result = this._doc.createDocumentFragment()
- if (this._response.mail) {
- var e = this._doc.createElement('span')
- e.className = 'mail'
- e.textContent = this._getHeaderMailText()
- result.appendChild(e)
- }
- return result
- }
- Factory.prototype._createHeaderTime = function() {
- var result = this._doc.createDocumentFragment()
- if (!Number.isNaN(this._response.jstTime)) {
- var datetime = this._doc.createElement('time')
- datetime.textContent = this._response.getDateTimeString()
- result.appendChild(datetime)
- }
- return result
- }
- Factory.prototype._createHeader = function() {
- var result = this._doc.createElement('header')
- result.appendChild(this._createHeaderNum())
- result.appendChild(this._createHeaderName())
- result.appendChild(this._createHeaderMail())
- result.appendChild(this._createHeaderTime())
- result.appendChild(this._createId())
- return result
- }
- Factory.prototype._createContent = function() {
- var f = this._doc.createDocumentFragment()
- this._response.contentNodes
- .map(invoke('cloneNode', [true]))
- .forEach(function(n) { f.appendChild(n) })
- replaceOutsideLinkFromCushionToDirect(f)
- replaceUpwardResAnchorWithTextNode(f, this._response.number)
- setupResAnchorsClassAndDataset(f)
- replaceTextNodeIfMatched(f, /h?ttps?:\/\/\S+/g, createLink(this._doc))
- var result = this._doc.createElement('div')
- result.className = 'content'
- if (this._response.hasAsciiArt()) result.classList.add('asciiArt')
- result.appendChild(f)
- return result
- }
- Factory.prototype.createResponseElement = function() {
- var result = this._doc.createElement('article')
- if (this._response.isNg()) {
- result.classList.add('ng')
- result.appendChild(this._createNgResponse())
- } else {
- result.appendChild(this._createHeader())
- result.appendChild(this._createContent())
- }
- if (this._root) result.id = result.dataset.id = this._response.number
- return result
- }
- Factory.prototype._createNgResponse = function() {
- var text = this._response.number + ' あぼーん'
- return this._doc.createTextNode(text)
- }
- Factory.prototype._createSubView = function(className, elements) {
- var result = this._doc.createElement('div')
- result.className = className
- elements.forEach(result.appendChild.bind(result))
- return result
- }
- Factory.prototype.createChildrenElement = function(responseElements) {
- return this._createSubView('children', responseElements)
- }
- Factory.prototype.createSameIdElement = function(responseElements) {
- return this._createSubView('sameId', responseElements)
- }
- Factory.prototype.createSameKorokoroElement = function(responseElements) {
- return this._createSubView('sameKorokoro', responseElements)
- }
- return Factory
- })()
- var TableConfigViewHeader = (function() {
- var createRemoveAllButton = function(doc) {
- var result = doc.createElement('span')
- result.className = 'removeAllButton'
- result.textContent = '[すべて削除]'
- return result
- }
- var create = function(doc, text) {
- var result = doc.createElement('h2')
- result.appendChild(doc.createTextNode(text))
- result.appendChild(createRemoveAllButton(doc))
- return result
- }
- return {create}
- })()
- var NgItemAddP = (function() {
- function NgItemAddP(doc) {
- this.doc = doc
- }
- NgItemAddP.prototype._createOption = function(value, text) {
- var result = this.doc.createElement('option')
- result.value = value
- result.textContent = text
- return result
- }
- NgItemAddP.prototype._createTargetSelect = function() {
- var result = this.doc.createElement('select')
- result.appendChild(this._createOption('thread', 'このスレッド'))
- result.appendChild(this._createOption('board', 'この板'))
- result.appendChild(this._createOption('all', '全体'))
- return result
- }
- NgItemAddP.prototype._createNgTextInput = function() {
- var result = this.doc.createElement('input')
- result.className = 'ngTextInput'
- return result
- }
- NgItemAddP.prototype._createNgWordAddButton = function() {
- var result = this.doc.createElement('input')
- result.className = 'addButton'
- result.type = 'button'
- result.value = '追加'
- return result
- }
- NgItemAddP.prototype.elem = function() {
- var result = this.doc.createElement('p')
- result.className = 'add'
- result.appendChild(this._createTargetSelect())
- result.appendChild(this._createNgTextInput())
- result.appendChild(this._createNgWordAddButton())
- return result
- }
- NgItemAddP.create = function(doc) {
- return new NgItemAddP(doc).elem()
- }
- return NgItemAddP
- })()
- var Table = (function() {
- var addTH = curry(function(row, text) {
- var doc = row.ownerDocument
- var th = doc.createElement('th')
- th.textContent = text
- row.appendChild(th)
- })
- var isNode = function(v) {
- return Boolean(v && v.nodeType)
- }
- var addCell = function(row, child) {
- var result = row.insertCell()
- if (isNode(child))
- result.appendChild(child)
- else
- result.textContent = child
- return result
- }
- var addDelCell = function(row) {
- var result = addCell(row, '削除')
- result.className = 'removeButton'
- return result
- }
- function Table(o) {
- Object.assign(this, o)
- }
- Table.create = function(o) {
- return new Table(o).elem()
- }
- Table.prototype.setTHead = function(tHead) {
- this.tHeadTexts.forEach(addTH(tHead.insertRow()))
- }
- Table.prototype.addDelCell = function(tRow, rowDataObj) {
- var c = addDelCell(tRow)
- this.setDelCellDataset(c.dataset, rowDataObj)
- }
- Table.prototype.setTRow = function(tRow, rowDataObj) {
- for (var cellChild of this.cellChildrenOf(rowDataObj, this.doc))
- addCell(tRow, cellChild)
- this.addDelCell(tRow, rowDataObj)
- }
- Table.prototype.setTBody = function(tBody) {
- this.rowDataObjs.slice().reverse().forEach(function(rowDataObj) {
- this.setTRow(tBody.insertRow(), rowDataObj)
- }, this)
- }
- Table.prototype.elem = function() {
- var result = this.doc.createElement('table')
- this.setTHead(result.createTHead())
- this.setTBody(result.createTBody())
- return result
- }
- return Table
- })()
- var ConfigView = (function() {
- var ConfigView = function(document, config) {
- this._doc = document
- this._config = config
- this.rootElement = null
- listeners.set(this._eventTypes, this)
- listeners.add(this._eventTypes, this, config)
- }
- ConfigView.prototype._eventTypes = []
- ConfigView.prototype.createRootElem = async function() {
- return this.rootElement = await this._createRootElem()
- }
- ConfigView.prototype.destroy = function() {
- this.rootElement.remove()
- listeners.remove(this._eventTypes, this, this._config)
- }
- ConfigView.prototype._createRootElem = async function() {
- var result = this._doc.createElement('div')
- result.className = 'config'
- result.appendChild(await this._createRootChild())
- return result
- }
- ConfigView.prototype._createRootChild = async function() {
- throw new Error('ConfigView#_createRootChild() must be implemented')
- }
- ConfigView.createToggle = function(document, configViewConstructor) {
- var result = document.createElement('span')
- result.className = configViewConstructor.toggleClass
- result.textContent = configViewConstructor.toggleText
- return result
- }
- return ConfigView
- })()
- var ViewConfigView = (function(_super) {
- var ViewConfigView = function(document, config) {
- _super.call(this, document, config)
- }
- ViewConfigView.toggleText = '表示'
- ViewConfigView.toggleClass = 'viewToggle'
- ViewConfigView.prototype = Object.create(_super.prototype)
- ViewConfigView.prototype.constructor = ViewConfigView
- ViewConfigView.prototype._createCenteringP = async function() {
- var checkbox = this._doc.createElement('input')
- checkbox.type = 'checkbox'
- checkbox.checked = await this._config.isPageCentering()
- var label = this._doc.createElement('label')
- label.appendChild(checkbox)
- label.appendChild(this._doc.createTextNode('ページ中央に配置'))
- var result = this._doc.createElement('p')
- result.className = 'centering'
- result.appendChild(label)
- return result
- }
- ViewConfigView.prototype._createMaxWidthP = async function() {
- var input = this._doc.createElement('input')
- input.type = 'number'
- input.valueAsNumber = await this._config.getPageMaxWidth()
- var label = this._doc.createElement('label')
- label.appendChild(this._doc.createTextNode('最大幅'))
- label.appendChild(input)
- label.appendChild(this._doc.createTextNode('px'))
- var result = this._doc.createElement('p')
- result.className = 'maxWidth'
- result.appendChild(label)
- return result
- }
- ViewConfigView.prototype._createNgVisibleP = async function() {
- var checkbox = this._doc.createElement('input')
- checkbox.type = 'checkbox'
- checkbox.checked = await this._config.isNgVisible()
- var label = this._doc.createElement('label')
- label.appendChild(checkbox)
- label.appendChild(this._doc.createTextNode('NG設定によるあぼーんを表示'))
- var result = this._doc.createElement('p')
- result.className = 'ngVisible'
- result.appendChild(label)
- return result
- }
- ViewConfigView.prototype._createRootChild = async function() {
- var h2 = this._doc.createElement('h2')
- h2.textContent = '表示'
- var result = this._doc.createElement('section')
- result.className = 'viewSection'
- result.appendChild(h2)
- result.appendChild(await this._createCenteringP())
- result.appendChild(await this._createMaxWidthP())
- result.appendChild(await this._createNgVisibleP())
- return result
- }
- ViewConfigView.prototype.isPageCenteringChecked = function() {
- return this.rootElement
- .querySelector('.viewSection .centering label input')
- .checked
- }
- ViewConfigView.prototype.isNgVisibleChecked = function() {
- return this.rootElement
- .querySelector('.viewSection .ngVisible label input')
- .checked
- }
- ViewConfigView.prototype.getPageMaxWidthValue = function() {
- return this.rootElement
- .querySelector('.viewSection .maxWidth label input')
- .valueAsNumber
- }
- return ViewConfigView
- })(ConfigView)
- var TableConfigView = (function(_super) {
- function TableConfigView(document, config) {
- _super.call(this, document, config)
- this._arrayStoreChangedListener = this._arrayStoreChanged.bind(this)
- this._getArrayStore()
- .addEventListener('changed', this._arrayStoreChangedListener)
- }
- TableConfigView.prototype = Object.create(_super.prototype)
- TableConfigView.prototype.constructor = TableConfigView
- TableConfigView.prototype.destroy = function() {
- _super.prototype.destroy.call(this)
- this._getArrayStore()
- .removeEventListener('changed', this._arrayStoreChangedListener)
- }
- TableConfigView.prototype._getTable = function() {
- return this.rootElement.querySelector('table')
- }
- TableConfigView.prototype._arrayStoreChanged = async function(array) {
- var newTable = await this._createTable(array)
- var oldTable = this._getTable()
- oldTable.parentNode.replaceChild(newTable, oldTable)
- }
- TableConfigView.prototype._getArrayStore = function() {
- throw new Error('TableConfigView#_getArrayStore() must be implemented')
- }
- TableConfigView.prototype._createTable = function() {
- throw new Error('TableConfigView#_createTable() must be implemented')
- }
- return TableConfigView
- })(ConfigView)
- var NgIdConfigView = (function(_super) {
- var NgIdConfigView = function(document, config) {
- _super.call(this, document, config)
- }
- NgIdConfigView.toggleText = 'NGID'
- NgIdConfigView.toggleClass = 'ngIdToggle'
- NgIdConfigView.prototype = Object.create(_super.prototype)
- NgIdConfigView.prototype.constructor = NgIdConfigView
- NgIdConfigView.prototype._getArrayStore = function() {
- return this._config.ngIds
- }
- NgIdConfigView.prototype._createTable = async function(ngIds) {
- var tHeadTexts = ['板', '有効日', 'ID', '']
- var rowDataObjs = ngIds || await this._config.ngIds.get()
- var cellChildrenOf = function(ngId) {
- return [ngId.boardId, ngId.getActiveDateString(), ngId.id]
- }
- var setDelCellDataset = function(dataset, ngId) {
- dataset.boardId = ngId.boardId
- dataset.activeDate = ngId.activeDate
- dataset.id = ngId.id
- }
- return Table.create({
- doc: this._doc,
- tHeadTexts,
- rowDataObjs,
- cellChildrenOf,
- setDelCellDataset,
- })
- }
- NgIdConfigView.prototype._createRootChild = async function() {
- var result = this._doc.createElement('section')
- result.className = 'ngIdSection'
- result.appendChild(TableConfigViewHeader.create(this._doc, 'NGID'))
- result.appendChild(await this._createTable())
- return result
- }
- return NgIdConfigView
- })(TableConfigView)
- var NgKorokoroConfigView = (function(_super) {
- var NgKorokoroConfigView = function(document, config) {
- _super.call(this, document, config)
- }
- NgKorokoroConfigView.toggleText = 'NGID(ワッチョイ)'
- NgKorokoroConfigView.toggleClass = 'ngKorokoroToggle'
- NgKorokoroConfigView.prototype = Object.create(_super.prototype)
- NgKorokoroConfigView.prototype.constructor = NgKorokoroConfigView
- NgKorokoroConfigView.prototype._getArrayStore = function() {
- return this._config.ngKorokoros
- }
- NgKorokoroConfigView.prototype._createTable = async function(ngKorokoros) {
- var tHeadTexts = ['板', '有効期間', 'ID', '']
- var rowDataObjs = ngKorokoros || await this._getArrayStore().get()
- var cellChildrenOf = function(ngKorokoro) {
- return [
- ngKorokoro.boardId,
- ngKorokoro.getAvailablePeriodString(),
- ngKorokoro.korokoro,
- ]
- }
- var setDelCellDataset = function(dataset, ngKorokoro) {
- dataset.boardId = ngKorokoro.boardId
- dataset.startOfAvailablePeriod = ngKorokoro.startOfAvailablePeriod
- dataset.korokoro = ngKorokoro.korokoro
- }
- return Table.create({
- doc: this._doc,
- tHeadTexts,
- rowDataObjs,
- cellChildrenOf,
- setDelCellDataset,
- })
- }
- NgKorokoroConfigView.prototype._createRootChild = async function() {
- var result = this._doc.createElement('section')
- result.className = 'ngKorokoroSection'
- result.appendChild(TableConfigViewHeader.create(this._doc, 'NGID(ワッチョイ)'))
- result.appendChild(await this._createTable())
- return result
- }
- return NgKorokoroConfigView
- })(TableConfigView)
- var BoundableNgItemConfigView = (function(_super) {
- var BoundableNgItemConfigView = function(document, config) {
- _super.call(this, document, config)
- }
- BoundableNgItemConfigView.prototype = Object.create(_super.prototype)
- BoundableNgItemConfigView.prototype.constructor = BoundableNgItemConfigView
- BoundableNgItemConfigView.prototype._createTable = async function(boundableNgItems) {
- var tHeadTexts = ['板', 'スレッド', this._getHeaderText(), '']
- var rowDataObjs = boundableNgItems || (await this._getArrayStore().get())
- var cellChildrenOf = function(ngItem) {
- return [ngItem.boardId, ngItem.threadNumber, this._getNgValueOf(ngItem)]
- }.bind(this)
- var setDelCellDataset = function(dataset, ngItem) {
- if (ngItem.boardId) dataset.boardId = ngItem.boardId
- if (ngItem.threadNumber) dataset.threadNumber = ngItem.threadNumber
- this._setNgValueToDataset(this._getNgValueOf(ngItem), dataset)
- }.bind(this)
- return Table.create({
- doc: this._doc,
- tHeadTexts,
- rowDataObjs,
- cellChildrenOf,
- setDelCellDataset,
- })
- }
- BoundableNgItemConfigView.prototype._createRootChild = async function() {
- var result = this._doc.createElement('section')
- result.className = this._getSectionClassName()
- result.appendChild(TableConfigViewHeader.create(this._doc, this._getHeaderText()))
- result.appendChild(NgItemAddP.create(this._doc))
- result.appendChild(await this._createTable())
- return result
- }
- BoundableNgItemConfigView.prototype._getNgTextInput = function() {
- return this.rootElement.querySelector('.add .ngTextInput')
- }
- BoundableNgItemConfigView.prototype.getNgTextInputValue = function() {
- return this._getNgTextInput().value.trim()
- }
- BoundableNgItemConfigView.prototype.clearNgTextInputValue = function() {
- this._getNgTextInput().value = ''
- }
- BoundableNgItemConfigView.prototype.getNgItemAddTarget = function() {
- return this.rootElement.querySelector('.add select').value
- }
- BoundableNgItemConfigView.prototype._getNgValueOf = function() {
- throw new Error('BoundableNgItemConfigView#_getNgValueOf(boundableNgItem) must be implemented')
- }
- BoundableNgItemConfigView.prototype._setNgValueToDataset = function() {
- throw new Error('BoundableNgItemConfigView#_setNgValueToDataset(ngValue, dataset) must be implemented')
- }
- BoundableNgItemConfigView.prototype._getSectionClassName = function() {
- throw new Error('BoundableNgItemConfigView#_getSectionClassName() must be implemented')
- }
- BoundableNgItemConfigView.prototype._getHeaderText = function() {
- throw new Error('BoundableNgItemConfigView#_getHeaderText() must be implemented')
- }
- return BoundableNgItemConfigView
- })(TableConfigView)
- var NgWordConfigView = (function(_super) {
- var NgWordConfigView = function(document, config) {
- _super.call(this, document, config)
- }
- NgWordConfigView.toggleText = 'NGワード'
- NgWordConfigView.toggleClass = 'ngWordToggle'
- NgWordConfigView.prototype = Object.create(_super.prototype)
- NgWordConfigView.prototype.constructor = NgWordConfigView
- NgWordConfigView.prototype._getArrayStore = function() {
- return this._config.ngWords
- }
- NgWordConfigView.prototype._getNgValueOf = function(ngWord) {
- return ngWord.ngWord
- }
- NgWordConfigView.prototype._setNgValueToDataset = function(ngValue, dataset) {
- dataset.ngWord = ngValue
- }
- NgWordConfigView.prototype._getSectionClassName = function() {
- return 'ngWordSection'
- }
- NgWordConfigView.prototype._getHeaderText = function() {
- return 'NGワード'
- }
- return NgWordConfigView
- })(BoundableNgItemConfigView)
- var NgNameConfigView = (function(_super) {
- var NgNameConfigView = function(document, config) {
- _super.call(this, document, config)
- }
- NgNameConfigView.toggleText = 'NGName'
- NgNameConfigView.toggleClass = 'ngNameToggle'
- NgNameConfigView.prototype = Object.create(_super.prototype)
- NgNameConfigView.prototype.constructor = NgNameConfigView
- NgNameConfigView.prototype._getArrayStore = function() {
- return this._config.ngNames
- }
- NgNameConfigView.prototype._getNgValueOf = function(ngName) {
- return ngName.ngName
- }
- NgNameConfigView.prototype._setNgValueToDataset = function(ngValue, dataset) {
- dataset.ngName = ngValue
- }
- NgNameConfigView.prototype._getSectionClassName = function() {
- return 'ngNameSection'
- }
- NgNameConfigView.prototype._getHeaderText = function() {
- return 'NGName'
- }
- return NgNameConfigView
- })(BoundableNgItemConfigView)
- var NgIdTailConfigView = (function(_super) {
- var NgIdTailConfigView = function(document, config) {
- _super.call(this, document, config)
- }
- NgIdTailConfigView.toggleText = 'NGID(末尾)'
- NgIdTailConfigView.toggleClass = 'ngIdTailToggle'
- NgIdTailConfigView.prototype = Object.create(_super.prototype)
- NgIdTailConfigView.prototype.constructor = NgIdTailConfigView
- NgIdTailConfigView.prototype._getArrayStore = function() {
- return this._config.ngIdTails
- }
- NgIdTailConfigView.prototype._getNgValueOf = function(ngIdTail) {
- return ngIdTail.ngIdTail
- }
- NgIdTailConfigView.prototype._setNgValueToDataset = function(ngValue, dataset) {
- dataset.ngIdTail = ngValue
- }
- NgIdTailConfigView.prototype._getSectionClassName = function() {
- return 'ngIdTailSection'
- }
- NgIdTailConfigView.prototype._getHeaderText = function() {
- return 'NGID(末尾)'
- }
- return NgIdTailConfigView
- })(BoundableNgItemConfigView)
- var NgSlipConfigView = (function(_super) {
- var textOf = function(type) {
- switch (type) {
- case 'id': return 'ID'
- case 'korokoro': return 'ID(ワッチョイ)'
- default: throw new TypeError(String(type))
- }
- }
- var createOption = function(doc, value, text) {
- var result = doc.createElement('option')
- result.value = value
- result.textContent = text
- return result
- }
- var createTypeSelect = function(doc) {
- var result = doc.createElement('select')
- result.className = 'type'
- result.appendChild(createOption(doc, 'korokoro', 'ID(ワッチョイ)'))
- result.appendChild(createOption(doc, 'id', 'ID'))
- return result
- }
- var createTargetSelect = function(doc) {
- var result = doc.createElement('select')
- result.className = 'target'
- result.appendChild(createOption(doc, 'thread', 'このスレッド'))
- result.appendChild(createOption(doc, 'board', 'この板'))
- return result
- }
- var createAddButton = function(doc) {
- var result = doc.createElement('input')
- result.className = 'addButton'
- result.type = 'button'
- result.value = 'NG'
- return result
- }
- var createInput = function(doc) {
- var result = doc.createElement('p')
- result.className = 'add'
- result.appendChild(createTargetSelect(doc))
- result.appendChild(doc.createTextNode('内で'))
- result.appendChild(createTypeSelect(doc))
- result.appendChild(doc.createTextNode('を持たないレスを'))
- result.appendChild(createAddButton(doc))
- return result
- }
- var NgSlipConfigView = function(document, config) {
- _super.call(this, document, config)
- }
- NgSlipConfigView.toggleText = 'NGSlip'
- NgSlipConfigView.toggleClass = 'ngSlipToggle'
- NgSlipConfigView.prototype = Object.create(_super.prototype)
- NgSlipConfigView.prototype.constructor = NgSlipConfigView
- NgSlipConfigView.prototype._getArrayStore = function() {
- return this._config.ngSlips
- }
- NgSlipConfigView.prototype._createTable = async function(ngSlips) {
- var tHeadTexts = ['板', 'スレッド', '対象', '']
- var rowDataObjs = ngSlips || await this._getArrayStore().get()
- var cellChildrenOf = function(ngSlip) {
- return [ngSlip.boardId, ngSlip.threadNumber, textOf(ngSlip.type)]
- }
- var setDelCellDataset = function(dataset, ngSlip) {
- dataset.boardId = ngSlip.boardId
- if (ngSlip.threadNumber) dataset.threadNumber = ngSlip.threadNumber
- dataset.type = ngSlip.type
- }
- return Table.create({
- doc: this._doc,
- tHeadTexts,
- rowDataObjs,
- cellChildrenOf,
- setDelCellDataset,
- })
- }
- NgSlipConfigView.prototype._createRootChild = async function() {
- var result = this._doc.createElement('section')
- result.className = 'ngSlipSection'
- result.appendChild(TableConfigViewHeader.create(this._doc, 'NGSlip'))
- result.appendChild(createInput(this._doc))
- result.appendChild(await this._createTable())
- return result
- }
- NgSlipConfigView.prototype.getNgItemAddTarget = function() {
- return this.rootElement.querySelector('.target').value
- }
- NgSlipConfigView.prototype.getNgSlipType = function() {
- return this.rootElement.querySelector('.type').value
- }
- return NgSlipConfigView
- })(TableConfigView)
- var NgConfigView = (function(_super) {
- function NgConfigView(document, config) {
- _super.call(this, document, config)
- this.configView = null
- }
- NgConfigView.toggleText = 'NG設定'
- NgConfigView.toggleClass = 'ngToggle'
- NgConfigView.prototype = Object.create(_super.prototype)
- NgConfigView.prototype.constructor = NgConfigView
- NgConfigView.prototype.destroy = function() {
- _super.prototype.destroy.call(this)
- if (this.configView) this.configView.destroy()
- }
- NgConfigView.prototype._createRootChild = function() {
- var ngToggleBar = this._doc.createElement('div')
- ngToggleBar.className = 'ngToggleBar'
- ;[ NgWordConfigView,
- NgNameConfigView,
- NgIdConfigView,
- NgKorokoroConfigView,
- NgIdTailConfigView,
- NgSlipConfigView,
- ].forEach(function(constructor) {
- var toggle = ConfigView.createToggle(this._doc, constructor)
- ngToggleBar.appendChild(toggle)
- }, this)
- var result = this._doc.createElement('section')
- result.className = 'ngSection'
- result.appendChild(ngToggleBar)
- return result
- }
- NgConfigView.prototype._addConfigViewOf = async function(constructor) {
- this.configView = new constructor(this._doc, this._config)
- this.rootElement
- .querySelector('.ngSection')
- .appendChild(await this.configView.createRootElem())
- var toggle = this.rootElement
- .querySelector(`.ngToggleBar .${constructor.toggleClass}`)
- toggle.textContent = constructor.toggleText
- toggle.classList.add('isSelected')
- }
- NgConfigView.prototype._deleteConfigView = function() {
- this.configView.destroy()
- var toggle = this.rootElement
- .querySelector(`.ngToggleBar .${this.configView.constructor.toggleClass}`)
- toggle.textContent = this.configView.constructor.toggleText
- toggle.classList.remove('isSelected')
- this.configView = null
- }
- NgConfigView.prototype._toggleConfigViewOf = async function(constructor) {
- if (this.configView) {
- var replace = !(this.configView instanceof constructor)
- this._deleteConfigView()
- if (replace) {
- await this._addConfigViewOf(constructor)
- }
- } else {
- await this._addConfigViewOf(constructor)
- }
- }
- NgConfigView.prototype.toggleNgWordConfig = async function() {
- await this._toggleConfigViewOf(NgWordConfigView)
- }
- NgConfigView.prototype.toggleNgNameConfig = async function() {
- await this._toggleConfigViewOf(NgNameConfigView)
- }
- NgConfigView.prototype.toggleNgIdConfig = async function() {
- await this._toggleConfigViewOf(NgIdConfigView)
- }
- NgConfigView.prototype.toggleNgKorokoroConfig = async function() {
- await this._toggleConfigViewOf(NgKorokoroConfigView)
- }
- NgConfigView.prototype.toggleNgIdTailConfig = async function() {
- await this._toggleConfigViewOf(NgIdTailConfigView)
- }
- NgConfigView.prototype.toggleNgSlipConfig = async function() {
- await this._toggleConfigViewOf(NgSlipConfigView)
- }
- NgConfigView.prototype.getNgTextInputValue = function() {
- return this.configView.getNgTextInputValue()
- }
- NgConfigView.prototype.clearNgTextInputValue = function() {
- this.configView.clearNgTextInputValue()
- }
- NgConfigView.prototype.getNgItemAddTarget = function() {
- return this.configView.getNgItemAddTarget()
- }
- NgConfigView.prototype.getNgSlipType = function() {
- return this.configView.getNgSlipType()
- }
- return NgConfigView
- })(ConfigView)
- var ThreadHistoryConfigView = (function(_super) {
- var ThreadHistoryConfigView = function(document, config) {
- _super.call(this, document, config)
- }
- ThreadHistoryConfigView.toggleText = '履歴'
- ThreadHistoryConfigView.toggleClass = 'threadHistoryToggle'
- ThreadHistoryConfigView.prototype = Object.create(_super.prototype)
- ThreadHistoryConfigView.prototype.constructor = ThreadHistoryConfigView
- ThreadHistoryConfigView.prototype._getArrayStore = function() {
- return this._config.threadHistories
- }
- ThreadHistoryConfigView.prototype._createTable = async function(threadHistories) {
- var tHeadTexts = ['タイトル', 'レス', '']
- var rowDataObjs = threadHistories || await this._getArrayStore().get()
- var cellChildrenOf = function(threadHistory, doc) {
- var a = doc.createElement('a')
- a.href = threadHistory.url
- a.textContent = threadHistory.title
- return [a, threadHistory.resNum]
- }
- var setDelCellDataset = function(dataset, threadHistory) {
- dataset.url = threadHistory.url
- dataset.title = threadHistory.title
- dataset.resNum = threadHistory.resNum
- }
- return Table.create({
- doc: this._doc,
- tHeadTexts,
- rowDataObjs,
- cellChildrenOf,
- setDelCellDataset,
- })
- }
- ThreadHistoryConfigView.prototype._createRootChild = async function() {
- var result = this._doc.createElement('section')
- result.className = 'threadHistorySection'
- result.appendChild(TableConfigViewHeader.create(this._doc, '履歴'))
- result.appendChild(await this._createTable())
- return result
- }
- return ThreadHistoryConfigView
- })(TableConfigView)
- var ThreadView = (function() {
- var createTopBar = function(document) {
- var createToggle = ConfigView.createToggle
- var result = document.createElement('div')
- result.className = 'topBar'
- result.appendChild(createToggle(document, NgConfigView))
- result.appendChild(createToggle(document, ViewConfigView))
- result.appendChild(createToggle(document, ThreadHistoryConfigView))
- return result
- }
- var createBottomBar = function(document) {
- var reloadButton = document.createElement('input')
- reloadButton.type = 'button'
- reloadButton.value = '新着レスの取得'
- reloadButton.className = 'reloadButton'
- var reloadMessage = document.createElement('span')
- reloadMessage.className = 'reloadMessage'
- var result = document.createElement('div')
- result.className = 'bottomBar'
- result.appendChild(reloadButton)
- result.appendChild(reloadMessage)
- return result
- }
- var createRoot = function(document) {
- var main = document.createElement('div')
- main.className = 'main'
- var result = document.createElement('div')
- result.className = 'threadView'
- result.appendChild(createTopBar(document))
- result.appendChild(main)
- result.appendChild(createBottomBar(document))
- return result
- }
- var ThreadView = function(document, thread) {
- this.doc = document
- this._thread = thread
- this.rootElement = createRoot(document)
- this._responseViews = []
- this.configView = null
- this.responsePostForm = null
- thread.addEventListener('responsesAdded', this._responsesAdded.bind(this))
- thread.config.addEventListener('pageCenteringChanged'
- , this.setPageCentering.bind(this))
- thread.config.addEventListener('pageMaxWidthChanged'
- , this._updateStyle.bind(this))
- thread.config.addEventListener('ngVisibleChanged'
- , this._updateStyle.bind(this))
- }
- ThreadView.prototype.getReloadButton = function() {
- return this.rootElement.querySelector('.reloadButton')
- }
- ThreadView.prototype.getReloadMessageElement = function() {
- return this.rootElement.querySelector('.reloadMessage')
- }
- ThreadView.prototype._getTopBar = function() {
- return this.rootElement.querySelector('.topBar')
- }
- ThreadView.prototype.replace = function(threadRootElement) {
- var p = threadRootElement.parentNode
- p.replaceChild(this.rootElement, threadRootElement)
- }
- ThreadView.prototype.disableReload = function() {
- this.rootElement.querySelector('.bottomBar').remove()
- }
- ThreadView.prototype._createResponseViews = function(responses) {
- return responses.map(function(r) {
- return new ResponseView(this.doc, r, true)
- }, this)
- }
- ThreadView.prototype._getMainElement = function() {
- return this.rootElement.querySelector('.main')
- }
- ThreadView.prototype._addResponseViewsToMainElement = function(views) {
- var main = this._getMainElement()
- views.map(prop('rootElement')).forEach(main.appendChild.bind(main))
- }
- ThreadView.prototype._getNewResponseBar = function() {
- return this.rootElement.querySelector('#new')
- }
- ThreadView.prototype._removeNewResponseBar = function() {
- var e = this._getNewResponseBar()
- if (e) e.remove()
- }
- ThreadView.prototype._addNewResponseBarIfRequired = function() {
- var newResCount = this._thread.newResCount
- if (newResCount === 0) return
- const newResBarText = this.doc.createElement('p')
- newResBarText.textContent = `${newResCount} 件の新着レス`
- var newResBar = this.doc.createElement('div')
- newResBar.id = 'new'
- newResBar.appendChild(newResBarText)
- var views = this._responseViews
- var e = views[views.length - newResCount].rootElement
- e.parentNode.insertBefore(newResBar, e)
- }
- ThreadView.prototype._scrollToNewResponseBar = function() {
- if (!this._getNewResponseBar()) return
- this.doc.location.hash = ''
- this.doc.location.hash = '#new'
- }
- ThreadView.prototype._responsesAdded = function(addedResponses) {
- var views = this._createResponseViews(addedResponses)
- ;[].push.apply(this._responseViews, views)
- this._addResponseViewsToMainElement(views)
- this._removeNewResponseBar()
- this._addNewResponseBarIfRequired()
- this._scrollToNewResponseBar()
- }
- ThreadView.prototype._toggleSubView = function(getView, toggle) {
- for (var i = 0; i < this._responseViews.length; i++) {
- var v = getView(this._responseViews[i])
- if (v) {
- toggle(v)
- break
- }
- }
- }
- ThreadView.prototype.toggleResponseChildren = function(numElem) {
- this._toggleSubView(invoke('getResponseViewByNumElem', [numElem])
- , invoke('toggleChildren', []))
- }
- ThreadView.prototype.toggleSameIdResponses = function(idValElem) {
- this._toggleSubView(invoke('getResponseViewByIdValElem', [idValElem])
- , invoke('toggleSameId', []))
- }
- ThreadView.prototype.toggleSameKorokoroResponses = function(korokoroValElem) {
- this._toggleSubView(invoke('getResponseViewByKorokoroValElem', [korokoroValElem])
- , invoke('toggleSameKorokoro', []))
- }
- ThreadView.prototype._removeConfigView = function(constructor) {
- var v = this.configView
- if (!v) return true
- this.configView = null
- v.destroy()
- var toggle = this.rootElement
- .querySelector(`.topBar .${v.constructor.toggleClass}`)
- toggle.textContent = v.constructor.toggleText
- toggle.classList.remove('isSelected')
- return !(v instanceof constructor)
- }
- ThreadView.prototype._addConfigView = async function(constructor) {
- this.configView = new constructor(this.doc, this._thread.config)
- this._getTopBar().appendChild(await this.configView.createRootElem())
- var toggle = this.rootElement
- .querySelector(`.topBar .${constructor.toggleClass}`)
- toggle.textContent = constructor.toggleText
- toggle.classList.add('isSelected')
- }
- ThreadView.prototype._toggleConfig = async function(constructor) {
- if (this._removeConfigView(constructor)) await this._addConfigView(constructor)
- }
- ThreadView.prototype.toggleNgConfig = async function() {
- await this._toggleConfig(NgConfigView)
- }
- ThreadView.prototype.toggleViewConfig = async function() {
- await this._toggleConfig(ViewConfigView)
- }
- ThreadView.prototype.toggleNgWordConfig = function() {
- if (!(this.configView instanceof NgConfigView)) throw new Error()
- this.configView.toggleNgWordConfig()
- }
- ThreadView.prototype.toggleNgNameConfig = function() {
- if (!(this.configView instanceof NgConfigView)) throw new Error()
- this.configView.toggleNgNameConfig()
- }
- ThreadView.prototype.toggleNgIdConfig = function() {
- if (!(this.configView instanceof NgConfigView)) throw new Error()
- this.configView.toggleNgIdConfig()
- }
- ThreadView.prototype.toggleNgKorokoroConfig = function() {
- if (!(this.configView instanceof NgConfigView)) throw new Error()
- this.configView.toggleNgKorokoroConfig()
- }
- ThreadView.prototype.toggleNgIdTailConfig = function() {
- if (!(this.configView instanceof NgConfigView)) throw new Error()
- this.configView.toggleNgIdTailConfig()
- }
- ThreadView.prototype.toggleNgSlipConfig = function() {
- if (!(this.configView instanceof NgConfigView)) throw new Error()
- this.configView.toggleNgSlipConfig()
- }
- ThreadView.prototype.toggleThreadHistoryConfig = async function() {
- await this._toggleConfig(ThreadHistoryConfigView)
- }
- ThreadView.prototype.close = function() {
- if (this.responsePostForm) this.responsePostForm.remove()
- this.responsePostForm = null
- this.disableReload()
- }
- ThreadView.prototype.setPageCentering = function(pageCentering) {
- var methodName = pageCentering ? 'add' : 'remove'
- this.doc.documentElement.classList[methodName]('centering')
- }
- ThreadView.prototype.addStyle = async function() {
- var e = this.doc.createElement('style')
- e.id = 'threadViewerStyle'
- e.textContent = await this._getStyleText()
- this.doc.head.appendChild(e)
- }
- ThreadView.prototype._updateStyle = async function() {
- this.doc.getElementById('threadViewerStyle')
- .textContent = await this._getStyleText()
- }
- ThreadView.prototype._getNgVisibleStyle = async function() {
- return await this._thread.config.isNgVisible()
- ? ''
- : '.threadView .main article.ng { display: none; }'
- }
- ThreadView.prototype._getStyleText = async function() {
- return `
- body {
- font-family: initial;
- font-size: initial;
- line-height: initial;
- color: initial;
- background-color: rgb(239, 239, 239);
- margin: 8px;
- }
- .navbar-fixed-top, .navbar-fixed-bottom {
- position: absolute;
- }
- .container_body {
- min-width: initial;
- left: initial;
- position: initial;
- width: initial;
- max-width: initial;
- margin-right: initial;
- margin-left: initial;
- padding-left: initial;
- padding-right: initial;
- background: initial;
- }
- .escaped {
- background-color: rgb(239, 239, 239);
- }
- html.centering {
- max-width: ${await this._thread.config.getPageMaxWidth()}px;
- margin: 0 auto;
- }
- .threadView,
- .post_hover {
- line-height: 1.5em;
- }
- .threadView .topBar {
- position: sticky;
- top: -1px;
- background-color: rgb(239, 239, 239);
- }
- ${await this._getNgVisibleStyle()}
- .threadView .main article header,
- .threadView .topBar .config table .removeButton,
- .threadView .topBar .config .threadHistorySection table th:nth-child(2),
- .threadView .main article header time,
- .threadView .main article header .id {
- white-space: nowrap;
- }
- .threadView .main article header .name,
- .post_hover header .name {
- color: green;
- font-weight: bold;
- }
- .threadView .topBar .ngToggle,
- .threadView .topBar .ngWordToggle,
- .threadView .topBar .ngNameToggle,
- .threadView .topBar .ngIdToggle,
- .threadView .topBar .ngKorokoroToggle,
- .threadView .topBar .ngIdTailToggle,
- .threadView .topBar .ngSlipToggle,
- .threadView .topBar .viewToggle,
- .threadView .topBar .threadHistoryToggle {
- margin-right: 0.5em;
- display: inline-block;
- height: 1.5em;
- }
- .threadView .main article header .name,
- .threadView .main article header time,
- .threadView .main article header .id,
- .post_hover header .name,
- .post_hover header time,
- .post_hover header .id {
- margin-left: 0.5em;
- }
- .threadView .main article header .headerNumber.hasChild,
- .threadView .main article header .id .value.sameIdExist,
- .threadView .main article header .id .ngButton,
- .threadView .main article header .korokoro .value.sameKorokoroExist,
- .threadView .main article header .korokoro .ngButton,
- .threadView .topBar .ngToggle,
- .threadView .topBar .viewToggle,
- .threadView .topBar .ngIdToggle,
- .threadView .topBar .ngWordToggle,
- .threadView .topBar .ngNameToggle,
- .threadView .topBar .ngKorokoroToggle,
- .threadView .topBar .ngIdTailToggle,
- .threadView .topBar .ngSlipToggle,
- .threadView .topBar .threadHistoryToggle,
- .threadView .topBar .config h2 .removeAllButton,
- .threadView .topBar .config table .removeButton {
- cursor: pointer;
- text-decoration: underline;
- }
- .threadView .topBar .ngToggle.isSelected,
- .threadView .topBar .viewToggle.isSelected,
- .threadView .topBar .ngIdToggle.isSelected,
- .threadView .topBar .ngWordToggle.isSelected,
- .threadView .topBar .ngNameToggle.isSelected,
- .threadView .topBar .ngKorokoroToggle.isSelected,
- .threadView .topBar .ngIdTailToggle.isSelected,
- .threadView .topBar .ngSlipToggle.isSelected,
- .threadView .topBar .threadHistoryToggle.isSelected {
- background-color: black;
- color: white;
- }
- .threadView .main article header .headerNumber.hasChild3,
- .threadView .main article header .id .value.sameIdExist5 {
- font-weight: bold;
- color: red;
- }
- .threadView .main article .content,
- .post_hover .content {
- margin: 0 0 1em 1em;
- }
- .threadView .main article .content a,
- .post_hover .content a {
- color: blue;
- text-decoration: underline !important;
- }
- .threadView .main article .content a:visited,
- .post_hover .content a:visited {
- color: purple;
- }
- .threadView .main article .content.asciiArt,
- .post_hover .content.asciiArt {
- white-space: nowrap;
- /* https://ja.wikipedia.org/wiki/アスキーアート */
- font-family: IPAMonaPGothic, "IPA モナー Pゴシック", Monapo, Mona, "MS PGothic", "MS Pゴシック", sans-serif;
- font-size: 16px;
- line-height: 18px;
- }
- .threadView .main article .sameId,
- .threadView .main article .children,
- .threadView .main article .sameKorokoro {
- border-top: solid black thin;
- border-left: solid black thin;
- padding: 5px 0 0 5px;
- }
- .post_hover header .id .ngButton,
- .post_hover header .korokoro .ngButton,
- .post_hover .sameId,
- .post_hover .children,
- .post_hover .sameKorokoro {
- display: none;
- }
- .threadView .main article .sameId > article > header .id .value,
- .threadView .main article .sameKorokoro > article > header .korokoro .value {
- color: black;
- background-color: yellow;
- }
- .threadView .main article.ng,
- .threadView .main article header .name,
- .threadView .main article header .mail,
- .threadView .main article header time,
- .threadView .main article header .id,
- .post_hover header .name,
- .post_hover header .mail,
- .post_hover header time,
- .post_hover header .id,
- .threadView .topBar .config h2 .removeAllButton {
- font-size: smaller;
- }
- .threadView .topBar .config {
- border: solid black thin;
- padding: 0 0.5em;
- }
- .threadView .topBar .config h2 {
- font-size: medium;
- }
- .threadView .topBar .config table {
- border-collapse: collapse;
- }
- .threadView .topBar .config table th,
- .threadView .topBar .config table td {
- border: solid thin black;
- line-height: 1.5em;
- padding: 0 0.5em;
- }
- .threadView .topBar .config .ngWordSection table td:nth-child(3),
- .threadView .topBar .config .ngNameSection table td:nth-child(3),
- .threadView .topBar .config .threadHistorySection table td:nth-child(1) {
- word-break: break-all;
- }
- .threadView .topBar .config .threadHistorySection table td:nth-child(2) {
- text-align: right;
- }
- .threadView .topBar .config .viewSection .maxWidth {
- margin-left: 2em;
- }
- .threadView .bottomBar {
- padding: 1em 0;
- }
- .postTarget {
- width: 100%;
- }
- .postTarget.loading {
- display: none;
- }
- #new {
- padding-top: 3em;
- }
- #new > p {
- background-color: lightblue;
- padding-left: 0.5em;
- }
- .threadView .topBar .config .threadHistorySection a:link,
- .threadView .topBar .config .threadHistorySection a:visited {
- color: black;
- text-decoration: none;
- }
- .threadView .topBar .config .threadHistorySection a:hover {
- color: purple;
- text-decoration: underline;
- }
- .threadView .topBar .viewToggle.isSelected ~ .config,
- .threadView .topBar .threadHistoryToggle.isSelected ~ .config {
- max-height: calc(90vh - 1.5em);
- overflow: auto;
- }
- .threadView .topBar .ngToggle.isSelected ~ .config .ngSection .config {
- max-height: calc(90vh - 1.5em - 1.5em);
- overflow: auto;
- }
- `
- }
- return ThreadView
- })()
- var ResponsePostForm = (function(_super) {
- var ResponsePostForm = function(form) {
- _super.call(this)
- this._form = this._initForm(form)
- this._progress = this._createProgress()
- this._target = null
- }
- ResponsePostForm.prototype = Object.create(_super.prototype)
- ResponsePostForm.prototype._initForm = function(form) {
- form.target = 'postTarget'
- form.addEventListener('submit', this._formSubmitted.bind(this))
- return form
- }
- ResponsePostForm.prototype._getDoc = function() {
- return this._form.ownerDocument
- }
- ResponsePostForm.prototype._createProgress = function() {
- var result = this._getDoc().createElement('p')
- result.textContent = '書き込み中...'
- return result
- }
- ResponsePostForm.prototype._insertProgress = function() {
- var f = this._form
- f.parentNode.insertBefore(this._progress, f.nextSibling)
- }
- ResponsePostForm.prototype._createTarget = function() {
- var result = this._getDoc().createElement('iframe')
- result.name = this._form.target
- result.className = 'postTarget loading'
- result.addEventListener('load', this._targetLoaded.bind(this))
- return result
- }
- ResponsePostForm.prototype._hideOrCreateTarget = function() {
- if (this._target) {
- this._target.classList.add('loading')
- } else {
- this._target = this._createTarget()
- var p = this._progress
- p.parentNode.insertBefore(this._target, p.nextSibling)
- }
- }
- ResponsePostForm.prototype._formSubmitted = function() {
- this._form.submit.disabled = true
- this._insertProgress()
- this._hideOrCreateTarget()
- }
- ResponsePostForm.prototype._getTargetLocation = function() {
- return this._target.contentDocument.location.toString()
- }
- ResponsePostForm.prototype._isPostDone = function() {
- return this._target.contentDocument.title.indexOf('書きこみました') >= 0
- }
- ResponsePostForm.prototype._targetLoaded = function() {
- if (this._getTargetLocation() === 'about:blank') return
- this._form.submit.disabled = false
- this._progress.remove()
- if (this._isPostDone()) {
- this._target.remove()
- this._target = null
- this._form.MESSAGE.value = ''
- this.fireEvent('postDone')
- } else {
- this._target.classList.remove('loading')
- }
- }
- ResponsePostForm.prototype.remove = function() {
- ;[this._form, this._progress, this._target]
- .filter(Boolean)
- .forEach(invoke('remove', []))
- }
- return ResponsePostForm
- })(Observable)
- var ThreadController = (function() {
- var ThreadController = function(thread, threadView) {
- this.thread = thread
- this.threadView = threadView
- }
- ThreadController.prototype.addCallback = function() {
- var r = this.threadView.rootElement
- r.addEventListener('click', this.callback.bind(this))
- r.addEventListener('keydown', this.keydownCallback.bind(this))
- r.addEventListener('change', this.changeCallback.bind(this))
- }
- ThreadController.prototype._getBaseURL = function() {
- const l = this.threadView.doc.location
- const p = l.pathname
- return `${l.protocol}//${l.host}${p.slice(0, p.lastIndexOf('/') + 1)}`
- }
- ThreadController.prototype.requestNewResponses = function() {
- this.threadView.getReloadButton().disabled = true
- this.threadView.getReloadMessageElement().textContent = ''
- var _this = this
- new ResponseRequest()
- .send(this._getBaseURL()
- , this.thread.getLastResponseNumber() + 1)
- .then(function(result) {
- _this.thread.addResponses(result.responses.map(Response.of))
- if (result.threadClosed) _this.threadView.close()
- })
- .catch(function(error) {
- _this.threadView.getReloadMessageElement().textContent = error
- })
- .then(function() {
- _this.threadView.getReloadButton().disabled = false
- })
- }
- ThreadController.prototype._addBoundableNgItem = function(o) {
- var view = this.threadView.configView
- var val = view.getNgTextInputValue()
- if (!val) return
- var boardId = view.getNgItemAddTarget() !== 'all'
- ? this.thread.boardId : undefined
- var threadNumber = view.getNgItemAddTarget() === 'thread'
- ? this.thread.threadNumber : undefined
- o.arrayStore(this.thread.config)
- .add(o.boundableNgItem(val, boardId, threadNumber))
- view.clearNgTextInputValue()
- }
- ThreadController.prototype._addNgWord = function() {
- this._addBoundableNgItem({
- arrayStore(config) {
- return config.ngWords
- },
- boundableNgItem(val, boardId, threadNumber) {
- return new NgWord(val, boardId, threadNumber)
- },
- })
- }
- ThreadController.prototype._addNgName = function() {
- this._addBoundableNgItem({
- arrayStore(config) {
- return config.ngNames
- },
- boundableNgItem(val, boardId, threadNumber) {
- return new NgName(val, boardId, threadNumber)
- },
- })
- }
- ThreadController.prototype._addNgIdTail = function() {
- this._addBoundableNgItem({
- arrayStore(config) {
- return config.ngIdTails
- },
- boundableNgItem(val, boardId, threadNumber) {
- return new NgIdTail(val, boardId, threadNumber)
- },
- })
- }
- ThreadController.prototype._addNgKorokoro = function(target) {
- var s = target.dataset
- this.thread.config.ngKorokoros.add(
- new NgKorokoro(this.thread.boardId, s.jstTime, s.korokoro))
- }
- ThreadController.prototype._removeNgWord = function(target) {
- this.thread.config.ngWords.remove(NgWord.of(target.dataset))
- }
- ThreadController.prototype._removeNgName = function(target) {
- this.thread.config.ngNames.remove(NgName.of(target.dataset))
- }
- ThreadController.prototype._addNgId = function(target) {
- this.thread.addNgId(target.dataset.jstTime, target.dataset.id)
- }
- ThreadController.prototype._removeNgId = function(target) {
- this.thread.config.ngIds.remove(NgId.of(target.dataset))
- }
- ThreadController.prototype._removeNgKorokoro = function(target) {
- this.thread.config.ngKorokoros.remove(NgKorokoro.of(target.dataset))
- }
- ThreadController.prototype._removeNgIdTail = function(target) {
- this.thread.config.ngIdTails.remove(NgIdTail.of(target.dataset))
- }
- ThreadController.prototype._removeThreadHistory = function(target) {
- this.thread.config.threadHistories.remove({
- title: target.dataset.title,
- url: target.dataset.url,
- resNum: parseInt(target.dataset.resNum),
- })
- }
- ThreadController.prototype._addNgSlip = function() {
- var view = this.threadView.configView
- var type = view.getNgSlipType()
- var boardId = this.thread.boardId
- var threadNumber = view.getNgItemAddTarget() === 'thread'
- ? this.thread.threadNumber : undefined
- this.thread.config.ngSlips.add(new NgSlip(type, boardId, threadNumber))
- }
- ThreadController.prototype._removeNgSlip = function(target) {
- this.thread.config.ngSlips.remove(NgSlip.of(target.dataset))
- }
- ThreadController.prototype._resAnchorClicked = function(target, event) {
- if (!this.thread.hasResponse(Number(target.dataset.resNum))) return
- event.preventDefault()
- this.threadView.doc.location.hash = '#' + target.dataset.resNum
- }
- ThreadController.prototype._actionMap = function() {
- var view = this.threadView
- var cfg = this.thread.config
- var article = '.threadView .main article'
- var header = `${article} header`
- var topBar = '.threadView .topBar'
- var config = `${topBar} .config`
- var ngIdSection = `${config} .ngIdSection`
- var ngWordSection = `${config} .ngWordSection`
- var ngNameSection = `${config} .ngNameSection`
- var ngKorokoroSection = `${config} .ngKorokoroSection`
- var ngIdTailSection = `${config} .ngIdTailSection`
- var ngSlipSection = `${config} .ngSlipSection`
- var threadHistorySection = `${config} .threadHistorySection`
- return {
- [`${article} .resAnchor`]: this._resAnchorClicked.bind(this),
- [`${header} .headerNumber`]: view.toggleResponseChildren.bind(view),
- [`${header} .id .value`]: view.toggleSameIdResponses.bind(view),
- [`${header} .korokoro .value`]: view.toggleSameKorokoroResponses.bind(view),
- [`${header} .id .ngButton`]: this._addNgId.bind(this),
- [`${header} .korokoro .ngButton`]: this._addNgKorokoro.bind(this),
- '.threadView .bottomBar .reloadButton': this.requestNewResponses.bind(this),
- [`${topBar} .viewToggle`]: view.toggleViewConfig.bind(view),
- [`${topBar} .ngToggle`]: view.toggleNgConfig.bind(view),
- [`${topBar} .ngWordToggle`]: view.toggleNgWordConfig.bind(view),
- [`${topBar} .ngNameToggle`]: view.toggleNgNameConfig.bind(view),
- [`${topBar} .ngIdToggle`]: view.toggleNgIdConfig.bind(view),
- [`${topBar} .ngKorokoroToggle`]: view.toggleNgKorokoroConfig.bind(view),
- [`${topBar} .ngIdTailToggle`]: view.toggleNgIdTailConfig.bind(view),
- [`${topBar} .ngSlipToggle`]: view.toggleNgSlipConfig.bind(view),
- [`${topBar} .threadHistoryToggle`]: view.toggleThreadHistoryConfig.bind(view),
- [`${ngIdSection} table .removeButton`]: this._removeNgId.bind(this),
- [`${ngIdSection} h2 .removeAllButton`]: cfg.ngIds.removeAll.bind(cfg.ngIds),
- [`${ngKorokoroSection} table .removeButton`]: this._removeNgKorokoro.bind(this),
- [`${ngKorokoroSection} h2 .removeAllButton`]: cfg.ngKorokoros.removeAll.bind(cfg.ngKorokoros),
- [`${ngIdTailSection} .add .addButton`]: this._addNgIdTail.bind(this),
- [`${ngIdTailSection} table .removeButton`]: this._removeNgIdTail.bind(this),
- [`${ngIdTailSection} h2 .removeAllButton`]: cfg.ngIdTails.removeAll.bind(cfg.ngIdTails),
- [`${ngWordSection} .add .addButton`]: this._addNgWord.bind(this),
- [`${ngWordSection} table .removeButton`]: this._removeNgWord.bind(this),
- [`${ngWordSection} h2 .removeAllButton`]: cfg.ngWords.removeAll.bind(cfg.ngWords),
- [`${ngNameSection} .add .addButton`]: this._addNgName.bind(this),
- [`${ngNameSection} table .removeButton`]: this._removeNgName.bind(this),
- [`${ngNameSection} h2 .removeAllButton`]: cfg.ngNames.removeAll.bind(cfg.ngNames),
- [`${ngSlipSection} .add .addButton`]: this._addNgSlip.bind(this),
- [`${ngSlipSection} table .removeButton`]: this._removeNgSlip.bind(this),
- [`${ngSlipSection} h2 .removeAllButton`]: cfg.ngSlips.removeAll.bind(cfg.ngSlips),
- [`${threadHistorySection} table .removeButton`]: this._removeThreadHistory.bind(this),
- [`${threadHistorySection} h2 .removeAllButton`]: cfg.threadHistories.removeAll.bind(cfg.threadHistories),
- }
- }
- ThreadController.prototype._getAction = function(map, target) {
- var selectors = Object.keys(map)
- for (var i = 0; i < selectors.length; i++) {
- var s = selectors[i]
- if (target.matches(s)) return map[s]
- }
- }
- ThreadController.prototype.callback = function(event) {
- var action = this._getAction(this._actionMap(), event.target)
- if (action) action(event.target, event)
- }
- ThreadController.prototype.keydownCallback = function(event) {
- var enterKeyCode = 13
- if (event.keyCode !== enterKeyCode) return
- var config = '.threadView .topBar .config'
- var map = {
- [`${config} .ngWordSection .add .ngTextInput`]: this._addNgWord.bind(this),
- [`${config} .ngNameSection .add .ngTextInput`]: this._addNgName.bind(this),
- [`${config} .ngIdTailSection .add .ngTextInput`]: this._addNgIdTail.bind(this),
- }
- var a = this._getAction(map, event.target)
- if (a) a(event.target)
- }
- ThreadController.prototype._setPageCentering = function() {
- this.thread.config.setPageCentering(
- this.threadView.configView.isPageCenteringChecked())
- }
- ThreadController.prototype._setNgVisible = function() {
- this.thread.config.setNgVisible(
- this.threadView.configView.isNgVisibleChecked())
- }
- ThreadController.prototype._setPageMaxWidth = function() {
- this.thread.config.setPageMaxWidth(
- this.threadView.configView.getPageMaxWidthValue())
- }
- ThreadController.prototype._changeActionMap = function() {
- var viewSection = '.threadView .topBar .config .viewSection'
- return {
- [`${viewSection} .centering label input`]: this._setPageCentering.bind(this),
- [`${viewSection} .maxWidth label input`]: this._setPageMaxWidth.bind(this),
- [`${viewSection} .ngVisible label input`]: this._setNgVisible.bind(this),
- }
- }
- ThreadController.prototype.changeCallback = function(event) {
- var action = this._getAction(this._changeActionMap(), event.target)
- if (action) action(event.target)
- }
- return ThreadController
- })()
- async function contentLoaded() {
- var parsed = Parser.of(document).parse()
- parsed.action()
- parsed.ads.forEach(function(e) { e.style.display = 'none' })
- parsed.elementsToRemove.forEach(invoke('remove', []))
- if (parsed.floatedSpan) parsed.floatedSpan.style.cssFloat = ''
- var config = new Config(typeof GM_getValue === 'undefined' ? GM.getValue : GM_getValue
- , typeof GM_setValue === 'undefined' ? GM.setValue : GM_setValue)
- var threadHistory = new ThreadHistory(
- config.threadHistories, document.location, document.title)
- var thread = new Thread(config, parsed.boardId, parsed.threadNumber, threadHistory)
- var threadView = new ThreadView(document, thread)
- threadView.setPageCentering(await config.isPageCentering())
- await threadView.addStyle()
- if (parsed.threadClosed) threadView.disableReload()
- threadView.replace(parsed.threadRootElement)
- await thread.addResponses(parsed.responses.map(Response.of))
- var ctrl = new ThreadController(thread, threadView)
- ctrl.addCallback()
- if (parsed.postForm) {
- var postForm = new ResponsePostForm(parsed.postForm)
- postForm.addEventListener('postDone'
- , ctrl.requestNewResponses.bind(ctrl))
- threadView.responsePostForm = postForm
- }
- }
- var main = function() {
- if (document.location.protocol === 'http:') {
- window.stop()
- document.location.replace('https' + document.location.href.slice('http'.length))
- return
- }
- if (['interactive', 'complete'].includes(document.readyState))
- contentLoaded()
- else
- document.addEventListener('DOMContentLoaded', contentLoaded)
- }
- main()
- })()
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址