]> git.parisson.com Git - telemeta.git/commitdiff
chenged timeside code with config functionalities easier to change (expecially regard...
authorriccardo <riccardo@parisson.com>
Thu, 16 Jun 2011 15:52:02 +0000 (17:52 +0200)
committerriccardo <riccardo@parisson.com>
Thu, 16 Jun 2011 15:52:02 +0000 (17:52 +0200)
telemeta/htdocs/timeside/js/markermap.js
telemeta/htdocs/timeside/js/ruler.js
telemeta/htdocs/timeside/js/rulermarker.js
telemeta/htdocs/timeside/js/timeside.js
telemeta/templates/telemeta_default/mediaitem_detail.html

index 99fb3b2811fda8acd0685134ad6a90aef28ec62e..b42bf3c83b0cb945812492baaab8c3364b891eb9 100644 (file)
@@ -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){
index 585c579e9471cd023d08e7951a108825074e4851..36f1bb24351818817f6dc51212c38e562c552d4d 100644 (file)
@@ -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;
index 35c6d8163a9038b9de24116a27e516e18b67b935..3cf886d8edf7a10083cdb90857357fba6df72f04 100644 (file)
@@ -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
index aeb262d3e306c387d828307364045018758ad007..0df4ac02eabfdabc82fa9efbb5026739bd19ff35 100644 (file)
  */
 
 /**
- * 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 <head> 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 <head> 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<len; i++){
             var obj = callbacks[i];
-            if('optionalThisArgInCallback' in obj){
+            if(obj.hasOwnProperty('optionalThisArgInCallback')){
                 obj.callback.apply(obj.optionalThisArgInCallback, [dataArgument]);
             }else{
                 obj.callback(dataArgument);
             }
         }
     },
-    /**
-     * function to calculate the text width according to a text and a given fontsize
-     */
-    textWidth : function(text, fontSize) {
-        var ratio = 3/5;
-        return text.length * ratio * fontSize;
-    },
     
     /*
      *formats (ie returns a string representation of) a time which is in the form seconds,milliseconds (eg 07.6750067)
@@ -348,303 +371,7 @@ Timeside.classes.TimesideClass = Timeside.Class.extend({
             }
         }
         return ret.join("");
-    },
-
-    
-    //vml (+css specific functions): Used in ruler.js and RulerMarker.js:
-
-    /**
-     * Returns whether SVG is supported. If it is the case, this property can simply return true.
-     * If full svg support will be a standard (hopefully...), for a a more clean code, one should remove all remaining
-     * properties/functions,
-     * check where we call isSvgSupported (currently, ruler.js and rulermarker.js) and eventually
-     * remove the vml methods, which should always be separated from the already implemented svg methods
-     */
-    isSvgSupported : Raphael.svg, //note that Raphael MUST be loaded!! (put it in the header scripts before Timeside)
-    /**
-     * Raphael unfortunately does not allow to wrap existing elements, which is a big lack not even planned to be implemented in
-     * future releases (see raphael forum). Therefore, we store here a map which binds html elements -> 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; i<len; i++){
-            var rules = ssheets[i].rules;
-            var l = rules.length;
-            for(var j=0; j <l; j++){
-                var rule = rules[j];
-//                if(i==2){
-//                    consolelog(rule.selectorText);
-//                }
-                if(rule.selectorText == className){
-                    
-                    var style = rule.style;
-                    for(var k =0; k<availableAttrs.length; k++){
-                        var val = style[availableAttrs[k]];
-                        if(val){
-                            attr[availableAttrs[k]] = val;
-                        //console.log(val); //REMOVE THIS
-                        }
-                    }
-                }
-            }
-        }
-        return attr;
-    },
-    //map to store each class name to the relative dictionary for raphael attr function (VML only)
-    classToRaphaelAttr : {} //,
-
-    //css specific functions:
-    //get computed style first (cross browser solution, from http://blog.stchur.com/2006/06/21/css-computed-style/
-    //not used anymnore, we keep it here because it can be useful
-//    getComputedStyle : function(_elem, _style){
-//        var computedStyle;
-//        var $J = this.$J;
-//        if(_elem instanceof $J){ //note: '_elem instanceof this.$J' doesnt work. why??
-//            _elem = _elem.get(0);
-//        }
-//        if (typeof _elem.currentStyle != 'undefined'){
-//            computedStyle = _elem.currentStyle;
-//        }else{
-//            computedStyle = document.defaultView.getComputedStyle(_elem, null);
-//        }
-//        return computedStyle[_style];
-//    },
-//    //returns a hex color from strColor. strColor can be one of the predefined css colors (eg, 'aliceBlue', case insensitive)
-//    //or rgb (eg: rgb(12,0,45)) or an hex color (eg, '#ff98a3' or '#f8g'). Leading and trailing spaces will be omitted,
-//    //case is insensitive, an empty string is returned in case of error (bad format string, parseInt errors etcetera..)
-//    color : function(strColor){
-//        if(!strColor){
-//            return '';
-//        }
-//        strColor = strColor.replace(/(^\s+|\s+$)/g,'').toLowerCase();
-//        if(!strColor){
-//            return '';
-//        }
-//        var predefined_colors = {
-//            aliceblue:"#f0f8ff",
-//            antiquewhite:"#faebd7",
-//            aqua:"#00ffff",
-//            aquamarine:"#7fffd4",
-//            azure:"#f0ffff",
-//            beige:"#f5f5dc",
-//            bisque:"#ffe4c4",
-//            black:"#000000",
-//            blanchedalmond:"#ffebcd",
-//            blue:"#0000ff",
-//            blueviolet:"#8a2be2",
-//            brown:"#a52a2a",
-//            burlywood:"#deb887",
-//            cadetblue:"#5f9ea0",
-//            chartreuse:"#7fff00",
-//            chocolate:"#d2691e",
-//            coral:"#ff7f50",
-//            cornflowerblue:"#6495ed",
-//            cornsilk:"#fff8dc",
-//            crimson:"#dc143c",
-//            cyan:"#00ffff",
-//            darkblue:"#00008b",
-//            darkcyan:"#008b8b",
-//            darkgoldenrod:"#b8860b",
-//            darkgray:"#a9a9a9",
-//            darkgrey:"#a9a9a9",
-//            darkgreen:"#006400",
-//            darkkhaki:"#bdb76b",
-//            darkmagenta:"#8b008b",
-//            darkolivegreen:"#556b2f",
-//            darkorange:"#ff8c00",
-//            darkorchid:"#9932cc",
-//            darkred:"#8b0000",
-//            darksalmon:"#e9967a",
-//            darkseagreen:"#8fbc8f",
-//            darkslateblue:"#483d8b",
-//            darkslategray:"#2f4f4f",
-//            darkslategrey:"#2f4f4f",
-//            darkturquoise:"#00ced1",
-//            darkviolet:"#9400d3",
-//            deeppink:"#ff1493",
-//            deepskyblue:"#00bfff",
-//            dimgray:"#696969",
-//            dimgrey:"#696969",
-//            dodgerblue:"#1e90ff",
-//            firebrick:"#b22222",
-//            floralwhite:"#fffaf0",
-//            forestgreen:"#228b22",
-//            fuchsia:"#ff00ff",
-//            gainsboro:"#dcdcdc",
-//            ghostwhite:"#f8f8ff",
-//            gold:"#ffd700",
-//            goldenrod:"#daa520",
-//            gray:"#808080",
-//            grey:"#808080",
-//            green:"#008000",
-//            greenyellow:"#adff2f",
-//            honeydew:"#f0fff0",
-//            hotpink:"#ff69b4",
-//            indianred:"#cd5c5c",
-//            indigo:"#4b0082",
-//            ivory:"#fffff0",
-//            khaki:"#f0e68c",
-//            lavender:"#e6e6fa",
-//            lavenderblush:"#fff0f5",
-//            lawngreen:"#7cfc00",
-//            lemonchiffon:"#fffacd",
-//            lightblue:"#add8e6",
-//            lightcoral:"#f08080",
-//            lightcyan:"#e0ffff",
-//            lightgoldenrodyellow:"#fafad2",
-//            lightgray:"#d3d3d3",
-//            lightgrey:"#d3d3d3",
-//            lightgreen:"#90ee90",
-//            lightpink:"#ffb6c1",
-//            lightsalmon:"#ffa07a",
-//            lightseagreen:"#20b2aa",
-//            lightskyblue:"#87cefa",
-//            lightslategray:"#778899",
-//            lightslategrey:"#778899",
-//            lightsteelblue:"#b0c4de",
-//            lightyellow:"#ffffe0",
-//            lime:"#00ff00",
-//            limegreen:"#32cd32",
-//            linen:"#faf0e6",
-//            magenta:"#ff00ff",
-//            maroon:"#800000",
-//            mediumaquamarine:"#66cdaa",
-//            mediumblue:"#0000cd",
-//            mediumorchid:"#ba55d3",
-//            mediumpurple:"#9370d8",
-//            mediumseagreen:"#3cb371",
-//            mediumslateblue:"#7b68ee",
-//            mediumspringgreen:"#00fa9a",
-//            mediumturquoise:"#48d1cc",
-//            mediumvioletred:"#c71585",
-//            midnightblue:"#191970",
-//            mintcream:"#f5fffa",
-//            mistyrose:"#ffe4e1",
-//            moccasin:"#ffe4b5",
-//            navajowhite:"#ffdead",
-//            navy:"#000080",
-//            oldlace:"#fdf5e6",
-//            olive:"#808000",
-//            olivedrab:"#6b8e23",
-//            orange:"#ffa500",
-//            orangered:"#ff4500",
-//            orchid:"#da70d6",
-//            palegoldenrod:"#eee8aa",
-//            palegreen:"#98fb98",
-//            paleturquoise:"#afeeee",
-//            palevioletred:"#d87093",
-//            papayawhip:"#ffefd5",
-//            peachpuff:"#ffdab9",
-//            peru:"#cd853f",
-//            pink:"#ffc0cb",
-//            plum:"#dda0dd",
-//            powderblue:"#b0e0e6",
-//            purple:"#800080",
-//            red:"#ff0000",
-//            rosybrown:"#bc8f8f",
-//            royalblue:"#4169e1",
-//            saddlebrown:"#8b4513",
-//            salmon:"#fa8072",
-//            sandybrown:"#f4a460",
-//            seagreen:"#2e8b57",
-//            seashell:"#fff5ee",
-//            sienna:"#a0522d",
-//            silver:"#c0c0c0",
-//            skyblue:"#87ceeb",
-//            slateblue:"#6a5acd",
-//            slategray:"#708090",
-//            slategrey:"#708090",
-//            snow:"#fffafa",
-//            springgreen:"#00ff7f",
-//            steelblue:"#4682b4",
-//            tan:"#d2b48c",
-//            teal:"#008080",
-//            thistle:"#d8bfd8",
-//            tomato:"#ff6347",
-//            turquoise:"#40e0d0",
-//            violet:"#ee82ee",
-//            wheat:"#f5deb3",
-//            white:"#ffffff",
-//            whitesmoke:"#f5f5f5",
-//            yellow:"#ffff00",
-//            yellowgreen:"#9acd32"
-//        };
-//        var cl = predefined_colors[strColor];
-//        if(cl){
-//            return cl;
-//        }
-//        var pint = parseInt;
-//        //color parsers: note that the order is not random: we put first the most likely case ('#aaaaaa') and at last
-//        //the less one ('rgb(...)'), this might increase performances in most cases, especially if this method is called from
-//        //within a loop
-//        var color_defs = [
-//        {
-//            re: /^#*(\w{2})(\w{2})(\w{2})$/, //example: ['#00ff00', '336699'],
-//            process: function (bits){
-//                return [pint(bits[1], 16),pint(bits[2], 16),pint(bits[3], 16)];
-//            }
-//        },
-//
-//        {
-//            re: /^#*(\w{1})(\w{1})(\w{1})$/, //example: ['#fb0', 'f0f'],
-//            process: function (bits){
-//                return [pint(bits[1] + bits[1], 16),pint(bits[2] + bits[2], 16),pint(bits[3] + bits[3], 16)];
-//            }
-//        },
-//        {
-//            re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/, //example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
-//            process: function (bits){
-//                return [pint(bits[1]), pint(bits[2]),pint(bits[3])];
-//            }
-//        }
-//
-//        ];
-//
-//        // search through the definitions to find a match
-//        var nan = isNaN;
-//        for (var i = 0; i < color_defs.length; i++) {
-//            var re = color_defs[i].re;
-//            var processor = color_defs[i].process;
-//            var bits = re.exec(strColor);
-//            if (bits) {
-//                var channels = processor(bits);
-//                if(channels.length ==3){
-//                    for(var j=0; j<3; j++){
-//                        var c = channels[j];
-//                        c = (nan(c) || c< 0 ? 0 : (c>255 ? 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 to<from, otherwise (to>from+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<len; i++){
-            scriptArray[i] = optionalRoot+scriptArray[i];
-        }
-    }
-
-    var $J = jQuery;
-
-    if(loadInSeries){
-        var load = function(index){
-            if(index<len){
-                $J.getScript(scriptArray[index],function(){
-                    load(index+1);
-                });
-            }else if(callback){
-                callback();
-            }
-        };
-        load(0);
-    }else{
-        var count=0;
-        var s;
-        for(i=0; i <len; i++){
-            s = scriptArray[i];
-            $J.getScript(s, function(){
-                count++;
-                if(count==len && callback){
-                    callback();
-                }
-            });
-        }
-    }
-}
 
+/**
+ *Main Timeside method to load player (see Timeside online doc)
+ */
 
 Timeside.load =function(container, soundUrl, durationInMsec, soundImgFcn, soundImgSize, markersArray, newMarkerCallback, onError, onReady){
 
     var $J = jQuery;
+    var win = window;
+    var doc = document;
     var playerDiv = container;
-    onError = onError && typeof onError === 'function' ? onError : function(msg){};
+    onError = onError && typeof onError === 'function' ? onError : function(msg){
+        //if no error callback is defined, we want however warn onError.
+        // Define a cross-browser window.console.log method.
+        // For IE and FF without Firebug, fallback to using an alert.
+        var console = win.console;
+        var log = console && console.error ? console.error : (console && console.log ? console.log : undefined);
+        if (!log) {
+            log = win.opera ? win.opera.postError : alert;
+        }
+        log(msg);
+    };
+    //onREady, if not defined, we set it as an empty function
     onReady = onReady && typeof onReady === 'function' ? onReady : function(player){};
     
     playerDiv = container instanceof $J ? container : $J(container);
@@ -929,7 +553,7 @@ Timeside.load =function(container, soundUrl, durationInMsec, soundImgFcn, soundI
     }
   
 
-    $J(window).ready(function(){
+    $J(win).ready(function(){
         //if soundmanager is ready, the callback is executed immetiately
         //onready is executed BEFORE onload, it basically queues several onload events.
         //It it is executed immetiately if soundmanager has already been loaded
@@ -956,15 +580,190 @@ Timeside.load =function(container, soundUrl, durationInMsec, soundImgFcn, soundI
                     }
                 }
             });
-            
-            Timeside.loadScripts(thisScriptPath,['rulermarker.js','markermap.js', 'player.js', 'ruler.js'], function() {
-                var p = new Timeside.classes.Player(playerDiv, sound, durationInMsec, soundImgFcn, soundImgSize,
-                markersArray,newMarkerCallback);
+
+            var ts = Timeside;
+            var ts_scripts = ts.config.timesideScripts;
+            //detect SVG support and load Raphael in case. Copied from Raphael code v 1.5.2:
+            var svg = (win.SVGAngle || doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
+            if(!svg){
+                //add the raphael path
+                ts_scripts.splice(0,0,ts.config.vml.raphaelScript);
+                //populate the vml object with methods to be used in ruler and rulermarker:
+
+                //global private variable:
+                //map to store each class name to the relative dictionary for raphael attr function (VML only)
+                var classToRaphaelAttr = {};
+                //here below we store  Raphael paper objects. var paper = Raphael(htmlElement) is the raphel method to build
+                //a new paper object. Internally, the method builds a div embedding vmls inside htmlElement
+                //However, calling again var paper = Raphael(htmlElement) does not use the already created paper,
+                //but creates a new object (and accordingly, a new div embedding vmls). Too bad. This features is not even
+                //planned according to raphael developers (see raphael forums). In case of markers lines, we want to draw a new marker
+                //on the same raphael paper. Therefore, we store here raphael papers in a map htmlElement -> 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<len; i++){
+                            var rules = ssheets[i].rules;
+                            var l = rules.length;
+                            for(var j=0; j <l; j++){
+                                var rule = rules[j];
+                                //                if(i==2){
+                                //                    consolelog(rule.selectorText);
+                                //                }
+                                if(rule.selectorText === dottedclassName){
+
+                                    var style = rule.style;
+                                    for(var k =0; k<availableAttrs.length; k++){
+                                        var val = style[availableAttrs[k]];
+                                        if(val){
+                                            attr[availableAttrs[k]] = val;
+                                        //console.log(val); //REMOVE THIS
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        classToRaphaelAttr[className] = attr;
+                        return attr;
+                    },
+
+                    Raphael: function(element,w,h){
+                        //var element = arguments[0]; //the first argument is the html element (NOT jQuery element!!!
+
+                        //                        if(raphael_papers[element]){
+                        //                            consolelog('vml.Raphael: '+element.tagName+' has paper');
+                        //                        }else{
+                        //                            consolelog('vml.Raphael: '+element.tagName+' does not have paper');
+                        //                        }
+
+                        //pass jQueryElm.get(0) as first argument, in case)
+                        if(raphael_papers[element]){
+                            return raphael_papers[element];
+                        }
+                        var paper = Raphael(element,w,h);
+                        raphael_papers[element] = 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)
+                        return paper;
+                    }
+
+                };
+
+            }
+            //finally,define the error function
+            ts.utils.loadScripts(thisScriptPath,ts_scripts, function() {
+                var p = new ts.classes.Player(playerDiv, sound, durationInMsec, soundImgFcn, soundImgSize,
+                    markersArray,newMarkerCallback);
                 //p.setupInterface(markerMap || []);
-                Timeside.player = p;
+                ts.player = p;
                 onReady(p);
                 return false;
-            });
+            },onError);
         });
     });
+}
+
+/**
+* Loads scripts asynchronously
+* can take up to four arguments:
+* scriptsOptionalRoot (optional): a string specifying the root (such as '/usr/local/'). IF IT IS A NONEMPTY STRING AND
+*                                 DOES NOT END WITH A SLASH, A SLASH WILL B APPENDED
+* scriptArray: a string array of js script filenames, such as ['script1.js','script2.js']
+* optionalOnOkCallback (optional): callback to be executed when ALL scripts are succesfully loaded
+* optionalOnErrorCallback (optional) a callback receiving a string as argument to be called if some script is not found
+* optionalSynchroLoad (optional): if true scripts are loaded in synchronously, ie each script is loaded only once the
+*                                 previous has been loaded. Otherise (including missing argument) an asynchronous load is performed
+*                                 and the optional onOkCallback is executed once ALL scripts are loaded
+*/
+Timeside.utils.loadScripts = function(scriptsOptionalRoot,scriptArray, optionalOnOkCallback, optionalOnErrorCallback, optionalSynchroLoad){
+    //var optionalRoot='', callback=undefined, loadInSeries=false;
+    if(!optionalOnOkCallback || typeof optionalOnOkCallback !== 'function'){
+        optionalOnOkCallback = function(){};
+    }
+    if(!optionalOnErrorCallback|| typeof optionalOnErrorCallback !== 'function'){
+        optionalOnErrorCallback = function(msg){};
+    }
+
+    if(!scriptArray || !scriptArray.length){
+        optionalOnOkCallback();
+        return;
+    }
+    var len = scriptArray.length;
+    var i=0;
+    if(scriptsOptionalRoot){
+        scriptsOptionalRoot = scriptsOptionalRoot.replace(/\/*$/,"/"); //add slash at end if not present
+        for(i =0; i<len; i++){
+            scriptArray[i] = scriptsOptionalRoot+scriptArray[i];
+        }
+    }
+
+    var $J = jQuery;
+    //there is a handy getScript function in jQuery, which however does NOT manage the onError case (script load error)
+    //looking at jQuery doc, getScript is the same as the followig ajax request,
+    //to which we added the error property to manage errors:
+    var loadScript = function(url,onSuccess,onError){
+        $J.ajax({
+            url: url,
+            dataType: 'script',
+            success: onSuccess,
+            error: function(a,b,errorThrown){
+                onError('file "'+url+'" error: '+errorThrown);
+            }
+        });
+    };
+    if(optionalSynchroLoad){
+        var load = function(index){
+            if(index<len){
+                loadScript(scriptArray[index],function(){
+                    load(index+1);
+                }, function(msg){
+                    optionalOnErrorCallback(msg);
+                });
+            }else if(index==len){
+                optionalOnOkCallback();
+            }
+        };
+        load(0);
+    }else{
+        var count=0;
+        var s;
+        for(i=0; i <len; i++){
+            s = scriptArray[i];
+            //this means that onError all scripts will be loaded.
+            //However, if everything works fine, asynchornous load (here) should be faster
+            loadScript(s, function(){
+                count++;
+                if(count===len){
+                    optionalOnOkCallback();
+                }
+            },function(msg){
+                count = len+1; //avoid calling optionalOkOnCallback
+                optionalOnErrorCallback(msg);
+            });
+        }
+    }
 }
\ No newline at end of file
index f69faab5e90798cf7c39b708980327bfd53d5ad2..cdfec55e77d83611243b0845281e5c98b3520e6a 100644 (file)
@@ -14,7 +14,6 @@
 {% if item %}
 
 <script src="{% url telemeta-timeside "js/libs/soundmanager2-nodebug-jsmin.js" %}" type="text/javascript"></script>
-<script src="{% url telemeta-timeside "js/libs/raphael-min.js" %}" type="text/javascript"></script>
 <script src="{% url telemeta-timeside "js/timeside.js" %}" type="text/javascript"></script>
 <script src="{% url telemeta-js "popupdiv.js" %}" type="text/javascript"></script>
 <script src="{% url telemeta-js "playlist.js" %}" type="text/javascript"></script>