Merge tag 'beta' into unreadcount

4chan X v1.8.7.

Conflicts:
	CHANGELOG.md
	LICENSE
	builds/4chan-X-beta.crx
	builds/4chan-X-beta.meta.js
	builds/4chan-X-beta.user.js
	builds/4chan-X-noupdate.crx
	builds/4chan-X-noupdate.user.js
	builds/4chan-X.crx
	builds/4chan-X.meta.js
	builds/4chan-X.user.js
	builds/4chan-X.zip
	builds/updates-beta.xml
	builds/updates.xml
	package.json
This commit is contained in:
ccd0 2014-07-23 07:27:41 -07:00
commit 8a86bb9835
36 changed files with 474 additions and 381 deletions

View File

@ -1,3 +1,21 @@
**ccd0**
- Fix unread count updating bug in Firefox as in v1.8.6.2.
### v1.8.7
*2014-07-20*
Based on v1.8.6.1.
**ccd0**
- Various bugfixes.
**MayhemYDG**
- Improvements to Chrom* storage API.
**Zixaphir**
- Add gallery option `Scroll to Post`: Scrolls to the post containing the currently active image.
- Gallery now loops.
### v1.8.6.2 ### v1.8.6.2
*2014-07-23* *2014-07-23*
@ -67,7 +85,6 @@
- Begin making available a version of the script with the updater disabled. - Begin making available a version of the script with the updater disabled.
- The removal of slugs from the URL when you open a thread is now optional, and can be disabled by unchecking `Normalize URL`. - The removal of slugs from the URL when you open a thread is now optional, and can be disabled by unchecking `Normalize URL`.
- The boards and file extensions for which a Sauce link is displayed can now be controlled by adding `;boards:[list]` and `types:[list]` respectively. - The boards and file extensions for which a Sauce link is displayed can now be controlled by adding `;boards:[list]` and `types:[list]` respectively.
- Restrict Sauce links to `http` and `https` to prevent malicious script installation.
- Although usually not needed, `%%` can be used in format specifiers to write a literal `%`. - Although usually not needed, `%%` can be used in format specifiers to write a literal `%`.
- Various bugfixes. - Various bugfixes.
@ -647,7 +664,7 @@ Remove /v/ from stable Foolz archive.
**Spittie** **Spittie**
- Check image dimension before uploading - Check image dimension before uploading
![Check image dimension](src/General/img/changelog/1.4.1.png) ![Check image dimension](img/1.4.1.png)
- Bug fixes - Bug fixes
- Update archives - Update archives
@ -695,7 +712,7 @@ Remove /v/ from stable Foolz archive.
**Spittie** **Spittie**
- Upload images directly from urls - Upload images directly from urls
![Upload from url](src/General/img/changelog/1.3.6.gif) ![Upload from url](img/1.3.6.gif)
- Add gfycat.com embedding - Add gfycat.com embedding
- Replace some icons with fontawesome - Replace some icons with fontawesome
- Add Metro favicons (lel) - Add Metro favicons (lel)
@ -771,7 +788,7 @@ Remove /v/ from stable Foolz archive.
- The last index refresh timer will now indicate the last time the index changed from 4chan's side, instead of the last time you refreshed the index. - The last index refresh timer will now indicate the last time the index changed from 4chan's side, instead of the last time you refreshed the index.
- You can now refresh the index page you are on with the refresh shortcut in the header bar or the same keybind for refreshing threads. - You can now refresh the index page you are on with the refresh shortcut in the header bar or the same keybind for refreshing threads.
- You can now switch between paged and all-threads index modes via the "Index Navigation" header sub-menu (note that this replaces infinite scrolling):<br> - You can now switch between paged and all-threads index modes via the "Index Navigation" header sub-menu (note that this replaces infinite scrolling):<br>
![index navigation](src/General/img/changelog/1.2.46.png) ![index navigation](img/1.2.46.png)
- Threads in the index can now be sorted by: - Threads in the index can now be sorted by:
<ul> <ul>
<li> Bump order <li> Bump order
@ -881,7 +898,7 @@ Remove /v/ from stable Foolz archive.
**Zixaphir**: **Zixaphir**:
- Fix an issue with the file dialog randomly opening multiple times (with seaweedchan) - Fix an issue with the file dialog randomly opening multiple times (with seaweedchan)
![Gallery](src/General/img/changelog/2.3.6.png) ![Gallery](img/2.3.6.png)
- Add new feature: `Gallery`. - Add new feature: `Gallery`.
* Opens images in a lightweight Gallery script. * Opens images in a lightweight Gallery script.
* If enabled while Image Expansion is disabled, will takeover as the default action when images are clicked. * If enabled while Image Expansion is disabled, will takeover as the default action when images are clicked.
@ -932,7 +949,7 @@ Remove /v/ from stable Foolz archive.
**seaweedchan**: **seaweedchan**:
![Board title editing in action](src/General/img/changelog/1.2.31.png) ![Board title editing in action](img/1.2.31.png)
- Ported `Custom Board Titles` feature from Appchan X (with Zixaphir) - Ported `Custom Board Titles` feature from Appchan X (with Zixaphir)
- This allows you to edit the board title and subtitle in real-time by ctrl+clicking them - This allows you to edit the board title and subtitle in real-time by ctrl+clicking them
@ -963,7 +980,7 @@ Remove /v/ from stable Foolz archive.
**MayhemYDG**: **MayhemYDG**:
![New thread watcher](src/General/img/changelog/1.2.28.png) ![New thread watcher](img/1.2.28.png)
- Greatly improved thread watcher - Greatly improved thread watcher
- Added submenu with ability to prune 404'd threads, filter by current board, etc - Added submenu with ability to prune 404'd threads, filter by current board, etc
@ -978,7 +995,7 @@ Remove /v/ from stable Foolz archive.
**Zixaphir**: **Zixaphir**:
![Linkifier in action](src/General/img/changelog/1.2.28-2.png) ![Linkifier in action](img/1.2.28-2.png)
- Drastically improved the accuracy and quality of the linkifier (with seaweedchan) - Drastically improved the accuracy and quality of the linkifier (with seaweedchan)
- Removed `Allow False Positives` option due to the accuracy of the new linkifier regex - Removed `Allow False Positives` option due to the accuracy of the new linkifier regex
@ -1220,7 +1237,7 @@ Remove /v/ from stable Foolz archive.
**seaweedchan**: **seaweedchan**:
- Small bug fixes - Small bug fixes
## v1.2.0 - "Youmu" ![Youmu](src/General/img/changelog/1.2.0.png) ## v1.2.0 - "Youmu" ![Youmu](img/1.2.0.png)
*2013-05-10* *2013-05-10*
**MayhemYDG**: **MayhemYDG**:
@ -1252,7 +1269,7 @@ Remove /v/ from stable Foolz archive.
- QR with 4chan Pass made a little wider - QR with 4chan Pass made a little wider
- Styling changes for spoiler label, also added `.has-spoiler` class for QR - Styling changes for spoiler label, also added `.has-spoiler` class for QR
![QR styling changes](src/General/img/changelog/1.1.18.png) ![QR styling changes](img/1.1.18.png)
### v1.1.17 ### v1.1.17
*2013-05-08* *2013-05-08*

View File

@ -180,16 +180,6 @@ module.exports = (grunt) ->
pkg = grunt.config 'pkg' pkg = grunt.config 'pkg'
pkg.type = type pkg.type = type
grunt.config 'pkg', pkg grunt.config 'pkg', pkg
if type is 'crx'
pkg.align = '-webkit-align'
pkg.justify = '-webkit-justify-content'
pkg.transform = '-webkit-transform'
else
pkg.align = 'align'
pkg.justify = 'justify-content'
pkg.transform = 'transform'
grunt.log.ok 'pkg.type = %s', type grunt.log.ok 'pkg.type = %s', type
grunt.registerTask 'set-channel', 'Set the update channel', (channel) -> grunt.registerTask 'set-channel', 'Set the update channel', (channel) ->

View File

@ -1,5 +1,5 @@
/* /*
* 4chan X - Version 1.8.6.2 - 2014-07-23 * 4chan X - Version 1.8.7 - 2014-07-20
* *
* Licensed under the MIT license. * Licensed under the MIT license.
* https://github.com/ccd0/4chan-x/blob/master/LICENSE * https://github.com/ccd0/4chan-x/blob/master/LICENSE

View File

@ -6,7 +6,10 @@ https://github.com/Nebukazar/OneeChan
## [Install](https://ccd0.github.io/4chan-x/builds/4chan-X.user.js) (Firefox) ## [Install](https://ccd0.github.io/4chan-x/builds/4chan-X.user.js) (Firefox)
Install [Greasemonkey](https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/), then click the link above to install. Install [Greasemonkey](https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/), then click the link above to install.
**Note**: The combination of Firefox 29 and Greasemonkey 2.0 may cause 4chan X not to work. You may want to try the [Greasemonkey 2.1 beta](https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/versions/2.1beta1), which fixes bugs in 2.0 that can prevent 4chan X from updating[[1]](https://github.com/greasemonkey/greasemonkey/issues/1938) or, in some versions of Firefox, break posting images from URLs and downloading with the original filename[[2]](https://github.com/greasemonkey/greasemonkey/issues/1937).
### Known issues
The combination of Firefox 29 and Greasemonkey 2.0 may cause 4chan X not to work.
Try [upgrading Firefox](http://www.mozilla.org/en-US/firefox/new/) to version 30 or higher. Try [upgrading Firefox](http://www.mozilla.org/en-US/firefox/new/) to version 30 or higher.
Alternatively, you can downgrade to [Greasemonkey 1.15](https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/versions/#version-1.15) and turn off automatic updates for Greasemonkey ([see pic](https://raw.githubusercontent.com/ccd0/4chan-x/master/img/2014-07-12_16-19-32.png)). Alternatively, you can downgrade to [Greasemonkey 1.15](https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/versions/#version-1.15) and turn off automatic updates for Greasemonkey ([see pic](https://raw.githubusercontent.com/ccd0/4chan-x/master/img/2014-07-12_16-19-32.png)).
@ -16,6 +19,9 @@ This should also work for non-Windows/dev/canary Chrome and Chromium-based versi
**Note**: The stable and beta releases of Chrome on Windows will disable extensions not installed from the Chrome store, so users will need to install 4chan X from [here](https://chrome.google.com/webstore/detail/4chan-x/ohnjgmpcibpbafdlkimncjhflgedgpam). **Note**: The stable and beta releases of Chrome on Windows will disable extensions not installed from the Chrome store, so users will need to install 4chan X from [here](https://chrome.google.com/webstore/detail/4chan-x/ohnjgmpcibpbafdlkimncjhflgedgpam).
### Known issues
Some recent versions of Chromium/Chrome (starting at 38.0.2085.0) suffer from a [bug](https://crbug.com/393686) that prevents extensions from making HTTP requests in the usual way. This breaks, among other things, thread updating, quick reply, and, when `JSON Navigation` is enabled, the thread index. Until this is fixed, try another version or a different browser.
## Other browsers ## Other browsers
This fork of 4chan X is not guaranteed to work correctly in other browsers, but you are welcome to try your luck. Pull requests to fix the bugs you will likely find are always welcome. This fork of 4chan X is not guaranteed to work correctly in other browsers, but you are welcome to try your luck. Pull requests to fix the bugs you will likely find are always welcome.
@ -32,7 +38,7 @@ New features and non-urgent bugfixes are released on the beta channel for furthe
- [Firefox version](https://ccd0.github.io/4chan-x/builds/4chan-X-beta.user.js) - [Firefox version](https://ccd0.github.io/4chan-x/builds/4chan-X-beta.user.js)
- [Chromium version](https://ccd0.github.io/4chan-x/builds/4chan-X-beta.crx) - [Chromium version](https://ccd0.github.io/4chan-x/builds/4chan-X-beta.crx)
## [Frequently Asked Questions](https://github.com/ccd0/4chan-x/wiki/Frequently-Asked-Questions) ## More information
### [Frequently Asked Questions](https://github.com/ccd0/4chan-x/wiki/Frequently-Asked-Questions)
## [Reporting Bugs and Contributing](https://github.com/ccd0/4chan-x/blob/master/CONTRIBUTING.md) ### [Reporting Bugs and Contributing](https://github.com/ccd0/4chan-x/blob/master/CONTRIBUTING.md)

Binary file not shown.

View File

@ -1,6 +1,6 @@
// ==UserScript== // ==UserScript==
// @name 4chan X // @name 4chan X
// @version 1.8.6.2 // @version 1.8.7
// @minGMVer 1.14 // @minGMVer 1.14
// @minFFVer 26 // @minFFVer 26
// @namespace 4chan-X // @namespace 4chan-X

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -1,6 +1,6 @@
// ==UserScript== // ==UserScript==
// @name 4chan X // @name 4chan X
// @version 1.8.6.2 // @version 1.8.7
// @minGMVer 1.14 // @minGMVer 1.14
// @minFFVer 26 // @minFFVer 26
// @namespace 4chan-X // @namespace 4chan-X

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'> <gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
<app appid='lacclbnghgdicfifcamcmcnilckjamag'> <app appid='lacclbnghgdicfifcamcmcnilckjamag'>
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X-beta.crx' version='1.8.6.2' /> <updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X-beta.crx' version='1.8.7' />
</app> </app>
</gupdate> </gupdate>

View File

@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'> <gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
<app appid='lacclbnghgdicfifcamcmcnilckjamag'> <app appid='lacclbnghgdicfifcamcmcnilckjamag'>
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X.crx' version='1.8.6.2' /> <updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X.crx' version='1.8.7' />
</app> </app>
</gupdate> </gupdate>

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 355 KiB

After

Width:  |  Height:  |  Size: 355 KiB

View File

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -1,6 +1,6 @@
{ {
"name": "4chan-X", "name": "4chan-X",
"version": "1.8.6.2", "version": "1.8.7",
"description": "Cross-browser userscript for maximum lurking on 4chan.", "description": "Cross-browser userscript for maximum lurking on 4chan.",
"meta": { "meta": {
"name": "4chan X", "name": "4chan X",

View File

@ -448,13 +448,15 @@ Config =
'Hide Thumbnails': [ 'Hide Thumbnails': [
false false
] ]
# Fit Width =/= Fit width 'Fit Width': [ # 'Fit width' (lowercase W) belongs to Image Expansion. Engine limitations, heh.
'Fit Width': [
true true
] ]
'Fit Height': [ 'Fit Height': [
true true
] ]
'Scroll to Post': [
true
]
'Slide Delay': [ 'Slide Delay': [
5.0 5.0
] ]

View File

@ -360,7 +360,7 @@ Header =
editCustomNav: -> editCustomNav: ->
Settings.open 'Advanced' Settings.open 'Advanced'
settings = $.id 'fourchanx-settings' settings = $.id 'fourchanx-settings'
$('input[name=boardnav]', settings).focus() $('textarea[name=boardnav]', settings).focus()
hashScroll: -> hashScroll: ->
hash = @location.hash[1..] hash = @location.hash[1..]

View File

@ -147,6 +147,7 @@ Index =
return if e.shiftKey or e.altKey or e.ctrlKey or e.metaKey or e.button isnt 0 return if e.shiftKey or e.altKey or e.ctrlKey or e.metaKey or e.button isnt 0
switch e.target.nodeName switch e.target.nodeName
when 'BUTTON' when 'BUTTON'
e.target.blur()
a = e.target.parentNode a = e.target.parentNode
when 'A' when 'A'
a = e.target a = e.target

View File

@ -35,7 +35,7 @@ Main =
Conf['CachedTitles'] = [] Conf['CachedTitles'] = []
$.get Conf, (items) -> $.get Conf, (items) ->
$.extend Conf, items $.extend Conf, items
$.asap (-> doc = d.documentElement), Main.initFeatures Main.initFeatures()
$.on d, '4chanMainInit', Main.initStyle $.on d, '4chanMainInit', Main.initStyle
@ -85,7 +85,7 @@ Main =
return if !Main.isThisPageLegit() or $.hasClass doc, 'fourchan-x' return if !Main.isThisPageLegit() or $.hasClass doc, 'fourchan-x'
# disable the mobile layout # disable the mobile layout
$('link[href*=mobile]', d.head)?.disabled = true $('link[href*=mobile]', d.head)?.disabled = true
$.addClass doc, 'fourchan-x', 'seaweedchan', g.VIEW, '<% if (type === 'crx') { %>blink<% } else { %>gecko<% } %>' $.addClass doc, 'fourchan-x', 'seaweedchan', g.VIEW, if chrome? then 'blink' else 'gecko'
$.addStyle Main.css $.addStyle Main.css
Main.setClass() Main.setClass()
@ -335,4 +335,4 @@ Main =
<% } %> <% } %>
] ]
Main.init() $.asap (-> (doc = d.documentElement) and d.head), Main.init

View File

@ -313,9 +313,9 @@ Settings =
interval.value = Conf['Interval'] interval.value = Conf['Interval']
customCSS.checked = Conf['Custom CSS'] customCSS.checked = Conf['Custom CSS']
inputs['usercss'].disabled = !Conf['Custom CSS'] inputs['usercss'].disabled = !Conf['Custom CSS']
$.on interval, 'change', ThreadUpdater.cb.interval $.on interval, 'change', ThreadUpdater.cb.interval
$.on customCSS, 'change', Settings.togglecss $.on customCSS, 'change', Settings.togglecss
$.on $.id('apply-css'), 'click', Settings.usercss $.on $('#apply-css', section), 'click', Settings.usercss
archBoards = {} archBoards = {}
for {name, boards, files, software, withCredentials} in Redirect.archives for {name, boards, files, software, withCredentials} in Redirect.archives
@ -357,7 +357,7 @@ Settings =
boardSelect = $('#archive-board-select', section) boardSelect = $('#archive-board-select', section)
$.add boardSelect, boardOptions $.add boardSelect, boardOptions
table = $.id 'archive-table' table = $('#archive-table', section)
$.on boardSelect, 'change', -> $.on boardSelect, 'change', ->
$('tbody > :not([hidden])', table).hidden = true $('tbody > :not([hidden])', table).hidden = true
$("tbody > .#{@value}", table).hidden = false $("tbody > .#{@value}", table).hidden = false

View File

@ -849,7 +849,9 @@ span.hide-announcement {
} }
.persona { .persona {
width: 100%; width: 100%;
display: -webkit-flex;
display: flex; display: flex;
-webkit-flex-direction: row;
flex-direction: row; flex-direction: row;
} }
#dump-button { #dump-button {
@ -869,6 +871,7 @@ span.hide-announcement {
opacity: 0.6; opacity: 0.6;
} }
.persona .field { .persona .field {
-webkit-flex: 1;
flex: 1; flex: 1;
width: 0; width: 0;
} }
@ -1279,22 +1282,32 @@ div.boardTitle {
left: 0; left: 0;
right: 0; right: 0;
z-index: 30; z-index: 30;
display: -webkit-flex;
display: flex; display: flex;
-webkit-flex-direction: row;
flex-direction: row; flex-direction: row;
background: rgba(0,0,0,0.7); background: rgba(0,0,0,0.7);
} }
.gal-viewport { .gal-viewport {
display: -webkit-flex;
display: flex; display: flex;
<%= align %>-items: stretch; -webkit-align-items: stretch;
align-items: stretch;
-webkit-flex-direction: row;
flex-direction: row; flex-direction: row;
-webkit-flex: 1 1 auto;
flex: 1 1 auto; flex: 1 1 auto;
} }
.gal-thumbnails { .gal-thumbnails {
-webkit-flex: 0 0 150px;
flex: 0 0 150px; flex: 0 0 150px;
overflow-y: auto; overflow-y: auto;
display: -webkit-flex;
display: flex; display: flex;
-webkit-flex-direction: column;
flex-direction: column; flex-direction: column;
<%= align %>-items: stretch; -webkit-align-items: stretch;
align-items: stretch;
text-align: center; text-align: center;
background: rgba(0,0,0,.5); background: rgba(0,0,0,.5);
border-left: 1px solid #222; border-left: 1px solid #222;
@ -1309,6 +1322,7 @@ div.boardTitle {
width: auto; width: auto;
} }
.gal-thumb { .gal-thumb {
-webkit-flex: 0 0 auto;
flex: 0 0 auto; flex: 0 0 auto;
padding: 3px; padding: 3px;
line-height: 0; line-height: 0;
@ -1327,6 +1341,7 @@ div.boardTitle {
} }
.gal-prev, .gal-prev,
.gal-next { .gal-next {
-webkit-flex: 0 0 20px;
flex: 0 0 20px; flex: 0 0 20px;
position: relative; position: relative;
cursor: pointer; cursor: pointer;
@ -1341,7 +1356,8 @@ div.boardTitle {
.gal-next::after { .gal-next::after {
position: absolute; position: absolute;
top: 48.6%; top: 48.6%;
<%= transform %>: translateY(-50%) -webkit-transform: translateY(-50%);
transform: translateY(-50%);
display: inline-block; display: inline-block;
border-top: 11px solid transparent; border-top: 11px solid transparent;
border-bottom: 11px solid transparent; border-bottom: 11px solid transparent;
@ -1357,10 +1373,14 @@ div.boardTitle {
} }
.gal-image { .gal-image {
order: 1; order: 1;
-webkit-flex: 1 0 auto;
flex: 1 0 auto; flex: 1 0 auto;
display: -webkit-flex;
display: flex; display: flex;
<%= align %>-items: flex-start; -webkit-align-items: flex-start;
<%= justify %>: space-around; align-items: flex-start;
-webkit-justify-content: space-around;
justify-content: space-around;
overflow: hidden; overflow: hidden;
/* Flex > Non-Flex child max-width and overflow fix (Firefox only?) */ /* Flex > Non-Flex child max-width and overflow fix (Firefox only?) */
width: 1%; width: 1%;

View File

@ -42,11 +42,24 @@ $.ajax = do ->
# With the `If-Modified-Since` header we only receive the HTTP headers and no body for 304 responses. # With the `If-Modified-Since` header we only receive the HTTP headers and no body for 304 responses.
# This saves a lot of bandwidth and CPU time for both the users and the servers. # This saves a lot of bandwidth and CPU time for both the users and the servers.
lastModified = {} lastModified = {}
blockedURLs = {}
blockedError = (url) ->
return if blockedURLs[url]
blockedURLs[url] = true
h_message = '<%= meta.name %> was blocked from loading the following URL:<br><span></span><br>'
h_message += '[<a href="<%= meta.faq %>#why-was-4chan-x-blocked-from-loading-a-url" target="_blank">More info</a>]'
message = $.el 'div', innerHTML: h_message
$('span', message).textContent = (if /^\/\//.test url then location.protocol else '') + url
new Notice 'error', message, 30, -> delete blockedURLs[url]
(url, options, extra={}) -> (url, options, extra={}) ->
{type, whenModified, upCallbacks, form} = extra {type, whenModified, upCallbacks, form} = extra
r = new XMLHttpRequest() r = new XMLHttpRequest()
type or= form and 'post' or 'get' type or= form and 'post' or 'get'
r.open type, url, true try
r.open type, url, true
catch err
blockedError url
return options.onerror?()
if whenModified if whenModified
r.setRequestHeader 'If-Modified-Since', lastModified[url] if url of lastModified r.setRequestHeader 'If-Modified-Since', lastModified[url] if url of lastModified
$.on r, 'load', -> lastModified[url] = r.getResponseHeader 'Last-Modified' $.on r, 'load', -> lastModified[url] = r.getResponseHeader 'Last-Modified'
@ -275,9 +288,6 @@ $.sync = do ->
cb changes[key].newValue, key cb changes[key].newValue, key
return return
(key, cb) -> $.syncing[key] = cb (key, cb) -> $.syncing[key] = cb
$.desync = (key) -> delete $.syncing[key]
$.localKeys = [ $.localKeys = [
# filters # filters
'name', 'name',
@ -295,85 +305,99 @@ $.localKeys = [
# custom css # custom css
'usercss' 'usercss'
] ]
# https://developer.chrome.com/extensions/storage.html # https://developer.chrome.com/extensions/storage.html
do ->
$.delete = (keys) ->
chrome.storage.sync.remove keys
$.get = (key, val, cb) ->
if typeof cb is 'function'
items = $.item key, val
else
items = key
cb = val
localItems = null
syncItems = null
for key, val of items
if key in $.localKeys
(localItems or= {})[key] = val
else
(syncItems or= {})[key] = val
count = 0
done = (item) ->
if chrome.runtime.lastError
c.error chrome.runtime.lastError.message
$.extend items, item
cb items unless --count
if localItems
count++
chrome.storage.local.get localItems, done
if syncItems
count++
chrome.storage.sync.get syncItems, done
$.set = do ->
items = items =
sync: {}
local: {} local: {}
timeout = {} sync: {}
$.delete = (keys) ->
if typeof keys is 'string'
keys = [keys]
local = []
sync = []
for key in keys
if key in $.localKeys
local.push key
delete items.local[key]
else
sync.push key
delete items.sync[key]
chrome.storage.local.remove local
chrome.storage.sync.remove sync
$.get = (key, val, cb) ->
if typeof cb is 'function'
data = $.item key, val
else
data = key
cb = val
localItems = null
syncItems = null
for key, val of data
if key in $.localKeys
(localItems or= {})[key] = val
else
(syncItems or= {})[key] = val
count = 0
done = (result) ->
if chrome.runtime.lastError
c.error chrome.runtime.lastError.message
$.extend data, result
cb data unless --count
if localItems
count++
chrome.storage.local.get localItems, done
if syncItems
count++
chrome.storage.sync.get syncItems, done
timeout = {}
setArea = (area) -> setArea = (area) ->
data = items[area] data = items[area]
return if !Object.keys(data).length or timeout[area] return if !Object.keys(data).length or timeout[area] > Date.now()
items[area] = {}
chrome.storage[area].set data, -> chrome.storage[area].set data, ->
if chrome.runtime.lastError if chrome.runtime.lastError
c.error chrome.runtime.lastError.message c.error chrome.runtime.lastError.message
for key, val of data when key not of items[area] for key, val of data when key not of items[area]
if area is 'sync' and chrome.storage.sync.QUOTA_BYTES_PER_ITEM < JSON.stringify(val).length + key.length
c.error chrome.runtime.lastError.message, key, val
continue
items[area][key] = val items[area][key] = val
timeout[area] = setTimeout setArea, $.MINUTE, area setTimeout setArea, $.MINUTE, area
timeout[area] = Date.now() + $.MINUTE
return return
delete timeout[area] delete timeout[area]
items[area] = {}
setAll = $.debounce $.SECOND, -> setSync = $.debounce $.SECOND, ->
for key in $.localKeys setArea 'sync'
if key of items.sync
items.local[key] = items.sync[key]
delete items.sync[key]
try
setArea 'local'
setArea 'sync'
catch err
c.error err.stack
(key, val) -> $.set = (key, val) ->
if typeof key is 'string' if typeof key is 'string'
items.sync[key] = val items.sync[key] = val
else else
$.extend items.sync, key $.extend items.sync, key
setAll() for key in $.localKeys when key of items.sync
$.clear = (cb) -> items.local[key] = items.sync[key]
count = 2 delete items.sync[key]
done = -> setArea 'local'
if chrome.runtime.lastError setSync()
c.error chrome.runtime.lastError.message
return $.clear = (cb) ->
cb?() unless --count items.local = {}
chrome.storage.local.clear done items.sync = {}
chrome.storage.sync.clear done count = 2
done = ->
if chrome.runtime.lastError
c.error chrome.runtime.lastError.message
return
cb?() unless --count
chrome.storage.local.clear done
chrome.storage.sync.clear done
<% } else { %> <% } else { %>
# http://wiki.greasespot.net/Main_Page # http://wiki.greasespot.net/Main_Page
@ -383,8 +407,6 @@ $.sync = do ->
cb JSON.parse(newValue), key cb JSON.parse(newValue), key
(key, cb) -> $.syncing[g.NAMESPACE + key] = cb (key, cb) -> $.syncing[g.NAMESPACE + key] = cb
$.desync = (key) -> delete $.syncing[g.NAMESPACE + key]
$.delete = (keys) -> $.delete = (keys) ->
unless keys instanceof Array unless keys instanceof Array
keys = [keys] keys = [keys]

View File

@ -1,5 +1,5 @@
class Notice class Notice
constructor: (type, content, @timeout) -> constructor: (type, content, @timeout, @onclose) ->
@el = $.el 'div', @el = $.el 'div',
innerHTML: '<a href="javascript:;" class="close fa fa-times" title="Close"></a><div class="message"></div>' innerHTML: '<a href="javascript:;" class="close fa fa-times" title="Close"></a><div class="message"></div>'
@el.style.opacity = 0 @el.style.opacity = 0
@ -27,3 +27,4 @@ class Notice
close: => close: =>
$.off d, 'visibilitychange', @add $.off d, 'visibilitychange', @add
$.rm @el $.rm @el
@onclose?()

View File

@ -77,7 +77,7 @@ Gallery =
nodes.current.parentElement.scrollTop = 0 nodes.current.parentElement.scrollTop = 0
Gallery.cb.open.call if image Gallery.cb.open.call if image
$ "[href='#{image.href.replace /https?:/, ''}']", nodes.thumbs $("[href='#{image.href}']", nodes.thumbs) or Gallery.images[0]
else else
Gallery.images[0] Gallery.images[0]
@ -86,6 +86,7 @@ Gallery =
generateThumb: (file) -> generateThumb: (file) ->
post = Get.postFromNode file post = Get.postFromNode file
return if post.isClone or post.isHidden
return unless post.file and (post.file.isImage or post.file.isVideo or Conf['PDF in Gallery']) return unless post.file and (post.file.isImage or post.file.isVideo or Conf['PDF in Gallery'])
return if Gallery.fullIDs[post.fullID] return if Gallery.fullIDs[post.fullID]
Gallery.fullIDs[post.fullID] = true Gallery.fullIDs[post.fullID] = true
@ -137,7 +138,9 @@ Gallery =
{nodes} = Gallery {nodes} = Gallery
{name} = nodes {name} = nodes
slideshow = Gallery.slideshow and +@dataset.id > +nodes.current.dataset.id oldID = +nodes.current.dataset.id
newID = +@dataset.id
slideshow = Gallery.slideshow and (newID > oldID or (oldID is Gallery.images.length-1 and newID is 0))
$.rmClass el, 'gal-highlight' if el = $ '.gal-highlight', nodes.thumbs $.rmClass el, 'gal-highlight' if el = $ '.gal-highlight', nodes.thumbs
$.addClass @, 'gal-highlight' $.addClass @, 'gal-highlight'
@ -162,6 +165,10 @@ Gallery =
nodes.next.focus() nodes.next.focus()
Gallery.cb[if slideshow then 'setupTimer' else 'stop']() Gallery.cb[if slideshow then 'setupTimer' else 'stop']()
# Scroll to post
if Conf['Scroll to Post'] and post = (post = g.posts[file.dataset.post])?.nodes.root
Header.scrollTo post
# Center selected thumbnail # Center selected thumbnail
nodes.thumbs.scrollTop = @offsetTop + @offsetHeight/2 - nodes.thumbs.clientHeight/2 nodes.thumbs.scrollTop = @offsetTop + @offsetHeight/2 - nodes.thumbs.clientHeight/2
@ -199,8 +206,14 @@ Gallery =
if postObj.filedeleted if postObj.filedeleted
post.kill true post.kill true
prev: -> Gallery.cb.open.call Gallery.images[+Gallery.nodes.current.dataset.id - 1] prev: ->
next: -> Gallery.cb.open.call Gallery.images[+Gallery.nodes.current.dataset.id + 1] Gallery.cb.open.call(
Gallery.images[+Gallery.nodes.current.dataset.id - 1] or Gallery.images[Gallery.images.length - 1]
)
next: ->
Gallery.cb.open.call(
Gallery.images[+Gallery.nodes.current.dataset.id + 1] or Gallery.images[0]
)
enterKey: -> if Gallery.nodes.current.paused then Gallery.nodes.current.play() else Gallery.cb.next() enterKey: -> if Gallery.nodes.current.paused then Gallery.nodes.current.play() else Gallery.cb.next()
click: -> Gallery.cb[if Gallery.nodes.current.controls then 'stop' else 'enterKey']() click: -> Gallery.cb[if Gallery.nodes.current.controls then 'stop' else 'enterKey']()
toggle: -> (if Gallery.nodes then Gallery.cb.close else Gallery.build)() toggle: -> (if Gallery.nodes then Gallery.cb.close else Gallery.build)()
@ -223,7 +236,6 @@ Gallery =
{current} = Gallery.nodes {current} = Gallery.nodes
isVideo = current.nodeName is 'VIDEO' isVideo = current.nodeName is 'VIDEO'
Video.start current if isVideo Video.start current if isVideo
return Gallery.cb.stop() if !Gallery.images[+Gallery.nodes.current.dataset.id + 1]
if (if isVideo then current.readyState > 4 else current.complete) or current.nodeName is 'IFRAME' if (if isVideo then current.readyState > 4 else current.complete) or current.nodeName is 'IFRAME'
Gallery.cb.startTimer() Gallery.cb.startTimer()
else else
@ -291,7 +303,7 @@ Gallery =
el: label el: label
createSubEntries: -> createSubEntries: ->
subEntries = ['Hide Thumbnails', 'Fit Width', 'Fit Height'].map Gallery.menu.createSubEntry subEntries = ['Hide Thumbnails', 'Fit Width', 'Fit Height', 'Scroll to Post'].map Gallery.menu.createSubEntry
delayLabel = $.el 'label', innerHTML: 'Slide Delay: <input type="number" name="Slide Delay" min="0" step="any" class="field">' delayLabel = $.el 'label', innerHTML: 'Slide Delay: <input type="number" name="Slide Delay" min="0" step="any" class="field">'
delayInput = delayLabel.firstElementChild delayInput = delayLabel.firstElementChild

View File

@ -10,22 +10,19 @@ ImageHover =
$.on @file.thumb, 'mouseover', ImageHover.mouseover $.on @file.thumb, 'mouseover', ImageHover.mouseover
mouseover: (e) -> mouseover: (e) ->
post = Get.postFromNode @ post = Get.postFromNode @
{isVideo} = post.file {file} = post
if post.file.fullImage {isVideo} = file
el = post.file.fullImage if el = file.fullImage
el.id = 'ihover'
TrashQueue.remove el TrashQueue.remove el
else else
el = $.el (if isVideo then 'video' else 'img'), file.fullImage = el = $.el (if isVideo then 'video' else 'img'),
className: 'full-image' className: 'full-image'
src: post.file.URL id: 'ihover'
post.file.fullImage = el el.dataset.fullID = post.fullID
{thumb} = post.file $.on el, 'error', ImageHover.error
if d.body.contains thumb el.src = file.URL
$.after thumb, el unless el is thumb.nextSibling $.after file.thumb, el
else
$.add Header.hover, el if el.parentNode isnt Header.hover
el.id = 'ihover'
el.dataset.fullID = post.fullID
if isVideo if isVideo
el.loop = true el.loop = true
el.controls = false el.controls = false
@ -35,7 +32,7 @@ ImageHover =
el: el el: el
latestEvent: e latestEvent: e
endEvents: 'mouseout click' endEvents: 'mouseout click'
asapTest: -> (if isVideo then el.videoHeight else el.naturalHeight) asapTest: -> (if isVideo then el.readyState >= el.HAVE_CURRENT_DATA else el.naturalHeight)
noRemove: true noRemove: true
cb: -> cb: ->
$.off el, 'error', ImageHover.error $.off el, 'error', ImageHover.error
@ -43,7 +40,6 @@ ImageHover =
el.pause() el.pause()
TrashQueue.add el, post TrashQueue.add el, post
el.removeAttribute 'id' el.removeAttribute 'id'
$.on el, 'error', ImageHover.error
error: -> error: ->
return unless doc.contains @ return unless doc.contains @
post = g.posts[@dataset.fullID] post = g.posts[@dataset.fullID]

View File

@ -44,7 +44,6 @@ Sauce =
a = Sauce.link.cloneNode true a = Sauce.link.cloneNode true
a.href = parts['url'] a.href = parts['url']
a.textContent = parts['text'] a.textContent = parts['text']
return null unless /^https?:$/.test a.protocol
a a
node: -> node: ->
return if @isClone or !@file return if @isClone or !@file

View File

@ -151,13 +151,12 @@ Linkify =
embed: (data) -> embed: (data) ->
[key, uid, options, link, post] = data [key, uid, options, link, post] = data
href = link.href
embed = $.el 'a', embed = $.el 'a',
className: 'embedder' className: 'embedder'
href: 'javascript:;' href: link.href
textContent: '(embed)' textContent: '(embed)'
embed.dataset[name] = value for name, value of {key, href, uid, options} embed.dataset[name] = value for name, value of {key, uid, options}
$.addClass link, "#{embed.dataset.key}" $.addClass link, "#{embed.dataset.key}"
@ -181,7 +180,8 @@ Linkify =
return return
cb: cb:
toggle: -> toggle: (e) ->
e?.preventDefault()
if $.hasClass @, "embedded" if $.hasClass @, "embedded"
$.rm @previousElementSibling $.rm @previousElementSibling
@previousElementSibling.hidden = false @previousElementSibling.hidden = false
@ -253,14 +253,14 @@ Linkify =
el: (a) -> el: (a) ->
el = $.el 'div' el = $.el 'div'
el.innerHTML = '<a target="_blank"><img></a>' el.innerHTML = '<a target="_blank"><img></a>'
el.firstChild.href = el.firstChild.firstChild.src = a.dataset.href el.firstChild.href = el.firstChild.firstChild.src = a.href
el el
, ,
key: 'InstallGentoo' key: 'InstallGentoo'
regExp: /.*(?:paste.installgentoo.com\/view\/)([0-9a-z_]+)/ regExp: /.*(?:paste.installgentoo.com\/view\/)([0-9a-z_]+)/
el: (a) -> el: (a) ->
$.el 'iframe', $.el 'iframe',
src: "http://paste.installgentoo.com/view/embed/#{a.dataset.uid}" src: "https://paste.installgentoo.com/view/embed/#{a.dataset.uid}"
, ,
key: 'Twitter' key: 'Twitter'
regExp: /.*twitter.com\/(.+\/status\/\d+)/ regExp: /.*twitter.com\/(.+\/status\/\d+)/
@ -302,7 +302,7 @@ Linkify =
el.firstChild.children[i].src = "https://mediacru.sh/#{a.dataset.uid}.#{ext}" el.firstChild.children[i].src = "https://mediacru.sh/#{a.dataset.uid}.#{ext}"
when 'image/svg+xml', 'image/png', 'image/gif', 'image/jpeg' when 'image/svg+xml', 'image/png', 'image/gif', 'image/jpeg'
el.innerHTML = '<a target="_blank"><img></a>' el.innerHTML = '<a target="_blank"><img></a>'
el.firstChild.href = a.dataset.href el.firstChild.href = a.href
el.firstChild.firstChild.src = "https://mediacru.sh/#{file.file}" el.firstChild.firstChild.src = "https://mediacru.sh/#{file.file}"
when 'audio/mpeg', 'audio/ogg' when 'audio/mpeg', 'audio/ogg'
el.innerHTML = '<audio controls><source type="audio/ogg"><source type="audio/mpeg"></audio>' el.innerHTML = '<audio controls><source type="audio/ogg"><source type="audio/mpeg"></audio>'
@ -322,20 +322,20 @@ Linkify =
regExp: /.*gfycat.com\/(?:iframe\/)?(\S*)/ regExp: /.*gfycat.com\/(?:iframe\/)?(\S*)/
el: (a) -> el: (a) ->
div = $.el 'iframe', div = $.el 'iframe',
src: "http://gfycat.com/iframe/#{a.dataset.uid}" src: "//gfycat.com/iframe/#{a.dataset.uid}"
, ,
key: 'SoundCloud' key: 'SoundCloud'
regExp: /.*(?:soundcloud.com\/|snd.sc\/)([^#\&\?]*).*/ regExp: /.*(?:soundcloud.com\/|snd.sc\/)([^#\&\?]*).*/
style: 'border: 0; width: 500px; height: 400px;' style: 'border: 0; width: 500px; height: 400px;'
el: (a) -> el: (a) ->
$.el 'iframe', $.el 'iframe',
src: "//w.soundcloud.com/player/?visual=true&show_comments=false&url=https%3A%2F%2Fsoundcloud.com%2F#{encodeURIComponent a.dataset.uid}" src: "https://w.soundcloud.com/player/?visual=true&show_comments=false&url=https%3A%2F%2Fsoundcloud.com%2F#{encodeURIComponent a.dataset.uid}"
title: title:
api: (uid) -> "//soundcloud.com/oembed?format=json&url=https%3A%2F%2Fsoundcloud.com%2F#{encodeURIComponent uid}" api: (uid) -> "//soundcloud.com/oembed?format=json&url=https%3A%2F%2Fsoundcloud.com%2F#{encodeURIComponent uid}"
text: (_) -> _.title text: (_) -> _.title
, ,
key: 'StrawPoll' key: 'StrawPoll'
regExp: /strawpoll\.me\/(?:embed_\d+\/)?(\d+)/ regExp: /strawpoll\.me\/(?:embed_\d+\/)?(\d+(?:\/r)?)/
style: 'border: 0; width: 600px; height: 406px;' style: 'border: 0; width: 600px; height: 406px;'
el: (a) -> el: (a) ->
$.el 'iframe', $.el 'iframe',