Don't extend $.
This commit is contained in:
parent
d2eda107c4
commit
dcba887954
511
lib/$.coffee
511
lib/$.coffee
@ -6,241 +6,238 @@ $ = (selector, root=d.body) ->
|
||||
$$ = (selector, root=d.body) ->
|
||||
[root.querySelectorAll(selector)...]
|
||||
|
||||
$.SECOND = 1000
|
||||
$.MINUTE = 1000 * 60
|
||||
$.HOUR = 1000 * 60 * 60
|
||||
$.DAY = 1000 * 60 * 60 * 24
|
||||
$.id = (id) ->
|
||||
d.getElementById id
|
||||
$.ready = (fc) ->
|
||||
if d.readyState in ['interactive', 'complete']
|
||||
$.queueTask fc
|
||||
return
|
||||
cb = ->
|
||||
$.off d, 'DOMContentLoaded', cb
|
||||
fc()
|
||||
$.on d, 'DOMContentLoaded', cb
|
||||
$.formData = (form) ->
|
||||
if form instanceof HTMLFormElement
|
||||
return new FormData form
|
||||
fd = new FormData()
|
||||
for key, val of form
|
||||
continue unless val
|
||||
# XXX GM bug
|
||||
# if val instanceof Blob
|
||||
if val.size and val.name
|
||||
fd.append key, val, val.name
|
||||
else
|
||||
fd.append key, val
|
||||
fd
|
||||
$.extend = (object, properties) ->
|
||||
for key, val of properties
|
||||
object[key] = val
|
||||
return
|
||||
|
||||
$.extend $,
|
||||
SECOND: 1000
|
||||
MINUTE: 1000 * 60
|
||||
HOUR : 1000 * 60 * 60
|
||||
DAY : 1000 * 60 * 60 * 24
|
||||
id: (id) ->
|
||||
d.getElementById id
|
||||
ready: (fc) ->
|
||||
if d.readyState in ['interactive', 'complete']
|
||||
$.queueTask fc
|
||||
return
|
||||
cb = ->
|
||||
$.off d, 'DOMContentLoaded', cb
|
||||
fc()
|
||||
$.on d, 'DOMContentLoaded', cb
|
||||
formData: (form) ->
|
||||
if form instanceof HTMLFormElement
|
||||
return new FormData form
|
||||
fd = new FormData()
|
||||
for key, val of form
|
||||
continue unless val
|
||||
# XXX GM bug
|
||||
# if val instanceof Blob
|
||||
if val.size and val.name
|
||||
fd.append key, val, val.name
|
||||
$.ajax = (url, callbacks, opts={}) ->
|
||||
{type, cred, headers, upCallbacks, form, sync} = opts
|
||||
r = new XMLHttpRequest()
|
||||
type or= form and 'post' or 'get'
|
||||
r.open type, url, !sync
|
||||
for key, val of headers
|
||||
r.setRequestHeader key, val
|
||||
$.extend r, callbacks
|
||||
$.extend r.upload, upCallbacks
|
||||
r.withCredentials = cred
|
||||
r.send form
|
||||
r
|
||||
$.cache = do ->
|
||||
reqs = {}
|
||||
(url, cb) ->
|
||||
if req = reqs[url]
|
||||
if req.readyState is 4
|
||||
cb.call req
|
||||
else
|
||||
fd.append key, val
|
||||
fd
|
||||
ajax: (url, callbacks, opts={}) ->
|
||||
{type, cred, headers, upCallbacks, form, sync} = opts
|
||||
r = new XMLHttpRequest()
|
||||
type or= form and 'post' or 'get'
|
||||
r.open type, url, !sync
|
||||
for key, val of headers
|
||||
r.setRequestHeader key, val
|
||||
$.extend r, callbacks
|
||||
$.extend r.upload, upCallbacks
|
||||
r.withCredentials = cred
|
||||
r.send form
|
||||
r
|
||||
cache: do ->
|
||||
reqs = {}
|
||||
(url, cb) ->
|
||||
if req = reqs[url]
|
||||
if req.readyState is 4
|
||||
cb.call req
|
||||
else
|
||||
req.callbacks.push cb
|
||||
return
|
||||
rm = -> delete reqs[url]
|
||||
req = $.ajax url,
|
||||
onload: (e) ->
|
||||
cb.call @, e for cb in @callbacks
|
||||
delete @callbacks
|
||||
onabort: rm
|
||||
onerror: rm
|
||||
req.callbacks = [cb]
|
||||
reqs[url] = req
|
||||
cb:
|
||||
checked: ->
|
||||
$.set @name, @checked
|
||||
Conf[@name] = @checked
|
||||
value: ->
|
||||
$.set @name, @value.trim()
|
||||
Conf[@name] = @value
|
||||
asap: (test, cb) ->
|
||||
if test()
|
||||
cb()
|
||||
else
|
||||
setTimeout $.asap, 25, test, cb
|
||||
addStyle: (css) ->
|
||||
style = $.el 'style',
|
||||
textContent: css
|
||||
$.asap (-> d.head), ->
|
||||
$.add d.head, style
|
||||
style
|
||||
x: (path, root=d.body) ->
|
||||
# XPathResult.ANY_UNORDERED_NODE_TYPE === 8
|
||||
d.evaluate(path, root, null, 8, null).singleNodeValue
|
||||
addClass: (el, className) ->
|
||||
el.classList.add className
|
||||
rmClass: (el, className) ->
|
||||
el.classList.remove className
|
||||
hasClass: (el, className) ->
|
||||
el.classList.contains className
|
||||
rm: do ->
|
||||
if 'remove' of Element.prototype
|
||||
(el) -> el.remove()
|
||||
else
|
||||
(el) -> el.parentNode?.removeChild el
|
||||
rmAll: (root) ->
|
||||
# jsperf.com/emptify-element
|
||||
while node = root.firstChild
|
||||
# HTMLSelectElement.remove !== Element.remove
|
||||
root.removeChild node
|
||||
return
|
||||
tn: (s) ->
|
||||
d.createTextNode s
|
||||
nodes: (nodes) ->
|
||||
unless nodes instanceof Array
|
||||
return nodes
|
||||
frag = d.createDocumentFragment()
|
||||
for node in nodes
|
||||
frag.appendChild node
|
||||
frag
|
||||
add: (parent, el) ->
|
||||
parent.appendChild $.nodes el
|
||||
prepend: (parent, el) ->
|
||||
parent.insertBefore $.nodes(el), parent.firstChild
|
||||
after: (root, el) ->
|
||||
root.parentNode.insertBefore $.nodes(el), root.nextSibling
|
||||
before: (root, el) ->
|
||||
root.parentNode.insertBefore $.nodes(el), root
|
||||
replace: (root, el) ->
|
||||
root.parentNode.replaceChild $.nodes(el), root
|
||||
el: (tag, properties) ->
|
||||
el = d.createElement tag
|
||||
$.extend el, properties if properties
|
||||
el
|
||||
on: (el, events, handler) ->
|
||||
for event in events.split ' '
|
||||
el.addEventListener event, handler, false
|
||||
return
|
||||
off: (el, events, handler) ->
|
||||
for event in events.split ' '
|
||||
el.removeEventListener event, handler, false
|
||||
return
|
||||
event: (event, detail, root=d) ->
|
||||
root.dispatchEvent new CustomEvent event, {bubbles: true, detail}
|
||||
open: do ->
|
||||
if GM_openInTab?
|
||||
(URL) ->
|
||||
# XXX fix GM opening file://// for protocol-less URLs.
|
||||
a = $.el 'a', href: URL
|
||||
GM_openInTab a.href
|
||||
else
|
||||
(URL) -> window.open URL, '_blank'
|
||||
debounce: (wait, fn) ->
|
||||
req.callbacks.push cb
|
||||
return
|
||||
rm = -> delete reqs[url]
|
||||
req = $.ajax url,
|
||||
onload: (e) ->
|
||||
cb.call @, e for cb in @callbacks
|
||||
delete @callbacks
|
||||
onabort: rm
|
||||
onerror: rm
|
||||
req.callbacks = [cb]
|
||||
reqs[url] = req
|
||||
$.cb =
|
||||
checked: ->
|
||||
$.set @name, @checked
|
||||
Conf[@name] = @checked
|
||||
value: ->
|
||||
$.set @name, @value.trim()
|
||||
Conf[@name] = @value
|
||||
$.asap = (test, cb) ->
|
||||
if test()
|
||||
cb()
|
||||
else
|
||||
setTimeout $.asap, 25, test, cb
|
||||
$.addStyle = (css) ->
|
||||
style = $.el 'style',
|
||||
textContent: css
|
||||
$.asap (-> d.head), ->
|
||||
$.add d.head, style
|
||||
style
|
||||
$.x = (path, root=d.body) ->
|
||||
# XPathResult.ANY_UNORDERED_NODE_TYPE === 8
|
||||
d.evaluate(path, root, null, 8, null).singleNodeValue
|
||||
$.addClass = (el, className) ->
|
||||
el.classList.add className
|
||||
$.rmClass = (el, className) ->
|
||||
el.classList.remove className
|
||||
$.hasClass = (el, className) ->
|
||||
el.classList.contains className
|
||||
$.rm = do ->
|
||||
if 'remove' of Element.prototype
|
||||
(el) -> el.remove()
|
||||
else
|
||||
(el) -> el.parentNode?.removeChild el
|
||||
$.rmAll = (root) ->
|
||||
# jsperf.com/emptify-element
|
||||
while node = root.firstChild
|
||||
# HTMLSelectElement.remove !== Element.remove
|
||||
root.removeChild node
|
||||
return
|
||||
$.tn = (s) ->
|
||||
d.createTextNode s
|
||||
$.nodes = (nodes) ->
|
||||
unless nodes instanceof Array
|
||||
return nodes
|
||||
frag = d.createDocumentFragment()
|
||||
for node in nodes
|
||||
frag.appendChild node
|
||||
frag
|
||||
$.add = (parent, el) ->
|
||||
parent.appendChild $.nodes el
|
||||
$.prepend = (parent, el) ->
|
||||
parent.insertBefore $.nodes(el), parent.firstChild
|
||||
$.after = (root, el) ->
|
||||
root.parentNode.insertBefore $.nodes(el), root.nextSibling
|
||||
$.before = (root, el) ->
|
||||
root.parentNode.insertBefore $.nodes(el), root
|
||||
$.replace = (root, el) ->
|
||||
root.parentNode.replaceChild $.nodes(el), root
|
||||
$.el = (tag, properties) ->
|
||||
el = d.createElement tag
|
||||
$.extend el, properties if properties
|
||||
el
|
||||
$.on = (el, events, handler) ->
|
||||
for event in events.split ' '
|
||||
el.addEventListener event, handler, false
|
||||
return
|
||||
$.off = (el, events, handler) ->
|
||||
for event in events.split ' '
|
||||
el.removeEventListener event, handler, false
|
||||
return
|
||||
$.event = (event, detail, root=d) ->
|
||||
root.dispatchEvent new CustomEvent event, {bubbles: true, detail}
|
||||
$.open = do ->
|
||||
if GM_openInTab?
|
||||
(URL) ->
|
||||
# XXX fix GM opening file://// for protocol-less URLs.
|
||||
a = $.el 'a', href: URL
|
||||
GM_openInTab a.href
|
||||
else
|
||||
(URL) -> window.open URL, '_blank'
|
||||
$.debounce = (wait, fn) ->
|
||||
timeout = null
|
||||
that = null
|
||||
args = null
|
||||
exec = ->
|
||||
fn.apply that, args
|
||||
timeout = null
|
||||
that = null
|
||||
args = null
|
||||
exec = ->
|
||||
fn.apply that, args
|
||||
timeout = null
|
||||
->
|
||||
args = arguments
|
||||
that = this
|
||||
if timeout
|
||||
# stop current reset
|
||||
clearTimeout timeout
|
||||
else
|
||||
exec()
|
||||
->
|
||||
args = arguments
|
||||
that = this
|
||||
if timeout
|
||||
# stop current reset
|
||||
clearTimeout timeout
|
||||
else
|
||||
exec()
|
||||
|
||||
# after wait, let next invocation execute immediately
|
||||
timeout = setTimeout exec, wait
|
||||
queueTask: do ->
|
||||
# inspired by https://www.w3.org/Bugs/Public/show_bug.cgi?id=15007
|
||||
taskQueue = []
|
||||
execTask = ->
|
||||
task = taskQueue.shift()
|
||||
func = task[0]
|
||||
args = Array::slice.call task, 1
|
||||
func.apply func, args
|
||||
if window.MessageChannel
|
||||
taskChannel = new MessageChannel()
|
||||
taskChannel.port1.onmessage = execTask
|
||||
->
|
||||
taskQueue.push arguments
|
||||
taskChannel.port2.postMessage null
|
||||
else # XXX Firefox
|
||||
->
|
||||
taskQueue.push arguments
|
||||
setTimeout execTask, 0
|
||||
globalEval: (code) ->
|
||||
script = $.el 'script',
|
||||
textContent: code
|
||||
$.add (d.head or doc), script
|
||||
$.rm script
|
||||
bytesToString: (size) ->
|
||||
unit = 0 # Bytes
|
||||
while size >= 1024
|
||||
size /= 1024
|
||||
unit++
|
||||
# Remove trailing 0s.
|
||||
size =
|
||||
if unit > 1
|
||||
# Keep the size as a float if the size is greater than 2^20 B.
|
||||
# Round to hundredth.
|
||||
Math.round(size * 100) / 100
|
||||
else
|
||||
# Round to an integer otherwise.
|
||||
Math.round size
|
||||
"#{size} #{['B', 'KB', 'MB', 'GB'][unit]}"
|
||||
syncing: {}
|
||||
sync: do ->
|
||||
# after wait, let next invocation execute immediately
|
||||
timeout = setTimeout exec, wait
|
||||
$.queueTask = do ->
|
||||
# inspired by https://www.w3.org/Bugs/Public/show_bug.cgi?id=15007
|
||||
taskQueue = []
|
||||
execTask = ->
|
||||
task = taskQueue.shift()
|
||||
func = task[0]
|
||||
args = Array::slice.call task, 1
|
||||
func.apply func, args
|
||||
if window.MessageChannel
|
||||
taskChannel = new MessageChannel()
|
||||
taskChannel.port1.onmessage = execTask
|
||||
->
|
||||
taskQueue.push arguments
|
||||
taskChannel.port2.postMessage null
|
||||
else # XXX Firefox
|
||||
->
|
||||
taskQueue.push arguments
|
||||
setTimeout execTask, 0
|
||||
$.globalEval = (code) ->
|
||||
script = $.el 'script',
|
||||
textContent: code
|
||||
$.add (d.head or doc), script
|
||||
$.rm script
|
||||
$.bytesToString = (size) ->
|
||||
unit = 0 # Bytes
|
||||
while size >= 1024
|
||||
size /= 1024
|
||||
unit++
|
||||
# Remove trailing 0s.
|
||||
size =
|
||||
if unit > 1
|
||||
# Keep the size as a float if the size is greater than 2^20 B.
|
||||
# Round to hundredth.
|
||||
Math.round(size * 100) / 100
|
||||
else
|
||||
# Round to an integer otherwise.
|
||||
Math.round size
|
||||
"#{size} #{['B', 'KB', 'MB', 'GB'][unit]}"
|
||||
$.syncing = {}
|
||||
$.sync = do ->
|
||||
<% if (type === 'crx') { %>
|
||||
chrome.storage.onChanged.addListener (changes) ->
|
||||
for key of changes
|
||||
if cb = $.syncing[key]
|
||||
cb changes[key].newValue
|
||||
return
|
||||
(key, cb) -> $.syncing[key] = cb
|
||||
chrome.storage.onChanged.addListener (changes) ->
|
||||
for key of changes
|
||||
if cb = $.syncing[key]
|
||||
cb changes[key].newValue
|
||||
return
|
||||
(key, cb) -> $.syncing[key] = cb
|
||||
<% } else { %>
|
||||
window.addEventListener 'storage', (e) ->
|
||||
if cb = $.syncing[e.key]
|
||||
cb JSON.parse e.newValue
|
||||
, false
|
||||
(key, cb) -> $.syncing[g.NAMESPACE + key] = cb
|
||||
$.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
|
||||
$.item = (key, val) ->
|
||||
item = {}
|
||||
item[key] = val
|
||||
item
|
||||
<% if (type === 'crx') { %>
|
||||
# https://developer.chrome.com/extensions/storage.html
|
||||
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
|
||||
chrome.storage.sync.get items, cb
|
||||
set: (key, val) ->
|
||||
items = if typeof key is 'string'
|
||||
$.item key, val
|
||||
else
|
||||
key
|
||||
chrome.storage.sync.set items
|
||||
# https://developer.chrome.com/extensions/storage.html
|
||||
$.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
|
||||
chrome.storage.sync.get items, cb
|
||||
$.set = (key, val) ->
|
||||
items = if typeof key is 'string'
|
||||
$.item key, val
|
||||
else
|
||||
key
|
||||
chrome.storage.sync.set items
|
||||
<% } else if (type === 'userjs') { %>
|
||||
do ->
|
||||
# http://www.opera.com/docs/userjs/specs/#scriptstorage
|
||||
@ -287,38 +284,38 @@ do ->
|
||||
return
|
||||
<% } else { %>
|
||||
# http://wiki.greasespot.net/Main_Page
|
||||
delete: (keys) ->
|
||||
unless keys instanceof Array
|
||||
keys = [keys]
|
||||
for key in keys
|
||||
key = g.NAMESPACE + key
|
||||
localStorage.removeItem key
|
||||
GM_deleteValue 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 = GM_getValue 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
|
||||
GM_setValue key, val
|
||||
(keys, val) ->
|
||||
if typeof keys is 'string'
|
||||
set keys, val
|
||||
return
|
||||
for key, val of keys
|
||||
set key, val
|
||||
$.delete = (keys) ->
|
||||
unless keys instanceof Array
|
||||
keys = [keys]
|
||||
for key in keys
|
||||
key = g.NAMESPACE + key
|
||||
localStorage.removeItem key
|
||||
GM_deleteValue 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 = GM_getValue 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
|
||||
GM_setValue key, val
|
||||
(keys, val) ->
|
||||
if typeof keys is 'string'
|
||||
set keys, val
|
||||
return
|
||||
for key, val of keys
|
||||
set key, val
|
||||
return
|
||||
<% } %>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user