/********************************************************************** * JavaScript Lib * at this point this is just a place I put most of the generic stuff I * use. * * P.S. the name "jli" just stands for Java script LIb, like how it * looks... **********************************************************************/ //var DEBUG = DEBUG != null ? DEBUG : true /*********************************************************************/ // XXX find a better name for this... // this will create a function that will add/remove a css_class to elem // calling the optional callbacks before and/or after. // // elem is a jquery compatible object; default use-case: a css selector. // // the resulting function understands the folowing arguments: // - 'on' : switch mode on // - 'off' : switch mode off // - '?' : return current state ('on'|'off') // - no arguments : toggle the state // // NOTE: of only one callback is given then it will be called after the // class change... // a way around this is to pass an empty function as callback_b // function createCSSClassToggler(elem, css_class, callback_a, callback_b){ // prepare the pre/post callbacks... if(callback_b == null){ var callback_pre = null var callback_post = callback_a } else { var callback_pre = callback_a var callback_post = callback_b } // build the acual toggler function... var func = function(action){ if(action == null || action == '?'){ var getter = action == '?' ? true : false action = 'on' // get current state... if( $(elem).hasClass(css_class) ){ action = 'off' } if(getter){ // as the above actions indicate intent and not state, // we'll need to swap the values... return action == 'on' ? 'off' : 'on' } } if(callback_pre != null){ callback_pre(action) } // play with the class... if(action == 'on'){ $(elem).addClass(css_class) } else { $(elem).removeClass(css_class) } if(callback_post != null){ callback_post(action) } } func.doc = 'With no arguments this will toggle between "on" and '+ '"off".\n'+ 'If either "on" or "off" are given then this will switch '+ 'to that mode.\n'+ 'If "?" is given, this will return either "on" or "off" '+ 'depending on the current state.' return func } // show a jQuary opject in viewer overlay... // XXX need to set .scrollTop(0) when showing different UI... // ...and not set it when the UI is the same // XXX this must create it's own overlay... function showInOverlay(obj){ obj.click(function(){ return false }) // XXX $('.viewer').addClass('overlay-mode') // clean things up... $('.overlay .content').children().remove() // put it in the overlay... $('.overlay .content').append(obj) // prepare the overlay... $('.overlay') .one('click', function(){ $('.overlay') .fadeOut(function(){ $('.overlay .content') .children() .remove() $('.overlay-mode').removeClass('overlay-mode') }) }) .fadeIn() return obj } function overlayMessage(text){ return showInOverlay($('
' +text+ '
')) } function unanimated(obj, func, time){ return function(){ if(time == null){ time = 5 } obj.addClass('unanimated') var res = func.apply(func, arguments) setTimeout(function(){obj.removeClass('unanimated')}, time) return res } } // Return a scale value for the given element(s). // NOTE: this will only return a single scale value... function getElementScale(elem){ //var transform = elem.css('transform') var vendors = ['o', 'moz', 'ms', 'webkit'] var transform = elem.css('transform') var res // go through vendor prefixes... (hate this!) if(!transform || transform == 'none'){ for(var i in vendors){ transform = elem.css('-' + vendors[i] + '-transform') if(transform && transform != 'none'){ break } } } // no transform is set... if(!transform || transform == 'none'){ return 1 } // get the scale value -- first argument of scale/matrix... return parseFloat((/(scale|matrix)\(([^,]*),.*\)/).exec(transform)[2]) } function setElementScale(elem, scale){ return elem.css({ 'transform': 'scale('+scale+')', '-moz-transform': 'scale('+scale+')', '-o-transform': 'scale('+scale+')', '-ms-transform': 'scale('+scale+')', '-webkit-transform': 'scale('+scale+')', }) } /************************************************* keyboard handler **/ // NOTE: don't understand why am I the one who has to write this... var SPECIAL_KEYS = { 9: 'Tab', 13: 'Enter', 16: 'Shift', 17: 'Ctrl', 18: 'Alt', 20: 'Caps Lock', 27: 'Esc', 32: 'Space', 33: 'PgUp', 34: 'PgDown', 35: 'End', 36: 'Home', 37: 'Right', 38: 'Up', 39: 'Left', 40: 'Down', 45: 'Ins', 46: 'Del', 80: 'Backspace', 91: 'Win', 93: 'Menu', 112: 'F1', 113: 'F2', 114: 'F3', 115: 'F4', 116: 'F5', 117: 'F6', 118: 'F7', 119: 'F8', 120: 'F9', 121: 'F10', 122: 'F11', 123: 'F12', } // XXX some keys look really wrong... function toKeyName(code){ // check for special keys... var k = SPECIAL_KEYS[code] if(k != null){ return k } // chars... k = String.fromCharCode(code) if(k != ''){ return k.toLowerCase() } return null } // if set to false the event handlers will always return false... var KEYBOARD_HANDLER_PROPAGATE = true /* Basic key format: * * : , * * : { * 'default': , * // a modifier can be any single modifier, like shift or a * // combination of modifers like 'ctrl+shift', given in order * // of priority. * // supported modifiers are (in order of priority): * // - ctrl * // - alt * // - shift * : [...] * }, * * : [ * // this can be any type of handler except for an alias... * , * * ], * * // alias... * : , * * XXX might need to add meta information to generate sensible help... */ function makeKeyboardHandler(keybindings, unhandled){ if(unhandled == null){ unhandled = function(){return false} } return function(evt){ var did_handling = false var res = null for(var mode in keybindings){ if($(mode).length > 0){ var bindings = keybindings[mode] var key = evt.keyCode if(bindings.ignore != null && bindings.ignore.indexOf(key) != -1){ // return true res = res == null ? true : res did_handling = true continue } // XXX ugly... var modifers = evt.ctrlKey ? 'ctrl' : '' modifers += evt.altKey ? (modifers != '' ? '+alt' : 'alt') : '' modifers += evt.shiftKey ? (modifers != '' ? '+shift' : 'shift') : '' var handler = bindings[key] // alias... while (typeof(handler) == typeof(123)) { handler = bindings[handler] } // no handler... if(handler == null){ continue } // Array, lisp style with docs... // XXX for some odd reason in chrome typeof([]) == typeof({})!!! if(typeof(handler) == typeof([]) && handler.constructor.name == 'Array'){ // we do not care about docs here, so just get the handler... handler = handler[0] } // complex handler... if(typeof(handler) == typeof({})){ var callback = handler[modifers] if(callback == null){ callback = handler['default'] } if(callback != null){ res = callback() did_handling = true continue } } else { // simple callback... res = handler() did_handling = true continue } } } if(!did_handling){ // key is unhandled by any modes... return unhandled(key) } else { // XXX should we handle multiple hits??? return KEYBOARD_HANDLER_PROPAGATE&&res?true:false } } } /************************************************ jQuery extensions **/ jQuery.fn.reverseChildren = function(){ return $(this).each(function(_, e){ return $(e).append($(e).children().detach().get().reverse()) }) } jQuery.fn.sortChildren = function(func){ return $(this).each(function(_, e){ return $(e).append($(e).children().detach().get().sort(func)) }) } /********************************************************************** * vim:set ts=4 sw=4 : */