]> git.parisson.com Git - telemeta.git/commitdiff
fixed popupdiv and playlists popup
authorriccardo <riccardo@parisson.com>
Mon, 16 May 2011 09:54:36 +0000 (11:54 +0200)
committerriccardo <riccardo@parisson.com>
Mon, 16 May 2011 09:54:36 +0000 (11:54 +0200)
telemeta/htdocs/js/popupdiv.js
telemeta/htdocs/timeside/src/playlist.js
telemeta/templates/telemeta_default/mediaitem_detail.html

index fd04123b3ae8fa7901c019e1e6d33d58c2eaef2b..01d99d950907244204e4f89dea6e0c8e17944382 100644 (file)
@@ -41,12 +41,56 @@ function PopupDiv(){
     }\r
 \r
     var k;\r
-    //setting static properties, if any:\r
+\r
+    //setting static properties, if any.\r
+    //The idea is that static PopupDiv properties SPP (eg, PopupDiv.shadowOffset = 5) should be added to the current PopupDiv\r
+    //instance prototype ONCE (properties in the prototype are shared between all PopupDiv instances)\r
+    //and then deleted from the PopupDiv function.\r
+    //The problem is how to access the prototype: nor __proto__ neither Object.getPrototypeOf(this) are cross browser\r
+    //(see http://ejohn.org/blog/objectgetprototypeof/, which suggests to rewrite a global Object.getPrototypeOf(arg), which\r
+    //however does not work if arg constructor has been manipulated). Eventually, we do the following:\r
+    //Find a prototype variable P: P= Object.getPrototypeOf: is it NOT a function? then P = this.__proto__. Is it NOT an object?\r
+    //then P= this.\r
+    //Populate P, if P = this, we are assigning SPP to each new instance and NOT ONCE to the prototype object, which of course\r
+    //means that SPP's cannot be deleted after their first assignment. This requires more work and more memory consumption\r
+    //but it assures cross browser compatibility\r
+\r
+    var staticProps = undefined;\r
     for(k in PopupDiv){\r
-        this.__proto__[k] = PopupDiv[k];\r
-        //        consolelog(k+' '+PopupDiv[k]);\r
-        delete PopupDiv[k];\r
+        if(!staticProps){\r
+            staticProps = {};\r
+        }\r
+        var f = PopupDiv[k];\r
+        if(typeof f !== 'function'){ //do not assign functions (PopupDiv.function... might be used in future as\r
+            //static functions accessible from outside\r
+            staticProps[k] = f;\r
+        }\r
     }\r
+    if(staticProps){\r
+        var remove = true;\r
+        var proto = undefined;\r
+        if ( typeof Object.getPrototypeOf !== "function" ) {\r
+            if ( typeof this.__proto__ === "object" ) {\r
+                proto = this.__proto__;\r
+            } else {\r
+                // May break if the constructor has been tampered with:\r
+                // proto =  this.constructor.prototype;\r
+                //so we assign tis class BUT we DO NOT remove static properties\r
+                proto = this;\r
+                remove = false;\r
+            }\r
+        }else{\r
+            proto = Object.getPrototypeOf(this);\r
+        }\r
+        for(k in staticProps){\r
+            proto[k] = staticProps[k];\r
+            if(remove){\r
+                delete PopupDiv[k];\r
+            }\r
+        }\r
+    }\r
+\r
+    \r
 \r
     //setting instance-specific properties:\r
     for(k in data){\r
@@ -124,14 +168,19 @@ function PopupDiv(){
     p.fadeOutTime = 0,\r
     p.shadowOpacity = 0.25;\r
     p.zIndex = 10000;\r
-    // p.listItemClass = '';\r
+    p.listItemClass = '';\r
+    p.listItemCss = '';\r
 \r
+    //returns the data associated to this popup. Basically, it searches for all input, select or textarea with attribute\r
+    //this.getFormDataAttrName(). The use of a custom attribute is cross browser, note that some attributes, eg name, are\r
+    //not (name is not safe in IE for instance)\r
     p.getFormData = function(){\r
         var elms = this.find('input,select,textarea');\r
         var ret = {};\r
+        var att = this.getFormDataAttrName();\r
         elms.each(function(i,e){\r
             var ee = $(e);\r
-            var key = ee.attr('name');\r
+            var key = ee.attr(att);\r
             if(key){\r
                 ret[key] = ee.val();\r
             }\r
@@ -208,14 +257,14 @@ function PopupDiv(){
         var container =   $($(div).children()[1]);\r
         //div.appendTo('body'); //necessary to properly display the div size\r
         container.empty();\r
-\r
+        var att = this.getFormDataAttrName();\r
         if(content instanceof $){\r
             container.append(content);\r
         }else if(content instanceof Array){\r
-            var jQ = $;\r
+            \r
             var me = this;\r
             //var name = this.getListItemName();\r
-            var input = $('<input/>').attr('type','hidden').attr('name','selIndex');\r
+            var input = $('<input/>').attr('type','hidden').attr(att,'selIndex');\r
             var setEvents = function(idx,anchor,input){\r
                 anchor.click(function(){\r
                     input.val(idx);\r
@@ -225,31 +274,31 @@ function PopupDiv(){
                     input.val(idx);\r
                 })\r
             };\r
+            var listItems = $([]);\r
             for(var h=0; h<content.length; h++){\r
                 var item = content[h];\r
-                var a = $('<a/>').attr('href','#');\r
-                if('class' in item){\r
-                    a.addClass(item['class']);\r
-                }\r
-                if('html' in item){\r
-                    a.html(item['html']);\r
-                }\r
-                if('name' in item){\r
-                    a.attr('name', item['name']);\r
-                }\r
-                if('id' in item){\r
-                    a.attr('id', item['id']);\r
-                }\r
-                if('css' in item){\r
-                    a.css(item['css']);\r
-                }\r
-                a.css({\r
-                    'display':'block',\r
-                    'margin':'2px'\r
-                }); //margin is used to display the outline (focus)\r
+                var a = $('<a/>').attr('href','#').html(""+item);\r
+                listItems = listItems.add(a);\r
                 setEvents(h,a,input);\r
                 container.append(a);\r
             }\r
+            //set css and class on all listitem anchor:\r
+            //set margin to properly display the outline (border focus)\r
+            //this css can be overridden (see lines below) as it is not strictly necessary\r
+            listItems.css({\r
+                'margin':'2px'\r
+            });\r
+            if(this.listItemClass){\r
+                listItems.addClass(this.listItemClass);\r
+            }\r
+            if(this.listItemCss){\r
+                listItems.css(this.listItemCss);\r
+            }\r
+            //override css which are necessary to properly display the listItem:\r
+            listItems.css({\r
+                'position' : '',\r
+                'display':'block'\r
+            });\r
             container.append(input);\r
         }else if(content && content.constructor == Object){\r
             var leftElements = $([]);\r
@@ -277,11 +326,11 @@ function PopupDiv(){
                     title = $('<span/>').html(k);\r
                     maxw[0] = max(maxw[0],k.length);\r
                     maxw[1] = max(maxw[1],val.length);\r
-                    component = $('<input/>').attr('type','text').val(val).attr('name',k);\r
+                    component = $('<input/>').attr('type','text').val(val).attr(att,k);\r
                     lineDivs = lineDivs.add(insert(title,component));\r
                 }else if(val === true || val === false){\r
                     var id = this.getId()+"_checkbox";\r
-                    title = $('<input/>').attr('type','checkbox').attr('name',k).attr('id',id);\r
+                    title = $('<input/>').attr('type','checkbox').attr(att,k).attr('id',id);\r
                     if(val){\r
                         title.attr('checked','checked');\r
                     }else{\r
@@ -293,7 +342,7 @@ function PopupDiv(){
                 }else if(val instanceof Array){\r
                     title = $('<span/>').html(k);\r
                     maxw[0] = max(maxw[0],k.length);\r
-                    component = $('<select/>').attr('size',1);\r
+                    component = $('<select/>').attr('size',1).attr(att,k);\r
                     for(var i=0; i< val.length; i++){\r
                         component.append($('<option/>').val(val[i]).html(val[i]));\r
                         maxw[1] = max(maxw[1],val[i].length);\r
@@ -328,7 +377,7 @@ function PopupDiv(){
                 'width':Math.round((3/5)*maxw[0])+'em'\r
             });\r
             rightElements.css({\r
-                'width':Math.round((3/5)*Math.max(maxw[0], maxw[1]))+'em'\r
+                'width':Math.round((3/5)*max(maxw[0], maxw[1]))+'em'\r
             }); //might be zero if default values are all ""\r
         }else{\r
             container.append(""+content);\r
@@ -352,11 +401,11 @@ function PopupDiv(){
             elementsWithFocus =elementsWithFocus.add(topDiv.find('a'));\r
         }\r
         if(this.showOk || this.title){\r
-           elementsWithFocus = elementsWithFocus.add(topDiv.find(':text'));\r
-           if(this.showOk){\r
-               elementsWithFocus = elementsWithFocus.add(bottomDiv.find('a'));\r
-           }\r
-       }\r
+            elementsWithFocus = elementsWithFocus.add(topDiv.find(':text'));\r
+            if(this.showOk){\r
+                elementsWithFocus = elementsWithFocus.add(bottomDiv.find('a'));\r
+            }\r
+        }\r
         elementsWithFocus = elementsWithFocus.add(popup);\r
         var focusNameSpace = "blur."+this.getId();\r
         if(!value){\r
@@ -389,7 +438,7 @@ function PopupDiv(){
                 //otherwise execute callback\r
                 setTimeout(function(){\r
                     var v = doc_.activeElement;\r
-                    console.log(v);\r
+                    //console.log(v);\r
                     if((v && $(v).attr(focusAttr)) || me.isClosing){\r
                         //if we are closing, we will call back this method which removes the focus attributes, bt meanwhile the\r
                         //timeout should execute\r
@@ -425,7 +474,7 @@ function PopupDiv(){
             this.popupCss = ''; //override prototype property\r
         }\r
         //css modified, restore properties we need not to change:\r
-       //cssModified should be true ALL first times we call show, as this.popupCss = {} )ie, it evaluates to TRUE)\r
+        //cssModified should be true ALL first times we call show, as this.popupCss = {} )ie, it evaluates to TRUE)\r
         if(cssModified){\r
             div.css({\r
                 'position':'absolute',\r
@@ -443,52 +492,67 @@ function PopupDiv(){
         var titleInput = topDiv.find(':text').eq(0); //$(':text') is equivalent to $('[type=text]') (selects all <input type="text"> elements)\r
         var closeBtn = topDiv.find('a').eq(0);\r
         if(!this.showClose && !this.title){\r
-         topDiv.hide();\r
-       }else{\r
-               topDiv.css({'paddingBottom':'1em','whiteSpace': 'nowrap'}).show(); //add padding to bottom\r
-                       //warning: do NOT use real numbers such as 0.5ex cause browsers round it in a different manner\r
-                       //whiteSpace is FUNDAMENTAL in calculating the popup div in case the title is the longest (max width) element\r
-                       //in the popup div. We will set the same whitespace css also on the title (see below)\r
-\r
-               if(this.showClose){\r
-                       closeBtn.attr('class',this.closeButtonClass); //removes all existing classes, if any (see jQuery removeClass doc)\r
-                       closeBtn.html(this.closeButtonTitle);\r
-                       closeBtn.css({\r
-                               'display':'inline-block','visibility':'visible','marginLeft':'1em'\r
-                               //warning: do NOT use real numbers such as 0.5ex cause browsers round it in a different manner\r
-                               //inline-block in order to retrieve/set width and height on the element\r
-                       });\r
-               }else{\r
-                       closeBtn.css({'margin':'0px'}).hide(); //margin:0 is to be sure, as afterwards we must span the title the whole popup width\r
-               }\r
-               //in any case, show titleElement cause even if title="", titleElement is used to position close on the right\r
-               titleInput.val(this.title).attr('readonly','readonly').attr('class',this.titleClass).removeClass().css({\r
-                 'display':'inline-block',\r
-                 'backgroundColor':'transparent',\r
-                 'padding': '0px', 'margin':'0px','border':'0px',\r
-                 'visibility': this.title ? 'visible' : 'hidden',\r
-                 'width':'',\r
-                 'maxWidth':'1px'      //it is too tricky to set the width of the input spanning the whole title (in case of long titles)\r
-                 //we might use a span, but we experienced problems in vertical align with the close button, as stated somewhere above.\r
-                 //Moreover, a long title messes up the calculations in popup mode:\r
-                 //a long title most likely determines the popup size, the latter the popup position, and once\r
-                 //positioned and sized the popup size determines the title width (in order to span the title or letting the close button be visible)\r
-                 //This is not robust at all and in fact it does not render the same popup position in all browsers.\r
-                 //So, finally, set the input to the minimum allowed width, This means that maxWidth and maxHeight\r
-                 //will be calculated based on the centraldiv dimensions, which is anyway the core div we want to properly visualize.\r
-                 //Moreover, this way title resizing does not interfeere with the position\r
-                });\r
-       }\r
+            topDiv.hide();\r
+        }else{\r
+            topDiv.css({\r
+                'paddingBottom':'1em',\r
+                'whiteSpace': 'nowrap'\r
+            }).show(); //add padding to bottom\r
+            //warning: do NOT use real numbers such as 0.5ex cause browsers round it in a different manner\r
+            //whiteSpace is FUNDAMENTAL in calculating the popup div in case the title is the longest (max width) element\r
+            //in the popup div. We will set the same whitespace css also on the title (see below)\r
+\r
+            if(this.showClose){\r
+                closeBtn.attr('class',this.closeButtonClass); //removes all existing classes, if any (see jQuery removeClass doc)\r
+                closeBtn.html(this.closeButtonTitle);\r
+                closeBtn.css({\r
+                    'display':'inline-block',\r
+                    'visibility':'visible',\r
+                    'marginLeft':'1em'\r
+                //warning: do NOT use real numbers such as 0.5ex cause browsers round it in a different manner\r
+                //inline-block in order to retrieve/set width and height on the element\r
+                });\r
+            }else{\r
+                closeBtn.css({\r
+                    'margin':'0px'\r
+                }).hide(); //margin:0 is to be sure, as afterwards we must span the title the whole popup width\r
+            }\r
+            //in any case, show titleElement cause even if title="", titleElement is used to position close on the right\r
+            titleInput.val(this.title).attr('readonly','readonly').attr('class',this.titleClass).removeClass().css({\r
+                'display':'inline-block',\r
+                'backgroundColor':'transparent',\r
+                'padding': '0px',\r
+                'margin':'0px',\r
+                'border':'0px',\r
+                'visibility': this.title ? 'visible' : 'hidden',\r
+                'width':'',\r
+                'maxWidth':'1px'       //it is too tricky to set the width of the input spanning the whole title (in case of long titles)\r
+            //we might use a span, but we experienced problems in vertical align with the close button, as stated somewhere above.\r
+            //Moreover, a long title messes up the calculations in popup mode:\r
+            //a long title most likely determines the popup size, the latter the popup position, and once\r
+            //positioned and sized the popup size determines the title width (in order to span the title or letting the close button be visible)\r
+            //This is not robust at all and in fact it does not render the same popup position in all browsers.\r
+            //So, finally, set the input to the minimum allowed width, This means that maxWidth and maxHeight\r
+            //will be calculated based on the centraldiv dimensions, which is anyway the core div we want to properly visualize.\r
+            //Moreover, this way title resizing does not interfeere with the position\r
+            });\r
+        }\r
 \r
         var bottomDiv = $(subdiv[2]);\r
         var okButton = bottomDiv.find('a').eq(0);\r
         //see note above about why we dont use okButton.is(':visible')\r
         if(this.showOk){\r
-            bottomDiv.css({'paddingTop':'1em','textAlign':this.okButtonAlign}).show(); //add padding to bottom\r
-           //warning: do NOT use real numbers such as 0.5ex cause browsers round it in a different manner\r
-                okButton.attr('class', this.okButtonClass); //removes all existing classes, if any\r
-                okButton.html(this.okButtonTitle);\r
-                okButton.css({'display':'inline-block','visibility':'visible'}); //in order to set width and height on the element\r
+            bottomDiv.css({\r
+                'paddingTop':'1em',\r
+                'textAlign':this.okButtonAlign\r
+            }).show(); //add padding to bottom\r
+            //warning: do NOT use real numbers such as 0.5ex cause browsers round it in a different manner\r
+            okButton.attr('class', this.okButtonClass); //removes all existing classes, if any\r
+            okButton.html(this.okButtonTitle);\r
+            okButton.css({\r
+                'display':'inline-block',\r
+                'visibility':'visible'\r
+            }); //in order to set width and height on the element\r
         }else{\r
             bottomDiv.hide();\r
         }\r
@@ -496,17 +560,17 @@ function PopupDiv(){
         var centralDiv = $(subdiv[1]);\r
         //reset properties of the central div\r
         centralDiv.css({\r
-           'overflow':'auto',\r
+            'overflow':'auto',\r
             'maxHeight':'',\r
             'maxWidth':'',\r
             'minHeight':'',\r
             'minWidth':'',\r
             'height':'',\r
             'width':'',\r
-                       'visibility':'visible'\r
+            'visibility':'visible'\r
         }).show();\r
 \r
-               this.setSizable();//this means the popupdiv is display: !none and visibility:hidden, so every element\r
+        this.setSizable();//this means the popupdiv is display: !none and visibility:hidden, so every element\r
         //inside it should be visible and therefore sizable. Being visible means that jQuery.is(':visible') returns true\r
         //start with showing top and bottom if some elements are visible\r
 \r
@@ -549,24 +613,27 @@ function PopupDiv(){
             this.setBoundsInside(invoker, this.bounds, this.boundsExact, true);\r
         }\r
 \r
-       //set title and close button to span whole width, if necessary\r
-       //closeButton.outerWidth should be zero if this.showClose = false\r
-       //titleInput.outerWidth(true) should be equal to titleInput.width(), as margins borders and padding are zero, however we want to calculate it safely\r
+        //set title and close button to span whole width, if necessary\r
+        //closeButton.outerWidth should be zero if this.showClose = false\r
+        //titleInput.outerWidth(true) should be equal to titleInput.width(), as margins borders and padding are zero, however we want to calculate it safely\r
         if(this.showClose || this.title){\r
             var titleW = topDiv.width() - closeBtn.outerWidth(true) - (titleInput.outerWidth(true)-titleInput.width());\r
-               titleInput.css({'maxWidth':'','width':(titleW)+'px'});\r
+            titleInput.css({\r
+                'maxWidth':'',\r
+                'width':(titleW)+'px'\r
+            });\r
         }\r
 \r
         //set central div max height ONLY IF NECESSARY (overflow). Until here, the main popup is sized and placed\r
-               //but the central div might overflow\r
-               var height = centralDiv.height();\r
+        //but the central div might overflow\r
+        var height = centralDiv.height();\r
         var maxHeight = (div.height()-topDiv.outerHeight(true)-bottomDiv.outerHeight(true)-\r
             (centralDiv.outerHeight(true)-centralDiv.height()));\r
-               if(maxHeight<height){\r
+        if(maxHeight<height){\r
             centralDiv.css('maxHeight',maxHeight+'px');\r
         }\r
-               //same for width:\r
-               var maxWidth = div.width();\r
+        //same for width:\r
+        var maxWidth = div.width();\r
         var width = centralDiv.outerWidth(true);\r
         if(maxWidth<width){\r
             centralDiv.css('maxWidth',maxWidth+'px');\r
@@ -574,23 +641,23 @@ function PopupDiv(){
 \r
         // var height = centralDiv.height();\r
         // if(sizeAsPopup && maxHeight<height){\r
-            // centralDiv.css('maxHeight',maxHeight+'px');\r
+        // centralDiv.css('maxHeight',maxHeight+'px');\r
         // }else{\r
-            // centralDiv.css({\r
-                // 'maxHeight': maxHeight+'px',\r
-                // 'minHeight': maxHeight+'px'\r
-            // });\r
+        // centralDiv.css({\r
+        // 'maxHeight': maxHeight+'px',\r
+        // 'minHeight': maxHeight+'px'\r
+        // });\r
         // }\r
         // //set central div max width ONLY IF NECESSARY:\r
         // var maxWidth = div.width();\r
         // var width = $(subdiv[1]).outerWidth(true);\r
         // if(sizeAsPopup && maxWidth<width){\r
-            // centralDiv.css('maxWidth',maxWidth+'px');\r
+        // centralDiv.css('maxWidth',maxWidth+'px');\r
         // }else{\r
-            // centralDiv.css({\r
-                // 'maxWidth': maxWidth+'px',\r
-                // 'minWidth':maxWidth+'px'\r
-            // });\r
+        // centralDiv.css({\r
+        // 'maxWidth': maxWidth+'px',\r
+        // 'minWidth':maxWidth+'px'\r
+        // });\r
         // }\r
 \r
 \r
@@ -634,24 +701,24 @@ function PopupDiv(){
         var div = this.getDiv();\r
         var oldCss= isSizable ?  undefined : this.setSizable();\r
 \r
-       var shadowOffset = this.shadowOffset;\r
+        var shadowOffset = this.shadowOffset;\r
         var windowRectangle = this.getBoundsOf(wdw); //returns the window rectangle\r
 \r
         var invokerOffset = invoker.offset();\r
 \r
-       var invokerOuterHeight = invoker.outerHeight();\r
-       var spaceAbove = invokerOffset.top - windowRectangle.y;\r
+        var invokerOuterHeight = invoker.outerHeight();\r
+        var spaceAbove = invokerOffset.top - windowRectangle.y;\r
         var spaceBelow = windowRectangle.height - invokerOuterHeight - spaceAbove;\r
         var placeAbove = spaceAbove > spaceBelow && div.outerHeight(false) + shadowOffset > spaceBelow;\r
 \r
-       var invokerOuterWidth = invoker.outerWidth();\r
-       var spaceRight = windowRectangle.x + windowRectangle.width - invokerOffset.left ;\r
+        var invokerOuterWidth = invoker.outerWidth();\r
+        var spaceRight = windowRectangle.x + windowRectangle.width - invokerOffset.left ;\r
         var spaceLeft = invokerOffset.left + invokerOuterWidth - windowRectangle.x;\r
         var placeLeft = spaceLeft > spaceRight && div.outerWidth(false) + shadowOffset > spaceRight;\r
 \r
         this.setMaxSize({\r
             height : (placeAbove ? spaceAbove : spaceBelow),\r
-                       width: (placeLeft ? spaceLeft : spaceRight)\r
+            width: (placeLeft ? spaceLeft : spaceRight)\r
         },isSizable); //width will be ignored (for the moment)\r
         //decrement of one pixel cause when the popup has to be reduced and the shadows bounds "touch" the window right or bottom sides,\r
         //the window scrolls (and it shouldn't)\r
@@ -949,5 +1016,8 @@ function PopupDiv(){
         return this.getId()+"_focus";\r
     }\r
 \r
+    p.getFormDataAttrName = function(){\r
+        return this.getId()+"_data";\r
+    }\r
 \r
 })(PopupDiv.prototype);\r
index 61736eeee7552d757db1c9433a9d2551ae395b3a..ecf774aa8d2e87c4e2e5b41799c7f9939b707a6d 100644 (file)
@@ -22,6 +22,7 @@ PopupDiv.closeButtonTitle =  '';
 PopupDiv.closeButtonClass =  'markersdivDelete';
 PopupDiv.defaultCloseOperation = 'remove';
 PopupDiv.focusable = true;
+PopupDiv.listItemClass = "component_icon list_item icon_playlist";
 
 var playlistUtils = {
     playlists : [],
@@ -94,10 +95,7 @@ var playlistUtils = {
         var ar = [];
         var playlists = this.playlists;
         for(var i=0; i< playlists.length; i++){
-            ar.push({
-                'html':playlists[i].name,
-                'class':"component_icon list_item icon_playlist"
-            });
+            ar.push(playlists[i].name);
         }
         if(!ar.length){
             return;
@@ -124,8 +122,6 @@ var playlistUtils = {
                     }
                 }
                 addFcn(playlists[val].id,resourceType,objectId,callbackok);
-
-
             }
         }).show();
 
index bca786ba29e60dcd473b04d3be2953d23e280a34..908c86b88b1e2582de1eff262aad5d0838d0788c 100644 (file)
@@ -55,7 +55,7 @@
     }
     //warn on soundmanager error:
     soundManager.onerror = function() {
-        playerError('SoundManager error. Try to:\n - Reload the page\n - Empty the cache (see browser preferences) and reload the page\n - Restart the browser');
+        playerError('SoundManager error. If your browser does not support HTML5, flash (version 9+) must be installed.\nIf it is the case, try to:\n - Reload the page\n - Empty the cache (see browser preferences) and reload the page\n - Restart the browser');
     };
 
     setTimeout(function(){