From: riccardo Date: Thu, 16 Jun 2011 15:52:02 +0000 (+0200) Subject: chenged timeside code with config functionalities easier to change (expecially regard... X-Git-Tag: 1.1~102 X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=2597e9f40e78b2cf654d6bb6f8c5602093121e1b;p=telemeta.git chenged timeside code with config functionalities easier to change (expecially regarding vml) and vml check in order to load raphael and build vml method if not needed --- diff --git a/telemeta/htdocs/timeside/js/markermap.js b/telemeta/htdocs/timeside/js/markermap.js index 99fb3b28..b42bf3c8 100644 --- a/telemeta/htdocs/timeside/js/markermap.js +++ b/telemeta/htdocs/timeside/js/markermap.js @@ -44,7 +44,7 @@ Timeside.classes.MarkerMap = Timeside.classes.TimesideArray.extend({ newMarker.offset = this.pFloat(newMarker.offset); } if(!('id' in newMarker)){ - newMarker.id = Timeside.utils.uniqid(); + newMarker.id = this.$TU.uniqid(); //Timeside.utils.uniqid(); } if(!('isEditable' in newMarker)){ newMarker.isEditable = false; @@ -220,8 +220,10 @@ Timeside.classes.MarkerMap = Timeside.classes.TimesideArray.extend({ while (low <= high) { var mid = (low + high) >>> 1; - //biwise operation equivalent to (but faster than): + //biwise operation is not as fast as in compiled languages such as C and java (see Jslint web page) + //However (tested on a PC in Chrome, IE and FF), it is faster than the equivalent: //var mid = parseInt((low + high)/2); + //even if we reference parseInt before this loop and we call the variable assigned to it var midVal = data[mid]; var cmp = comparatorFunction(midVal,object); if (cmp < 0){ diff --git a/telemeta/htdocs/timeside/js/ruler.js b/telemeta/htdocs/timeside/js/ruler.js index 585c579e..36f1bb24 100644 --- a/telemeta/htdocs/timeside/js/ruler.js +++ b/telemeta/htdocs/timeside/js/ruler.js @@ -166,11 +166,13 @@ Timeside.classes.Ruler = Timeside.classes.TimesideArray.extend({ var upperRectClass = cssPref + 'svg-' + 'ruler-upper-rect'; var rulerLinesClass = cssPref + 'svg-' + 'ruler-lines'; - if(!this.isSvgSupported){ + var vml = this.$TU.vml; + if(vml){ + //we create each time a new Raphael object. This is not a big performance issue var paper = Raphael(rulerContainer[0], rulerContainer.width(), h); var rect = paper.rect(0,0, rulerContainer.width(), h/2); var path = paper.path(rulerLinesPath); - var attr = this.getVmlAttr; + var attr = vml.getVmlAttr; rect.attr(attr(upperRectClass)); path.attr(attr(rulerLinesClass)); return; diff --git a/telemeta/htdocs/timeside/js/rulermarker.js b/telemeta/htdocs/timeside/js/rulermarker.js index 35c6d816..3cf886d8 100644 --- a/telemeta/htdocs/timeside/js/rulermarker.js +++ b/telemeta/htdocs/timeside/js/rulermarker.js @@ -92,7 +92,8 @@ Timeside.classes.RulerMarker = Timeside.classes.TimesideClass.extend({ var canvas = undefined; var canvasClass = cssPref + 'svg-'+className+'-line'; - if(this.isSvgSupported){ + var vml = this.$TU.vml; //if vml, this class is populated with methods and NOT undefined + if(!vml){ canvas = this.createCanvasSvg(waveImgDiv, arrowBaselineWidth); var path = canvas.childNodes[0]; //note that $J(canvas).find('path') does not work in FF at least 3.5 path.setAttributeNS(null,'class',canvasClass); @@ -103,11 +104,12 @@ Timeside.classes.RulerMarker = Timeside.classes.TimesideClass.extend({ }else{ canvas = this.createCanvasVml(waveImgDiv, arrowBaselineWidth); this.jQueryCanvas = $J(canvas.node); - var attributes = ruler.classToRaphaelAttr[canvasClass]; - if(!attributes){ - attributes = ruler.getVmlAttr(canvasClass); - ruler.classToRaphaelAttr[canvasClass] = attributes; - } + var attributes = vml.getVmlAttr(canvasClass); +// var attributes = ruler.classToRaphaelAttr[canvasClass]; +// if(!attributes){ +// attributes = ruler.getVmlAttr(canvasClass); +// ruler.classToRaphaelAttr[canvasClass] = attributes; +// } canvas.attr(attributes); //Raphael method this.moveCanvas = function(pixelOffset){ //for some reason, coordinates inside the VML object are stored by raphael with a zoom of 10: @@ -224,37 +226,43 @@ Timeside.classes.RulerMarker = Timeside.classes.TimesideClass.extend({ }, createCanvasVml: function(container, arrowBaseWidth){ - //for creating a vml object, we make use of raphael to avoid a pain in the ... implementing a non standard Microsoft syntax - //(which, after a glance, it's even syntactically a mess) - //unfotunately (and this is a real lack not even planned to be fixed, see raphael forums), - //raphael does not allow to wrap existing object, so we have to register in this.elementToPaperMap (see timeside.js) - //which is a map where to each container is associated a raphael paper: - var paper = this.elementToPaperMap && this.elementToPaperMap[container.get(0)]; - if(!paper){ - var obj = this.elementToPaperMap; - if(!obj){ - this.elementToPaperMap = {}; - obj = this.elementToPaperMap; - } - paper = Raphael(container.get(0),container.width(),container.height()); - obj[container.get(0)] = paper; - //paper canvas is a div with weird dimensions. You can check it by printing paper.canvas.outerHTML in IE. - //We set them to 100% so we dont have clipping regions when resizing (maximizing) - paper.canvas.style.width='100%'; - paper.canvas.style.height='100%'; - paper.canvas.width='100%'; - paper.canvas.height='100%'; - //apparently, there is also a clip style declaration made by raphael. The following code trhows an error in IE7: - //paper.canvas.style.clip = 'auto'; - //however, even leaving the clip style declaration as it is, it seems to work (the div spans the whole width) - } - - + var vml = this.$TU.vml; + var paper = vml.Raphael(container.get(0),container.width(),container.height()); var shape = paper.path(this.createCanvasPath(0, arrowBaseWidth)); return shape; }, +// createCanvasVml: function(container, arrowBaseWidth){ +// //for creating a vml object, we make use of raphael to avoid a pain in the ... implementing a non standard Microsoft syntax +// //(which, after a glance, it's even syntactically a mess) +// //unfotunately (and this is a real lack not even planned to be fixed, see raphael forums), +// //raphael does not allow to wrap existing object, so we have to register in this.elementToPaperMap (see timeside.js) +// //which is a map where to each container is associated a raphael paper: +// var paper = this.elementToPaperMap && this.elementToPaperMap[container.get(0)]; +// if(!paper){ +// var obj = this.elementToPaperMap; +// if(!obj){ +// this.elementToPaperMap = {}; +// obj = this.elementToPaperMap; +// } +// paper = Raphael(container.get(0),container.width(),container.height()); +// obj[container.get(0)] = paper; +// //paper canvas is a div with weird dimensions. You can check it by printing paper.canvas.outerHTML in IE. +// //We set them to 100% so we dont have clipping regions when resizing (maximizing) +// paper.canvas.style.width='100%'; +// paper.canvas.style.height='100%'; +// paper.canvas.width='100%'; +// paper.canvas.height='100%'; +// //apparently, there is also a clip style declaration made by raphael. The following code trhows an error in IE7: +// //paper.canvas.style.clip = 'auto'; +// //however, even leaving the clip style declaration as it is, it seems to work (the div spans the whole width) +// } +// +// +// var shape = paper.path(this.createCanvasPath(0, arrowBaseWidth)); +// return shape; +// }, - //w must be odd. Cause le central line must be centered. Example: + //w must be odd. Cause the central line must be centered. Example: // // xxxxx // xxx diff --git a/telemeta/htdocs/timeside/js/timeside.js b/telemeta/htdocs/timeside/js/timeside.js index aeb262d3..0df4ac02 100644 --- a/telemeta/htdocs/timeside/js/timeside.js +++ b/telemeta/htdocs/timeside/js/timeside.js @@ -23,25 +23,54 @@ */ /** - * Base class defining classes for TimesideUI + * Root javascript file for TimesideUI, to be manually included in your web page (see online doc) */ /** - *global variable housing all Timeside variable/classes: + *global variable housing all Timeside variables/mathods/classes: */ var Timeside = { Class:undefined, classes:{}, player:undefined, + config: { + /* + * timeside scripts to be loaded when Timeside.load is called. URL paths are relative to the timeside folder, which + * will be determined according to the src attribute of the timeside.js script path (to be included in the of the page) + */ + timesideScripts: ['rulermarker.js','markermap.js', 'player.js', 'ruler.js'], + //vml config variables. Used only if svg is NOT supported + vml : { + /* + * raphael script to be loaded when Timeside.load is called and svg is not supported. It will be prepended to the + * timesideScripts array defined above in config. URL paths are relative to the timeside folder, which + * will be determined according to the src attribute of the timeside.js script path (to be included in the of the page) + */ + raphaelScript : 'libs/raphael-min.js', + /* + * available attributes which can be converted from css-svg to Raphael attributes (see Raphael.js): + */ + raphaelAttributes : ["clip-rect", "cursor",'fill', "fill-opacity",'opacity', 'stroke', "stroke-dasharray", "stroke-linecap", "stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width", "text-anchor"] + } + }, utils:{ - /** - * Returns an uniqid by creating the current local time in millisecond + a random number. Used for markers and some json calls + * Returns an uniqid by creating the current local time in millisecond + a random number. + * Used for markers in markermap. The method is kind of public in order to be more accessible for other functions + * by calling Timeside.utils.uniqid(), in case it is needed */ uniqid : function() { var d = new Date(); return new String(d.getTime() + '' + Math.floor(Math.random() * 1000000)).substr(0, 18); - } + }, + /** + * vml object which will be populated by vml functions to interface timeside and raphael. See timeside.load. + * We could implement functions here for code readability, however, + * we delegate Timeside.load so that if svg is supported memory is free from unused vml methods. + * IN ANY CASE, svg support can be detected anywhere by calling, eg: + * var svg = !Timeside.utils.vml; + */ + vml: undefined } }; @@ -182,9 +211,7 @@ var Timeside = { }; })(Timeside); -//not really ortodox: we should create the function Class inside Timeside (above) -//Timeside.Class = Class; -//delete Class; + //Defining the base TimeClass class. Timeside.classes.[Player, Ruler, MarkerMap...] are typical implementations (see js files) //Basically we store here static methods which must be accessible in several timside sub-classes @@ -199,7 +226,8 @@ Timeside.classes.TimesideClass = Timeside.Class.extend({ }, cssPrefix : 'ts-', //actually almost uneuseful, still here for backward compatibility with old code (TODO: remove?) - $J : jQuery, + $J : jQuery, //reference to jQuery for faster lookup inside methods + $TU : Timeside.utils, //reference to Timeside variable for faster lookup inside methods debugging : false, debug : function(message) { if (this.debugging && typeof console != 'undefined' && console.log) { @@ -208,19 +236,19 @@ Timeside.classes.TimesideClass = Timeside.Class.extend({ }, /** - * 3 methods defining listeners, events fire and bind (aloing the lines of jQuery.bind, unbind and trigger): + * 3 methods defining listeners, events fire and bind (aloing the lines of jQuery.bind, unbind and trigger. The latter is 'fire' here): */ - bind : function(key, callback, optionalThisArgInCallback){ - if(!(callback && callback instanceof Function)){ - this.debug('cannot bind '+key+' to callback: the latter is null or not a function'); + bind : function(eventType, callback, optionalThisArgInCallback){ + if(!callback || typeof callback !== 'function'){ + this.debug('cannot bind '+eventType+' to callback: the latter is null or not a function'); return; } var listenersMap = this.listenersMap; - var keyAlreadyRegistered = (key in listenersMap); + var keyAlreadyRegistered = (listenersMap.hasOwnProperty(eventType)); if(!keyAlreadyRegistered){ - listenersMap[key] = []; + listenersMap[eventType] = []; } - listenersMap[key].push({ + listenersMap[eventType].push({ callback:callback, optionalThisArgInCallback:optionalThisArgInCallback }); @@ -229,18 +257,20 @@ Timeside.classes.TimesideClass = Timeside.Class.extend({ var listenersMap = this.listenersMap; if(arguments.length>0){ var key = arguments[0]; - if(key in listenersMap){ + if(listenersMap.hasOwnProperty(key)){ delete listenersMap[key]; } }else{ for(key in listenersMap){ - delete listenersMap[key]; + if(listenersMap.hasOwnProperty(key)){ + delete listenersMap[key]; + } } } }, fire : function(key, dataArgument){ var listenersMap = this.listenersMap; - if(!(key in listenersMap)){ + if(!(listenersMap.hasOwnProperty(key))){ //this.debug('"'+key+'" fired but no binding associated to it'); return; } @@ -251,20 +281,13 @@ Timeside.classes.TimesideClass = Timeside.Class.extend({ var len = callbacks && callbacks.length ? callbacks.length : 0; for(var i=0; i Raphael paper object - * This property can be deleted if svg is supported - */ - elementToPaperMap: {}, - - //use this function only IF isVmlSupported = true. Converts a class name declared in a stylesheet to - //the equivalent Raphael attr argument. This function has been tested only under IE - getVmlAttr: function(className){ - var d = document; - className = className.replace(/^\.*/,'.'); //add a dot if not present - var ssheets = d.styleSheets; - var len = ssheets.length-1; - //available attributes which can be converted from css svg to Raphael attributes (see Raphael.js): - var availableAttrs = ["clip-rect", "cursor",'fill', "fill-opacity",'opacity', 'stroke', "stroke-dasharray", "stroke-linecap", "stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width", "text-anchor"]; - - //var availableAttrs = ['fill','stroke','stroke-width','fill-opacity','stroke-opacity']; - var attr = {}; - for(var i=0; i255 ? 255 :c)); -// c = c.toString(16); -// var len = c.length; -// switch(len){ -// case 1: -// c = '0'+c; -// break; -// case 2: -// break; -// default: -// return ''; -// } -// channels[j] = c; -// } -// return '#'+channels.join(''); -// } -// } -// } -// return ''; -// } -// + } }); /** @@ -774,135 +501,32 @@ Timeside.classes.TimesideArray = Timeside.classes.TimesideClass.extend({ return to; } - //moves the element from position [from] to position [to]. Shifts all elements - //from position [to] (inclusive) of one position. Note that the elemnt at position from is first removed - //and then inserted at position to. Therefore, - //if to==from+1 the element is not moved. Returns from if the element - //is not moved, i.e. either in the case above, or when: - //1) from or to are not integers or from or to are lower than zero or greater than the array length. - //in any other case, returns the index of the element moved, which is not necessarily to: - //It is, if tofrom+1) is to-1 -// move : function(from, to){ -// -// var pInt = parseInt; -// if(pInt(from)!==from || pInt(to)!==to){ -// return from; -// } -// var me =this.toArray(); -// var len = me.length; -// if((from<0 || from>len)||(to<0 || to>len)){ -// return from; -// } -// //if we moved left to right, the insertion index is actually -// //newIndex-1, as we must also consider the removal of the object at index from -// if(to>from){ -// to--; -// } -// if(from != to){ -// var elm = me.splice(from,1)[0]; -// me.splice(to,0,elm); -// } -// return to; -// } }); -/** -* Loads scripts asynchronously -* can take up to four arguments: -* root (optional): a string specifying the root (such as '/usr/local/'). Must end with slash, otherwise -* each element in scriptArray must begin with a slash -* scriptArray: a string array of js script filenames, such as ['script1.js','script2.js'] -* callback (optional): callback to be executed when ALL scripts are succesfully loaded -* loadInSeries (optional): if true scripts are loaded in synchronously, ie each script is loaded only once the -* previous has been loaded. The default (argument missing) is false -* -* Examples. Given scripts = ['s1.js', 's2.js'] -* loadScripts(scripts) //loads (asynchronously) scripts -* loadScripts('/usr/', scripts) //loads (asynchronously) ['/usr/s1.js', '/usr/s2.js'] -* loadScripts(scripts, callback) //loads (asynchronously) scripts. When loaded, executes callback -* loadScripts('/usr/', scripts, callback) //loads (asynchronously) ['/usr/s1.js', '/usr/s2.js']. When loaded, executes callback -* loadScripts(scripts, callback, true) //loads (synchronously) scripts. When loaded, executes callback -* loadScripts('/usr/', scripts, callback, true) //loads (synchronously) ['/usr/s1.js', '/usr/s2.js']. When loaded, executes callback -* -*/ -Timeside.loadScripts = function(){ - var optionalRoot='', scriptArray=[], callback=undefined, loadInSeries=false; - var len = arguments.length; - if(len==1){ - scriptArray = arguments[0]; - }else if(len==2){ - if(typeof arguments[0] == 'string'){ - optionalRoot = arguments[0]; - scriptArray = arguments[1]; - }else{ - scriptArray = arguments[0]; - callback = arguments[1]; - } - }else if(len>2){ - if(typeof arguments[0] == 'string'){ - optionalRoot = arguments[0]; - scriptArray = arguments[1]; - callback = arguments[2]; - if(len>3){ - loadInSeries = arguments[3]; - } - }else{ - scriptArray = arguments[0]; - callback = arguments[1]; - loadInSeries = arguments[2]; - } - } - - if(!scriptArray){ - if(callback){ - callback(); - } - return; - } - len = scriptArray.length; - var i=0; - if(optionalRoot){ - optionalRoot = optionalRoot.replace(/\/*$/,"/"); //add slash at end if not present - for(i =0; i paper + var raphael_papers = {}; + //get the raphael attributes for which a conversion css -> raphael_attribute is possible: + var availableAttrs = ts.config.vml.raphaelAttributes; + ts.utils.vml = { + getVmlAttr: function(className){ + // if(className in classToRaphaelAttr){ + // consolelog('getVmlAttr: '+className+' exists'); + // }else{ + // consolelog('getVmlAttr: '+className+' to be created'); + // } + if(classToRaphaelAttr.hasOwnProperty(className)){ + //if(className in classToRaphaelAttr){ + return classToRaphaelAttr[className]; + } + var d = document; + var dottedclassName = className.replace(/^\.*/,'.'); //add a dot if not present + var ssheets = d.styleSheets; + var len = ssheets.length-1; + + var attr = {}; + for(var i=0; i -