diff --git a/ui (gen4)/index.html b/ui (gen4)/index.html index dc0711d5..9038624f 100755 --- a/ui (gen4)/index.html +++ b/ui (gen4)/index.html @@ -178,6 +178,8 @@ typeof(require) != 'undefined' && require('nw.gui').Window.get().showDevTools() + + diff --git a/ui (gen4)/lib/util.js b/ui (gen4)/lib/util.js index 8b78aa51..ed62ea7c 100755 --- a/ui (gen4)/lib/util.js +++ b/ui (gen4)/lib/util.js @@ -156,7 +156,7 @@ Object.keys(_transform_parse).forEach(function(func){ // -> data // // Supported transformations: -// x/y +// x/y/z // scale // scaleX/scaleY // origin @@ -164,10 +164,20 @@ Object.keys(_transform_parse).forEach(function(func){ // // NOTE: pixel values are converted to numbers and back by default... // +// +// XXX this should consist of: +// - transform string parser -> functions format +// - functions format generator *** +// - generate single value functions (scaleX(), translateZ(), ...) +// - optionally merge into multivalue funcs (scale(), translate3d(), ...) +// - transform string generator +// +// XXX BUG: does not work with empty initial state, i.e. without +// transforms set... // XXX this will get/set values only on the first element, is this correct??? // XXX how do we combine translate(..) and translate3d(..)??? jQuery.fn.transform = function(){ - var that = this + var that = $(this) var args = args2array(arguments) // XXX get the browser prefix... @@ -181,8 +191,8 @@ jQuery.fn.transform = function(){ : args var elem = $(this)[0] - var origin_str = elem.style[prefix + 'transformOrigin'] - var transform_str = elem.style[prefix + 'transform'] + var origin_str = elem ? elem.style[prefix + 'transformOrigin'] : '' + var transform_str = elem ? elem.style[prefix + 'transform'] : '' // origin... var origin = origin_str @@ -335,6 +345,11 @@ jQuery.fn.transform = function(){ // set data... // transform -> functions } else { + // empty elem... + if(that.length == 0){ + return that + } + Object.keys(args).forEach(function(arg){ var val = args[arg] @@ -357,25 +372,37 @@ jQuery.fn.transform = function(){ return typeof(a) != typeof('str') ? a + u : a }) } - // got an arg... } else if(arg in attrs){ attrs[arg](val) + + // new arg... + } else if(arg in _transform_parse_func){ + _transform_parse_func[arg] } }) - elem.style.transform = Object.keys(functions) + var t = Object.keys(functions) .map(function(func){ return func +'('+ functions[func].join(', ') + ')' }) .join(' ') - elem.style.transformOrigin = transform['origin'] != '' ? + var o = (transform['origin'] && transform['origin'] != '') ? transform['origin'] .map(function(e){ return typeof(e) == typeof('str') ? e : e + 'px' }).join(' ') : '' + + that.css({ + 'transform-origin': o, + 'transform' : t, + }) + /* + elem.style.transformOrigin = o + elem.style.transform = t + */ } return $(this) @@ -400,6 +427,282 @@ jQuery.fn.origin = function(a, b, c){ } + + +// convert a transform string to an object... +// +// Format: +// { +// : [, ...], +// ... +// } +// +// NOTE: this does not care about the semantics of the format, just the +// general structure... +var transform2obj = function(str){ + var res = {} + // parse the string... + (str || '') + // split functions... + .split(/(\w+\([^\)]*)\)/) + // remove empty strings... + .filter(function(e){ return e.trim().length > 0}) + // split each function... + .map(function(e){ return e + // split args... + .split(/\s*[\(,\s]\s*/) + // cleanup... + .filter(function(e){ return e.trim().length > 0 }) }) + // build the structure... + .forEach(function(data){ + var func = data.shift() + var args = data + + res[func] = data + }) + return res +} + +// Convert the object similar in structure to the produced by +// transform2obj(..) to a transform string... +// +// NOTE: this does not care about the actual semantics of the format, +// e.g. argument units or function names... +var obj2transform = function(obj){ + return Object.keys(obj) + .map(function(func){ + return func +'('+ obj[func].join(', ') + ')' + }) + .join(' ') +} + + +// XXX BUG: passing '' to an alias will clear ALL the aliased functions... +// ...should clear only full matches... +// XXX move the grammar out of this... +// XXX need: +// - a way to minimize this, i.e. get only full and minimal functions... +// - a way to get what was defined as-is... +var transformEditor = function(){ + var editor = { + // data set... + data: {}, + + // function that directly edit the data... + direct: {}, + } + var func = function(name, args){ + args = args || [] + editor.direct[name] = function(val){ + var that = this + // set... + if(val != null && val != ''){ + val = val instanceof Array ? val : [val] + var res = this.data[name] = this.data[name] || [] + // add units and general processing... + val.map(function(arg, i){ + // special case, if an arg is undefined do not change it... + if(arg === undefined){ + return + } + var unit = args[i] || '' + res[i] = typeof(arg) == typeof(123) + || (typeof(arg) == typeof('str') + && /^[0-9\.]+$/.test(arg)) ? + arg + unit + : arg + }) + return res + + // delete... + } else if(val == ''){ + delete this.data[name] + + // get... + } else { + var res = (this.data[name] || []) + // remove default unit... + .map(function(arg, i){ + var unit = args[i] || '' + return arg.slice(-unit.length) == unit + || /^[0-9\.]+$/.test(arg)? + parseFloat(arg) + : arg + }) + return res + } + } + } + + var alias = function(spec){ + // alias runner... + var handler = function(alias, args){ + var that = this + // we only care for the source argument and only it will get + // passed next... + // NOTE: this is the name of the called alias... + var arg = args[spec[alias]] + + return Object.keys(spec).map(function(k){ + var i = spec[k] + + if(args.length == 0){ + return k in that.direct ? + that.direct[k].call(that) + : null + } + + var a = [] + a[i] = arg + + return k in that.direct ? + that.direct[k].call(that, a) + : null + }) + .filter(function(e){ return e != null }) + .slice(-1)[0] + } + + // setup the aliases... + Object.keys(spec).forEach(function(k){ + var i = spec[k] + + var func = i instanceof Function ? i : handler + + // NOTE: we will pass the called alias name to the handler + // via 'this'... + var f = editor[k] + editor[k] = f ? + // wrap the original alias... + function(){ + var args = args2array(arguments) + if(args.length == 0 && k in this.direct){ + return this.direct[k].call(this) + } + + var a = f.apply(this, args) + var b = func.call(this, k, args) + + if(k in this.direct){ + return this.direct[k].call(this) + } + return b + } + : function(){ + var args = args2array(arguments) + return func.call(this, k, args) } + + }) + } + + // XXX get these from grammar... + func('translate', ['px', 'px']) + func('translate3d', ['px', 'px', 'px']) + func('translateX', ['px']) + func('translateY', ['px']) + func('translateZ', ['px']) + alias({ translate3d: 0, translate: 0, translateX: 0, x: 0 }) + alias({ translate3d: 1, translate: 1, translateY: 0, y: 0, }) + alias({ translate3d: 2, translateZ: 0, z: 0, }) + + func('scale') + func('scale3d') + func('scaleX') + func('scaleY') + func('scaleZ') + alias({ scale: 0, scale3d: 0, scaleX: 0, }) + alias({ scale: 1, scale3d: 1, scaleY: 0, }) + alias({ scale3d: 2, scaleZ: 0, }) + // special case: single arg scale: scale(n) -> scale(n, n) + alias({ scale: function(){ + if(arguments.length == 1){ + return this.scale(arguments[0], arguments[0]) + } + return this.direct.scale.apply(this) + } }) + + func('rotate', ['deg']) + func('rotate3d', ['px', 'px', 'px', 'deg']) + func('rotateX', ['deg']) + func('rotateY', ['deg']) + func('rotateZ', ['deg']) + + func('matrix') + func('matrix3d') + + func('skew') + func('skewX') + func('skewY') + alias({skewX: 0, skew: 0}) + alias({skewY: 0, skew: 1}) + + func('perspective') + + // proxy the undefined in aliases functions... + Object.keys(editor.direct).forEach(function(k){ + if(!(k in editor)){ + editor[k] = function(){ return editor.direct[k].apply(this, arguments) } + } + }) + + return editor +} + +// XXX STUB: for testing only... +window.transformEditor = transformEditor + +var transform = function(){ + var that = this + var elem = $(this)[0] + + var args = args2array(arguments) + // normalize... + args = args.length == 0 + || typeof(args[0]) == typeof('str') ? args + : args[0].constructor === Array + || args.length == 1 ? args[0] + : args + + // XXX do vendor tags... + var prefix = '' + + // get the current state... + var transform = transform2obj(elem && elem.style[prefix + 'transform']) + var origin = (elem ? elem.style[prefix + 'transformOrigin'] : '').split(/\s+/) + + /* XXX not critical yet... + var style = this.style.transformStyle + var prespective = this.style.prespective + var prespectiveOrigin = this.style.prespectiveOrigin + var backfaceVisibility = this.style.backfaceVisibility + */ + + // XXX populate transformEditor with current state... + // XXX + + // get state... + if(args.constructor === Array){ + // XXX minimize transformEditor and return + // XXX + + // XXX + return + + // set state... + } else { + // XXX add user inputs... + // XXX + + // XXX minimize transformEditor and set... + // XXX + } + + return $(this) +} + + + + /********************************************************************** * vim:set ts=4 sw=4 : */ return module }) diff --git a/ui (gen4)/ribbons.js b/ui (gen4)/ribbons.js index b805ea40..1be738ab 100755 --- a/ui (gen4)/ribbons.js +++ b/ui (gen4)/ribbons.js @@ -59,6 +59,33 @@ var RIBBON = '.ribbon:not(.clone)' // // NOTE: there can be only one .ribbon-set element. // +// +// XXX need to replace soemlegacy CSS API and make this compatible with +// modern libs like velocity.js... +// - jli.getElementOrigin(..) +// .transform('origin') +// +// - jli.getElementScale(..) +// .transform('scale') +// +// - jli.getRelativeOffset(..) +// XXX offset if x from y... +// +// - jli.setElementOffset(..) +// .transform({x: , y: , z: 0}) +// .velocity({translateX: , translateY: , translateZ: 0}) +// +// - jli.setElementScale(..) +// .transform({scale, }) +// .velocity({scale, }) +// +// - jli.shiftOriginTo(..) +// XXX this sets origin and compensates for offsets... +// +// XXX think if a way to manage animation timings... +// +// +// /*********************************************************************/ var RibbonsClassPrototype = {