From 8560f204b2baea84f9469fcc55db89de7349f4af Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sun, 9 Jun 2013 17:21:36 +0200 Subject: [PATCH] Remove userjs support and Presto-related code. Add `minimum_opera_version` in the manifest. Up the min Chrome version for unprefixed MutationObserver support. --- .gitignore | 1 - CONTRIBUTING.md | 3 +- Gruntfile.js | 19 +------- css/style.css | 54 ++++++++++++----------- html/Posting/QR.html | 2 +- lib/$.coffee | 68 +++++------------------------ src/General/Globals.coffee | 6 --- src/General/Main.coffee | 18 +++----- src/Images/ImageExpand.coffee | 13 ------ src/Meta/manifest.json | 3 +- src/Monitoring/ThreadUpdater.coffee | 3 +- src/Monitoring/Unread.coffee | 4 +- src/Posting/QR.coffee | 59 +++++-------------------- src/Quotelinks/QuotePreview.coffee | 15 ------- 14 files changed, 64 insertions(+), 204 deletions(-) diff --git a/.gitignore b/.gitignore index 868b74e84..7820bd9be 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ builds/ node_modules/ tmp-crx/ -tmp-userjs/ tmp-userscript/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a1164bc88..735b0841c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,9 +11,8 @@ Reporting bugs: 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. +- `Ctrl + Shift + J` on Chrome and Opera. - `Ctrl + Shift + K` on Firefox. -- `Ctrl + Shift + O` on Opera. Respect these guidelines: - Describe the issue clearly, put some effort into it. A one-liner isn't a good enough description. diff --git a/Gruntfile.js b/Gruntfile.js index 9bf70810d..69100ad0f 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -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: { options: concatOptions, files: { @@ -102,7 +93,7 @@ module.exports = function(grunt) { } }, concurrent: { - build: ['build-crx', 'build-userjs', 'build-userscript'] + build: ['build-crx', 'build-userscript'] }, bump: { options: { @@ -161,7 +152,6 @@ module.exports = function(grunt) { clean: { builds: 'builds', tmpcrx: 'tmp-crx', - tmpuserjs: 'tmp-userjs', tmpuserscript: 'tmp-userscript' } }); @@ -193,13 +183,6 @@ module.exports = function(grunt) { 'copy:crx', 'clean:tmpcrx' ]); - grunt.registerTask('build-userjs', [ - 'set-build:userjs', - 'concat:coffee', - 'coffee:script', - 'concat:userjs', - 'clean:tmpuserjs' - ]); grunt.registerTask('build-userscript', [ 'set-build:userscript', 'concat:coffee', diff --git a/css/style.css b/css/style.css index ce398bc5e..28dfb5bed 100644 --- a/css/style.css +++ b/css/style.css @@ -278,10 +278,8 @@ a[href="javascript:;"] { 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; @@ -468,7 +466,8 @@ a.hide-announcement { .deadlink { text-decoration: none !important; } -.backlink.deadlink:not(.forwardlink), .quotelink.deadlink:not(.forwardlink) { +.backlink.deadlink:not(.forwardlink), +.quotelink.deadlink:not(.forwardlink) { text-decoration: underline !important; } .inlined { @@ -508,8 +507,6 @@ a.hide-announcement { padding: 2px 2px 5px; } #qp img { - max-height: 300px; - max-width: 500px; max-height: 80vh; max-width: 50vw; } @@ -541,8 +538,7 @@ a.hide-announcement { :root.fit-width .full-image { max-width: 100%; } -:root.gecko.fit-width .full-image, -:root.presto.fit-width .full-image { +:root.gecko.fit-width .full-image { width: 100%; } #ihover { @@ -616,9 +612,6 @@ a.hide-announcement { color: #000; background-color: #F7F7F7; } -.presto #qr select { - height: 1em; -} #qr .close { padding: 0 3px; } @@ -649,13 +642,15 @@ a.hide-announcement { outline: none; width: 30px; } -#dump-button:hover, #dump-button:focus { +#dump-button:hover, +#dump-button:focus { 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); } -.gecko #dump-button { +:root.gecko #dump-button { padding: 0; } #qr:not(.dump) #dump-list-container { @@ -670,7 +665,10 @@ a.hide-announcement { } #dump-list { counter-reset: qrpreviews; - top: 0; right: 0; bottom: 0; left: 0; + top: 0; + right: 0; + bottom: 0; + left: 0; overflow: hidden; position: absolute; white-space: nowrap; @@ -696,8 +694,10 @@ a.hide-announcement { box-sizing: border-box; cursor: move; display: inline-block; - height: 92px; width: 92px; - margin: 4px; padding: 2px; + height: 92px; + width: 92px; + margin: 4px; + padding: 2px; opacity: .6; outline: none; overflow: hidden; @@ -707,7 +707,8 @@ a.hide-announcement { vertical-align: top; white-space: pre; } -.qr-preview:hover, .qr-preview:focus { +.qr-preview:hover, +.qr-preview:focus { opacity: .9; color: #FFF !important; } @@ -720,7 +721,8 @@ a.hide-announcement { font-weight: 700; text-shadow: 0 0 3px #000, 0 0 5px #000; position: absolute; - top: 3px; right: 3px; + top: 3px; + right: 3px; } .qr-preview.drag { border-color: red; @@ -740,7 +742,9 @@ a.hide-announcement { } .qr-preview > label { background: rgba(0, 0, 0, .5); - right: 0; bottom: 0; left: 0; + right: 0; + bottom: 0; + left: 0; position: absolute; text-align: center; } @@ -756,7 +760,8 @@ a.hide-announcement { line-height: 1; text-align: center; position: absolute; - right: 0; bottom: 0; + right: 0; + bottom: 0; z-index: 1; } #qr textarea { @@ -822,7 +827,10 @@ a.hide-announcement { } #qr-filename { position: absolute; - top: 0; right: 0; bottom: 0; left: 0; + top: 0; + right: 0; + bottom: 0; + left: 0; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; @@ -838,10 +846,6 @@ a.hide-announcement { -webkit-order: 1; order: 1; } -#qr input[type='file'] { - position: absolute; - visibility: hidden; -} /* Menu */ .menu-button { diff --git a/html/Posting/QR.html b/html/Posting/QR.html index b02ef3b5f..b34fb36b3 100644 --- a/html/Posting/QR.html +++ b/html/Posting/QR.html @@ -31,7 +31,7 @@ × - + diff --git a/lib/$.coffee b/lib/$.coffee index 40b283713..de39560c9 100644 --- a/lib/$.coffee +++ b/lib/$.coffee @@ -208,26 +208,19 @@ $.bytesToString = (size) -> # Round to an integer otherwise. Math.round size "#{size} #{['B', 'KB', 'MB', 'GB'][unit]}" +$.item = (key, val) -> + item = {} + item[key] = val + item $.syncing = {} -$.sync = do -> <% if (type === 'crx') { %> +$.sync = do -> chrome.storage.onChanged.addListener (changes) -> for key of changes if cb = $.syncing[key] cb changes[key].newValue return (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 = [ # filters 'name', @@ -300,52 +293,13 @@ $.set = do -> else $.extend items, key 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 { %> - # 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) -> unless keys instanceof Array keys = [keys] diff --git a/src/General/Globals.coffee b/src/General/Globals.coffee index ad48281e4..d5d09eaa6 100644 --- a/src/General/Globals.coffee +++ b/src/General/Globals.coffee @@ -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 = {} c = console d = document diff --git a/src/General/Main.coffee b/src/General/Main.coffee index b023d704f..09fe39241 100644 --- a/src/General/Main.coffee +++ b/src/General/Main.coffee @@ -127,8 +127,6 @@ Main = <% if (type === 'crx') { %> $.addClass doc, 'webkit' $.addClass doc, 'blink' - <% } else if (type === 'userjs') { %> - $.addClass doc, 'presto' <% } else { %> $.addClass doc, 'gecko' <% } %> @@ -151,13 +149,9 @@ Main = $.addClass doc, style setStyle() return unless mainStyleSheet - if window.MutationObserver - observer = new MutationObserver setStyle - observer.observe mainStyleSheet, - attributes: true - attributeFilter: ['href'] - else - $.on mainStyleSheet, 'DOMAttrModified', setStyle + new MutationObserver(setStyle).observe mainStyleSheet, + attributes: true + attributeFilter: ['href'] initReady: -> if d.title is '4chan - 404 Not Found' @@ -252,12 +246,10 @@ Main = checkUpdate: -> return unless Conf['Check for Updates'] and Main.isThisPageLegit() - # Check for updates after: - # - 6 hours since the last update on Opera because it lacks auto-updating. - # - 7 days since the last update on Chrome/Firefox. + # Check for updates after 7 days since the last update. # After that, check for updates every day if we still haven't updated. now = Date.now() - freq = <% if (type === 'userjs') { %>6 * $.HOUR<% } else { %>7 * $.DAY<% } %> + freq = 7 * $.DAY items = lastupdate: 0 lastchecked: 0 diff --git a/src/Images/ImageExpand.coffee b/src/Images/ImageExpand.coffee index 18d91fcc1..777cceea8 100644 --- a/src/Images/ImageExpand.coffee +++ b/src/Images/ImageExpand.coffee @@ -52,19 +52,6 @@ ImageExpand = return setFitness: -> (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) -> {thumb} = post.file diff --git a/src/Meta/manifest.json b/src/Meta/manifest.json index b9793bda3..fb8cfba4e 100644 --- a/src/Meta/manifest.json +++ b/src/Meta/manifest.json @@ -15,7 +15,8 @@ "run_at": "document_start" }], "homepage_url": "<%= meta.page %>", - "minimum_chrome_version": "26", + "minimum_chrome_version": "27", + "minimum_opera_version": "15", "permissions": [ "storage" ] diff --git a/src/Monitoring/ThreadUpdater.coffee b/src/Monitoring/ThreadUpdater.coffee index 0c3f5317c..7dab2983a 100644 --- a/src/Monitoring/ThreadUpdater.coffee +++ b/src/Monitoring/ThreadUpdater.coffee @@ -114,8 +114,7 @@ ThreadUpdater = 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. ### - # XXX 304 -> 0 in Opera - [text, klass] = if req.status in [0, 304] + [text, klass] = if req.status is 304 [null, null] else ["#{req.statusText} (#{req.status})", 'warning'] diff --git a/src/Monitoring/Unread.coffee b/src/Monitoring/Unread.coffee index 6ad07f03e..1e0b63fd6 100644 --- a/src/Monitoring/Unread.coffee +++ b/src/Monitoring/Unread.coffee @@ -184,9 +184,7 @@ Unread = else Favicon.default - <% if (type !== 'crx') { %> + <% if (type === 'userscript') { %> # `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 <% } %> diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index fb5bce620..981053704 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -330,7 +330,6 @@ QR = post = Get.postFromNode @ text = ">>#{post}\n" 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>' text += ">#{s}\n" @@ -501,7 +500,6 @@ QR = else if @ is QR.selected (QR.posts[index-1] or QR.posts[index+1]).select() QR.posts.splice index, 1 - return unless window.URL URL.revokeObjectURL @URL lock: (lock=true) -> @isLocked = lock @@ -558,25 +556,14 @@ QR = @filename = "#{file.name} (#{$.bytesToString file.size})" @nodes.el.title = @filename @nodes.label.hidden = false if QR.spoiler - URL.revokeObjectURL @URL if window.URL + URL.revokeObjectURL @URL @showFileData() unless /^image/.test file.type @nodes.el.style.backgroundImage = null return @setThumbnail() - setThumbnail: (fileURL) -> - # XXX Opera does not support blob URL + setThumbnail: -> # 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.onload = => @@ -588,7 +575,7 @@ QR = s *= 3 if @file.type is 'image/gif' # let them animate {height, width} = img if height < s or width < s - @URL = fileURL if window.URL + @URL = fileURL @nodes.el.style.backgroundImage = "url(#{@URL})" return if height <= width @@ -601,10 +588,6 @@ QR = cv.height = img.height = height cv.width = img.width = width 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 applyBlob = (blob) => @URL = URL.createObjectURL blob @@ -622,6 +605,7 @@ QR = applyBlob new Blob [ui8a], type: 'image/png' + fileURL = URL.createObjectURL @file img.src = fileURL rmFile: -> delete @file @@ -630,7 +614,6 @@ QR = @nodes.el.style.backgroundImage = null @nodes.label.hidden = true if QR.spoiler @showFileData() - return unless window.URL URL.revokeObjectURL @URL showFileData: -> if @file @@ -652,22 +635,17 @@ QR = QR.nodes.com.value = @com @nodes.span.textContent = @com reader.readAsText file - dragStart: -> - $.addClass @, 'drag' - dragEnd: -> - $.rmClass @, 'drag' - dragEnter: -> - $.addClass @, 'over' - dragLeave: -> - $.rmClass @, 'over' + dragStart: -> $.addClass @, 'drag' + dragEnd: -> $.rmClass @, 'drag' + dragEnter: -> $.addClass @, 'over' + dragLeave: -> $.rmClass @, 'over' dragOver: (e) -> e.preventDefault() e.dataTransfer.dropEffect = 'move' drop: -> - el = $ '.drag', @parentNode - $.rmClass el, 'drag' # Opera doesn't fire dragEnd if we drop it on something else - $.rmClass @, 'over' + $.rmClass @, 'over' return unless @draggable + el = $ '.drag', @parentNode index = (el) -> [el.parentNode.children...].indexOf el oldIndex = index el newIndex = index @ @@ -700,12 +678,8 @@ QR = img: imgContainer.firstChild input: input - if window.MutationObserver - observer = new MutationObserver @load.bind @ - observer.observe @nodes.challenge, - childList: true - else - $.on @nodes.challenge, 'DOMNodeInserted', @load.bind @ + new MutationObserver(@load.bind @).observe @nodes.challenge, + childList: true $.on imgContainer, 'click', @reload.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. QR.mimeTypes.push '' 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]' nodes.spoiler.hidden = !QR.spoiler @@ -1018,11 +988,6 @@ QR = QR.status() 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 delete QR.req diff --git a/src/Quotelinks/QuotePreview.coffee b/src/Quotelinks/QuotePreview.coffee index fcd0bfd98..ab21dfa78 100644 --- a/src/Quotelinks/QuotePreview.coffee +++ b/src/Quotelinks/QuotePreview.coffee @@ -28,21 +28,6 @@ QuotePreview = cb: QuotePreview.mouseout 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}"] if Conf['Quote Highlighting']