Merge branch 'v3'

Conflicts:
	CHANGELOG.md
	LICENSE
	builds/4chan-X.js
	builds/4chan-X.meta.js
	builds/appchan-x.user.js
	builds/crx/manifest.json
	builds/crx/script.js
	latest.js
	package.json
	src/Filtering/PostHiding.coffee
	src/General/Build.coffee
	src/General/Header.coffee
	src/General/Main.coffee
	src/General/css/style.css
	src/General/html/Features/QuickReply.html
	src/Menu/Menu.coffee
	src/Miscellaneous/AnnouncementHiding.coffee
	src/Posting/QuickReply.coffee
This commit is contained in:
Zixaphir 2013-05-10 02:41:08 -07:00
commit 9ce09d216e
25 changed files with 12135 additions and 432 deletions

View File

@ -1,3 +1,19 @@
MayhemYDG:
- Added Foolzashit archive
- Added `blink` class to document in preparation for future versions of Chrome and Opera
- Take advantage of announcement's new `data-utc` value for hiding
- `data-utc` is a timestamp, this allows us to not have to store the entire text content of the announcement
seaweedchan:
- Hide stub link added in menus of stubs
- #dump-button moved into #qr-filename-container as a simple + link
- QR with 4chan Pass made a little wider
- Styling changes for spoiler label, also added `.has-spoiler` class for QR
- Turn all brackets into pseudo-elements. Brackets can be changed by overwriting the `content` of `.fourchanx-link::before` (`[`) and `.fourchanx-link::after` (`]`), or removed entirely with ease.
- Note: This does not change the default brackets around `toggle-all` in the custom navigation. These are up to the user.
![QR styling changes](src/General/img/changelog/1.1.18.png)
### 2.0.2 - 2013-05-09 ### 2.0.2 - 2013-05-09
zixaphir zixaphir
- More mascot and theme editor fixes - More mascot and theme editor fixes
@ -25,4 +41,4 @@ Completely rebased off https://github.com/seaweedchan/4chan-x/ 1.1.16
I hate changelogs so I'd rather not talk about it, but rest assured it I hate changelogs so I'd rather not talk about it, but rest assured it
comes with various performance improvements, layout changes, and the comes with various performance improvements, layout changes, and the
like. If you don't like it, I'm sorry, but change comes with sacrifice, like. If you don't like it, I'm sorry, but change comes with sacrifice,
and we've certainly gained more than we've lost. and we've certainly gained more than we've lost.

10354
builds/4chan-X.js Normal file

File diff suppressed because one or more lines are too long

19
builds/4chan-X.meta.js Normal file
View File

@ -0,0 +1,19 @@
// ==UserScript==
// @name 4chan X
// @version 1.1.18
// @namespace 4chan-X
// @description Cross-browser userscript for maximum lurking on 4chan.
// @license MIT; https://github.com/seaweedchan/4chan-x/blob/master/LICENSE
// @match *://api.4chan.org/*
// @match *://boards.4chan.org/*
// @match *://images.4chan.org/*
// @match *://sys.4chan.org/*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_openInTab
// @run-at document-start
// @updateURL https://github.com/seaweedchan/4chan-x/raw/stable/builds/4chan-X.meta.js
// @downloadURL https://github.com/seaweedchan/4chan-x/raw/stable/builds/4chan-X.user.js
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAgMAAAAqbBEUAAAACVBMVEUAAGcAAABmzDNZt9VtAAAAAXRSTlMAQObYZgAAAHFJREFUKFOt0LENACEIBdBv4Qju4wgWanEj3D6OcIVMKaitYHEU/jwTCQj8W75kiVCSBvdQ5/AvfVHBin11BgdRq3ysBgfwBDRrj3MCIA+oAQaku/Q1cNctrAmyDl577tOThYt/Y1RBM4DgOHzM0HFTAyLukH/cmRnqAAAAAElFTkSuQmCC
// ==/UserScript==

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

@ -29,7 +29,7 @@
"grunt-contrib-compress": "~0.5.0", "grunt-contrib-compress": "~0.5.0",
"grunt-contrib-concat": "~0.3.0", "grunt-contrib-concat": "~0.3.0",
"grunt-contrib-copy": "~0.4.1", "grunt-contrib-copy": "~0.4.1",
"grunt-contrib-watch": "~0.4.0", "grunt-contrib-watch": "~0.4.2",
"grunt-shell": "~0.2.2" "grunt-shell": "~0.2.2"
}, },
"repository": { "repository": {
@ -44,6 +44,6 @@
"license": "MIT", "license": "MIT",
"readmeFilename": "README.md", "readmeFilename": "README.md",
"engines": { "engines": {
"node": ">=0.8" "node": ">=0.10"
} }
} }

View File

@ -14,14 +14,16 @@ Redirect =
cgl: "//rbt.asia/" cgl: "//rbt.asia/"
c: "//archive.nyafuu.org/" c: "//archive.nyafuu.org/"
d: "//loveisover.me/" d: "//loveisover.me/"
e: "http://archive.foolzashit.com"
hr: "http://archive.4plebs.org/" hr: "http://archive.4plebs.org/"
u: "//nsfw.foolz.us/" u: "//nsfw.foolz.us/"
po: "//archive.thedarkcave.org/" po: "//archive.thedarkcave.org/"
vg: "http://nth.pensivenonsen.se/" vg: "http://nth.pensivenonsen.se/"
c: "//archive.nyafuu.org/" c: "//archive.nyafuu.org/"
o.adv = o.asp = o.cm = o.i = o.n = o.o = o.p = o.s = o.t = o.trv = o.y = o.lgbt = o.s4s = o.e
o.gd = o.jp = o.m = o.q = o.tg = o.vp = o.vr = o.wsg = o.a o.gd = o.jp = o.m = o.q = o.tg = o.vp = o.vr = o.wsg = o.a
o.fa = o.lit = o.s4s = o.ck o.fa = o.lit = o.ck
o.k = o.toy = o.x = o.an o.k = o.toy = o.x = o.an
o.g = o.mu = o.cgl o.g = o.mu = o.cgl
o.w = o.wg = o.c o.w = o.wg = o.c
@ -99,6 +101,10 @@ Redirect =
base: 'http://nth.pensivenonsen.se' base: 'http://nth.pensivenonsen.se'
boards: ['vg'] boards: ['vg']
type: 'foolfuuka' type: 'foolfuuka'
'FoolzaShit':
base: 'http://archive.foolzashit.com'
boards: ["adv", "asp", "cm", "e", "i", "lgbt", "n", "o", "p", "s", "s4s", "t", "trv", "y"]
type: 'foolfuuka'
'Warosu': 'Warosu':
base: '//fuuka.warosu.org' base: '//fuuka.warosu.org'
boards: ['cgl', 'ck', 'fa', 'jp', 'lit', 's4s', 'q', 'tg', 'vr'] boards: ['cgl', 'ck', 'fa', 'jp', 'lit', 's4s', 'q', 'tg', 'vr']

View File

@ -64,6 +64,10 @@ PostHiding =
innerHTML: '<input type=checkbox name=thisPost> This post' innerHTML: '<input type=checkbox name=thisPost> This post'
replies = $.el 'label', replies = $.el 'label',
innerHTML: "<input type=checkbox name=replies> Show replies" innerHTML: "<input type=checkbox name=replies> Show replies"
hideStubLink = $.el 'a',
textContent: 'Hide stub'
href: 'javascript:;'
$.on hideStubLink, 'click', PostHiding.menu.hideStub
$.event 'AddMenuEntry', $.event 'AddMenuEntry',
type: 'post' type: 'post'
@ -80,6 +84,18 @@ PostHiding =
true true
subEntries: [{el: apply}, {el: thisPost}, {el: replies}] subEntries: [{el: apply}, {el: thisPost}, {el: replies}]
# Extra Entry to hide stubs on hidden posts.
$.event 'AddMenuEntry',
type: 'post'
el: hideStubLink
order: 15
open: (post) ->
if !post.isReply or post.isClone or !post.isHidden
return false
unless data = PostHiding.db.get {boardID: post.board.ID, threadID: post.thread.ID, postID: post.ID}
return false
PostHiding.menu.post = post
hide: -> hide: ->
parent = @parentNode parent = @parentNode
thisPost = $('input[name=thisPost]', parent).checked thisPost = $('input[name=thisPost]', parent).checked
@ -110,11 +126,16 @@ PostHiding =
if data = PostHiding.db.get {boardID: post.board.ID, threadID: post.thread.ID, postID: post.ID} if data = PostHiding.db.get {boardID: post.board.ID, threadID: post.thread.ID, postID: post.ID}
PostHiding.saveHiddenState post, !(thisPost and replies), !thisPost, data.makeStub, !replies PostHiding.saveHiddenState post, !(thisPost and replies), !thisPost, data.makeStub, !replies
$.event 'CloseMenu' $.event 'CloseMenu'
hideStub: ->
{post} = PostHiding.menu
post.nodes.root.hidden = true
$.event 'CloseMenu'
return
makeButton: (post, type) -> makeButton: (post, type) ->
a = $.el 'a', a = $.el 'a',
className: "#{type}-reply-button" className: "#{type}-reply-button"
innerHTML: "<span>[&nbsp;#{if type is 'hide' then '-' else '+'}&nbsp;]</span>" innerHTML: "<span class=fourchanx-link>&nbsp;#{if type is 'hide' then '-' else '+'}&nbsp;</span>"
href: 'javascript:;' href: 'javascript:;'
$.on a, 'click', PostHiding.toggle $.on a, 'click', PostHiding.toggle
a a

View File

@ -71,6 +71,11 @@ ThreadHiding =
makeStub = $.el 'label', makeStub = $.el 'label',
innerHTML: "<input type=checkbox #{if Conf['Stubs'] then 'checked' else ''}> Make stub" innerHTML: "<input type=checkbox #{if Conf['Stubs'] then 'checked' else ''}> Make stub"
hideStubLink = $.el 'a',
textContent: 'Hide stub'
href: 'javascript:;'
$.on hideStubLink, 'click', ThreadHiding.menu.hideStub
$.event 'AddMenuEntry', $.event 'AddMenuEntry',
type: 'post' type: 'post'
el: div el: div
@ -81,17 +86,32 @@ ThreadHiding =
ThreadHiding.menu.thread = thread ThreadHiding.menu.thread = thread
true true
subEntries: [el: apply; el: makeStub] subEntries: [el: apply; el: makeStub]
$.event 'AddMenuEntry',
type: 'post'
el: hideStubLink
order: 15
open: ({thread, isReply}) ->
if isReply or !thread.isHidden
return false
ThreadHiding.menu.thread = thread
hide: -> hide: ->
makeStub = $('input', @parentNode).checked makeStub = $('input', @parentNode).checked
{thread} = ThreadHiding.menu {thread} = ThreadHiding.menu
ThreadHiding.hide thread, makeStub ThreadHiding.hide thread, makeStub
ThreadHiding.saveHiddenState thread, makeStub ThreadHiding.saveHiddenState thread, makeStub
$.event 'CloseMenu' $.event 'CloseMenu'
hideStub: ->
{thread} = ThreadHiding.menu
ThreadHiding.hide thread, false
$.event 'CloseMenu'
return
makeButton: (thread, type) -> makeButton: (thread, type) ->
a = $.el 'a', a = $.el 'a',
className: "#{type}-thread-button" className: "#{type}-thread-button"
innerHTML: "<span>[&nbsp;#{if type is 'hide' then '-' else '+'}&nbsp;]</span>" innerHTML: "<span class=fourchanx-link>&nbsp;#{if type is 'hide' then '-' else '+'}&nbsp;</span>"
href: 'javascript:;' href: 'javascript:;'
a.setAttribute 'data-fullid', thread.fullID a.setAttribute 'data-fullid', thread.fullID
$.on a, 'click', ThreadHiding.toggle $.on a, 'click', ThreadHiding.toggle
@ -122,7 +142,6 @@ ThreadHiding =
ThreadHiding.saveHiddenState thread ThreadHiding.saveHiddenState thread
hide: (thread, makeStub=Conf['Stubs']) -> hide: (thread, makeStub=Conf['Stubs']) ->
return if thread.isHidden
{OP} = thread {OP} = thread
threadRoot = OP.nodes.root.parentNode threadRoot = OP.nodes.root.parentNode
thread.isHidden = true thread.isHidden = true

View File

@ -35,7 +35,10 @@ Build =
o.file = o.file =
name: data.filename + data.ext name: data.filename + data.ext
timestamp: "#{data.tim}#{data.ext}" timestamp: "#{data.tim}#{data.ext}"
url: "//images.4chan.org/#{boardID}/src/#{data.tim}#{data.ext}" url: if boardID is 'f'
"//images.4channel.org/#{boardID}/src/#{data.filename}#{data.ext}"
else
"//images.4chan.org/#{boardID}/src/#{data.tim}#{data.ext}"
height: data.h height: data.h
width: data.w width: data.w
MD5: data.md5 MD5: data.md5
@ -60,7 +63,7 @@ Build =
} = o } = o
isOP = postID is threadID isOP = postID is threadID
staticPath = '//static.4chan.org' staticPath = '//static.4chan.org/image/'
if email if email
emailStart = '<a href="mailto:' + email + '" class="useremail">' emailStart = '<a href="mailto:' + email + '" class="useremail">'
@ -83,21 +86,21 @@ Build =
capcodeClass = " capcodeAdmin" capcodeClass = " capcodeAdmin"
capcodeStart = " <strong class='capcode hand id_admin'" + capcodeStart = " <strong class='capcode hand id_admin'" +
"title='Highlight posts by the Administrator'>## Admin</strong>" "title='Highlight posts by the Administrator'>## Admin</strong>"
capcode = " <img src='#{staticPath}/image/adminicon.gif' " + capcode = " <img src='#{staticPath}adminicon.gif' " +
"alt='This user is the 4chan Administrator.' " + "alt='This user is the 4chan Administrator.' " +
"title='This user is the 4chan Administrator.' class=identityIcon>" "title='This user is the 4chan Administrator.' class=identityIcon>"
when 'mod' when 'mod'
capcodeClass = " capcodeMod" capcodeClass = " capcodeMod"
capcodeStart = " <strong class='capcode hand id_mod' " + capcodeStart = " <strong class='capcode hand id_mod' " +
"title='Highlight posts by Moderators'>## Mod</strong>" "title='Highlight posts by Moderators'>## Mod</strong>"
capcode = " <img src='#{staticPath}/image/modicon.gif' " + capcode = " <img src='#{staticPath}modicon.gif' " +
"alt='This user is a 4chan Moderator.' " + "alt='This user is a 4chan Moderator.' " +
"title='This user is a 4chan Moderator.' class=identityIcon>" "title='This user is a 4chan Moderator.' class=identityIcon>"
when 'developer' when 'developer'
capcodeClass = " capcodeDeveloper" capcodeClass = " capcodeDeveloper"
capcodeStart = " <strong class='capcode hand id_developer' " + capcodeStart = " <strong class='capcode hand id_developer' " +
"title='Highlight posts by Developers'>## Developer</strong>" "title='Highlight posts by Developers'>## Developer</strong>"
capcode = " <img src='#{staticPath}/image/developericon.gif' " + capcode = " <img src='#{staticPath}developericon.gif' " +
"alt='This user is a 4chan Developer.' " + "alt='This user is a 4chan Developer.' " +
"title='This user is a 4chan Developer.' class=identityIcon>" "title='This user is a 4chan Developer.' class=identityIcon>"
else else
@ -113,15 +116,14 @@ Build =
'' ''
if file?.isDeleted if file?.isDeleted
fileHTML = fileHtml = if isOP
if isOP "<div class=file id=f#{data.no}><div class=fileInfo></div><span class=fileThumb>" +
"<div id=f#{postID} class=file><div class=fileInfo></div><span class=fileThumb>" + "<img src='#{staticPath}filedeleted.gif' alt='File deleted.' class=fileDeletedRes>" +
"<img src='#{staticPath}/image/filedeleted.gif' alt='File deleted.' class='fileDeleted retina'>" + "</span></div>"
"</span></div>" else
else "<div class=file id=f#{data.no}><span class=fileThumb>" +
"<div id=f#{postID} class=file><span class=fileThumb>" + "<img src='#{staticPath}filedeleted-res.gif' alt='File deleted.' class=fileDeletedRes>" +
"<img src='#{staticPath}/image/filedeleted-res.gif' alt='File deleted.' class='fileDeletedRes retina'>" + "</span></div>"
"</span></div>"
else if file else if file
ext = file.name[-3..] ext = file.name[-3..]
if !file.twidth and !file.theight and ext is 'gif' # wtf ? if !file.twidth and !file.theight and ext is 'gif' # wtf ?
@ -134,16 +136,19 @@ Build =
if file.isSpoiler if file.isSpoiler
fileSize = "Spoiler Image, #{fileSize}" fileSize = "Spoiler Image, #{fileSize}"
unless isArchived unless isArchived
fileThumb = '//static.4chan.org/image/spoiler' fileThumb = "#{staticPath}spoiler"
if spoilerRange = Build.spoilerRange[boardID] if spoilerRange = Build.spoilerRange[boardID]
# Randomize the spoiler image. # Randomize the spoiler image.
fileThumb += "-#{boardID}" + Math.floor 1 + spoilerRange * Math.random() fileThumb += "-#{boardID}" + Math.floor 1 + spoilerRange * Math.random()
fileThumb += '.png' fileThumb += '.png'
file.twidth = file.theight = 100 file.twidth = file.theight = 100
if boardID.ID isnt 'f' imgSrc = if boardID is 'f'
imgSrc = "<a class='fileThumb#{if file.isSpoiler then ' imgspoiler' else ''}' href='#{file.url}' target=_blank>" + ''
"<img src='#{fileThumb}' alt='#{fileSize}' data-md5=#{file.MD5} style='height: #{file.theight}px; width: #{file.twidth}px;'></a>" else
"<a class='fileThumb#{if file.isSpoiler then ' imgspoiler' else ''}' href='#{file.url}' target=_blank>" +
"<img src='#{fileThumb}' alt='#{fileSize}' data-md5=#{file.MD5} style='height: #{file.theight}px; width: #{file.twidth}px;'>" +
"</a>"
# Ha ha, filenames! # Ha ha, filenames!
# html -> text, translate WebKit's %22s into "s # html -> text, translate WebKit's %22s into "s
@ -179,12 +184,12 @@ Build =
sticky = sticky =
if isSticky if isSticky
' <img src=//static.4chan.org/image/sticky.gif alt=Sticky title=Sticky class=stickyIcon>' " <img src=#{staticPath}sticky.gif alt=Sticky title=Sticky class=stickyIcon>"
else else
'' ''
closed = closed =
if isClosed if isClosed
' <img src=//static.4chan.org/image/closed.gif alt=Closed title=Closed class=closedIcon>' " <img src=#{staticPath}closed.gif alt=Closed title=Closed class=closedIcon>"
else else
'' ''
@ -249,4 +254,4 @@ Build =
continue if href[0] is '/' # Cross-board quote, or board link continue if href[0] is '/' # Cross-board quote, or board link
quote.href = "/#{boardID}/res/#{href}" # Fix pathnames quote.href = "/#{boardID}/res/#{href}" # Fix pathnames
container container

View File

@ -786,9 +786,9 @@ http://iqdb.org/?url=%TURL
boardnav: '[ toggle-all ] [current-title]' boardnav: '[ toggle-all ] [current-title]'
QR: QR:
'QR.personas': [ 'QR.personas': """
'#email:"sage";boards:jp;always' #email:"sage";boards:jp;always
].join '\n' """
time: '%m/%d/%y(%a)%H:%M:%S' time: '%m/%d/%y(%a)%H:%M:%S'

View File

@ -55,7 +55,7 @@ Header =
return unless Main.isThisPageLegit() return unless Main.isThisPageLegit()
# Wait for #boardNavMobile instead of #boardNavDesktop, # Wait for #boardNavMobile instead of #boardNavDesktop,
# it might be incomplete otherwise. # it might be incomplete otherwise.
$.asap (-> $.id('boardNavMobile') or d.readyState is 'complete'), @setBoardList $.asap (-> $.id('boardNavMobile') or d.readyState in ['interactive', 'complete']), @setBoardList
$.prepend d.body, @bar $.prepend d.body, @bar
$.add d.body, Header.hover $.add d.body, Header.hover
@setBarPosition Conf['Bottom Header'] @setBarPosition Conf['Bottom Header']
@ -82,7 +82,7 @@ Header =
boardList = $.el 'span', boardList = $.el 'span',
id: 'board-list' id: 'board-list'
innerHTML: "<span id=custom-board-list></span><span id=full-board-list hidden>[<a href=javascript:; class='hide-board-list-button'> - </a>] #{fourchannav.innerHTML}</span>" innerHTML: "<span id=custom-board-list></span><span id=full-board-list hidden><a href=javascript:; class='hide-board-list-button fourchanx-link'>&nbsp;&nbsp;-&nbsp;&nbsp;</a> #{fourchannav.innerHTML}</span>"
fullBoardList = $ '#full-board-list', boardList fullBoardList = $ '#full-board-list', boardList
btn = $ '.hide-board-list-button', fullBoardList btn = $ '.hide-board-list-button', fullBoardList
$.on btn, 'click', Header.toggleBoardList $.on btn, 'click', Header.toggleBoardList
@ -245,8 +245,8 @@ Header =
addShortcut: (el) -> addShortcut: (el) ->
shortcut = $.el 'span', shortcut = $.el 'span',
className: 'shortcut' className: 'shortcut fourchanx-link'
$.add shortcut, [$.tn(' ['), el, $.tn(']')] $.add shortcut, el
$.prepend Header.shortcuts, shortcut $.prepend Header.shortcuts, shortcut
menuToggle: (e) -> menuToggle: (e) ->

View File

@ -1272,8 +1272,10 @@ if _conf['Post Form Style'] isnt 'float' and _conf["Post Form Slideout Transitio
#{ #{
if _conf['Compact Post Form Inputs'] then " if _conf['Compact Post Form Inputs'] then "
.persona input.field { .persona input.field {
width: 29.6%; width: 33%;
margin: 0 0 0 0.4%; }
.persona input.field:not(:first-child) {
margin: 0 0 0 0.5%;
} }
#qr textarea.field { #qr textarea.field {
height: 14.9em; height: 14.9em;
@ -1288,10 +1290,6 @@ if _conf['Compact Post Form Inputs'] then "
.persona input.field { .persona input.field {
width: 100%; width: 100%;
} }
.persona input.field[name='name'] {
width: 89.6%;
margin: 0 0 0 0.4%;
}
#qr textarea.field { #qr textarea.field {
height: 11.6em; height: 11.6em;
min-height: 6em; min-height: 6em;
@ -1352,13 +1350,21 @@ input:not([type=radio]) {
} }
/* Fake File Input */ /* Fake File Input */
#qr-filename, #qr-filename,
#qr-filerm,
.has-file #qr-no-file { .has-file #qr-no-file {
display: none; display: none;
} }
#qr-no-file, #qr-no-file,
.has-file #qr-filerm,
.has-file #qr-filename { .has-file #qr-filename {
display: block; display: block;
} }
#qr-extras-container {
position: absolute;
right: 3px;
top: 2px;
z-index: 2;
}
#qr-filename-container { #qr-filename-container {
#{Style.sizing}: border-box; #{Style.sizing}: border-box;
display: inline-block; display: inline-block;
@ -1370,12 +1376,6 @@ input:not([type=radio]) {
overflow: hidden; overflow: hidden;
padding: 2px 1px 0; padding: 2px 1px 0;
} }
#qr-filerm {
position: absolute;
right: 3px;
top: 2px;
z-index: 2;
}
/* Thread Select / Spoiler Label */ /* Thread Select / Spoiler Label */
#qr-thread-select { #qr-thread-select {
vertical-align: bottom; vertical-align: bottom;

997
src/General/css/style.css Normal file
View File

@ -0,0 +1,997 @@
/* General */
.dialog {
box-shadow: 0 1px 2px rgba(0, 0, 0, .15);
border: 1px solid;
display: block;
padding: 0;
}
.captcha-img,
.field {
background-color: #FFF;
border: 1px solid #CCC;
-moz-box-sizing: border-box;
box-sizing: border-box;
color: #333;
font: 13px sans-serif;
outline: none;
transition: color .25s, border-color .25s;
transition: color .25s, border-color .25s;
}
.field::-moz-placeholder,
.field:hover::-moz-placeholder {
color: #AAA !important;
font-size: 13px !important;
opacity: 1.0 !important;
}
.captch-img:hover,
.field:hover {
border-color: #999;
}
.field:hover, .field:focus {
color: #000;
}
.field[disabled] {
background-color: #F2F2F2;
color: #888;
}
.move {
cursor: move;
overflow: hidden;
}
label, .favicon {
cursor: pointer;
}
a[href="javascript:;"] {
text-decoration: none;
}
.warning {
color: red;
}
#boardNavDesktop {
display: none !important;
}
a {
outline: none !important;
}
/* 4chan style fixes */
.opContainer, .op {
display: block !important;
overflow: visible !important;
}
[hidden] {
display: none !important;
}
/* fixed, z-index */
#overlay,
#fourchanx-settings,
#qp, #ihover,
#navlinks, .fixed #header-bar,
#watcher,
:root.float #updater,
:root.float #thread-stats,
#qr {
position: fixed;
}
#fourchanx-settings {
z-index: 999;
}
#overlay {
z-index: 900;
}
#notifications {
z-index: 70;
}
#qp, #ihover {
z-index: 60;
}
#menu {
z-index: 50;
}
#navlinks, #updater, #thread-stats {
z-index: 40;
}
.fixed #header-bar.autohide {
z-index: 35;
}
#qr {
z-index: 30;
}
#watcher {
z-index: 20;
}
.fixed #header-bar {
z-index: 10;
}
/* Header */
.fixed.top body {
padding-top: 2em;
}
.fixed.bottom body {
padding-bottom: 2em;
}
.fixed #header-bar {
right: 0;
left: 0;
padding: 3px 4px 4px;
}
.fixed.top #header-bar {
top: 0;
}
.fixed.bottom #header-bar {
bottom: 0;
}
#header-bar {
border-width: 0;
transition: all .1s .05s ease-in-out;
}
:root.centered-links #header-bar {
text-align: center;
}
:root.centered-links #custom-board-list {
position: relative;
left: 80px;
}
.fixed.top #header-bar {
border-bottom-width: 1px;
}
.fixed.bottom #header-bar {
box-shadow: 0 -1px 2px rgba(0, 0, 0, .15);
border-top-width: 1px;
}
.fixed.bottom #header-bar .menu-button i {
border-top: none;
border-bottom: 6px solid;
}
#board-list {
text-align: center;
}
.fixed #header-bar.autohide:not(:hover) {
box-shadow: none;
transition: all .8s .6s cubic-bezier(.55, .055, .675, .19);
}
.fixed.top #header-bar.autohide:not(:hover) {
margin-bottom: -1em;
-webkit-transform: translateY(-100%);
transform: translateY(-100%);
}
.fixed.bottom #header-bar.autohide:not(:hover) {
-webkit-transform: translateY(100%);
transform: translateY(100%);
}
#scroll-marker {
left: 0;
right: 0;
height: 10px;
position: absolute;
}
#header-bar #scroll-marker {
display: none;
}
.fixed #header-bar #scroll-marker {
display: block;
}
.fixed.top #header-bar #scroll-marker {
top: 100%;
}
.fixed.bottom #header-bar #scroll-marker {
bottom: 100%;
}
#header-bar a:not(.entry):not(.close) {
text-decoration: none;
padding: 1px;
}
#header-bar input {
margin: 0;
vertical-align: bottom;
}
#shortcuts:empty {
display: none;
}
.brackets-wrap::before {
content: "\\00a0[";
}
.brackets-wrap::after {
content: "]\\00a0";
}
.disabled,
.expand-all-shortcut {
opacity: .45;
}
#shortcuts {
float: right;
}
.shortcut {
margin-left: 3px;
}
#navbotright,
#navtopright {
display: none;
}
#toggleMsgBtn {
display: none !important;
}
/* 4chan X link brackets */
.fourchanx-link::after {
content: "]";
}
.fourchanx-link::before {
content: "[";
}
/* Notifications */
#notifications {
position: fixed;
top: 0;
height: 0;
text-align: center;
right: 0;
left: 0;
transition: all .8s .6s cubic-bezier(.55, .055, .675, .19);
}
.fixed.top #header-bar #notifications {
position: absolute;
top: 100%;
}
.notification {
color: #FFF;
font-weight: 700;
text-shadow: 0 1px 2px rgba(0, 0, 0, .5);
box-shadow: 0 1px 2px rgba(0, 0, 0, .15);
border-radius: 2px;
margin: 1px auto;
width: 500px;
max-width: 100%;
position: relative;
transition: all .25s ease-in-out;
}
.notification.error {
background-color: hsla(0, 100%, 38%, .9);
}
.notification.warning {
background-color: hsla(36, 100%, 38%, .9);
}
.notification.info {
background-color: hsla(200, 100%, 38%, .9);
}
.notification.success {
background-color: hsla(104, 100%, 38%, .9);
}
.notification a {
color: white;
}
.notification > .close {
padding: 6px;
top: 0;
right: 5px;
position: absolute;
}
.message {
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 6px 20px;
max-height: 200px;
width: 100%;
overflow: auto;
}
/* Settings */
:root.fourchan-x body {
-moz-box-sizing: border-box;
box-sizing: border-box;
}
#overlay {
background-color: rgba(0, 0, 0, .5);
top: 0;
left: 0;
height: 100%;
width: 100%;
}
#fourchanx-settings {
-moz-box-sizing: border-box;
box-sizing: border-box;
box-shadow: 0 0 15px rgba(0, 0, 0, .15);
height: 600px;
min-height: 0;
max-height: 100%;
width: 900px;
min-width: 0;
max-width: 100%;
margin: auto;
padding: 3px;
top: 50%;
left: 50%;
-moz-transform: translate(-50%, -50%);
-webkit-transform: translate(-50%, -50%);
-o-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
#fourchanx-settings > nav {
padding: 2px 2px 0;
height: 15px;
}
#fourchanx-settings > nav a {
text-decoration: underline;
}
#fourchanx-settings > nav a.close {
text-decoration: none;
padding: 2px;
}
.section-container {
overflow: auto;
position: absolute;
top: 2.1em;
right: 5px;
bottom: 5px;
left: 5px;
padding-right: 5px;
}
.sections-list {
padding: 0 3px;
float: left;
}
.credits {
float: right;
}
.tab-selected {
font-weight: 700;
}
.section-sauce ul,
.section-advanced ul {
list-style: none;
margin: 0;
}
.section-sauce ul {
padding: 8px;
}
.section-advanced ul {
padding: 0px;
}
.section-sauce li,
.section-advanced li {
padding-left: 4px;
}
.section-main label {
text-decoration: underline;
}
.section-filter ul {
padding: 0;
}
.section-filter li {
margin: 10px 40px;
}
.section-filter textarea {
height: 500px;
}
.section-sauce textarea {
height: 350px;
}
.section-advanced .field[name="boardnav"] {
width: 100%;
}
.section-advanced textarea {
height: 150px;
}
#fourchanx-settings fieldset {
border: 1px solid;
border-radius: 3px;
}
#fourchanx-settings legend {
font-weight: 700;
}
#fourchanx-settings textarea {
font-family: monospace;
min-width: 100%;
max-width: 100%;
}
#fourchanx-settings code {
color: #000;
background-color: #FFF;
padding: 0 2px;
}
.unscroll {
overflow: hidden;
}
/* Announcement Hiding */
:root.hide-announcement #globalMessage {
display: none;
}
a.hide-announcement {
float: left;
}
/* Unread */
#unread-line {
margin: 0;
border-color: rgb(255,0,0);
}
/* Thread Updater */
#updater {
background: none;
border: none;
box-shadow: none;
}
#updater > .move {
padding: 5px 3px 0px;
margin-bottom: -3px;
}
#updater > div:last-child {
text-align: center;
}
#updater input[type=number] {
width: 4em;
}
:root.float #updater {
padding: 0px 3px;
}
.new {
color: limegreen;
}
#update-status.warning, #update-status.new {
margin-right: 5px;
}
#update-timer {
cursor: pointer;
}
/* Thread Watcher */
#watcher {
padding-bottom: 3px;
overflow: hidden;
white-space: nowrap;
min-width: 120px;
max-height: 92%;
overflow-y: auto;
}
#watcher > .move {
padding-top: 3px;
}
#watcher > div {
max-width: 250px;
overflow: hidden;
padding-left: 3px;
padding-right: 3px;
text-overflow: ellipsis;
}
#watcher a {
text-decoration: none;
}
#watcher .move>.close {
position: absolute;
right: 0px;
top: 0px;
padding: 0px 4px;
}
/* Thread Stats */
#thread-stats {
background: none;
border: none;
box-shadow: none;
}
:root.float #post-count, :root.float #file-count {
pointer-events: none;
}
:root.float #thread-stats {
padding: 0px 3px;
}
/* Quote */
.deadlink {
text-decoration: none !important;
}
.backlink.deadlink:not(.forwardlink), .quotelink.deadlink:not(.forwardlink) {
text-decoration: underline !important;
}
.inlined {
opacity: .5;
}
#qp input, .forwarded {
display: none;
}
.quotelink.forwardlink,
.backlink.forwardlink {
text-decoration: none;
border-bottom: 1px dashed;
}
.filtered {
text-decoration: underline line-through;
}
:root.hide-backlinks .backlink.filtered {
display: none;
}
.inline {
border: 1px solid;
display: table;
margin: 2px 0;
}
.inline .post {
border: 0 !important;
background-color: transparent !important;
display: table !important;
margin: 0 !important;
padding: 1px 2px !important;
}
#qp > .opContainer::after {
content: '';
clear: both;
display: table;
}
#qp .post {
border: none;
margin: 0;
padding: 2px 2px 5px;
}
#qp img {
max-height: 300px;
max-width: 500px;
max-height: 80vh;
max-width: 50vw;
}
.qphl {
outline: 2px solid rgba(216, 94, 49, .7);
}
:root.highlight-own .yourPost>.reply,
:root.highlight-you .quotesYou>.reply {
border-left: 2px solid rgba(221,0,0,.5);
}
/* Quote Threading */
.threadContainer {
margin-left: 20px;
border-left: 1px solid rgba(128,128,128,.3);
}
.threadOP {
clear: both;
}
/* File */
.fileText:hover .fntrunc,
.fileText:not(:hover) .fnfull,
.expanded-image > .post > .file > .fileThumb > img[data-md5],
:not(.expanded-image) > .post > .file > .fileThumb > .full-image {
display: none;
}
.expanding {
opacity: .5;
}
.expanded-image {
clear: both;
}
.expanded-image > .op > .file::after {
content: '';
clear: both;
display: table;
}
:root.fit-width .full-image {
max-width: 100%;
}
:root.gecko.fit-width .full-image,
:root.presto.fit-width .full-image {
width: 100%;
}
#ihover {
-moz-box-sizing: border-box;
box-sizing: border-box;
max-height: 100%;
max-width: 75%;
padding-bottom: 16px;
}
.fappeTyme .thread > .noFile,
.fappeTyme .threadContainer > .noFile {
display: none;
}
/* Index/Reply Navigation */
#navlinks {
font-size: 16px;
top: 25px;
right: 10px;
}
/* Filter */
.opContainer.filter-highlight {
box-shadow: inset 5px 0 rgba(255, 0, 0, .5);
}
.filter-highlight > .reply {
box-shadow: -5px 0 rgba(255, 0, 0, .5);
}
/* Thread & Reply Hiding */
.hide-thread-button,
.hide-reply-button {
float: left;
margin-right: 2px;
}
.stub ~ * {
display: none !important;
}
.stub input {
display: inline-block;
}
/* QR */
:root.hide-original-post-form #postForm,
:root.hide-original-post-form .postingMode,
:root.hide-original-post-form #togglePostForm,
#qr.autohide:not(.has-focus):not(:hover) > form,
.postingMode ~ #qr select,
#file-n-submit:not(.has-file) #qr-filerm {
display: none;
}
#qr select, #dump-button, .remove, .captcha-img {
cursor: pointer;
}
#qr {
z-index: 20;
position: fixed;
padding: 1px;
border: 1px solid transparent;
min-width: 300px;
border-radius: 3px 3px 0 0;
}
#qrtab {
border-radius: 3px 3px 0 0;
}
#qrtab {
margin-bottom: 1px;
}
#qr .close {
float: right;
padding: 0 3px;
}
#qr .warning {
min-height: 1.6em;
vertical-align: middle;
padding: 0 1px;
border-width: 1px;
border-style: solid;
}
.qr-link {
text-align: center;
}
.persona {
width: 248px;
max-width: 100%;
min-width: 100%;
}
#dump-button {
width: 10%;
margin: 0;
margin-right: 4px;
font: 13px sans-serif;
padding: 1px 0px 2px;
opacity: 0.6;
}
.persona .field:not(#dump) {
width: 95px;
min-width: 33.3%;
max-width: 33.3%;
}
#qr textarea.field {
height: 14.8em;
min-height: 9em;
}
#qr.has-captcha textarea.field {
height: 9em;
}
input.field.tripped:not(:hover):not(:focus) {
color: transparent !important; text-shadow: none !important;
}
#qr textarea {
resize: both;
}
.captcha-img {
margin: 0px;
text-align: center;
background-image: #fff;
font-size: 0px;
min-height: 59px;
min-width: 302px;
}
.captcha-input {
width: 100%;
margin: 1px 0 0;
}
.field {
-moz-box-sizing: border-box;
margin: 0px;
padding: 2px 4px 3px;
}
#qr textarea {
min-width: 100%;
}
#qr [type='submit'] {
width: 25%;
vertical-align: top;
}
:root.webkit #qr [type='submit'] {
height: 24px;
}
/* Fake File Input */
#qr-filename,
.has-file #qr-no-file {
display: none;
}
#qr-no-file,
.has-file #qr-filename {
display: inline-block;
padding: 0px 4px;
margin-bottom: 2px;
overflow: hidden;
text-overflow: ellipsis;
max-width: 88%;
}
#qr-no-file {
color: #AAA;
}
#qr-filename-container {
-moz-box-sizing: border-box;
display: inline-block;
position: relative;
width: 100px;
min-width: 74.6%;
max-width: 74.6%;
margin-right: 0.4%;
margin-top: 1px;
overflow: hidden;
padding: 2px 1px 0;
height: 22px;
}
#qr-filename-container:hover {
cursor: text;
}
#qr-extras-container {
position: absolute;
right: 0px;
}
#qr-filerm {
margin-right: 2px;
z-index: 2;
}
#file-n-submit {
height: 23px;
}
#qr input[type=file] {
display: none;
}
/* Thread Select / Spoiler Label */
#qr select {
float: right;
}
#qr.has-spoiler .has-file #qr-spoiler-label {
width: 6.7%;
min-width: 6.7%;
max-width: 6.7%;
display: inline-block;
text-align: center;
vertical-align: top;
}
#qr.has-spoiler #file-n-submit:not(.has-file) #qr-spoiler-label {
display: none;
}
#qr.has-spoiler .has-file #qr-filename-container {
max-width: 67.9%;
min-width: 67.9%;
}
#qr-spoiler-label input {
position: relative;
top: 3px;
}
/* Dumping UI */
.dump #dump-list-container {
display: block;
}
#dump-list-container {
display: none;
position: relative;
overflow-y: hidden;
margin-top: 1px;
}
#dump-list {
overflow-x: auto;
overflow-y: hidden;
white-space: pre;
width: 248px;
max-width: 100%;
min-width: 100%;
}
#dump-list:hover {
overflow-x: auto;
}
.qr-preview {
-moz-box-sizing: border-box;
counter-increment: thumbnails;
cursor: move;
display: inline-block;
height: 90px;
width: 90px;
padding: 2px;
opacity: .5;
overflow: hidden;
position: relative;
text-shadow: 0 1px 1px #000;
-moz-transition: opacity .25s ease-in-out;
vertical-align: top;
}
.qr-preview:hover,
.qr-preview:focus {
opacity: .9;
}
.qr-preview::before {
content: counter(thumbnails);
color: #fff;
position: absolute;
top: 3px;
right: 3px;
text-shadow: 0 0 3px #000, 0 0 8px #000;
}
.qr-preview#selected {
opacity: 1;
}
.qr-preview.drag {
box-shadow: 0 0 10px rgba(0,0,0,.5);
}
.qr-preview.over {
border-color: #fff;
}
.qr-preview > span {
color: #fff;
}
.remove {
background: none;
color: #e00;
font-weight: 700;
padding: 3px;
}
a:only-of-type > .remove {
display: none;
}
.remove:hover::after {
content: " Remove";
}
.qr-preview > label {
background: rgba(0,0,0,.5);
color: #fff;
right: 0; bottom: 0; left: 0;
position: absolute;
text-align: center;
}
.qr-preview > label > input {
margin: 0;
}
#add-post {
cursor: pointer;
font-size: 2em;
position: absolute;
top: 50%;
right: 10px;
-moz-transform: translateY(-50%);
}
.textarea {
position: relative;
}
:root.webkit .textarea {
margin-bottom: -2px;
}
#char-count {
color: #000;
background: hsla(0, 0%, 100%, .5);
font-size: 8pt;
position: absolute;
bottom: 1px;
right: 1px;
pointer-events: none;
}
/* Menu */
.menu-button {
display: inline-block;
position: relative;
cursor: pointer;
}
.menu-button i {
border-top: 6px solid;
border-right: 4px solid transparent;
border-left: 4px solid transparent;
display: inline-block;
margin: 2px;
vertical-align: middle;
}
#menu {
position: fixed;
outline: none;
}
.entry {
border-bottom: 1px solid rgba(0,0,0,.25);
cursor: pointer;
display: block;
outline: none;
padding: 3px 7px;
position: relative;
text-decoration: none;
white-space: nowrap;
}
.left>.entry.has-submenu {
padding-right: 17px !important;
}
.entry:last-child {
border-bottom: 0;
}
.has-submenu::after {
content: "";
border-left: .5em solid;
border-top: .3em solid transparent;
border-bottom: .3em solid transparent;
display: inline-block;
margin: .3em;
position: absolute;
right: 3px;
}
.left .has-submenu::after {
border-left: 0;
border-right: .5em solid;
}
.submenu {
display: none;
position: absolute;
left: 100%;
top: -1px;
}
.focused .submenu {
display: block;
}
.imp-exp-result {
position: absolute;
text-align: center;
margin: auto;
right: 0px;
left: 0px;
width: 200px;
}
.export, .import {
cursor: pointer;
text-decoration: none !important;
}
/* Link Title Favicons */
.linkify.YouTube {
background: transparent url('data:image/png;base64,<%= grunt.file.read("src/General/img/links/youtube.png", {encoding: "base64"}) %>') center left no-repeat!important;
padding-left: 18px;
}
.linkify.Vimeo {
background: transparent url('data:image/png;base64,<%= grunt.file.read("src/General/img/links/vimeo.png", {encoding: "base64"}) %>') center left no-repeat!important;
padding-left: 18px;
}
.linkify.SoundCloud {
background: transparent url('data:image/png;base64,<%= grunt.file.read("src/General/img/links/soundcloud.png", {encoding: "base64"}) %>') center left no-repeat!important;
padding-left: 18px;
}
.linkify.audio {
background: transparent url('data:image/png;base64,<%= grunt.file.read("src/General/img/links/audio.png", {encoding: "base64"}) %>') center left no-repeat!important;
padding-left: 18px;
}
.linkify.LiveLeak {
background: transparent url('data:image/png;base64,<%= grunt.file.read("src/General/img/links/liveleak.png", {encoding: "base64"}) %>') center left no-repeat!important;
padding-left: 18px;
}
.linkify.Vocaroo {
background: transparent url('data:image/png;base64,<%= grunt.file.read("src/General/img/links/vocaroo.png", {encoding: "base64"}) %>') center left no-repeat!important;
padding-left: 18px;
}
.linkify.pastebin {
background: transparent url('data:image/png;base64,<%= grunt.file.read("src/General/img/links/pastebin.png", {encoding: "base64"}) %>') center left no-repeat!important;
padding-left: 18px;
}
.linkify.gist {
background: transparent url('data:image/png;base64,<%= grunt.file.read("src/General/img/links/gist.png", {encoding: "base64"}) %>') center left no-repeat!important;
padding-left: 18px;
}
.linkify.image {
background: transparent url('data:image/png;base64,<%= grunt.file.read("src/General/img/links/image.png", {encoding: "base64"}) %>') center left no-repeat!important;
padding-left: 18px;
}
.linkify.InstallGentoo {
background: transparent url('data:image/png;base64,<%= grunt.file.read("src/General/img/links/installgentoo.png", {encoding: "base64"}) %>') center left no-repeat!important;
padding-left: 18px;
}

View File

@ -4,9 +4,8 @@
</div> </div>
<form> <form>
<div class=persona> <div class=persona>
<input id=dump-button type=button title='Dump list' value=+ tabindex=0> <input name=name data-name=name list="list-name" placeholder=Name class=field size=1 tabindex=10>
<input name=name data-name=name list="list-name" placeholder=Name class=field size=1 tabindex=10> <input name=email data-name=email list="list-email" placeholder=E-mail class=field size=1 tabindex=20>
<input name=email data-name=email list="list-email" placeholder=E-mail class=field size=1 tabindex=20>
<input name=sub data-name=sub list="list-sub" placeholder=Subject class=field size=1 tabindex=30> <input name=sub data-name=sub list="list-sub" placeholder=Subject class=field size=1 tabindex=30>
</div> </div>
<div class=textarea> <div class=textarea>
@ -21,9 +20,15 @@
<span id=qr-filename-container class=field tabindex=60> <span id=qr-filename-container class=field tabindex=60>
<span id=qr-no-file>No selected file</span> <span id=qr-no-file>No selected file</span>
<span id=qr-filename></span> <span id=qr-filename></span>
<a id=qr-filerm href=javascript:; title='Remove file' tabindex=80>×</a> <span id=qr-extras-container>
<a id=qr-filerm href=javascript:; title='Remove file'>×</a>
<a id=dump-button title='Dump list'>+</a>
</span>
</span> </span>
<input type=submit tabindex=70> <label id=qr-spoiler-label>
<input type=checkbox id=qr-file-spoiler title='Spoiler image' tabindex=70>
</label>
<input type=submit tabindex=80>
</div> </div>
<input type=file multiple> <input type=file multiple>
<div id=qr-thread-select> <div id=qr-thread-select>
@ -31,9 +36,6 @@
<option value=new>New thread</option> <option value=new>New thread</option>
</select> </select>
</div> </div>
<label id=qr-spoiler-label>
<input type=checkbox id=qr-file-spoiler title='Spoiler image' tabindex=90>Spoiler?
</label>
</form> </form>
<datalist id="list-name"></datalist> <datalist id="list-name"></datalist>
<datalist id="list-email"></datalist> <datalist id="list-email"></datalist>

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -8,7 +8,7 @@ DownloadLink =
$.event 'AddMenuEntry', $.event 'AddMenuEntry',
type: 'post' type: 'post'
el: a el: a
order: 70 order: 100
open: ({file}) -> open: ({file}) ->
return false unless file return false unless file
a.href = file.URL a.href = file.URL

View File

@ -18,8 +18,8 @@ Menu =
a = null a = null
(post) -> (post) ->
a or= $.el 'a', a or= $.el 'a',
className: 'menu-button' className: 'menu-button brackets-wrap'
innerHTML: '[<span class=drop-marker></span>]' innerHTML: '<span class=drop-marker></span>'
href: 'javascript:;' href: 'javascript:;'
clone = a.cloneNode true clone = a.cloneNode true
clone.setAttribute 'data-postid', post.fullID clone.setAttribute 'data-postid', post.fullID

View File

@ -2,6 +2,15 @@ PSAHiding =
init: -> init: ->
return unless Conf['Announcement Hiding'] return unless Conf['Announcement Hiding']
$.addClass doc, 'hide-announcement'
$.on d, '4chanXInitFinished', @setup
setup: ->
$.off d, '4chanXInitFinished', PSAHiding.setup
unless psa = $.id 'globalMessage'
return
entry = entry =
type: 'header' type: 'header'
el: $.el 'a', el: $.el 'a',
@ -9,54 +18,48 @@ PSAHiding =
className: 'show-announcement' className: 'show-announcement'
href: 'javascript:;' href: 'javascript:;'
order: 50 order: 50
open: -> open: -> psa.hidden
if $.id('globalMessage')?.hidden
return true
false
$.event 'AddMenuEntry', entry $.event 'AddMenuEntry', entry
$.on entry.el, 'click', PSAHiding.toggle
$.on entry.el, 'click', PSAHiding.toggle
$.addClass doc, 'hide-announcement'
$.on d, '4chanXInitFinished', @setup
setup: ->
$.off d, '4chanXInitFinished', PSAHiding.setup
unless psa = $.id 'globalMessage'
return
PSAHiding.btn = btn = $.el 'a', PSAHiding.btn = btn = $.el 'a',
innerHTML: '<span>[&nbsp;-&nbsp;]</span>' innerHTML: '<span class=fourchanx-link>&nbsp;-&nbsp;</span>'
title: 'Hide announcement.' title: 'Hide announcement.'
className: 'hide-announcement' className: 'hide-announcement'
href: 'javascript:;' href: 'javascript:;'
textContent: '[ - ]' textContent: '[ - ]'
$.on btn, 'click', PSAHiding.toggle $.on btn, 'click', PSAHiding.toggle
$.get 'hiddenPSAs', [], (item) -> # XXX remove hiddenPSAs workaround in the future.
PSAHiding.sync item['hiddenPSAs'] items =
hiddenPSA: 0
hiddenPSAs: null
$.get items, ({hiddenPSA, hiddenPSAs}) ->
if hiddenPSAs
$.delete 'hiddenPSAs'
if psa.textContent.replace(/\W+/g, '').toLowerCase() in hiddenPSAs
hiddenPSA = +$.id('globalMessage').dataset.utc
$.set 'hiddenPSA', hiddenPSA
PSAHiding.sync hiddenPSA
$.prepend psa, btn
$.rmClass doc, 'hide-announcement'
$.sync 'hiddenPSA', PSAHiding.sync
toggle: (e) -> toggle: (e) ->
text = PSAHiding.trim $.id 'globalMessage' if $.hasClass @, 'hide-announcement'
$.get 'hiddenPSAs', [], ({hiddenPSAs}) -> UTC = +$.id('globalMessage').dataset.utc
if hide $.set 'hiddenPSA', UTC
hiddenPSAs.push text else
hiddenPSAs = hiddenPSAs[-5..] $.event 'CloseMenu'
else $.delete 'hiddenPSA'
$.event 'CloseMenu' PSAHiding.sync UTC
i = hiddenPSAs.indexOf text sync: (UTC) ->
hiddenPSAs.splice i, 1
PSAHiding.sync hiddenPSAs
$.set 'hiddenPSAs', hiddenPSAs
sync: (hiddenPSAs) ->
psa = $.id 'globalMessage' psa = $.id 'globalMessage'
psa.hidden = PSAHiding.btn.hidden = if hiddenPSAs.contains PSAHiding.trim(psa) psa.hidden = PSAHiding.btn.hidden = if UTC and UTC >= +psa.dataset.utc
true true
else else
false false
if (hr = psa.nextElementSibling) and hr.nodeName is 'HR' if (hr = psa.nextElementSibling) and hr.nodeName is 'HR'
hr.hidden = psa.hidden hr.hidden = psa.hidden
trim: (psa) -> Style.iconPositions()
psa.textContent.replace(/\W+/g, '').toLowerCase()

View File

@ -30,7 +30,8 @@ Unread =
for ID, post of Unread.thread.posts for ID, post of Unread.thread.posts
posts.push post if post.isReply posts.push post if post.isReply
Unread.addPosts posts Unread.addPosts posts
Unread.scroll() if Conf['Scroll to Last Read Post'] return unless Conf['Scroll to Last Read Post']
Unread.scroll()
scroll: -> scroll: ->
# Let the header's onload callback handle it. # Let the header's onload callback handle it.
@ -43,11 +44,15 @@ Unread =
break if prevID is post.ID break if prevID is post.ID
prevID = post.ID prevID = post.ID
break unless post.isHidden break unless post.isHidden
root.scrollIntoView false onload = -> root.scrollIntoView false
return else
# Scroll to the last read post. # Scroll to the last read post.
posts = Object.keys Unread.thread.posts posts = Object.keys Unread.thread.posts
Header.scrollToPost Unread.thread.posts[posts[posts.length - 1]].nodes.root post = Unread.thread.posts[posts[posts.length - 1]]
onload = -> Header.scrollToPost post.nodes.root
# Prevent the browser to scroll back to
# the previous scroll location on page load.
$.on window, 'load', onload
sync: -> sync: ->
lastReadPost = Unread.db.get lastReadPost = Unread.db.get

View File

@ -891,6 +891,7 @@ QR =
fileSubmit: $ '#file-n-submit', dialog fileSubmit: $ '#file-n-submit', dialog
filename: $ '#qr-filename', dialog filename: $ '#qr-filename', dialog
fileRM: $ '#qr-filerm', dialog fileRM: $ '#qr-filerm', dialog
fileExtras: $ '#qr-extras-container', dialog
spoiler: $ '#qr-file-spoiler', dialog spoiler: $ '#qr-file-spoiler', dialog
status: $ '[type=submit]', dialog status: $ '[type=submit]', dialog
fileInput: $ '[type=file]', dialog fileInput: $ '[type=file]', dialog
@ -916,7 +917,10 @@ QR =
<% } %> <% } %>
QR.spoiler = !!$ 'input[name=spoiler]' QR.spoiler = !!$ 'input[name=spoiler]'
nodes.spoiler.parentElement.hidden = !QR.spoiler if QR.spoiler
$.addClass QR.nodes.el, 'has-spoiler'
else
nodes.spoiler.parentElement.hidden = true
if g.BOARD.ID is 'f' if g.BOARD.ID is 'f'
nodes.flashTag = $.el 'select', nodes.flashTag = $.el 'select',
@ -953,9 +957,8 @@ QR =
$.on nodes.dumpButton, 'click', -> nodes.el.classList.toggle 'dump' $.on nodes.dumpButton, 'click', -> nodes.el.classList.toggle 'dump'
$.on nodes.addPost, 'click', -> new QR.post true $.on nodes.addPost, 'click', -> new QR.post true
$.on nodes.form, 'submit', QR.submit $.on nodes.form, 'submit', QR.submit
$.on nodes.fileRM, 'click', (e) -> $.on nodes.fileRM, 'click', -> QR.selected.rmFile()
e.stopPropagation() $.on nodes.fileExtras, 'click', (e) -> e.stopPropagation()
QR.selected.rmFile()
$.on nodes.spoiler, 'change', -> QR.selected.nodes.spoiler.click() $.on nodes.spoiler, 'change', -> QR.selected.nodes.spoiler.click()
$.on nodes.fileInput, 'change', QR.fileInput $.on nodes.fileInput, 'change', QR.fileInput
# save selected post's data # save selected post's data

View File

@ -33,6 +33,21 @@ QuotePreview =
cb: QuotePreview.mouseout cb: QuotePreview.mouseout
asapTest: -> qp.firstElementChild asapTest: -> qp.firstElementChild
<% if (type === 'userjs') { %>
# XXX Opera workaround for "no mouseout fired" bug.
# Remove it once Opera uses Blink.
root = @
workaround = (e) ->
if @ is root
e.stopPropagation()
return
$.event 'mouseout', null, root
$.off d, 'mousemove', workaround
$.off root, 'mousemove', workaround
$.on d, 'mousemove', workaround
$.on root, 'mousemove', workaround
<% } %>
return unless origin = g.posts["#{boardID}.#{postID}"] return unless origin = g.posts["#{boardID}.#{postID}"]
if Conf['Quote Highlighting'] if Conf['Quote Highlighting']
@ -60,4 +75,4 @@ QuotePreview =
return unless Conf['Quote Highlighting'] return unless Conf['Quote Highlighting']
for post in [post].concat post.clones for post in [post].concat post.clones
$.rmClass post.nodes.post, 'qphl' $.rmClass post.nodes.post, 'qphl'
return return

View File

@ -2,8 +2,14 @@ QuoteYou =
init: -> init: ->
return if g.VIEW is 'catalog' or !Conf['Mark Quotes of You'] or !Conf['Quick Reply'] return if g.VIEW is 'catalog' or !Conf['Mark Quotes of You'] or !Conf['Quick Reply']
if Conf['Highlight Own Posts']
$.addClass doc, 'highlight-own'
if Conf['Highlight Posts Quoting You']
$.addClass doc, 'highlight-you'
# \u00A0 is nbsp # \u00A0 is nbsp
@text = '\u00A0(You)' @text =
Post::callbacks.push Post::callbacks.push
name: 'Mark Quotes of You' name: 'Mark Quotes of You'
cb: @node cb: @node
@ -14,18 +20,11 @@ QuoteYou =
if @info.yours if @info.yours
$.addClass @nodes.root, 'yourPost' $.addClass @nodes.root, 'yourPost'
if Conf['Highlight Own Posts']
$.addClass doc, 'highlight-own'
if Conf['Highlight Posts Quoting You']
$.addClass doc, 'highlight-you'
# Stop there if there's no quotes in that post. # Stop there if there's no quotes in that post.
return unless (quotes = @quotes).length return unless @quotes.length
{quotelinks} = @nodes
for quotelink in quotelinks for quotelink in @nodes.quotelinks
if QR.db.get Get.postDataFromLink quotelink if QR.db.get Get.postDataFromLink quotelink
$.add quotelink, $.tn QuoteYou.text $.add quotelink, $.tn '\u00A0(You)'
$.addClass @nodes.root, 'quotesYou' $.addClass @nodes.root, 'quotesYou'
return return

View File

@ -267,7 +267,7 @@ Style =
[ [
true true
_conf['Slideout Navigation'] isnt 'hide' _conf['Slideout Navigation'] isnt 'hide'
_conf['Announcements'] is 'slideout' and $ '#globalMessage', d.body _conf['Announcements'] is 'slideout' and (psa = $ '#globalMessage', d.body) and !psa.hidden
_conf['Thread Watcher'] and _conf['Slideout Watcher'] _conf['Thread Watcher'] and _conf['Slideout Watcher']
$ '#navtopright .exlinksOptionsLink', d.body $ '#navtopright .exlinksOptionsLink', d.body
notCatalog and $ 'body > a[style="cursor: pointer; float: right;"]', d.body notCatalog and $ 'body > a[style="cursor: pointer; float: right;"]', d.body
@ -299,7 +299,7 @@ Style =
true true
true true
_conf['Slideout Navigation'] isnt 'hide' _conf['Slideout Navigation'] isnt 'hide'
_conf['Announcements'] is 'slideout' and $ '#globalMessage', d.body _conf['Announcements'] is 'slideout' and (psa = $ '#globalMessage', d.body) and !psa.hidden
_conf['Thread Watcher'] and _conf['Slideout Watcher'] _conf['Thread Watcher'] and _conf['Slideout Watcher']
notCatalog and $ 'body > a[style="cursor: pointer; float: right;"]', d.body notCatalog and $ 'body > a[style="cursor: pointer; float: right;"]', d.body
$ '#navtopright .exlinksOptionsLink', d.body $ '#navtopright .exlinksOptionsLink', d.body