diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a50a4f19..cda2ec51f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +- **New feature**: `Quick Reply Personas` + - Add custom auto-completion for the name, e-mail and subject inputs. + - Always use a specific persona. + - Per-board configuration. + - Access it in the `QR` tab of the Settings window. + ### 3.2.3 - *2013-04-30* - Update archive redirection for /c/, /d/, /v/, /vg/, /w/ and /wg/. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8108da2b8..a1164bc88 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,7 @@ Reporting bugs: 1. Precise steps to reproduce the problem, with the expected and actual results. 2. Console errors, if any. 3. Browser version. - 4. Your exported settings. + 4. Your exported settings. If your settings contains sensible information (e.g. personas), edit the text file manually. Open your console with: - `Ctrl + Shift + J` on Chrome. diff --git a/css/style.css b/css/style.css index 8511a659c..0aa8ffa2d 100644 --- a/css/style.css +++ b/css/style.css @@ -335,15 +335,20 @@ a[href="javascript:;"] { .section-main label { text-decoration: underline; } -.section-filter ul { +.section-filter ul, +.section-qr ul { padding: 0; } -.section-filter li { +.section-filter li, +.section-qr li { margin: 10px 40px; } .section-filter textarea { height: 500px; } +.section-qr textarea { + height: 200px; +} .section-sauce textarea { height: 350px; } diff --git a/html/General/Settings-section-QR.html b/html/General/Settings-section-QR.html new file mode 100644 index 000000000..372e74c44 --- /dev/null +++ b/html/General/Settings-section-QR.html @@ -0,0 +1,16 @@ +
diff --git a/html/Posting/QR.html b/html/Posting/QR.html index ef6776598..b02ef3b5f 100644 --- a/html/Posting/QR.html +++ b/html/Posting/QR.html @@ -8,22 +8,22 @@ + + + diff --git a/src/General/Config.coffee b/src/General/Config.coffee index afccfe169..f53f67de8 100644 --- a/src/General/Config.coffee +++ b/src/General/Config.coffee @@ -147,6 +147,11 @@ Config = 'Top Board List': false 'Bottom Board List': false 'Custom Board Navigation': true + QR: + 'QR.personas': [ + '#email:"sage";boards:jp;always' + 'email:"sage"' + ].join '\n' boardnav: '[current-title / toggle-all]' time: '%m/%d/%y(%a)%H:%M:%S' backlink: '>>%id' diff --git a/src/General/Settings.coffee b/src/General/Settings.coffee index 02f7de8ad..5e9292419 100644 --- a/src/General/Settings.coffee +++ b/src/General/Settings.coffee @@ -42,6 +42,7 @@ Settings = Settings.addSection 'Main', Settings.main Settings.addSection 'Filter', Settings.filter + Settings.addSection 'QR', Settings.qr Settings.addSection 'Sauce', Settings.sauce Settings.addSection 'Rice', Settings.rice Settings.addSection 'Keybinds', Settings.keybinds @@ -320,14 +321,23 @@ Settings = <%= grunt.file.read('html/General/Settings-section-Filter-guide.html').replace(/>\s+<').trim() %> """ + qr: (section) -> + section.innerHTML = """ + <%= grunt.file.read('html/General/Settings-section-QR.html').replace(/>\s+<').trim() %> + """ + ta = $ 'textarea', section + $.get 'QR.personas', Conf['QR.personas'], (item) -> + ta.value = item['QR.personas'] + $.on ta, 'change', $.cb.value + sauce: (section) -> section.innerHTML = """ <%= grunt.file.read('html/General/Settings-section-Sauce.html').replace(/>\s+<').trim() %> """ - sauce = $ 'textarea', section + ta = $ 'textarea', section $.get 'sauces', Conf['sauces'], (item) -> - sauce.value = item['sauces'] - $.on sauce, 'change', $.cb.value + ta.value = item['sauces'] + $.on ta, 'change', $.cb.value rice: (section) -> section.innerHTML = """ diff --git a/src/Menu/DeleteLink.coffee b/src/Menu/DeleteLink.coffee index b3c35d673..fa1b5c5fb 100644 --- a/src/Menu/DeleteLink.coffee +++ b/src/Menu/DeleteLink.coffee @@ -46,18 +46,12 @@ DeleteLink = $.off @, 'click', DeleteLink.delete @textContent = "Deleting #{@textContent}..." - pwd = - if m = d.cookie.match /4chan_pass=([^;]+)/ - decodeURIComponent m[1] - else - $.id('delPassword').value - fileOnly = $.hasClass @, 'delete-file' form = mode: 'usrdel' onlyimgdel: fileOnly - pwd: pwd + pwd: QR.persona.getPassword() form[post.ID] = 'delete' link = @ diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index dadde52d0..b0e25f14a 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -134,6 +134,73 @@ QR = value status.disabled = disabled or false + persona: + pwd: '' + always: {} + init: -> + QR.persona.getPassword() + $.get 'QR.personas', Conf['QR.personas'], ({'QR.personas': personas}) -> + types = + name: [] + email: [] + sub: [] + for item in personas.split '\n' + QR.persona.parseItem item.trim(), types + for type, arr of types + QR.persona.loadPersonas type, arr + return + parseItem: (item, types) -> + return if item[0] is '#' + return unless match = item.match /(name|email|subject|password):"(.*)"/i + [match, type, val] = match + + # Don't mix up item settings with val. + item = item.replace match, '' + + boards = item.match(/boards:([^;]+)/i)?[1].toLowerCase() or 'global' + if boards isnt 'global' and not (g.BOARD.ID in boards.split ',') + return + + if type is 'password' + QR.persona.pwd = val + return + + type = 'sub' if type is 'subject' + + if /always/i.test item + QR.persona.always[type] = val + + unless val in types[type] + types[type].push val + loadPersonas: (type, arr) -> + list = $ "#list-#{type}", QR.nodes.el + for val in arr + $.add list, $.el 'option', + textContent: val + return + getPassword: -> + unless QR.persona.pwd + QR.persona.pwd = if m = d.cookie.match /4chan_pass=([^;]+)/ + decodeURIComponent m[1] + else if input = $.id 'postPassword' + input.value + else + # If we're in a closed thread, #postPassword isn't available. + # And since #delPassword.value is only filled on window.onload + # we'd rather use #postPassword when we can. + $.id('delPassword').value + return QR.persona.pwd + get: (cb) -> + $.get 'QR.persona', {}, ({'QR.persona': persona}) -> + cb persona + set: (post) -> + $.get 'QR.persona', {}, ({'QR.persona': persona}) -> + persona = + name: post.name + email: if /^sage$/.test post.email then persona.email else post.email + sub: if Conf['Remember Subject'] then post.sub else undefined + $.set 'QR.persona', persona + cooldown: init: -> return unless Conf['Cooldown'] @@ -403,18 +470,27 @@ QR = prev.spoiler else false - $.get 'QR.persona', {}, (item) => - persona = item['QR.persona'] - @name = if prev + QR.persona.get (persona) => + @name = if 'name' of QR.persona.always + QR.persona.always.name + else if prev prev.name else persona.name - @email = if prev and !/^sage$/.test prev.email + + @email = if 'email' of QR.persona.always + QR.persona.always.email + else if prev and !/^sage$/.test prev.email prev.email else persona.email - if Conf['Remember Subject'] - @sub = if prev then prev.sub else persona.sub + + @sub = if 'sub' of QR.persona.always + QR.persona.always.sub + else if Conf['Remember Subject'] + if prev then prev.sub else persona.sub + else + '' @load() if QR.selected is @ # load persona @select() if select @unlock() @@ -818,8 +894,8 @@ QR = $.set 'QR Size', @style.cssText <% } %> + QR.persona.init() new QR.post true - QR.status() QR.cooldown.init() QR.captcha.init() @@ -899,7 +975,7 @@ QR = spoiler: post.spoiler textonly: textOnly mode: 'regist' - pwd: if m = d.cookie.match(/4chan_pass=([^;]+)/) then decodeURIComponent m[1] else $.id('postPassword').value + pwd: QR.persona.pwd recaptcha_challenge_field: challenge recaptcha_response_field: response @@ -1002,13 +1078,7 @@ QR = QR.cleanNotifications() QR.notifications.push new Notification 'success', h1.textContent, 5 - $.get 'QR.persona', {}, (item) -> - persona = item['QR.persona'] - persona = - name: post.name - email: if /^sage$/.test post.email then persona.email else post.email - sub: if Conf['Remember Subject'] then post.sub else null - $.set 'QR.persona', persona + QR.persona.set post [_, threadID, postID] = h1.nextSibling.textContent.match /thread:(\d+),no:(\d+)/ postID = +postID