Merge branch 'v3' of git://github.com/MayhemYDG/4chan-x into v3

Conflicts:
	.gitignore
	Gruntfile.js
	src/config.coffee
	src/css/style.css
	src/features.coffee
	src/features/posting/qr.coffee
This commit is contained in:
Zixaphir 2013-04-22 01:24:11 -07:00
commit 4856a6778d
23 changed files with 4932 additions and 302 deletions

7
.gitignore vendored
View File

@ -1,7 +1,6 @@
node_modules/
tmp/
4chan_x.user.js
Cakefile
script.coffee
*~
*.db
tmp-crx/
tmp-userjs/
tmp-userscript/

View File

@ -1,3 +1,5 @@
- Added the option `Hide Unread Count at (0)`, disabled by default.
### 3.1.4 - *2013-04-17*
- Fix QR remembering the file spoiler state when it shouldn't, for real this time.

View File

@ -1,4 +1,6 @@
## Reporting bugs
## Reporting bugs and suggestions
Reporting bugs:
1. Make sure both your **browser** and **4chan X** are up to date.
2. Disable your other extensions & scripts to identify conflicts.
@ -13,6 +15,12 @@ Open your console with:
- `Ctrl + Shift + K` on Firefox.
- `Ctrl + Shift + O` on Opera.
Respect these guidelines:
- Describe the issue clearly, put some effort into it. A one-liner isn't a good enough description.
- If you want to get your suggestion implemented sooner, make it convincing.
- If you want to criticize, make it convincing and constructive.
- Be mature. Act like an idiot and you will be blocked without warning.
## Development & Contribution
### Get started

View File

@ -5,6 +5,11 @@ module.exports = (grunt) ->
process:
data: pkg
shellOptions =
stdout: true
stderr: true
failOnError: true
# Project configuration.
grunt.initConfig
pkg: pkg
@ -68,27 +73,25 @@ module.exports = (grunt) ->
'build-userscript'
]
exec:
shell:
commit:
command: ->
release = "#{pkg.meta.name} v#{pkg.version}"
return [
'git checkout ' + pkg.meta.mainBranch,
'git commit -am "Release ' + release + '."',
'git tag -a ' + pkg.version + ' -m "' + release + '."',
'git tag -af stable-v3 -m "' + release + '."'
].join(' && ');
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(' && ')
stdout: true
push:
command: 'git push origin --all && git push origin --tags'
stdout: true
options: shellOptions
command: 'git push origin --tags -f && git push origin --all'
watch:
all:
options:
interrupt: true
nospawn: true
files: [
'Gruntfile.coffee'
'package.json'
@ -120,7 +123,7 @@ module.exports = (grunt) ->
grunt.loadNpmTasks 'grunt-contrib-concat'
grunt.loadNpmTasks 'grunt-contrib-copy'
grunt.loadNpmTasks 'grunt-contrib-watch'
grunt.loadNpmTasks 'grunt-exec'
grunt.loadNpmTasks 'grunt-shell'
grunt.registerTask 'default', [
'build'
@ -161,8 +164,8 @@ module.exports = (grunt) ->
grunt.registerTask 'release', [
'default'
'exec:commit'
'exec:push'
'shell:commit'
'shell:push'
]
grunt.registerTask 'patch', [

194
Gruntfile.js Normal file
View File

@ -0,0 +1,194 @@
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/config.coffee',
'src/globals.coffee',
'lib/ui.coffee',
'lib/$.coffee',
'lib/polyfill.coffee',
'src/features.coffee',
'src/qr.coffee',
'src/report.coffee',
'src/databoard.coffee',
'src/main.coffee'
],
dest: 'tmp-<%= pkg.type %>/script.coffee'
},
crx: {
options: concatOptions,
files: {
'builds/crx/manifest.json': 'src/manifest.json',
'builds/crx/script.js': [
'src/banner.js',
'tmp-<%= pkg.type %>/script.js'
]
}
},
userjs: {
options: concatOptions,
src: [
'src/metadata.js',
'src/banner.js',
'tmp-<%= pkg.type %>/script.js'
],
dest: 'builds/<%= pkg.name %>.js'
},
userscript: {
options: concatOptions,
files: {
'builds/<%= pkg.name %>.meta.js': 'src/metadata.js',
'builds/<%= pkg.name %>.user.js': [
'src/metadata.js',
'src/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/**/*',
'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');
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 + '.');
});
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -17,15 +17,15 @@
},
"devDependencies": {
"grunt": "~0.4.1",
"grunt-bump": "~0.0.0",
"grunt-concurrent": "~0.1.1",
"grunt-contrib-clean": "~0.4.0",
"grunt-contrib-coffee": "~0.6.6",
"grunt-bump": "~0.0.2",
"grunt-concurrent": "~0.2.0",
"grunt-contrib-clean": "~0.4.1",
"grunt-contrib-coffee": "~0.6.7",
"grunt-contrib-compress": "~0.4.10",
"grunt-contrib-concat": "~0.2.0",
"grunt-contrib-copy": "~0.4.1",
"grunt-contrib-watch": "~0.3.1",
"grunt-exec": "~0.4.0"
"grunt-shell": "~0.2.2"
},
"repository": {
"type": "git",

View File

@ -97,10 +97,6 @@ Config =
true
'Add buttons to hide single replies.'
]
'Hiding Buttons': [
true
'Add buttons to hide threads / replies, in addition to menu links.'
]
'Stubs': [
true
'Show stubs of hidden threads / replies.'
@ -141,6 +137,10 @@ Config =
true
'Add a drop-down menu to posts.'
]
'Report Link': [
true
'Add a report link to the menu.'
]
'Thread Hiding Link': [
true
'Add a link to hide entire threads.'
@ -148,19 +148,17 @@ Config =
'Reply Hiding Link': [
true
'Add a link to hide single replies.'
]
'Report Link': [
true
'Add a report link to the menu.'
]
'Delete Link': [
true
'Add post and image deletion links to the menu.'
]
<% if (type === 'crx') { %>
'Download Link': [
true
'Add a download with original filename link to the menu. Chrome-only currently.'
]
<% } %>
'Archive Link': [
true
'Add an archive link to the menu.'
@ -175,6 +173,10 @@ Config =
true
'Show the unread posts count in the tab title.'
]
'Hide Unread Count at (0)': [
false
'Hide the unread posts count when it reaches 0.'
]
'Unread Tab Icon': [
true
'Show a different favicon when there are unread posts.'
@ -183,6 +185,10 @@ Config =
true
'Show a line to distinguish read posts from unread ones.'
]
'Scroll to Last Read Post': [
true
'Scroll back to the last read post when reopening a thread.'
]
'Thread Excerpt': [
true
'Show an excerpt of the thread in the tab title.'

View File

@ -97,10 +97,6 @@ a[href="javascript:;"] {
z-index: 10;
}
/* Header */
.fourchan-x body {
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.fixed.top body {
padding-top: 2em;
}
@ -155,24 +151,18 @@ a[href="javascript:;"] {
height: 10px;
position: absolute;
}
#header-bar #toggle-header-bar {
#boardNavDesktop #toggle-header-bar {
display: none;
}
.fixed #header-bar #toggle-header-bar {
.fixed #boardNavDesktop #toggle-header-bar {
display: block;
}
.fixed #header-bar #toggle-header-bar {
cursor: n-resize;
}
.fixed.top header-bar #toggle-header-bar {
.fixed.top boardNavDesktop #toggle-header-bar {
top: 100%;
}
.fixed.bottom #header-bar #toggle-header-bar {
.fixed.bottom #boardNavDesktop #toggle-header-bar {
bottom: 100%;
}
.fixed #header-bar #header-bar.autohide #toggle-header-bar {
cursor: s-resize;
}
#header-bar a:not(.entry) {
text-decoration: none;
padding: 1px;
@ -203,16 +193,17 @@ a[href="javascript:;"] {
/* Notifications */
#notifications {
height: 0;
text-align: center;
position: fixed;
top: 0;
height: 0;
text-align: center;
right: 0;
left: 0;
transition: all .8s .6s cubic-bezier(.55, .055, .675, .19);
}
.top:not(.autohide) ~ #notifications {
top: 2em;
.fixed.top #header-bar #notifications {
position: absolute;
top: 100%;
}
.notification {
color: #FFF;
@ -257,6 +248,10 @@ a[href="javascript:;"] {
}
/* Settings */
:root.fourchan-x body {
-moz-box-sizing: border-box;
box-sizing: border-box;
}
#overlay {
background-color: rgba(0, 0, 0, .5);
top: 0;
@ -274,6 +269,7 @@ a[href="javascript:;"] {
width: 900px;
min-width: 0;
max-width: 100%;
margin: auto;
padding: 3px;
top: 50%;
left: 50%;
@ -478,6 +474,8 @@ a.hide-announcement {
#qp img {
max-height: 300px;
max-width: 500px;
max-height: 80vh;
max-width: 50vw;
}
.qphl {
outline: 2px solid rgba(216, 94, 49, .7);

4382
src/features.coffee Normal file

File diff suppressed because it is too large Load Diff

View File

@ -127,7 +127,7 @@ ThreadHiding =
ThreadHiding.saveHiddenState thread
hide: (thread, makeStub=Conf['Stubs']) ->
return if thread.hidden
return if thread.isHidden
{OP} = thread
threadRoot = OP.nodes.root.parentNode
threadRoot.hidden = thread.isHidden = true

View File

@ -1,14 +1,7 @@
DownloadLink =
init: ->
<% if (type === 'userscript') { %>
# Firefox won't let us download cross-domain content.
return
<% } %>
return if g.VIEW is 'catalog' or !Conf['Menu'] or !Conf['Download Link']
# Test for download feature support.
return unless 'download' of $.el 'a'
a = $.el 'a',
className: 'download-link'
textContent: 'Download file'

View File

@ -5,6 +5,7 @@ PSAHiding =
$.addClass doc, 'hide-announcement'
$.on d, '4chanXInitFinished', @setup
setup: ->
$.off d, '4chanXInitFinished', PSAHiding.setup
@ -24,11 +25,11 @@ PSAHiding =
$.rmClass doc, 'hide-announcement'
$.sync 'hiddenPSAs', PSAHiding.sync
toggle: (e) ->
hide = $.hasClass @, 'hide-announcement'
text = PSAHiding.trim $.id 'globalMessage'
$.get 'hiddenPSAs', [], (item) ->
{hiddenPSAs} = item
$.get 'hiddenPSAs', [], ({hiddenPSAs}) ->
if hide
hiddenPSAs.push text
else
@ -37,12 +38,13 @@ PSAHiding =
hiddenPSAs = hiddenPSAs[-5..]
PSAHiding.sync hiddenPSAs
$.set 'hiddenPSAs', hiddenPSAs
sync: (hiddenPSAs) ->
{btn} = PSAHiding
psa = $.id 'globalMessage'
[psa.hidden, btn.innerHTML, btn.className] = if PSAHiding.trim(psa) in hiddenPSAs
[true, '<span>[&nbsp;+&nbsp;]</span>', 'show-announcement']
[psa.hidden, btn.firstChild.textContent, btn.className] = if PSAHiding.trim(psa) in hiddenPSAs
[true, '[\u00A0+\u00A0]', 'show-announcement']
else
[false, '<span>[&nbsp;-&nbsp;]</span>', 'hide-announcement']
[false, '[\u00A0-\u00A0]', 'hide-announcement']
trim: (psa) ->
psa.textContent.replace(/\W+/g, '').toLowerCase()

View File

@ -9,6 +9,7 @@ CatalogLinks =
input = $ 'input', el
$.on input, 'change', @toggle
$.sync 'Header catalog links', CatalogLinks.set
$.event 'AddMenuEntry',
type: 'header'
@ -21,10 +22,15 @@ CatalogLinks =
# it might be incomplete otherwise.
$.asap (-> $.id 'boardNavMobile'), ->
# Set links on load.
CatalogLinks.toggle.call input
CatalogLinks.set input.checked
toggle: ->
$.event 'CloseMenu'
$.set 'Header catalog links', useCatalog = @checked
CatalogLinks.set useCatalog
set: (useCatalog) ->
path = if useCatalog then 'catalog' else ''
for a in $$ 'a', $.id('boardNavDesktop')
board = a.pathname.split('/')[1]
continue if ['f', 'status', '4chan'].contains(board) or !board
@ -34,7 +40,7 @@ CatalogLinks =
else
"//boards.4chan.org/#{board}/"
else
a.pathname = "/#{board}/#{if useCatalog then 'catalog' else ''}"
a.pathname = "/#{board}/#{path}"
a.title = if useCatalog then "#{a.title} - Catalog" else a.title.replace(/\ -\ Catalog$/, '')
@title = "Turn catalog links #{if useCatalog then 'off' else 'on'}."

View File

@ -5,36 +5,32 @@ Header =
innerHTML: '<i></i>'
@menu = new UI.Menu 'header'
$.on @menuButton, 'click', @menuToggle
$.on @toggle, 'mousedown', @toggleBarVisibility
$.on window, 'load hashchange', Header.hashScroll
@positionToggler = $.el 'span',
textContent: 'Header Position'
className: 'header-position-link'
headerToggler = $.el 'label',
innerHTML: '<input type=checkbox name="Header auto-hide"> Auto-hide header'
@headerToggler = headerToggler.firstElementChild
$.on @menuButton, 'click', @menuToggle
$.on window, 'load hashchange', Header.hashScroll
$.on @headerToggler, 'change', @toggleBarVisibility
{createSubEntry} = Header
subEntries = []
for setting in ['sticky top', 'sticky bottom', 'top']
subEntries.push createSubEntry setting
subEntries.push {el: headerToggler}
@addShortcut Header.menuButton
$.event 'AddMenuEntry',
type: 'header'
el: @positionToggler
order: 108
type: 'header'
el: $.el 'span',
textContent: 'Header'
order: 105
subEntries: subEntries
@headerToggler = $.el 'label',
innerHTML: "<input type=checkbox #{if Conf['Header auto-hide'] then 'checked' else ''}> Auto-hide header"
$.on @headerToggler.firstElementChild, 'change', @toggleBarVisibility
$.event 'AddMenuEntry',
type: 'header'
el: @headerToggler
order: 109
$.on d, 'CreateNotification', @createNotification
$.asap (-> d.body), ->
@ -57,11 +53,8 @@ Header =
toggle: $.el 'div',
id: 'toggle-header-bar'
settings: $.el 'div',
id: 'settings-container'
createSubEntry: (setting)->
createSubEntry: (setting) ->
label = $.el 'label',
textContent: "#{setting}"
@ -85,7 +78,7 @@ Header =
$.sync 'Header auto-hide', Header.setBarVisibility
$.add fullBoardList, [nav.childNodes...]
$.add nav, [fullBoardList, Header.shortcuts, Header.bar, Header.toggle, Header.settings]
$.add nav, [fullBoardList, Header.shortcuts, Header.bar, Header.toggle]
if Conf['Custom Board Navigation']
fullBoardList.hidden = true
@ -181,11 +174,27 @@ Header =
$.addClass doc, 'top'
setBarVisibility: (hide) ->
Header.headerToggler.firstElementChild.checked = hide
Header.headerToggler.checked = hide
$.event 'CloseMenu'
(if hide then $.addClass else $.rmClass) Header.nav, 'autohide'
toggleBarVisibility: (e) ->
return if e.type is 'mousedown' and e.button isnt 0 # not LMB
hide = if @nodeName is 'INPUT'
@checked
else
!$.hasClass Header.bar, 'autohide'
Conf['Header auto-hide'] = hide
$.set 'Header auto-hide', hide
Header.setBarVisibility hide
message = if hide
'The header bar will automatically hide itself.'
else
'The header bar will remain visible.'
new Notification 'info', message, 2
hashScroll: ->
return unless post = @location.hash[1..]
return unless post = $.id @location.hash[1..]
return if (Get.postFromRoot post).isHidden
Header.scrollToPost post
@ -196,20 +205,6 @@ Header =
top += - headRect.top - headRect.height
(if $.engine is 'webkit' then d.body else doc).scrollTop += top
toggleBarVisibility: (e) ->
return if e.type is 'mousedown' and e.button isnt 0 # not LMB
hide = if @nodeName is 'INPUT'
@checked
else
!$.hasClass Header.nav, 'autohide'
Header.setBarVisibility hide
message = if hide
'The header bar will automatically hide itself.'
else
'The header bar will remain visible.'
new Notification 'info', message, 2
$.set 'Header auto-hide', hide
addShortcut: (el) ->
shortcut = $.el 'span',
className: 'shortcut'

View File

@ -8,6 +8,8 @@ Redirect =
"//nsfw.foolz.us/#{boardID}/full_image/#{filename}"
when 'po'
"//archive.thedarkcave.org/#{boardID}/full_image/#{filename}"
when 'hr', 'tv'
"http://archive.4plebs.org/#{boardID}/full_image/#{filename}"
when 'ck', 'fa', 'lit', 's4s'
"//fuuka.warosu.org/#{boardID}/full_image/#{filename}"
when 'cgl', 'g', 'mu', 'w'
@ -26,6 +28,8 @@ Redirect =
"https://nsfw.foolz.us/_/api/chan/post/?board=#{boardID}&num=#{postID}"
when 'c', 'int', 'out', 'po'
"//archive.thedarkcave.org/_/api/chan/post/?board=#{boardID}&num=#{postID}"
when 'hr', 'x'
"http://archive.4plebs.org/_/api/chan/post/?board=#{boardID}&num=#{postID}"
# for fuuka-based archives:
# https://github.com/eksopl/fuuka/issues/27
to: (data) ->
@ -37,6 +41,8 @@ Redirect =
Redirect.path '//nsfw.foolz.us', 'foolfuuka', data
when 'int', 'out', 'po'
Redirect.path '//archive.thedarkcave.org', 'foolfuuka', data
when 'hr'
Redirect.path 'http://archive.4plebs.org', 'foolfuuka', data
when 'ck', 'fa', 'lit', 's4s'
Redirect.path '//fuuka.warosu.org', 'fuuka', data
when 'diy', 'g', 'sci'

View File

@ -6,7 +6,4 @@ ThreadExcerpt =
name: 'Thread Excerpt'
cb: @node
node: ->
d.title = if (excerpt = Get.threadExcerpt @).length > 80
"#{excerpt[...77]}..."
else
excerpt
d.title = Get.threadExcerpt @

View File

@ -26,8 +26,9 @@ Unread =
$.on d, 'ThreadUpdate', Unread.onUpdate
$.on d, 'scroll visibilitychange', Unread.read
$.on d, 'visibilitychange', Unread.setLine if Conf['Unread Line']
$.on window, 'load', Unread.scroll if Conf['Scroll to Last Read Post']
return unless Conf['Scroll to Last Read Post']
scroll: ->
# Let the header's onload callback handle it.
return if (hash = location.hash.match /\d+/) and hash[0] of @posts
if Unread.posts.length
@ -136,10 +137,7 @@ Unread =
count = Unread.posts.length
if Conf['Unread Count']
d.title = if g.DEAD
"(#{Unread.posts.length}) /#{g.BOARD}/ - 404"
else
"(#{Unread.posts.length}) #{Unread.title}"
d.title = "#{if count or !Conf['Hide Unread Count at (0)'] then "(#{count}) " else ''}#{if g.DEAD then "/#{g.BOARD}/ - 404" else "#{Unread.title}"}"
<% if (type === 'crx') { %>
# XXX Chrome bug where it doesn't always update the tab title.
# crbug.com/124381

View File

@ -805,7 +805,7 @@ QR =
QR.mimeTypes = mimeTypes.split ', '
# Add empty mimeType to avoid errors with URLs selected in Window's file dialog.
QR.mimeTypes.push ''
nodes.fileInput.max = $('input[name=MAX_FILE_SIZE]').value
nodes.fileInput.max = $('input[name=MAX_FILE_SIZE]').value
<% if (type !== 'userjs') { %>
# Opera's accept attribute is fucked up
nodes.fileInput.accept = "text/*, #{mimeTypes}"
@ -842,8 +842,8 @@ QR =
$.on elm, 'blur', QR.focusout
$.on elm, 'focus', QR.focusin
<% } %>
$.on QR.nodes.el, 'focusin', QR.focusin
$.on QR.nodes.el, 'focusout', QR.focusout
$.on dialog, 'focusin', QR.focusin
$.on dialog, 'focusout', QR.focusout
$.on nodes.autohide, 'change', QR.toggleHide
$.on nodes.close, 'click', QR.close
$.on nodes.dumpButton, 'click', -> nodes.el.classList.toggle 'dump'

View File

@ -5,6 +5,8 @@ Get =
OP.info.comment.replace(/\n+/g, ' // ') or
Conf['Anonymize'] and 'Anonymous' or
$('.nameBlock', OP.nodes.info).textContent.trim()
if excerpt.length > 70
excerpt = "#{excerpt[...67]}..."
"/#{thread.board}/ - #{excerpt}"
postFromRoot: (root) ->
link = $ 'a[title="Highlight this post"]', root

View File

@ -51,7 +51,7 @@ Settings =
<div class=credits>
<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 %>/CONTRIBUTING.md#reporting-bugs' target=_blank>Issues</a> |
<a href='<%= meta.repo %>blob/<%= meta.mainBranch %>/CONTRIBUTING.md#reporting-bugs-and-suggestions' target=_blank>Issues</a> |
<a href=javascript:; class=close title=Close>×</a>
</div>
</nav>