Merge pull request #1183 from MayhemYDG/opera

Drop Opera <15 support.
This commit is contained in:
Mayhem 2013-07-09 01:56:58 -07:00
commit 39aa9d3cb5
15 changed files with 65 additions and 207 deletions

1
.gitignore vendored
View File

@ -1,5 +1,4 @@
builds/ builds/
node_modules/ node_modules/
tmp-crx/ tmp-crx/
tmp-userjs/
tmp-userscript/ tmp-userscript/

View File

@ -11,9 +11,8 @@ Reporting bugs:
4. Your exported settings. If your settings contains sensible information (e.g. personas), edit the text file manually. 4. Your exported settings. If your settings contains sensible information (e.g. personas), edit the text file manually.
Open your console with: Open your console with:
- `Ctrl + Shift + J` on Chrome. - `Ctrl + Shift + J` on Chrome and Opera.
- `Ctrl + Shift + K` on Firefox. - `Ctrl + Shift + K` on Firefox.
- `Ctrl + Shift + O` on Opera.
Respect these guidelines: Respect these guidelines:
- Describe the issue clearly, put some effort into it. A one-liner isn't a good enough description. - Describe the issue clearly, put some effort into it. A one-liner isn't a good enough description.

View File

@ -56,15 +56,6 @@ module.exports = function(grunt) {
] ]
} }
}, },
userjs: {
options: concatOptions,
src: [
'src/Meta/metadata.js',
'src/Meta/banner.js',
'tmp-<%= pkg.type %>/script.js'
],
dest: 'builds/<%= pkg.name %>.js'
},
userscript: { userscript: {
options: concatOptions, options: concatOptions,
files: { files: {
@ -102,7 +93,7 @@ module.exports = function(grunt) {
} }
}, },
concurrent: { concurrent: {
build: ['build-crx', 'build-userjs', 'build-userscript'] build: ['build-crx', 'build-userscript']
}, },
bump: { bump: {
options: { options: {
@ -161,7 +152,6 @@ module.exports = function(grunt) {
clean: { clean: {
builds: 'builds', builds: 'builds',
tmpcrx: 'tmp-crx', tmpcrx: 'tmp-crx',
tmpuserjs: 'tmp-userjs',
tmpuserscript: 'tmp-userscript' tmpuserscript: 'tmp-userscript'
} }
}); });
@ -193,13 +183,6 @@ module.exports = function(grunt) {
'copy:crx', 'copy:crx',
'clean:tmpcrx' 'clean:tmpcrx'
]); ]);
grunt.registerTask('build-userjs', [
'set-build:userjs',
'concat:coffee',
'coffee:script',
'concat:userjs',
'clean:tmpuserjs'
]);
grunt.registerTask('build-userscript', [ grunt.registerTask('build-userscript', [
'set-build:userscript', 'set-build:userscript',
'concat:coffee', 'concat:coffee',

View File

@ -278,10 +278,8 @@ a[href="javascript:;"] {
box-sizing: border-box; box-sizing: border-box;
box-shadow: 0 0 15px rgba(0, 0, 0, .15); box-shadow: 0 0 15px rgba(0, 0, 0, .15);
height: 600px; height: 600px;
min-height: 0;
max-height: 100%; max-height: 100%;
width: 900px; width: 900px;
min-width: 0;
max-width: 100%; max-width: 100%;
margin: auto; margin: auto;
padding: 3px; padding: 3px;
@ -468,7 +466,8 @@ a.hide-announcement {
.deadlink { .deadlink {
text-decoration: none !important; text-decoration: none !important;
} }
.backlink.deadlink:not(.forwardlink), .quotelink.deadlink:not(.forwardlink) { .backlink.deadlink:not(.forwardlink),
.quotelink.deadlink:not(.forwardlink) {
text-decoration: underline !important; text-decoration: underline !important;
} }
.inlined { .inlined {
@ -508,8 +507,6 @@ a.hide-announcement {
padding: 2px 2px 5px; padding: 2px 2px 5px;
} }
#qp img { #qp img {
max-height: 300px;
max-width: 500px;
max-height: 80vh; max-height: 80vh;
max-width: 50vw; max-width: 50vw;
} }
@ -541,8 +538,7 @@ a.hide-announcement {
:root.fit-width .full-image { :root.fit-width .full-image {
max-width: 100%; max-width: 100%;
} }
:root.gecko.fit-width .full-image, :root.gecko.fit-width .full-image {
:root.presto.fit-width .full-image {
width: 100%; width: 100%;
} }
#ihover { #ihover {
@ -616,9 +612,6 @@ a.hide-announcement {
color: #000; color: #000;
background-color: #F7F7F7; background-color: #F7F7F7;
} }
.presto #qr select {
height: 1em;
}
#qr .close { #qr .close {
padding: 0 3px; padding: 0 3px;
} }
@ -649,13 +642,15 @@ a.hide-announcement {
outline: none; outline: none;
width: 30px; width: 30px;
} }
#dump-button:hover, #dump-button:focus { #dump-button:hover,
#dump-button:focus {
background: linear-gradient(#FFF, #DDD); background: linear-gradient(#FFF, #DDD);
} }
#dump-button:active, .dump #dump-button:not(:hover):not(:focus) { #dump-button:active,
.dump #dump-button:not(:hover):not(:focus) {
background: linear-gradient(#CCC, #DDD); background: linear-gradient(#CCC, #DDD);
} }
.gecko #dump-button { :root.gecko #dump-button {
padding: 0; padding: 0;
} }
#qr:not(.dump) #dump-list-container { #qr:not(.dump) #dump-list-container {
@ -670,7 +665,10 @@ a.hide-announcement {
} }
#dump-list { #dump-list {
counter-reset: qrpreviews; counter-reset: qrpreviews;
top: 0; right: 0; bottom: 0; left: 0; top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: hidden; overflow: hidden;
position: absolute; position: absolute;
white-space: nowrap; white-space: nowrap;
@ -696,8 +694,10 @@ a.hide-announcement {
box-sizing: border-box; box-sizing: border-box;
cursor: move; cursor: move;
display: inline-block; display: inline-block;
height: 92px; width: 92px; height: 92px;
margin: 4px; padding: 2px; width: 92px;
margin: 4px;
padding: 2px;
opacity: .6; opacity: .6;
outline: none; outline: none;
overflow: hidden; overflow: hidden;
@ -707,7 +707,8 @@ a.hide-announcement {
vertical-align: top; vertical-align: top;
white-space: pre; white-space: pre;
} }
.qr-preview:hover, .qr-preview:focus { .qr-preview:hover,
.qr-preview:focus {
opacity: .9; opacity: .9;
color: #FFF !important; color: #FFF !important;
} }
@ -720,7 +721,8 @@ a.hide-announcement {
font-weight: 700; font-weight: 700;
text-shadow: 0 0 3px #000, 0 0 5px #000; text-shadow: 0 0 3px #000, 0 0 5px #000;
position: absolute; position: absolute;
top: 3px; right: 3px; top: 3px;
right: 3px;
} }
.qr-preview.drag { .qr-preview.drag {
border-color: red; border-color: red;
@ -740,7 +742,9 @@ a.hide-announcement {
} }
.qr-preview > label { .qr-preview > label {
background: rgba(0, 0, 0, .5); background: rgba(0, 0, 0, .5);
right: 0; bottom: 0; left: 0; right: 0;
bottom: 0;
left: 0;
position: absolute; position: absolute;
text-align: center; text-align: center;
} }
@ -756,7 +760,8 @@ a.hide-announcement {
line-height: 1; line-height: 1;
text-align: center; text-align: center;
position: absolute; position: absolute;
right: 0; bottom: 0; right: 0;
bottom: 0;
z-index: 1; z-index: 1;
} }
#qr textarea { #qr textarea {
@ -822,7 +827,10 @@ a.hide-announcement {
} }
#qr-filename { #qr-filename {
position: absolute; position: absolute;
top: 0; right: 0; bottom: 0; left: 0; top: 0;
right: 0;
bottom: 0;
left: 0;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
@ -838,10 +846,6 @@ a.hide-announcement {
-webkit-order: 1; -webkit-order: 1;
order: 1; order: 1;
} }
#qr input[type='file'] {
position: absolute;
visibility: hidden;
}
/* Menu */ /* Menu */
.menu-button { .menu-button {

View File

@ -31,7 +31,7 @@
<a id="qr-filerm" href="javascript:;" title="Remove file">×</a> <a id="qr-filerm" href="javascript:;" title="Remove file">×</a>
<input type="checkbox" id="qr-file-spoiler" title="Spoiler image"> <input type="checkbox" id="qr-file-spoiler" title="Spoiler image">
</div> </div>
<input type="file" multiple> <input type="file" multiple hidden>
</form> </form>
<datalist id="list-name"></datalist> <datalist id="list-name"></datalist>
<datalist id="list-email"></datalist> <datalist id="list-email"></datalist>

View File

@ -208,26 +208,19 @@ $.bytesToString = (size) ->
# Round to an integer otherwise. # Round to an integer otherwise.
Math.round size Math.round size
"#{size} #{['B', 'KB', 'MB', 'GB'][unit]}" "#{size} #{['B', 'KB', 'MB', 'GB'][unit]}"
$.item = (key, val) ->
item = {}
item[key] = val
item
$.syncing = {} $.syncing = {}
$.sync = do ->
<% if (type === 'crx') { %> <% if (type === 'crx') { %>
$.sync = do ->
chrome.storage.onChanged.addListener (changes) -> chrome.storage.onChanged.addListener (changes) ->
for key of changes for key of changes
if cb = $.syncing[key] if cb = $.syncing[key]
cb changes[key].newValue cb changes[key].newValue
return return
(key, cb) -> $.syncing[key] = cb (key, cb) -> $.syncing[key] = cb
<% } else { %>
$.on window, 'storage', (e) ->
if cb = $.syncing[e.key]
cb JSON.parse e.newValue
(key, cb) -> $.syncing[g.NAMESPACE + key] = cb
<% } %>
$.item = (key, val) ->
item = {}
item[key] = val
item
<% if (type === 'crx') { %>
$.localKeys = [ $.localKeys = [
# filters # filters
'name', 'name',
@ -300,52 +293,13 @@ $.set = do ->
else else
$.extend items, key $.extend items, key
set() set()
<% } else if (type === 'userjs') { %>
do ->
# http://www.opera.com/docs/userjs/specs/#scriptstorage
# http://www.opera.com/docs/userjs/using/#securepages
# The scriptStorage object is available only during
# the main User JavaScript thread, being therefore
# accessible only in the main body of the user script.
# To access the storage object later, keep a reference
# to the object.
{scriptStorage} = opera
$.delete = (keys) ->
unless keys instanceof Array
keys = [keys]
for key in keys
key = g.NAMESPACE + key
localStorage.removeItem key
delete scriptStorage[key]
return
$.get = (key, val, cb) ->
if typeof cb is 'function'
items = $.item key, val
else
items = key
cb = val
$.queueTask ->
for key of items
if val = scriptStorage[g.NAMESPACE + key]
items[key] = JSON.parse val
cb items
$.set = do ->
set = (key, val) ->
key = g.NAMESPACE + key
val = JSON.stringify val
if key of $.syncing
# for `storage` events
localStorage.setItem key, val
scriptStorage[key] = val
(keys, val) ->
if typeof keys is 'string'
set keys, val
return
for key, val of keys
set key, val
return
<% } else { %> <% } else { %>
# http://wiki.greasespot.net/Main_Page # http://wiki.greasespot.net/Main_Page
$.sync = do ->
$.on window, 'storage', (e) ->
if cb = $.syncing[e.key]
cb JSON.parse e.newValue
(key, cb) -> $.syncing[g.NAMESPACE + key] = cb
$.delete = (keys) -> $.delete = (keys) ->
unless keys instanceof Array unless keys instanceof Array
keys = [keys] keys = [keys]

View File

@ -1,9 +1,3 @@
<% if (type === 'userjs') { %>
# Opera doesn't support the @match metadata key,
# return 4chan X here if we're not on 4chan.
return unless /^(boards|images|sys)\.4chan\.org$/.test location.hostname
<% } %>
Conf = {} Conf = {}
c = console c = console
d = document d = document

View File

@ -127,8 +127,6 @@ Main =
<% if (type === 'crx') { %> <% if (type === 'crx') { %>
$.addClass doc, 'webkit' $.addClass doc, 'webkit'
$.addClass doc, 'blink' $.addClass doc, 'blink'
<% } else if (type === 'userjs') { %>
$.addClass doc, 'presto'
<% } else { %> <% } else { %>
$.addClass doc, 'gecko' $.addClass doc, 'gecko'
<% } %> <% } %>
@ -151,13 +149,9 @@ Main =
$.addClass doc, style $.addClass doc, style
setStyle() setStyle()
return unless mainStyleSheet return unless mainStyleSheet
if window.MutationObserver new MutationObserver(setStyle).observe mainStyleSheet,
observer = new MutationObserver setStyle attributes: true
observer.observe mainStyleSheet, attributeFilter: ['href']
attributes: true
attributeFilter: ['href']
else
$.on mainStyleSheet, 'DOMAttrModified', setStyle
initReady: -> initReady: ->
if d.title is '4chan - 404 Not Found' if d.title is '4chan - 404 Not Found'
@ -252,12 +246,10 @@ Main =
checkUpdate: -> checkUpdate: ->
return unless Conf['Check for Updates'] and Main.isThisPageLegit() return unless Conf['Check for Updates'] and Main.isThisPageLegit()
# Check for updates after: # Check for updates after 7 days since the last update.
# - 6 hours since the last update on Opera because it lacks auto-updating.
# - 7 days since the last update on Chrome/Firefox.
# After that, check for updates every day if we still haven't updated. # After that, check for updates every day if we still haven't updated.
now = Date.now() now = Date.now()
freq = <% if (type === 'userjs') { %>6 * $.HOUR<% } else { %>7 * $.DAY<% } %> freq = 7 * $.DAY
items = items =
lastupdate: 0 lastupdate: 0
lastchecked: 0 lastchecked: 0

View File

@ -52,19 +52,6 @@ ImageExpand =
return return
setFitness: -> setFitness: ->
(if @checked then $.addClass else $.rmClass) doc, @name.toLowerCase().replace /\s+/g, '-' (if @checked then $.addClass else $.rmClass) doc, @name.toLowerCase().replace /\s+/g, '-'
<% if (type === 'userjs') { %>
# XXX Opera doesn't support CSS vh.
return unless @name is 'Fit height'
if @checked
$.on window, 'resize', ImageExpand.resize
unless ImageExpand.style
ImageExpand.style = $.addStyle null
ImageExpand.resize()
else
$.off window, 'resize', ImageExpand.resize
resize: ->
ImageExpand.style.textContent = ":root.fit-height .full-image {max-height:#{doc.clientHeight}px}"
<% } %>
toggle: (post) -> toggle: (post) ->
{thumb} = post.file {thumb} = post.file

View File

@ -4,12 +4,10 @@ Sauce =
links = [] links = []
for link in Conf['sauces'].split '\n' for link in Conf['sauces'].split '\n'
continue if link[0] is '#'
try try
links.push @createSauceLink link.trim() links.push @createSauceLink link.trim() if link[0] isnt '#'
catch err catch err
# Don't add random text plz. # Don't add random text plz.
continue
return unless links.length return unless links.length
@links = links @links = links
@link = $.el 'a', target: '_blank' @link = $.el 'a', target: '_blank'

View File

@ -15,7 +15,8 @@
"run_at": "document_start" "run_at": "document_start"
}], }],
"homepage_url": "<%= meta.page %>", "homepage_url": "<%= meta.page %>",
"minimum_chrome_version": "26", "minimum_chrome_version": "27",
"minimum_opera_version": "15",
"permissions": [ "permissions": [
"storage" "storage"
] ]

View File

@ -114,8 +114,7 @@ ThreadUpdater =
By sending the `If-Modified-Since` header we get a proper status code, and no response. By sending the `If-Modified-Since` header we get a proper status code, and no response.
This saves bandwidth for both the user and the servers and avoid unnecessary computation. This saves bandwidth for both the user and the servers and avoid unnecessary computation.
### ###
# XXX 304 -> 0 in Opera [text, klass] = if req.status is 304
[text, klass] = if req.status in [0, 304]
[null, null] [null, null]
else else
["#{req.statusText} (#{req.status})", 'warning'] ["#{req.statusText} (#{req.status})", 'warning']

View File

@ -182,9 +182,7 @@ Unread =
else else
Favicon.default Favicon.default
<% if (type !== 'crx') { %> <% if (type === 'userscript') { %>
# `favicon.href = href` doesn't work on Firefox. # `favicon.href = href` doesn't work on Firefox.
# `favicon.href = href` isn't enough on Opera.
# Opera won't always update the favicon if the href didn't change.
$.add d.head, Favicon.el $.add d.head, Favicon.el
<% } %> <% } %>

View File

@ -330,7 +330,6 @@ QR =
post = Get.postFromNode @ post = Get.postFromNode @
text = ">>#{post}\n" text = ">>#{post}\n"
if (s = sel.toString().trim()) and post is Get.postFromNode sel.anchorNode if (s = sel.toString().trim()) and post is Get.postFromNode sel.anchorNode
# XXX Opera doesn't retain `\n`s?
s = s.replace /\n/g, '\n>' s = s.replace /\n/g, '\n>'
text += ">#{s}\n" text += ">#{s}\n"
@ -501,7 +500,6 @@ QR =
else if @ is QR.selected else if @ is QR.selected
(QR.posts[index-1] or QR.posts[index+1]).select() (QR.posts[index-1] or QR.posts[index+1]).select()
QR.posts.splice index, 1 QR.posts.splice index, 1
return unless window.URL
URL.revokeObjectURL @URL URL.revokeObjectURL @URL
lock: (lock=true) -> lock: (lock=true) ->
@isLocked = lock @isLocked = lock
@ -558,25 +556,14 @@ QR =
@filename = "#{file.name} (#{$.bytesToString file.size})" @filename = "#{file.name} (#{$.bytesToString file.size})"
@nodes.el.title = @filename @nodes.el.title = @filename
@nodes.label.hidden = false if QR.spoiler @nodes.label.hidden = false if QR.spoiler
URL.revokeObjectURL @URL if window.URL URL.revokeObjectURL @URL
@showFileData() @showFileData()
unless /^image/.test file.type unless /^image/.test file.type
@nodes.el.style.backgroundImage = null @nodes.el.style.backgroundImage = null
return return
@setThumbnail() @setThumbnail()
setThumbnail: (fileURL) -> setThumbnail: ->
# XXX Opera does not support blob URL
# Create a redimensioned thumbnail. # Create a redimensioned thumbnail.
unless window.URL
unless fileURL
reader = new FileReader()
reader.onload = (e) =>
@setThumbnail e.target.result
reader.readAsDataURL @file
return
else
fileURL = URL.createObjectURL @file
img = $.el 'img' img = $.el 'img'
img.onload = => img.onload = =>
@ -588,7 +575,7 @@ QR =
s *= 3 if @file.type is 'image/gif' # let them animate s *= 3 if @file.type is 'image/gif' # let them animate
{height, width} = img {height, width} = img
if height < s or width < s if height < s or width < s
@URL = fileURL if window.URL @URL = fileURL
@nodes.el.style.backgroundImage = "url(#{@URL})" @nodes.el.style.backgroundImage = "url(#{@URL})"
return return
if height <= width if height <= width
@ -601,10 +588,6 @@ QR =
cv.height = img.height = height cv.height = img.height = height
cv.width = img.width = width cv.width = img.width = width
cv.getContext('2d').drawImage img, 0, 0, width, height cv.getContext('2d').drawImage img, 0, 0, width, height
unless window.URL
@nodes.el.style.backgroundImage = "url(#{cv.toDataURL()})"
delete @URL
return
URL.revokeObjectURL fileURL URL.revokeObjectURL fileURL
applyBlob = (blob) => applyBlob = (blob) =>
@URL = URL.createObjectURL blob @URL = URL.createObjectURL blob
@ -622,6 +605,7 @@ QR =
applyBlob new Blob [ui8a], type: 'image/png' applyBlob new Blob [ui8a], type: 'image/png'
fileURL = URL.createObjectURL @file
img.src = fileURL img.src = fileURL
rmFile: -> rmFile: ->
delete @file delete @file
@ -630,7 +614,6 @@ QR =
@nodes.el.style.backgroundImage = null @nodes.el.style.backgroundImage = null
@nodes.label.hidden = true if QR.spoiler @nodes.label.hidden = true if QR.spoiler
@showFileData() @showFileData()
return unless window.URL
URL.revokeObjectURL @URL URL.revokeObjectURL @URL
showFileData: -> showFileData: ->
if @file if @file
@ -652,22 +635,17 @@ QR =
QR.nodes.com.value = @com QR.nodes.com.value = @com
@nodes.span.textContent = @com @nodes.span.textContent = @com
reader.readAsText file reader.readAsText file
dragStart: -> dragStart: -> $.addClass @, 'drag'
$.addClass @, 'drag' dragEnd: -> $.rmClass @, 'drag'
dragEnd: -> dragEnter: -> $.addClass @, 'over'
$.rmClass @, 'drag' dragLeave: -> $.rmClass @, 'over'
dragEnter: ->
$.addClass @, 'over'
dragLeave: ->
$.rmClass @, 'over'
dragOver: (e) -> dragOver: (e) ->
e.preventDefault() e.preventDefault()
e.dataTransfer.dropEffect = 'move' e.dataTransfer.dropEffect = 'move'
drop: -> drop: ->
el = $ '.drag', @parentNode $.rmClass @, 'over'
$.rmClass el, 'drag' # Opera doesn't fire dragEnd if we drop it on something else
$.rmClass @, 'over'
return unless @draggable return unless @draggable
el = $ '.drag', @parentNode
index = (el) -> [el.parentNode.children...].indexOf el index = (el) -> [el.parentNode.children...].indexOf el
oldIndex = index el oldIndex = index el
newIndex = index @ newIndex = index @
@ -700,12 +678,8 @@ QR =
img: imgContainer.firstChild img: imgContainer.firstChild
input: input input: input
if window.MutationObserver new MutationObserver(@load.bind @).observe @nodes.challenge,
observer = new MutationObserver @load.bind @ childList: true
observer.observe @nodes.challenge,
childList: true
else
$.on @nodes.challenge, 'DOMNodeInserted', @load.bind @
$.on imgContainer, 'click', @reload.bind @ $.on imgContainer, 'click', @reload.bind @
$.on input, 'keydown', @keydown.bind @ $.on input, 'keydown', @keydown.bind @
@ -836,10 +810,6 @@ QR =
# Add empty mimeType to avoid errors with URLs selected in Window's file dialog. # Add empty mimeType to avoid errors with URLs selected in Window's file dialog.
QR.mimeTypes.push '' QR.mimeTypes.push ''
nodes.fileInput.max = $('input[name=MAX_FILE_SIZE]').value nodes.fileInput.max = $('input[name=MAX_FILE_SIZE]').value
<% if (type !== 'userjs') { %>
# Opera's accept attribute is fucked up
nodes.fileInput.accept = "text/*, #{mimeTypes}"
<% } %>
QR.spoiler = !!$ 'input[name=spoiler]' QR.spoiler = !!$ 'input[name=spoiler]'
nodes.spoiler.hidden = !QR.spoiler nodes.spoiler.hidden = !QR.spoiler
@ -1018,11 +988,6 @@ QR =
QR.status() QR.status()
response: -> response: ->
<% if (type === 'userjs') { %>
# The upload.onload callback is not called
# or at least not in time with Opera.
QR.req.upload.onload()
<% } %>
{req} = QR {req} = QR
delete QR.req delete QR.req

View File

@ -28,21 +28,6 @@ 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']