Merge Mayhem X
This commit is contained in:
commit
4f779ae64d
@ -1,6 +1,10 @@
|
|||||||
seaweedchan:
|
seaweedchan:
|
||||||
- Chrome doesn't get .null, so don't style it
|
- Chrome doesn't get .null, so don't style it
|
||||||
- Fix count when auto update is disabled and set updater text to "Update"
|
- Fix count when auto update is disabled and set updater text to "Update"
|
||||||
|
- Remove /v/ and /vg/ redirection. See https://archive.foolz.us/foolz/thread/509388/ for news and how you can donate to bring /v/ and /vg/ archiving back.
|
||||||
|
|
||||||
|
MayhemYDG:
|
||||||
|
- Fix Unread Count taking into account hidden posts.
|
||||||
|
|
||||||
### 1.1.2 - 2013-04-26
|
### 1.1.2 - 2013-04-26
|
||||||
seaweedchan:
|
seaweedchan:
|
||||||
|
|||||||
210
Gruntfile.js
Normal file
210
Gruntfile.js
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
module.exports = function(grunt) {
|
||||||
|
|
||||||
|
var pkg = grunt.file.readJSON('package.json');
|
||||||
|
var concatOptions = {
|
||||||
|
process: {
|
||||||
|
data: pkg
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var shellOptions = {
|
||||||
|
stdout: true,
|
||||||
|
stderr: true,
|
||||||
|
failOnError: true
|
||||||
|
};
|
||||||
|
|
||||||
|
// Project configuration.
|
||||||
|
grunt.initConfig({
|
||||||
|
pkg: pkg,
|
||||||
|
concat: {
|
||||||
|
coffee: {
|
||||||
|
options: concatOptions,
|
||||||
|
src: [
|
||||||
|
'src/General/Config.coffee',
|
||||||
|
'src/General/Globals.coffee',
|
||||||
|
'lib/**/*',
|
||||||
|
'src/General/UI.coffee',
|
||||||
|
'src/General/Header.coffee',
|
||||||
|
'src/General/Notification.coffee',
|
||||||
|
'src/General/Settings.coffee',
|
||||||
|
'src/General/Get.coffee',
|
||||||
|
'src/General/Build.coffee',
|
||||||
|
// Features -->
|
||||||
|
'src/Filtering/**/*',
|
||||||
|
'src/Quotelinks/**/*',
|
||||||
|
'src/Posting/**/*',
|
||||||
|
'src/Images/**/*',
|
||||||
|
'src/Menu/**/*',
|
||||||
|
'src/Monitoring/**/*',
|
||||||
|
'src/Archive/**/*',
|
||||||
|
'src/Miscellaneous/**/*',
|
||||||
|
// <--|
|
||||||
|
'src/General/Board.coffee',
|
||||||
|
'src/General/Thread.coffee',
|
||||||
|
'src/General/Post.coffee',
|
||||||
|
'src/General/Clone.coffee',
|
||||||
|
'src/General/DataBoard.coffee',
|
||||||
|
'src/General/Main.coffee'
|
||||||
|
],
|
||||||
|
dest: 'tmp-<%= pkg.type %>/script.coffee'
|
||||||
|
},
|
||||||
|
crx: {
|
||||||
|
options: concatOptions,
|
||||||
|
files: {
|
||||||
|
'builds/crx/manifest.json': 'src/Meta/manifest.json',
|
||||||
|
'builds/crx/script.js': [
|
||||||
|
'src/Meta/banner.js',
|
||||||
|
'tmp-<%= pkg.type %>/script.js'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
userjs: {
|
||||||
|
options: concatOptions,
|
||||||
|
src: [
|
||||||
|
'src/Meta/metadata.js',
|
||||||
|
'src/Meta/banner.js',
|
||||||
|
'tmp-<%= pkg.type %>/script.js'
|
||||||
|
],
|
||||||
|
dest: 'builds/<%= pkg.name %>.js'
|
||||||
|
},
|
||||||
|
userscript: {
|
||||||
|
options: concatOptions,
|
||||||
|
files: {
|
||||||
|
'builds/<%= pkg.name %>.meta.js': 'src/Meta/metadata.js',
|
||||||
|
'builds/<%= pkg.name %>.user.js': [
|
||||||
|
'src/Meta/metadata.js',
|
||||||
|
'src/Meta/banner.js',
|
||||||
|
'tmp-<%= pkg.type %>/script.js'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
copy: {
|
||||||
|
crx: {
|
||||||
|
src: 'img/*.png',
|
||||||
|
dest: 'builds/crx/',
|
||||||
|
expand: true,
|
||||||
|
flatten: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
coffee: {
|
||||||
|
script: {
|
||||||
|
src: 'tmp-<%= pkg.type %>/script.coffee',
|
||||||
|
dest: 'tmp-<%= pkg.type %>/script.js'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
concurrent: {
|
||||||
|
build: ['build-crx', 'build-userjs', 'build-userscript']
|
||||||
|
},
|
||||||
|
shell: {
|
||||||
|
commit: {
|
||||||
|
options: shellOptions,
|
||||||
|
command: [
|
||||||
|
'git checkout <%= pkg.meta.mainBranch %>',
|
||||||
|
'git commit -am "Release <%= pkg.meta.name %> v<%= pkg.version %>."',
|
||||||
|
'git tag -a <%= pkg.version %> -m "<%= pkg.meta.name %> v<%= pkg.version %>."',
|
||||||
|
'git tag -af stable-v3 -m "<%= pkg.meta.name %> v<%= pkg.version %>."'
|
||||||
|
].join(' && ')
|
||||||
|
},
|
||||||
|
push: {
|
||||||
|
options: shellOptions,
|
||||||
|
command: 'git push origin --tags -f && git push origin --all'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
all: {
|
||||||
|
options: {
|
||||||
|
interrupt: true
|
||||||
|
},
|
||||||
|
files: [
|
||||||
|
'Gruntfile.js',
|
||||||
|
'package.json',
|
||||||
|
'lib/**/*',
|
||||||
|
'src/**/*',
|
||||||
|
'html/**/*',
|
||||||
|
'css/**/*',
|
||||||
|
'img/**/*'
|
||||||
|
],
|
||||||
|
tasks: 'build'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
compress: {
|
||||||
|
crx: {
|
||||||
|
options: {
|
||||||
|
archive: 'builds/<%= pkg.name %>.zip',
|
||||||
|
level: 9,
|
||||||
|
pretty: true
|
||||||
|
},
|
||||||
|
expand: true,
|
||||||
|
flatten: true,
|
||||||
|
src: 'builds/crx/*',
|
||||||
|
dest: '/'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clean: {
|
||||||
|
builds: 'builds',
|
||||||
|
tmpcrx: 'tmp-crx',
|
||||||
|
tmpuserjs: 'tmp-userjs',
|
||||||
|
tmpuserscript: 'tmp-userscript'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
grunt.loadNpmTasks('grunt-bump');
|
||||||
|
grunt.loadNpmTasks('grunt-concurrent');
|
||||||
|
grunt.loadNpmTasks('grunt-contrib-clean');
|
||||||
|
grunt.loadNpmTasks('grunt-contrib-coffee');
|
||||||
|
grunt.loadNpmTasks('grunt-contrib-compress');
|
||||||
|
grunt.loadNpmTasks('grunt-contrib-concat');
|
||||||
|
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||||
|
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||||
|
grunt.loadNpmTasks('grunt-shell');
|
||||||
|
|
||||||
|
grunt.registerTask('default', ['build']);
|
||||||
|
|
||||||
|
grunt.registerTask('set-build', 'Set the build type variable', function(type) {
|
||||||
|
pkg.type = type;
|
||||||
|
grunt.log.ok('pkg.type = %s', type);
|
||||||
|
});
|
||||||
|
grunt.registerTask('build', ['concurrent:build']);
|
||||||
|
grunt.registerTask('build-crx', [
|
||||||
|
'set-build:crx',
|
||||||
|
'concat:coffee',
|
||||||
|
'coffee:script',
|
||||||
|
'concat:crx',
|
||||||
|
'copy:crx',
|
||||||
|
'clean:tmpcrx'
|
||||||
|
]);
|
||||||
|
grunt.registerTask('build-userjs', [
|
||||||
|
'set-build:userjs',
|
||||||
|
'concat:coffee',
|
||||||
|
'coffee:script',
|
||||||
|
'concat:userjs',
|
||||||
|
'clean:tmpuserjs'
|
||||||
|
]);
|
||||||
|
grunt.registerTask('build-userscript', [
|
||||||
|
'set-build:userscript',
|
||||||
|
'concat:coffee',
|
||||||
|
'coffee:script',
|
||||||
|
'concat:userscript',
|
||||||
|
'clean:tmpuserscript'
|
||||||
|
]);
|
||||||
|
|
||||||
|
grunt.registerTask('release', ['shell:commit', 'shell:push', 'build-crx', 'compress:crx']);
|
||||||
|
grunt.registerTask('patch', ['bump', 'reloadPkg', 'updcl:3', 'release']);
|
||||||
|
grunt.registerTask('minor', ['bump:minor', 'reloadPkg', 'updcl:2', 'release']);
|
||||||
|
grunt.registerTask('major', ['bump:major', 'reloadPkg', 'updcl:1', 'release']);
|
||||||
|
|
||||||
|
grunt.registerTask('reloadPkg', 'Reload the package', function() {
|
||||||
|
// Update the `pkg` object with the new version.
|
||||||
|
pkg = grunt.file.readJSON('package.json');
|
||||||
|
grunt.config.data.pkg = concatOptions.process.data = pkg;
|
||||||
|
grunt.log.ok('pkg reloaded.');
|
||||||
|
});
|
||||||
|
|
||||||
|
grunt.registerTask('updcl', 'Update the changelog', function(i) {
|
||||||
|
// i is the number of #s for markdown.
|
||||||
|
var version = new Array(+i + 1).join('#') + ' ' + pkg.version + ' - *' + grunt.template.today('yyyy-mm-dd') + '*';
|
||||||
|
grunt.file.write('CHANGELOG.md', version + '\n\n' + grunt.file.read('CHANGELOG.md'));
|
||||||
|
grunt.log.ok('Changelog updated for v' + pkg.version + '.');
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
BIN
builds/4chan-X.zip
Normal file
BIN
builds/4chan-X.zip
Normal file
Binary file not shown.
@ -25,7 +25,7 @@
|
|||||||
"grunt-contrib-clean": "~0.4.1",
|
"grunt-contrib-clean": "~0.4.1",
|
||||||
"grunt-contrib-coffee": "~0.7.0",
|
"grunt-contrib-coffee": "~0.7.0",
|
||||||
"grunt-contrib-compress": "~0.5.0",
|
"grunt-contrib-compress": "~0.5.0",
|
||||||
"grunt-contrib-concat": "~0.2.0",
|
"grunt-contrib-concat": "~0.3.0",
|
||||||
"grunt-contrib-copy": "~0.4.1",
|
"grunt-contrib-copy": "~0.4.1",
|
||||||
"grunt-contrib-watch": "~0.3.1",
|
"grunt-contrib-watch": "~0.3.1",
|
||||||
"grunt-shell": "~0.2.2"
|
"grunt-shell": "~0.2.2"
|
||||||
|
|||||||
@ -9,7 +9,7 @@ Redirect =
|
|||||||
image: (boardID, filename) ->
|
image: (boardID, filename) ->
|
||||||
# Do not use g.BOARD, the image url can originate from a cross-quote.
|
# Do not use g.BOARD, the image url can originate from a cross-quote.
|
||||||
switch boardID
|
switch boardID
|
||||||
when 'a', 'gd', 'jp', 'm', 'q', 'tg', 'vg', 'vp', 'vr', 'wsg'
|
when 'a', 'gd', 'jp', 'm', 'q', 'tg', 'vp', 'vr', 'wsg'
|
||||||
"//archive.foolz.us/#{boardID}/full_image/#{filename}"
|
"//archive.foolz.us/#{boardID}/full_image/#{filename}"
|
||||||
when 'u'
|
when 'u'
|
||||||
"//nsfw.foolz.us/#{boardID}/full_image/#{filename}"
|
"//nsfw.foolz.us/#{boardID}/full_image/#{filename}"
|
||||||
@ -61,7 +61,7 @@ Redirect =
|
|||||||
archiver:
|
archiver:
|
||||||
'Foolz':
|
'Foolz':
|
||||||
base: 'https://archive.foolz.us'
|
base: 'https://archive.foolz.us'
|
||||||
boards: ['a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'v', 'vg', 'vp', 'vr', 'wsg']
|
boards: ['a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'vp', 'vr', 'wsg']
|
||||||
type: 'foolfuuka'
|
type: 'foolfuuka'
|
||||||
'NSFWFoolz':
|
'NSFWFoolz':
|
||||||
base: 'https://nsfw.foolz.us'
|
base: 'https://nsfw.foolz.us'
|
||||||
@ -130,4 +130,4 @@ Redirect =
|
|||||||
"##{postID}"
|
"##{postID}"
|
||||||
else
|
else
|
||||||
"#p#{postID}"
|
"#p#{postID}"
|
||||||
"#{base}/#{path}"
|
"#{base}/#{path}"
|
||||||
|
|||||||
@ -285,4 +285,4 @@ Header =
|
|||||||
createNotification: (e) ->
|
createNotification: (e) ->
|
||||||
{type, content, lifetime, cb} = e.detail
|
{type, content, lifetime, cb} = e.detail
|
||||||
notif = new Notification type, content, lifetime
|
notif = new Notification type, content, lifetime
|
||||||
cb notif if cb
|
cb notif if cb
|
||||||
|
|||||||
@ -47,20 +47,7 @@ Settings =
|
|||||||
$.event 'CloseMenu'
|
$.event 'CloseMenu'
|
||||||
|
|
||||||
html = """
|
html = """
|
||||||
<nav>
|
<%= grunt.file.read('src/General/html/Settings/Settings.html').replace(/>\s+</g, '><').trim() %>
|
||||||
<div class=sections-list></div>
|
|
||||||
<p class='imp-exp-result warning'></p>
|
|
||||||
<div class=credits>
|
|
||||||
<a class=export>Export</a> |
|
|
||||||
<a class=import>Import</a> |
|
|
||||||
<input type=file style='display: none;'>
|
|
||||||
<a href='<%= meta.page %>' target=_blank><%= meta.name %></a> |
|
|
||||||
<a href='<%= meta.repo %>blob/<%= meta.mainBranch %>/CHANGELOG.md' target=_blank>#{g.VERSION}</a> |
|
|
||||||
<a href='<%= meta.repo %>blob/<%= meta.mainBranch %>/README.md#reporting-bugs-and-suggestions' target=_blank>Issues</a> |
|
|
||||||
<a href=javascript:; class=close title=Close>×</a>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<div class=section-container><section></section></div>
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Settings.overlay = overlay = $.el 'div',
|
Settings.overlay = overlay = $.el 'div',
|
||||||
@ -297,22 +284,7 @@ Settings =
|
|||||||
|
|
||||||
filter: (section) ->
|
filter: (section) ->
|
||||||
section.innerHTML = """
|
section.innerHTML = """
|
||||||
<select name=filter>
|
<%= grunt.file.read('src/General/html/Settings/Filter-guide.html').replace(/>\s+</g, '><').trim() %>
|
||||||
<option value=guide>Guide</option>
|
|
||||||
<option value=name>Name</option>
|
|
||||||
<option value=uniqueID>Unique ID</option>
|
|
||||||
<option value=tripcode>Tripcode</option>
|
|
||||||
<option value=capcode>Capcode</option>
|
|
||||||
<option value=email>E-mail</option>
|
|
||||||
<option value=subject>Subject</option>
|
|
||||||
<option value=comment>Comment</option>
|
|
||||||
<option value=flag>Flag</option>
|
|
||||||
<option value=filename>Filename</option>
|
|
||||||
<option value=dimensions>Image dimensions</option>
|
|
||||||
<option value=filesize>Filesize</option>
|
|
||||||
<option value=MD5>Image MD5</option>
|
|
||||||
</select>
|
|
||||||
<div></div>
|
|
||||||
"""
|
"""
|
||||||
select = $ 'select', section
|
select = $ 'select', section
|
||||||
$.on select, 'change', Settings.selectFilter
|
$.on select, 'change', Settings.selectFilter
|
||||||
@ -331,49 +303,12 @@ Settings =
|
|||||||
$.add div, ta
|
$.add div, ta
|
||||||
return
|
return
|
||||||
div.innerHTML = """
|
div.innerHTML = """
|
||||||
<div class=warning #{if Conf['Filter'] then 'hidden' else ''}><code>Filter</code> is disabled.</div>
|
<%= grunt.file.read('src/General/html/Settings/Filter-select.html').replace(/>\s+</g, '><').trim() %>
|
||||||
<p>
|
|
||||||
Use <a href=https://developer.mozilla.org/en/JavaScript/Guide/Regular_Expressions>regular expressions</a>, one per line.<br>
|
|
||||||
Lines starting with a <code>#</code> will be ignored.<br>
|
|
||||||
For example, <code>/weeaboo/i</code> will filter posts containing the string `<code>weeaboo</code>`, case-insensitive.<br>
|
|
||||||
MD5 filtering uses exact string matching, not regular expressions.
|
|
||||||
</p>
|
|
||||||
<ul>You can use these settings with each regular expression, separate them with semicolons:
|
|
||||||
<li>
|
|
||||||
Per boards, separate them with commas. It is global if not specified.<br>
|
|
||||||
For example: <code>boards:a,jp;</code>.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Filter OPs only along with their threads (`only`), replies only (`no`), or both (`yes`, this is default).<br>
|
|
||||||
For example: <code>op:only;</code>, <code>op:no;</code> or <code>op:yes;</code>.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Overrule the `Show Stubs` setting if specified: create a stub (`yes`) or not (`no`).<br>
|
|
||||||
For example: <code>stub:yes;</code> or <code>stub:no;</code>.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Highlight instead of hiding. You can specify a class name to use with a userstyle.<br>
|
|
||||||
For example: <code>highlight;</code> or <code>highlight:wallpaper;</code>.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Highlighted OPs will have their threads put on top of board pages by default.<br>
|
|
||||||
For example: <code>top:yes;</code> or <code>top:no;</code>.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
sauce: (section) ->
|
sauce: (section) ->
|
||||||
section.innerHTML = """
|
section.innerHTML = """
|
||||||
<div class=warning #{if Conf['Sauce'] then 'hidden' else ''}><code>Sauce</code> is disabled.</div>
|
<%= grunt.file.read('src/General/html/Settings/Sauce.html').replace(/>\s+</g, '><').trim() %>
|
||||||
<div>Lines starting with a <code>#</code> will be ignored.</div>
|
|
||||||
<div>You can specify a display text by appending <code>;text:[text]</code> to the URL.</div>
|
|
||||||
<ul>These parameters will be replaced by their corresponding values:
|
|
||||||
<li><code>%TURL</code>: Thumbnail URL.</li>
|
|
||||||
<li><code>%URL</code>: Full image URL.</li>
|
|
||||||
<li><code>%MD5</code>: MD5 hash.</li>
|
|
||||||
<li><code>%board</code>: Current board.</li>
|
|
||||||
</ul>
|
|
||||||
<textarea name=sauces class=field spellcheck=false></textarea>
|
|
||||||
"""
|
"""
|
||||||
sauce = $ 'textarea', section
|
sauce = $ 'textarea', section
|
||||||
$.get 'sauces', Conf['sauces'], (item) ->
|
$.get 'sauces', Conf['sauces'], (item) ->
|
||||||
@ -382,102 +317,7 @@ Settings =
|
|||||||
|
|
||||||
advanced: (section) ->
|
advanced: (section) ->
|
||||||
section.innerHTML = """
|
section.innerHTML = """
|
||||||
<fieldset>
|
<%= grunt.file.read('src/General/html/Settings/Advanced.html').replace(/>\s+</g, '><').trim() %>
|
||||||
<legend>Archiver</legend>
|
|
||||||
Select an Archiver for this board:
|
|
||||||
<select name=archiver></select>
|
|
||||||
</fieldset>
|
|
||||||
<fieldset>
|
|
||||||
<legend>Custom Board Navigation</span></legend>
|
|
||||||
<div><input name=boardnav class=field spellcheck=false></div>
|
|
||||||
<div>In the following, <code>board</code> can translate to a board ID (<code>a</code>, <code>b</code>, etc...), the current board (<code>current</code>), or the Status/Twitter link (<code>status</code>, <code>@</code>).</div>
|
|
||||||
<div>
|
|
||||||
For example:<br>
|
|
||||||
<code>[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h] [t-text:"Piracy"]</code><br>
|
|
||||||
will give you<br>
|
|
||||||
<code>[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy]</code><br>
|
|
||||||
if you are on /g/.
|
|
||||||
</div>
|
|
||||||
<div>Board link: <code>board</code></div>
|
|
||||||
<div>Title link: <code>board-title</code></div>
|
|
||||||
<div>Board link (Replace with title when on that board): <code>board-replace</code></div>
|
|
||||||
<div>Full text link: <code>board-full</code></div>
|
|
||||||
<div>Custom text link: <code>board-text:"VIP Board"</code></div>
|
|
||||||
<div>Index-only link: <code>board-index</code></div>
|
|
||||||
<div>Catalog-only link: <code>board-catalog</code></div>
|
|
||||||
<div>Combinations are possible: <code>board-index-text:"VIP Index"</code></div>
|
|
||||||
<div>Full board list toggle: <code>toggle-all</code></div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
|
||||||
<legend>Time Formatting <span class=warning #{if Conf['Time Formatting'] then 'hidden' else ''}>is disabled.</span></legend>
|
|
||||||
<div><input name=time class=field spellcheck=false>: <span class=time-preview></span></div>
|
|
||||||
<div>Supported <a href=//en.wikipedia.org/wiki/Date_%28Unix%29#Formatting>format specifiers</a>:</div>
|
|
||||||
<div>Day: <code>%a</code>, <code>%A</code>, <code>%d</code>, <code>%e</code></div>
|
|
||||||
<div>Month: <code>%m</code>, <code>%b</code>, <code>%B</code></div>
|
|
||||||
<div>Year: <code>%y</code></div>
|
|
||||||
<div>Hour: <code>%k</code>, <code>%H</code>, <code>%l</code>, <code>%I</code>, <code>%p</code>, <code>%P</code></div>
|
|
||||||
<div>Minute: <code>%M</code></div>
|
|
||||||
<div>Second: <code>%S</code></div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
|
||||||
<legend>Quote Backlinks formatting <span class=warning #{if Conf['Quote Backlinks'] then 'hidden' else ''}>is disabled.</span></legend>
|
|
||||||
<div><input name=backlink class=field spellcheck=false>: <span class=backlink-preview></span></div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
|
||||||
<legend>File Info Formatting <span class=warning #{if Conf['File Info Formatting'] then 'hidden' else ''}>is disabled.</span></legend>
|
|
||||||
<div><input name=fileInfo class=field spellcheck=false>: <span class='fileText file-info-preview'></span></div>
|
|
||||||
<div>Link: <code>%l</code> (truncated), <code>%L</code> (untruncated), <code>%T</code> (Unix timestamp)</div>
|
|
||||||
<div>Original file name: <code>%n</code> (truncated), <code>%N</code> (untruncated), <code>%t</code> (Unix timestamp)</div>
|
|
||||||
<div>Spoiler indicator: <code>%p</code></div>
|
|
||||||
<div>Size: <code>%B</code> (Bytes), <code>%K</code> (KB), <code>%M</code> (MB), <code>%s</code> (4chan default)</div>
|
|
||||||
<div>Resolution: <code>%r</code> (Displays 'PDF' for PDF files)</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
|
||||||
<legend>Unread Favicon <span class=warning #{if Conf['Unread Favicon'] then 'hidden' else ''}>is disabled.</span></legend>
|
|
||||||
<select name=favicon>
|
|
||||||
<option value=ferongr>ferongr</option>
|
|
||||||
<option value=xat->xat-</option>
|
|
||||||
<option value=Mayhem>Mayhem</option>
|
|
||||||
<option value=Original>Original</option>
|
|
||||||
</select>
|
|
||||||
<span class=favicon-preview></span>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
|
||||||
<legend>Emoji <span class=warning #{if Conf['Emoji'] then 'hidden' else ''}>is disabled.</span></legend>
|
|
||||||
<div>
|
|
||||||
Sage Icon: <select name=sageEmoji>
|
|
||||||
<option value="4chan SS">4chan SS</option>
|
|
||||||
<option value="appchan">appchan</option>
|
|
||||||
</select>
|
|
||||||
<span class=sage-icon-preview></span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
Position: <select name=emojiPos>
|
|
||||||
<option value="before">Before</option>
|
|
||||||
<option value="after">After</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
|
||||||
<legend>Thread Updater <span class=warning #{if Conf['Thread Updater'] then 'hidden' else ''}>is disabled.</span></legend>
|
|
||||||
<div>
|
|
||||||
Interval: <input type=number name=Interval class=field min=1 value=#{Conf['Interval']}>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
|
||||||
<legend>
|
|
||||||
<label><input type=checkbox name='Custom CSS' #{if Conf['Custom CSS'] then 'checked' else ''}> Custom CSS</label>
|
|
||||||
</legend>
|
|
||||||
<button id=apply-css>Apply CSS</button>
|
|
||||||
<textarea name=usercss class=field spellcheck=false #{if Conf['Custom CSS'] then '' else 'disabled'}></textarea>
|
|
||||||
</fieldset>
|
|
||||||
"""
|
"""
|
||||||
items = {}
|
items = {}
|
||||||
inputs = {}
|
inputs = {}
|
||||||
@ -523,7 +363,7 @@ Settings =
|
|||||||
funk = Time.createFunc @value
|
funk = Time.createFunc @value
|
||||||
@nextElementSibling.textContent = funk Time, new Date()
|
@nextElementSibling.textContent = funk Time, new Date()
|
||||||
backlink: ->
|
backlink: ->
|
||||||
@nextElementSibling.textContent = Conf['backlink'].replace /%id/, '123456789'
|
@nextElementSibling.textContent = @value.replace /%id/, '123456789'
|
||||||
fileInfo: ->
|
fileInfo: ->
|
||||||
data =
|
data =
|
||||||
isReply: true
|
isReply: true
|
||||||
@ -561,12 +401,7 @@ Settings =
|
|||||||
|
|
||||||
keybinds: (section) ->
|
keybinds: (section) ->
|
||||||
section.innerHTML = """
|
section.innerHTML = """
|
||||||
<div class=warning #{if Conf['Keybinds'] then 'hidden' else ''}><code>Keybinds</code> are disabled.</div>
|
<%= grunt.file.read('src/General/html/Settings/Keybinds.html').replace(/>\s+</g, '><').trim() %>
|
||||||
<div>Allowed keys: <kbd>a-z</kbd>, <kbd>0-9</kbd>, <kbd>Ctrl</kbd>, <kbd>Shift</kbd>, <kbd>Alt</kbd>, <kbd>Meta</kbd>, <kbd>Enter</kbd>, <kbd>Esc</kbd>, <kbd>Up</kbd>, <kbd>Down</kbd>, <kbd>Right</kbd>, <kbd>Left</kbd>.</div>
|
|
||||||
<div>Press <kbd>Backspace</kbd> to disable a keybind.</div>
|
|
||||||
<table><tbody>
|
|
||||||
<tr><th>Actions</th><th>Keybinds</th></tr>
|
|
||||||
</tbody></table>
|
|
||||||
"""
|
"""
|
||||||
tbody = $ 'tbody', section
|
tbody = $ 'tbody', section
|
||||||
items = {}
|
items = {}
|
||||||
@ -591,4 +426,4 @@ Settings =
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
return unless (key = Keybinds.keyCode e)?
|
return unless (key = Keybinds.keyCode e)?
|
||||||
@value = key
|
@value = key
|
||||||
$.cb.value.call @
|
$.cb.value.call @
|
||||||
|
|||||||
38
src/General/html/Features/QuickReply.html
Normal file
38
src/General/html/Features/QuickReply.html
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<div class=move>
|
||||||
|
<label>
|
||||||
|
<input type=checkbox id=autohide title=Auto-hide>
|
||||||
|
Quick Reply
|
||||||
|
</label>
|
||||||
|
<a href=javascript:; class=close title=Close>×</a>
|
||||||
|
<select data-name=thread title='Create a new thread / Reply'>
|
||||||
|
<option value=new>New thread</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<form>
|
||||||
|
<div class=persona>
|
||||||
|
<input id=dump-button type=button title='Dump list' value=+ tabindex=0>
|
||||||
|
<input name=name data-name=name title=Name placeholder=Name class=field size=1 tabindex=10>
|
||||||
|
<input name=email data-name=email title=E-mail placeholder=E-mail class=field size=1 tabindex=20>
|
||||||
|
<input name=sub data-name=sub title=Subject placeholder=Subject class=field size=1 tabindex=30>
|
||||||
|
</div>
|
||||||
|
<div class=textarea>
|
||||||
|
<textarea data-name=com title=Comment placeholder=Comment class=field tabindex=40></textarea>
|
||||||
|
<span id=char-count></span>
|
||||||
|
</div>
|
||||||
|
<div id=dump-list-container>
|
||||||
|
<div id=dump-list></div>
|
||||||
|
<a id=add-post href=javascript:; title="Add a post" tabindex=50>+</a>
|
||||||
|
</div>
|
||||||
|
<div id=file-n-submit>
|
||||||
|
<span id=qr-filename-container class=field tabindex=60>
|
||||||
|
<span id=qr-no-file>No selected file</span>
|
||||||
|
<span id=qr-filename></span>
|
||||||
|
</span>
|
||||||
|
<a id=qr-filerm href=javascript:; title='Remove file' tabindex=80>×</a>
|
||||||
|
<input type=submit tabindex=70>
|
||||||
|
</div>
|
||||||
|
<input type=file multiple>
|
||||||
|
<label id=qr-spoiler-label>
|
||||||
|
<input type=checkbox id=qr-file-spoiler title='Spoiler image' tabindex=90>Spoiler?
|
||||||
|
</label>
|
||||||
|
</form>
|
||||||
96
src/General/html/Settings/Advanced.html
Normal file
96
src/General/html/Settings/Advanced.html
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
<fieldset>
|
||||||
|
<legend>Archiver</legend>
|
||||||
|
Select an Archiver for this board:
|
||||||
|
<select name=archiver></select>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset>
|
||||||
|
<legend>Custom Board Navigation</span></legend>
|
||||||
|
<div><input name=boardnav class=field spellcheck=false></div>
|
||||||
|
<div>In the following, <code>board</code> can translate to a board ID (<code>a</code>, <code>b</code>, etc...), the current board (<code>current</code>), or the Status/Twitter link (<code>status</code>, <code>@</code>).</div>
|
||||||
|
<div>
|
||||||
|
For example:<br>
|
||||||
|
<code>[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h] [t-text:"Piracy"]</code><br>
|
||||||
|
will give you<br>
|
||||||
|
<code>[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy]</code><br>
|
||||||
|
if you are on /g/.
|
||||||
|
</div>
|
||||||
|
<div>Board link: <code>board</code></div>
|
||||||
|
<div>Title link: <code>board-title</code></div>
|
||||||
|
<div>Board link (Replace with title when on that board): <code>board-replace</code></div>
|
||||||
|
<div>Full text link: <code>board-full</code></div>
|
||||||
|
<div>Custom text link: <code>board-text:"VIP Board"</code></div>
|
||||||
|
<div>Index-only link: <code>board-index</code></div>
|
||||||
|
<div>Catalog-only link: <code>board-catalog</code></div>
|
||||||
|
<div>Combinations are possible: <code>board-index-text:"VIP Index"</code></div>
|
||||||
|
<div>Full board list toggle: <code>toggle-all</code></div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Time Formatting <span class=warning #{if Conf['Time Formatting'] then 'hidden' else ''}>is disabled.</span></legend>
|
||||||
|
<div><input name=time class=field spellcheck=false>: <span class=time-preview></span></div>
|
||||||
|
<div>Supported <a href=//en.wikipedia.org/wiki/Date_%28Unix%29#Formatting>format specifiers</a>:</div>
|
||||||
|
<div>Day: <code>%a</code>, <code>%A</code>, <code>%d</code>, <code>%e</code></div>
|
||||||
|
<div>Month: <code>%m</code>, <code>%b</code>, <code>%B</code></div>
|
||||||
|
<div>Year: <code>%y</code></div>
|
||||||
|
<div>Hour: <code>%k</code>, <code>%H</code>, <code>%l</code>, <code>%I</code>, <code>%p</code>, <code>%P</code></div>
|
||||||
|
<div>Minute: <code>%M</code></div>
|
||||||
|
<div>Second: <code>%S</code></div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Quote Backlinks formatting <span class=warning #{if Conf['Quote Backlinks'] then 'hidden' else ''}>is disabled.</span></legend>
|
||||||
|
<div><input name=backlink class=field spellcheck=false>: <span class=backlink-preview></span></div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>File Info Formatting <span class=warning #{if Conf['File Info Formatting'] then 'hidden' else ''}>is disabled.</span></legend>
|
||||||
|
<div><input name=fileInfo class=field spellcheck=false>: <span class='fileText file-info-preview'></span></div>
|
||||||
|
<div>Link: <code>%l</code> (truncated), <code>%L</code> (untruncated), <code>%T</code> (Unix timestamp)</div>
|
||||||
|
<div>Original file name: <code>%n</code> (truncated), <code>%N</code> (untruncated), <code>%t</code> (Unix timestamp)</div>
|
||||||
|
<div>Spoiler indicator: <code>%p</code></div>
|
||||||
|
<div>Size: <code>%B</code> (Bytes), <code>%K</code> (KB), <code>%M</code> (MB), <code>%s</code> (4chan default)</div>
|
||||||
|
<div>Resolution: <code>%r</code> (Displays 'PDF' for PDF files)</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Unread Favicon <span class=warning #{if Conf['Unread Favicon'] then 'hidden' else ''}>is disabled.</span></legend>
|
||||||
|
<select name=favicon>
|
||||||
|
<option value=ferongr>ferongr</option>
|
||||||
|
<option value=xat->xat-</option>
|
||||||
|
<option value=Mayhem>Mayhem</option>
|
||||||
|
<option value=Original>Original</option>
|
||||||
|
</select>
|
||||||
|
<span class=favicon-preview></span>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Emoji <span class=warning #{if Conf['Emoji'] then 'hidden' else ''}>is disabled.</span></legend>
|
||||||
|
<div>
|
||||||
|
Sage Icon: <select name=sageEmoji>
|
||||||
|
<option value="4chan SS">4chan SS</option>
|
||||||
|
<option value="appchan">appchan</option>
|
||||||
|
</select>
|
||||||
|
<span class=sage-icon-preview></span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Position: <select name=emojiPos>
|
||||||
|
<option value="before">Before</option>
|
||||||
|
<option value="after">After</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Thread Updater <span class=warning #{if Conf['Thread Updater'] then 'hidden' else ''}>is disabled.</span></legend>
|
||||||
|
<div>
|
||||||
|
Interval: <input type=number name=Interval class=field min=1 value=#{Conf['Interval']}>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>
|
||||||
|
<label><input type=checkbox name='Custom CSS' #{if Conf['Custom CSS'] then 'checked' else ''}> Custom CSS</label>
|
||||||
|
</legend>
|
||||||
|
<button id=apply-css>Apply CSS</button>
|
||||||
|
<textarea name=usercss class=field spellcheck=false #{if Conf['Custom CSS'] then '' else 'disabled'}></textarea>
|
||||||
|
</fieldset>
|
||||||
29
src/General/html/Settings/Filter-guide.html
Normal file
29
src/General/html/Settings/Filter-guide.html
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<div class=warning #{if Conf['Filter'] then 'hidden' else ''}><code>Filter</code> is disabled.</div>
|
||||||
|
<p>
|
||||||
|
Use <a href=https://developer.mozilla.org/en/JavaScript/Guide/Regular_Expressions>regular expressions</a>, one per line.<br>
|
||||||
|
Lines starting with a <code>#</code> will be ignored.<br>
|
||||||
|
For example, <code>/weeaboo/i</code> will filter posts containing the string `<code>weeaboo</code>`, case-insensitive.<br>
|
||||||
|
MD5 filtering uses exact string matching, not regular expressions.
|
||||||
|
</p>
|
||||||
|
<ul>You can use these settings with each regular expression, separate them with semicolons:
|
||||||
|
<li>
|
||||||
|
Per boards, separate them with commas. It is global if not specified.<br>
|
||||||
|
For example: <code>boards:a,jp;</code>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Filter OPs only along with their threads (`only`), replies only (`no`), or both (`yes`, this is default).<br>
|
||||||
|
For example: <code>op:only;</code>, <code>op:no;</code> or <code>op:yes;</code>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Overrule the `Show Stubs` setting if specified: create a stub (`yes`) or not (`no`).<br>
|
||||||
|
For example: <code>stub:yes;</code> or <code>stub:no;</code>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Highlight instead of hiding. You can specify a class name to use with a userstyle.<br>
|
||||||
|
For example: <code>highlight;</code> or <code>highlight:wallpaper;</code>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Highlighted OPs will have their threads put on top of board pages by default.<br>
|
||||||
|
For example: <code>top:yes;</code> or <code>top:no;</code>.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
16
src/General/html/Settings/Filter-select.html
Normal file
16
src/General/html/Settings/Filter-select.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<select name=filter>
|
||||||
|
<option value=guide>Guide</option>
|
||||||
|
<option value=name>Name</option>
|
||||||
|
<option value=uniqueID>Unique ID</option>
|
||||||
|
<option value=tripcode>Tripcode</option>
|
||||||
|
<option value=capcode>Capcode</option>
|
||||||
|
<option value=email>E-mail</option>
|
||||||
|
<option value=subject>Subject</option>
|
||||||
|
<option value=comment>Comment</option>
|
||||||
|
<option value=flag>Flag</option>
|
||||||
|
<option value=filename>Filename</option>
|
||||||
|
<option value=dimensions>Image dimensions</option>
|
||||||
|
<option value=filesize>Filesize</option>
|
||||||
|
<option value=MD5>Image MD5</option>
|
||||||
|
</select>
|
||||||
|
<div></div>
|
||||||
6
src/General/html/Settings/Keybinds.html
Normal file
6
src/General/html/Settings/Keybinds.html
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<div class=warning #{if Conf['Keybinds'] then 'hidden' else ''}><code>Keybinds</code> are disabled.</div>
|
||||||
|
<div>Allowed keys: <kbd>a-z</kbd>, <kbd>0-9</kbd>, <kbd>Ctrl</kbd>, <kbd>Shift</kbd>, <kbd>Alt</kbd>, <kbd>Meta</kbd>, <kbd>Enter</kbd>, <kbd>Esc</kbd>, <kbd>Up</kbd>, <kbd>Down</kbd>, <kbd>Right</kbd>, <kbd>Left</kbd>.</div>
|
||||||
|
<div>Press <kbd>Backspace</kbd> to disable a keybind.</div>
|
||||||
|
<table><tbody>
|
||||||
|
<tr><th>Actions</th><th>Keybinds</th></tr>
|
||||||
|
</tbody></table>
|
||||||
10
src/General/html/Settings/Sauce.html
Normal file
10
src/General/html/Settings/Sauce.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<div class=warning #{if Conf['Sauce'] then 'hidden' else ''}><code>Sauce</code> is disabled.</div>
|
||||||
|
<div>Lines starting with a <code>#</code> will be ignored.</div>
|
||||||
|
<div>You can specify a display text by appending <code>;text:[text]</code> to the URL.</div>
|
||||||
|
<ul>These parameters will be replaced by their corresponding values:
|
||||||
|
<li><code>%TURL</code>: Thumbnail URL.</li>
|
||||||
|
<li><code>%URL</code>: Full image URL.</li>
|
||||||
|
<li><code>%MD5</code>: MD5 hash.</li>
|
||||||
|
<li><code>%board</code>: Current board.</li>
|
||||||
|
</ul>
|
||||||
|
<textarea name=sauces class=field spellcheck=false></textarea>
|
||||||
14
src/General/html/Settings/Settings.html
Normal file
14
src/General/html/Settings/Settings.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<nav>
|
||||||
|
<div class=sections-list></div>
|
||||||
|
<p class='imp-exp-result warning'></p>
|
||||||
|
<div class=credits>
|
||||||
|
<a class=export>Export</a> |
|
||||||
|
<a class=import>Import</a> |
|
||||||
|
<input type=file style='display: none;'>
|
||||||
|
<a href='<%= meta.page %>' target=_blank><%= meta.name %></a> |
|
||||||
|
<a href='<%= meta.repo %>blob/<%= meta.mainBranch %>/CHANGELOG.md' target=_blank>#{g.VERSION}</a> |
|
||||||
|
<a href='<%= meta.repo %>blob/<%= meta.mainBranch %>/README.md#reporting-bugs-and-suggestions' target=_blank>Issues</a> |
|
||||||
|
<a href=javascript:; class=close title=Close>×</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<div class=section-container><section></section></div>
|
||||||
@ -321,4 +321,4 @@ ThreadUpdater =
|
|||||||
deletedPosts: deletedPosts
|
deletedPosts: deletedPosts
|
||||||
deletedFiles: deletedFiles
|
deletedFiles: deletedFiles
|
||||||
postCount: OP.replies + 1
|
postCount: OP.replies + 1
|
||||||
fileCount: OP.images + (!!ThreadUpdater.thread.OP.file and !ThreadUpdater.thread.OP.file.isDead)
|
fileCount: OP.images + (!!ThreadUpdater.thread.OP.file and !ThreadUpdater.thread.OP.file.isDead)
|
||||||
|
|||||||
@ -747,45 +747,8 @@ QR =
|
|||||||
|
|
||||||
dialog: ->
|
dialog: ->
|
||||||
dialog = UI.dialog 'qr', 'top:0;right:0;', """
|
dialog = UI.dialog 'qr', 'top:0;right:0;', """
|
||||||
<div class=move>
|
<%= grunt.file.read('src/General/html/Features/QuickReply.html').replace(/>\s+</g, '><').trim() %>
|
||||||
<label>
|
"""
|
||||||
<input type=checkbox id=autohide title=Auto-hide>
|
|
||||||
Quick Reply
|
|
||||||
</label>
|
|
||||||
<a href=javascript:; class=close title=Close>×</a>
|
|
||||||
<select data-name=thread title='Create a new thread / Reply'>
|
|
||||||
<option value=new>New thread</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<form>
|
|
||||||
<div class=persona>
|
|
||||||
<input id=dump-button type=button title='Dump list' value=+ tabindex=0>
|
|
||||||
<input name=name data-name=name title=Name placeholder=Name class=field size=1 tabindex=10>
|
|
||||||
<input name=email data-name=email title=E-mail placeholder=E-mail class=field size=1 tabindex=20>
|
|
||||||
<input name=sub data-name=sub title=Subject placeholder=Subject class=field size=1 tabindex=30>
|
|
||||||
</div>
|
|
||||||
<div class=textarea>
|
|
||||||
<textarea data-name=com title=Comment placeholder=Comment class=field tabindex=40></textarea>
|
|
||||||
<span id=char-count></span>
|
|
||||||
</div>
|
|
||||||
<div id=dump-list-container>
|
|
||||||
<div id=dump-list></div>
|
|
||||||
<a id=add-post href=javascript:; title="Add a post" tabindex=50>+</a>
|
|
||||||
</div>
|
|
||||||
<div id=file-n-submit>
|
|
||||||
<span id=qr-filename-container class=field tabindex=60>
|
|
||||||
<span id=qr-no-file>No selected file</span>
|
|
||||||
<span id=qr-filename></span>
|
|
||||||
</span>
|
|
||||||
<a id=qr-filerm href=javascript:; title='Remove file' tabindex=80>×</a>
|
|
||||||
<input type=submit tabindex=70>
|
|
||||||
</div>
|
|
||||||
<input type=file multiple>
|
|
||||||
<label id=qr-spoiler-label>
|
|
||||||
<input type=checkbox id=qr-file-spoiler title='Spoiler image' tabindex=90>Spoiler?
|
|
||||||
</label>
|
|
||||||
</form>
|
|
||||||
""".replace />\s+</g, '><' # get rid of spaces between elements
|
|
||||||
|
|
||||||
QR.nodes = nodes =
|
QR.nodes = nodes =
|
||||||
el: dialog
|
el: dialog
|
||||||
Loading…
x
Reference in New Issue
Block a user