267 lines
7.0 KiB
CoffeeScript
Executable File
267 lines
7.0 KiB
CoffeeScript
Executable File
Filter =
|
|
filters: {}
|
|
init: ->
|
|
return if g.VIEW is 'catalog' or !Conf['Filter']
|
|
|
|
unless Conf['Filtered Backlinks']
|
|
$.addClass doc, 'hide-backlinks'
|
|
|
|
for key of Config.filter
|
|
@filters[key] = []
|
|
for filter in Conf[key].split '\n'
|
|
continue if filter[0] is '#'
|
|
|
|
unless regexp = filter.match /\/(.+)\/(\w*)/
|
|
continue
|
|
|
|
# Don't mix up filter flags with the regular expression.
|
|
filter = filter.replace regexp[0], ''
|
|
|
|
# Do not add this filter to the list if it's not a global one
|
|
# and it's not specifically applicable to the current board.
|
|
# Defaults to global.
|
|
boards = filter.match(/boards:([^;]+)/)?[1].toLowerCase() or 'global'
|
|
if boards isnt 'global' and g.BOARD.ID not in boards.split ','
|
|
continue
|
|
|
|
if key in ['uniqueID', 'MD5']
|
|
# MD5 filter will use strings instead of regular expressions.
|
|
regexp = regexp[1]
|
|
else
|
|
try
|
|
# Please, don't write silly regular expressions.
|
|
regexp = RegExp regexp[1], regexp[2]
|
|
catch err
|
|
# I warned you, bro.
|
|
new Notice 'warning', err.message, 60
|
|
continue
|
|
|
|
# Filter OPs along with their threads, replies only, or both.
|
|
# Defaults to both.
|
|
op = filter.match(/[^t]op:(yes|no|only)/)?[1] or 'yes'
|
|
|
|
# Overrule the `Show Stubs` setting.
|
|
# Defaults to stub showing.
|
|
stub = switch filter.match(/stub:(yes|no)/)?[1]
|
|
when 'yes'
|
|
true
|
|
when 'no'
|
|
false
|
|
else
|
|
Conf['Stubs']
|
|
|
|
# Highlight the post, or hide it.
|
|
# If not specified, the highlight class will be filter-highlight.
|
|
# Defaults to post hiding.
|
|
if hl = /highlight/.test filter
|
|
hl = filter.match(/highlight:(\w+)/)?[1] or 'filter-highlight'
|
|
# Put highlighted OP's thread on top of the board page or not.
|
|
# Defaults to on top.
|
|
top = filter.match(/top:(yes|no)/)?[1] or 'yes'
|
|
top = top is 'yes' # Turn it into a boolean
|
|
|
|
@filters[key].push @createFilter regexp, op, stub, hl, top
|
|
|
|
# Only execute filter types that contain valid filters.
|
|
unless @filters[key].length
|
|
delete @filters[key]
|
|
|
|
return unless Object.keys(@filters).length
|
|
Post.callbacks.push
|
|
name: 'Filter'
|
|
cb: @node
|
|
|
|
createFilter: (regexp, op, stub, hl, top) ->
|
|
test =
|
|
if typeof regexp is 'string'
|
|
# MD5 checking
|
|
(value) -> regexp is value
|
|
else
|
|
(value) -> regexp.test value
|
|
settings =
|
|
hide: !hl
|
|
stub: stub
|
|
class: hl
|
|
top: top
|
|
(value, isReply) ->
|
|
if isReply and op is 'only' or !isReply and op is 'no'
|
|
return false
|
|
unless test value
|
|
return false
|
|
settings
|
|
|
|
node: ->
|
|
return if @isClone or @isFetchedQuote
|
|
for key of Filter.filters
|
|
value = Filter[key] @
|
|
# Continue if there's nothing to filter (no tripcode for example).
|
|
continue if value is false
|
|
|
|
for filter in Filter.filters[key]
|
|
unless result = filter value, @isReply
|
|
continue
|
|
|
|
# Hide
|
|
if result.hide
|
|
if @isReply
|
|
PostHiding.hide @, result.stub
|
|
else if g.VIEW is 'index'
|
|
ThreadHiding.hide @thread, result.stub
|
|
else
|
|
continue
|
|
return
|
|
|
|
# Highlight
|
|
$.addClass @nodes.root, result.class
|
|
unless @highlights and result.class in @highlights
|
|
(@highlights or= []).push result.class
|
|
if !@isReply and result.top
|
|
@thread.isOnTop = true
|
|
|
|
name: (post) ->
|
|
if 'name' of post.info
|
|
return post.info.name
|
|
false
|
|
uniqueID: (post) ->
|
|
if 'uniqueID' of post.info
|
|
return post.info.uniqueID
|
|
false
|
|
tripcode: (post) ->
|
|
if 'tripcode' of post.info
|
|
return post.info.tripcode
|
|
false
|
|
capcode: (post) ->
|
|
if 'capcode' of post.info
|
|
return post.info.capcode
|
|
false
|
|
subject: (post) ->
|
|
if 'subject' of post.info
|
|
return post.info.subject or false
|
|
false
|
|
comment: (post) ->
|
|
if 'comment' of post.info
|
|
return post.info.comment
|
|
false
|
|
flag: (post) ->
|
|
if 'flag' of post.info
|
|
return post.info.flag
|
|
false
|
|
filename: (post) ->
|
|
if post.file
|
|
return post.file.name
|
|
false
|
|
dimensions: (post) ->
|
|
if post.file and post.file.isImage
|
|
return post.file.dimensions
|
|
false
|
|
filesize: (post) ->
|
|
if post.file
|
|
return post.file.size
|
|
false
|
|
MD5: (post) ->
|
|
if post.file
|
|
return post.file.MD5
|
|
false
|
|
|
|
menu:
|
|
init: ->
|
|
return if g.VIEW is 'catalog' or !Conf['Menu'] or !Conf['Filter']
|
|
|
|
div = $.el 'div',
|
|
textContent: 'Filter'
|
|
|
|
entry =
|
|
el: div
|
|
order: 50
|
|
open: (post) ->
|
|
Filter.menu.post = post
|
|
true
|
|
subEntries: []
|
|
|
|
for type in [
|
|
['Name', 'name']
|
|
['Unique ID', 'uniqueID']
|
|
['Tripcode', 'tripcode']
|
|
['Capcode', 'capcode']
|
|
['Subject', 'subject']
|
|
['Comment', 'comment']
|
|
['Flag', 'flag']
|
|
['Filename', 'filename']
|
|
['Image dimensions', 'dimensions']
|
|
['Filesize', 'filesize']
|
|
['Image MD5', 'MD5']
|
|
]
|
|
# Add a sub entry for each filter type.
|
|
entry.subEntries.push Filter.menu.createSubEntry type[0], type[1]
|
|
|
|
Menu.menu.addEntry entry
|
|
|
|
createSubEntry: (text, type) ->
|
|
el = $.el 'a',
|
|
href: 'javascript:;'
|
|
textContent: text
|
|
el.dataset.type = type
|
|
$.on el, 'click', Filter.menu.makeFilter
|
|
|
|
return {
|
|
el: el
|
|
open: (post) ->
|
|
value = Filter[type] post
|
|
value isnt false
|
|
}
|
|
|
|
makeFilter: ->
|
|
{type} = @dataset
|
|
# Convert value -> regexp, unless type is MD5
|
|
value = Filter[type] Filter.menu.post
|
|
re = if type in ['uniqueID', 'MD5'] then value else value.replace ///
|
|
/
|
|
| \\
|
|
| \^
|
|
| \$
|
|
| \n
|
|
| \.
|
|
| \(
|
|
| \)
|
|
| \{
|
|
| \}
|
|
| \[
|
|
| \]
|
|
| \?
|
|
| \*
|
|
| \+
|
|
| \|
|
|
///g, (c) ->
|
|
if c is '\n'
|
|
'\\n'
|
|
else if c is '\\'
|
|
'\\\\'
|
|
else
|
|
"\\#{c}"
|
|
|
|
re = if type in ['uniqueID', 'MD5']
|
|
"/#{re}/"
|
|
else
|
|
"/^#{re}$/"
|
|
|
|
# Add a new line before the regexp unless the text is empty.
|
|
$.get type, Conf[type], (item) ->
|
|
save = item[type]
|
|
save =
|
|
if save
|
|
"#{save}\n#{re}"
|
|
else
|
|
re
|
|
$.set type, save
|
|
|
|
# Open the settings and display & focus the relevant filter textarea.
|
|
Settings.open 'Filter'
|
|
section = $ '.section-container'
|
|
select = $ 'select[name=filter]', section
|
|
select.value = type
|
|
Settings.selectFilter.call select
|
|
ta = $ 'textarea', section
|
|
tl = ta.textLength
|
|
ta.setSelectionRange tl, tl
|
|
ta.focus()
|