Skip to content

Instantly share code, notes, and snippets.

@PetrKaleta
Created January 8, 2012 21:38
Show Gist options
  • Save PetrKaleta/1579788 to your computer and use it in GitHub Desktop.
Save PetrKaleta/1579788 to your computer and use it in GitHub Desktop.
Micro JavaScript library written in CoffeeScript to solve my needs when creating mobile web apps for iOS.
###
Caffeinated.js 1.0.1
(c) 2012 Petr Kaleta, @petrkaleta
Caffeinated.js is freely distributable under the MIT license.
Micro JavaScript library written in CoffeeScript to make my life easier when creating mobile web apps for iOS.
I don't like extending built-in JavaScript objects, so I've created this lib as an separate object.
I used underscore identifier to make its calls short as possible. So please do not mess this lib with gorgeous
Underscore.js lib by Jeremy Ashkenas, DocumentCloud Inc.
Some methods are inspired or borrowed from popular JavaScript frameworks like jQuery, Underscore.js and Prototype.js
Note: feel free to change lib's identifier to prevent conflicts with Underscore.js
Changelog:
1.0.1:
- added offset(el) method to get element's position relative to window
- renamed scrollTop method to scrollTo(target) and now accepts numeric or element attribute
to specify scroll position
###
_ =
# Caffeinated Way
# --------------------------------------------------
# More caffeinated way to setTimeout
after: (ms, func) -> setTimeout func, ms
# More caffeinated way to setInterval
every: (ms, func) -> setInterval func, ms
# Object Related Functions
# --------------------------------------------------
# Fill object with missing default properties
defaults: (obj, def) ->
(obj[prop] = def[prop] unless obj[prop]?) for prop of def
obj
# Detection Properties
# --------------------------------------------------
# Supports browser's feature?
supports: {
touch : 'ontouchstart' of window
history : window.history?
classList : 'classList' of document.createElement 'span'
}
# CSS Related Functions
# --------------------------------------------------
# Show element
show: (el) ->
el.style['display'] = '' if el.style['display'] is 'none'
# Hide element
hide: (el) ->
el.style['display'] = 'none' unless el.style['display'] is 'none'
# Add CSS class
addClass: (el, cls) ->
if @supports.classList
el.classList.add cls
else
el.className += " #{cls}" unless @hasClass el, cls
# Remove CSS class
removeClass: (el, cls) ->
if @supports.classList
el.classList.remove cls
else
el.className = el.className.replace new RegExp('(\\s|^)' + cls + '(\\s|$)') if @hasClass el, cls
# Toggle CSS class
toggleClass: (el, cls) ->
if @supports.classList
el.classList.toggle cls
else
if @hasClass el, cls then @removeClass el, cls else @addClass el, cls
# Has CSS class?
hasClass: (el, cls) ->
if @supports.classList
el.classList.contains cls
else
el.className.match new RegExp('(\\s|^)' + cls + '(\\s|$)')
# Switch CSS class with one of its variants
switchClass: (el, cls1, cls2) ->
if @hasClass(el, cls1) or @hasClass(el, cls2)
@toggleClass el, cls1
@toggleClass el, cls2
else
@addClass el, cls1
# DOM Related Functions
# --------------------------------------------------
# Append contents (HTML/DOMElement) into element
append: (el, contents) ->
# if contents is HTML append it using wrapper else if its DOMElement append it directly
if typeof contents is 'string'
# used just for htmlString => DOMElement conversion
wrap = document.createElement 'span'
wrap.innerHTML = contents
# append all first childs
el.appendChild wrap.firstChild while wrap.firstChild
else if contents.nodeType?
el.appendChild contents
return
# Remove all contents of element
empty: (el) ->
el.removeChild el.firstChild while el.firstChild
# Get HTML5 data attribute value
# Automatic type conversion (boolean, numeric, JSON, string)
getData: (el, key) ->
data = el.getAttribute "data-#{key}"
if typeof data is 'string'
try
value = if data is 'true' then true else
if data is 'false' then false else
if data is 'null' then null else
if not isNaN(parseFloat(data)) and isFinite(data) then parseFloat(data) else
if /^(?:\{.*\}|\[.*\])$/.test(data) then JSON.parse(data) else data
value
catch error
data
# Set HTML5 data attribute value
# Objects are stringified to JSON
setData: (el, key, value) ->
value = if typeof value is 'object' then JSON.stringify value else value
el.setAttribute "data-#{key}", value
# Get elements offset relative to window
offset: (el) ->
curLeft = curTop = 0
if el.offsetParent
loop
curLeft += el.offsetLeft
curTop += el.offsetTop
break unless el = el.offsetParent
left: curLeft, top: curTop
# Scroll window by y axis to the target (numeric position/DOMElement's position)
scrollTo: (target) ->
if typeof target is 'number'
window.scrollTo 0, target
else if target.nodeType?
window.scrollTo 0, @offset(target).top
# Simulate click event using touch events (remove click delay on iOS)
# Uses click event if browser has no touch support
listenTouchClick: (el, func, shouldPreventAction = no) ->
if @supports.touch
hasMoved = false
onTouchStart = (e) ->
e.preventDefault() if shouldPreventAction
hasMoved = false
# detection listeners
el.addEventListener 'touchmove', onTouchMove, no
el.addEventListener 'touchend', onTouchEnd, no
onTouchMove = ->
hasMoved = true
onTouchEnd = (e) ->
el.removeEventListener 'touchmove', onTouchMove, no
el.removeEventListener 'touchend', onTouchEnd, no
# callback
func.call(null, e) unless hasMoved
el.addEventListener 'touchstart', onTouchStart, no
else
el.addEventListener 'click', func, no
# URL Related Functions
# --------------------------------------------------
# Get url params Object
params: ->
hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split '&'
obj = {}
for hash in hashes
[key, value] = hash.split '='
obj[key] = value
obj
# Change URL in addressbar
# Makes redirect if browser has no history support
updateUrl: (newUrl) ->
if @supports.history
window.history.replaceState null, null, newUrl
else
window.location.href = newUrl
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment