]> git.parisson.com Git - telemeta.git/commitdiff
markerdiv: added click moves the pointer on the relative marker on the ruler, ENTER...
authorriccardo <riccardo@parisson.com>
Mon, 9 May 2011 00:24:00 +0000 (02:24 +0200)
committerriccardo <riccardo@parisson.com>
Mon, 9 May 2011 00:24:00 +0000 (02:24 +0200)
telemeta/htdocs/css/telemeta.css
telemeta/htdocs/js/application.js
telemeta/htdocs/timeside/src/divmarker.js
telemeta/htdocs/timeside/src/player.js
telemeta/htdocs/timeside/src/playlist.js
telemeta/templates/telemeta_default/home.html
telemeta/templates/telemeta_default/mediaitem_detail.html

index 83c712a778ca643477df72b1492d3f4b029ce03d..765f539030bc93cb2c78b8a051868bebbfc8613b 100644 (file)
@@ -990,7 +990,8 @@ a.image-link {
 .markerdiv .ts-marker, .markerdiv .ts-marker:hover, .markerdiv .ts-marker:visited{
     font-family: monospace; background: #e65911;color: #FFF;padding-left: .3ex; padding-right:.3ex;
 }
-.markersdivDelete{    background-image: url('/images/del_marker.png');width:15px;height:2ex;}
+.markersdivDelete{    background-image: url('/images/del_marker.png');width:15px;height:2ex;background-repeat: no-repeat;}
+/*backfround-repeat is redundant with .markerDiv a,.. defined above but this way .markersDivDelete is re-usable in other context (eg popupdiv*/
 .markersdivAddPlaylist{    background-image: url('/images/add_playlist_marker.png');width:13px;height:2ex; }
 .markersdivTitle{    font-weight:bold;}
 .markersdivEdit, .markersdivEdit:hover, .markersdivEdit:visited{
index b7de4bc17326f437fc660114ff703ccd259a49e5..5d200e83d07128dd5244bd4013d4e774508ae924 100644 (file)
@@ -1000,412 +1000,397 @@ function DivDialog(content){
         return me;\r
     }\r
 }\r
+//------------\r
 \r
 \r
 \r
-function PopupDiv(content){\r
-    var $J = this.$J;\r
-    \r
+\r
+\r
+function PopupDiv(){\r
+    var $J = jQuery;\r
+    var me = this;\r
+    var data = arguments.length && arguments[0] || {};\r
+   \r
     //var wdw = $J(window);\r
-    var div  = $J('<div/>').addClass(this.defaultClasses).css({\r
-        'position':'absolute',\r
-        'zIndex':this.zIndex,\r
-        //        'display':'none',\r
-        //        'left':wdw.scrollLeft()+'px',\r
-        //        'top':wdw.scrollTop()+'px',\r
-        //        'overflow':'auto',\r
-        'padding':'1ex',\r
-        'border':'1px solid #666'\r
-    });\r
-    var header = $J('<div/>'); //.css('float','right');\r
+    var div  = $J('<div/>');\r
+    var header = $J('<div/>').append($J('<input/>').attr('type','text')).append($J('<a/>').attr('href','#').click(function(){\r
+        me.close();\r
+        return false;\r
+    })); //.css('float','right');\r
     var container = $J('<div/>').css('overflow','auto');\r
-    var footer = $J('<div/>');\r
+    var footer = $J('<div/>').css({\r
+        'textAlign':'right'\r
+    }).append($J('<a/>').attr('href','#').click(function(){\r
+        me.trigger('ok',true);\r
+        return false;\r
+    }));\r
+    header.find('*').add(footer.find('*')).css('display','none');\r
     div.append(header).append(container).append(footer);\r
     //defining immediately the method getDiv (because it is used below)\r
     this.getDiv = function(){\r
         return div;\r
     }\r
-\r
-    //div.appendTo('body'); //necessary to properly display the div size\r
-    if(content instanceof $J){\r
-        container.append(content);\r
-    }else if(typeof content == 'string'){\r
-        container.html(""+content);\r
-    }\r
-    //    else if(content instanceof Array){\r
-    //        for(var k=0; k<content.length;i++){\r
-    //            (function(value){container.append($J('<a/>').attr('href','#').html(value).click(\r
-    //            function(){\r
-    //                if(optionalCallbackOnClick){\r
-    //                    optionalCallbackOnClick(value);\r
-    //                }\r
-    //            }\r
-    //            ))})(content[k]);\r
-    //        }\r
-    //}\r
-    else{\r
-        var leftElements = $J([]);\r
-        var rightElements = $J([]);\r
-        var maxw = [0,0];\r
-        var insert = function(e1,e2){\r
-            var lineDiv = $J('<div/>');\r
-            if(!e2){\r
-                e2=e1;\r
-                e1 = $J('<span/>');\r
-            } \r
-            rightElements = rightElements.add(e2);\r
-            leftElements = leftElements.add(e1);\r
-            container.append(lineDiv.append(e1).append(e2));\r
-            return lineDiv;\r
-        }\r
-        var title, component;\r
-        \r
-        var max = Math.max; //instantiate once\r
-        var lineDiv = undefined;\r
-        var needAlign = false;\r
-        var lineDivs = $J([]);\r
-        for(var k in content){\r
-            var val = content[k];\r
-            //alert(k);\r
-            //            if(val instanceof Function){\r
-            //                //alert('inserting anchor/function');\r
-            //                component = $J('<a/>').html(k).attr('href','#').click(function(evt){\r
-            //                    val();\r
-            //                    return false;\r
-            //                });\r
-            //                lineDivs = lineDivs.add(insert(component));\r
-            //                maxw[1] = max(maxw[1],k.length);\r
-            //            }else\r
-            if(typeof val == 'string' || typeof val == 'number'){\r
-                //alert('inserting string/number');\r
-                title = $J('<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
-                lineDivs = lineDivs.add(insert(title,component));\r
-                needAlign = true;\r
-            }else if(val === true || val === false){\r
-                //alert('inserting boolean');\r
-                var id = this.getId()+"_checkbox";\r
-                title = $('<input/>').attr('type','checkbox').attr('name',k).attr('id',id);\r
-                if(val){\r
-                    title.attr('checked','checked');\r
-                }else{\r
-                    title.removeAttr('checked');\r
-                }\r
-                component = $J('<label/>').attr('for',id).html(k);\r
-                maxw[1] = max(maxw[1],k.length);\r
-                lineDivs = lineDivs.add(insert($J('<span/>').append(title),component));\r
-                needAlign = true;\r
-            }else if(val instanceof Array){\r
-                //alert('inserting array');\r
-                title = $J('<span/>').html(k);\r
-                maxw[0] = max(maxw[0],k.length);\r
-                component = $J('<select/>').attr('size',1);\r
-                for(var i=0; i< val.length; i++){\r
-                    component.append($J('<option/>').val(val[i]).html(val[i]));\r
-                    maxw[1] = max(maxw[1],val[i].length);\r
-                }\r
-                lineDivs = lineDivs.add(insert(title,component));\r
-                needAlign = true;\r
-            }\r
-            if(lineDiv){\r
-                lineDiv.css('marginBottom','1ex');\r
-            }\r
-        }\r
-        lineDivs.css({\r
-            'white-space': 'nowrap',\r
-            'marginBottom':'0.5ex'\r
-        });\r
-        //last div erase marginBottom\r
-        $J(lineDivs[lineDivs.length-1]).css('marginBottom','');\r
-        \r
-        //as ex is aproximately 1/3 em, we use a measure in between:\r
-        if(needAlign){\r
-            //display: inline-block below assures that width are properly set\r
-            //IE 6/7 accepts the value only on elements with a natural display: inline.\r
-            //(see http://www.quirksmode.org/css/display.html#t03)\r
-            //span and anchors are among them\r
-            //(see http://www.maxdesign.com.au/articles/inline/)\r
-            leftElements.add(rightElements).css({\r
-                'display':'inline-block',\r
-                'margin':'0px',\r
-                'padding':'0px'\r
-            });\r
-            leftElements.css({\r
-                'textAlign':'right',\r
-                'marginRight':'0.5ex',\r
-                'width':Math.round((3/5)*maxw[0])+'em'\r
-            });\r
-            rightElements.css({\r
-                'width':Math.round((3/5)*maxw[1])+'em'\r
-            });\r
-        }\r
-    }\r
\r
-    \r
-    //callback to be called BEFORE showing the popupdiv.\r
-    //it is usually a function to place the div in the correct point and recalculate its size\r
-    //Note that when called, the popup div is NOT visible BUT has display!='none', so that width and height can be calculated safely\r
-    this.callbackPreShow = null;\r
-    //callback to be called AFTER the popup is shown, it is usually a function to set the focus in case of popups\r
-    this.callbackPostShow = null;\r
     //setting functions:\r
-    var sizable = false;\r
-    var wdw = this.$J(window);\r
-    this.isSizable = function(){\r
-        return sizable;\r
-    }\r
-    this.setSizable = function(value){\r
-        //if false, just update the flag\r
-        if(!value){\r
-            sizable = false;\r
-            return undefined;\r
-        }\r
-        if(!div.parent().length){\r
-            div.appendTo('body');\r
-        }\r
-        var keys = ['display','visibility','left','top','maxWidth','maxHeight','minWidth','minHeight'];\r
-        var css = {};\r
-        for(var i=0; i<keys.length; i++){\r
-            css[keys[i]] = div.css(keys[i]);\r
-        }\r
-        div.offset({\r
-            'left':wdw.scrollLeft(),\r
-            'top':wdw.scrollTop()\r
-        });\r
-        //set the div invisible but displayable to calculate the size (callbackPreShow)\r
-        div.css({\r
-            'visibility':'hidden',\r
-            'maxWidth':'',\r
-            'maxHeight':'',\r
-            'minWidth':'',\r
-            'minHeight':'',\r
-            'height':'',\r
-            'width':''\r
-        }).show();\r
-        sizable = true;\r
-        return css;\r
-    }\r
-\r
+    \r
     var listeners = {};\r
     this.getListeners = function(){\r
         return listeners;\r
     }\r
-    \r
-    var pding = this.defaultBounds;\r
-    this.setBoundsInInvoker = function(padding){\r
-        var newp = {};\r
-        var db = this.defaultBounds;\r
-        var keys = ['top','bottom','left','right'];\r
-        for(var i=0; i<keys.length; i++){\r
-            if(!(keys[i] in padding)){\r
-                newp[keys[i]] = db[keys[i]];\r
-            }\r
-        }\r
-        pding = newp;\r
-    }\r
-    this.getBoundsInInvoker = function(){\r
-        return pding;\r
-    }\r
 \r
-    var invk = this.defaultInvoker;\r
-    this.setInvoker = function(invoker){\r
-        var focusAttr = this.getFocusAttr();\r
-        consolelog(focusAttr);\r
-        if(this.isClickElement(invk)){\r
-            invk.unbind('click').removeAttr('tabindex').removeAttr(focusAttr);\r
-        }\r
-        \r
-        if(this.isClickElement(invoker)){\r
-            var me = this;\r
-            me.setFocusable(true);\r
-            invoker.unbind('click').bind('click',function(evt){\r
-                //let the invoker have focus and let it be recognized as an element which does not blur the popup:\r
-                invoker.attr('tabindex',0).attr(focusAttr,'true');\r
-                var popupDiv = me.getDiv();\r
-                if(popupDiv.length && popupDiv.is(':visible')){\r
-                    me.getFirstFocusableElement().focus();\r
-                    return false;\r
-                }\r
-                me.show.apply(me);\r
-                return false;\r
-            });\r
-        }\r
-        \r
-        invk = invoker;\r
-    }\r
-    this.getInvoker = function(){\r
-        return invk && invk instanceof this.$J ? invk : this.defaultInvoker;\r
-    }\r
-    \r
-    var co;\r
-    this.setCloseOperation = function(hideOrRemove){\r
-        if(hideOrRemove == 'remove'){\r
-            co = 'remove';\r
-        }else{\r
-            co = undefined;\r
-        }\r
-    }\r
-    this.getCloseOperation = function(){\r
-        return co ? co : this.defaultCloseOperation;\r
+    var k;\r
+    //setting static properties, if any:\r
+    for(k in PopupDiv){\r
+        this.__proto__[k] = PopupDiv[k];\r
+        //        consolelog(k+' '+PopupDiv[k]);\r
+        delete PopupDiv[k];\r
     }\r
 \r
-    this.getShadowDivId = function(){\r
-        return this.getId()+"_shadow";\r
+    //setting instance-specific properties:\r
+    for(k in data){\r
+        if(k == 'ok' || k == 'blur' || k == 'close'){\r
+            this.bind(k,data[k]);\r
+        }else if(k == 'content'){\r
+            this.setContent(data[k]);\r
+        }else {\r
+            this[k] = data[k];\r
+        }\r
     }\r
 \r
-    this.getFocusAttr = function(){\r
-        return this.getId()+"_focus";\r
+    if(!this.popupCss){\r
+        this.popupCss = {}; //workaround to update css the first time we call show\r
+    //note that {} evaluates to true, but jQueryElement.css({}) is harmless\r
     }\r
+    \r
 \r
 }\r
+\r
 (function(p){\r
+    //private static variables\r
+    var $ = jQuery;\r
+    var w_ = window;\r
+    var d_ = document;\r
+    var wdw = $(w_);\r
+    var popupStaticId = 'popup_'+(new Date().getTime());\r
+    //var doc = $(d_);\r
+\r
+\r
+    //in the functions below, this refers to the new Popup instance, not to the prototype\r
+\r
+    \r
 \r
     p.isClickElement = function(element){\r
-return element && element.length && element instanceof this.$J && element[0] !== window && element[0] !== document &&\r
+        return element && element.length==1 && element instanceof $ && element[0] !== w_ && element[0] !== d_ &&\r
         (element.is('a') || element.is('input[type=button]') || element.is('button') ||\r
             element.is('input[type=submit]'));\r
-    }\r
+    };\r
 \r
     p.getId = function(){\r
         var div = this.getDiv();\r
         if(!(div.attr('id'))){\r
-            div.attr('id',this.defaultId+'_'+(new Date().getTime()));\r
+            div.attr('id',popupStaticId+'_'+(new Date().getTime()));\r
         }\r
         return div.attr('id');\r
-    }\r
+    };\r
 \r
-    //populating the prototype:\r
-    //properties:\r
-    p.defaultFadeTime = 'fast',\r
-    p.defaultFadeOutTime = 0,\r
-    p.$J = jQuery;\r
-    p.shadowOpacity = 0.3;\r
-    p.shadowOffset = 5;\r
-    p.zIndex = 1000;\r
-    p.defaultClasses = 'control component';\r
-    p.defaultId = 'popup_'+(new Date().getTime());\r
-    p.okButtonClass =  'component_icon button icon_ok';\r
-    p.cancelButtonClass = 'component_icon button icon_cancel';\r
+    \r
+    //default properties which can be overridden\r
+    p.shadowOffset = 4;\r
+    p.invoker = wdw;\r
+    p.bounds = {\r
+        'top':0.25,\r
+        'left':0.25,\r
+        'right':0.25,\r
+        'bottom':0.25\r
+    }; //note that sepcifying top+bottom>=1 there is undefined behaviour (in chrome, offset is set but height takes all available space)\r
+    p.boundsexact = false;\r
+    p.popupClass = '';\r
+    p.popupCss = {};\r
+    p.showok = false;\r
+    p.showclose=false;\r
+    p.title = "";\r
+    p.okButtonClass =  '';\r
+    p.closeButtonClass =  '';\r
+    p.okButtonTitle =  'Ok';\r
+    p.closeButtonTitle =  'x';\r
     p.defaultCloseOperation = 'hide';\r
-    p.defaultInvoker = p.$J(window);\r
-    p.defaultBounds = {\r
-        'top':0.5,\r
-        'left':0.5,\r
-        'right':0.5,\r
-        'bottom':0.5\r
+    p.focusable = false;\r
+    p.fadInTime = 'fast',\r
+    p.fadeOutTime = 0,\r
+    p.shadowOpacity = 0.3;\r
+    p.zIndex = 10000;\r
+    p.listItemClass = '';\r
+    \r
+    p.getFormData = function(){\r
+        var elms = this.find('input,select,textarea');\r
+        var ret = {};\r
+        consolelog(elms);\r
+        elms.each(function(i,e){\r
+            var ee = $(e);\r
+            var key = ee.attr('name');\r
+            if(key){\r
+                ret[key] = ee.val();\r
+            }\r
+        });\r
+        return ret;\r
     };\r
-    //p.wdow = p.$J(window);\r
-    //methods:\r
 \r
-        p.getFormData = function(){\r
-            var elms = this.find('input,select,textarea');\r
-            var ret = {};\r
-            var $J = this.$J;\r
-            elms.each(function(i,e){\r
-                var ee = $J(e);\r
-                var key = ee.attr('name');\r
-                if(key){\r
-                    ret[key] = ee.val();\r
-                }\r
-            });\r
-            return ret;\r
-        }\r
+    //methods:\r
+    p.find = function(argumentAsInJQueryFind){\r
+        return $(this.getDiv().children()[1]).find(argumentAsInJQueryFind);\r
+    };\r
 \r
-    p.bind = function(eventName, callback){ //eventname: show, blur or ok\r
+    p.bind = function(eventName, callback){ //eventname: show, close or ok\r
         var listeners = this.getListeners();\r
         if(eventName in listeners){\r
             listeners[eventName].push(callback);\r
         }else{\r
             listeners[eventName] = [callback];\r
         }\r
-    }\r
+    };\r
+\r
+\r
     p.unbind = function(eventName){\r
         var listeners = this.getListeners();\r
-        if(eventName in listeners){\r
+        if(eventName && eventName in listeners){\r
             delete listeners[eventName];\r
+        }else if(!eventName){\r
+            for(var k in listeners){\r
+                delete listeners[k];\r
+            }\r
         }\r
-    }\r
-    p.trigger = function(eventName, extraParameters){\r
+    };\r
+    \r
+    p.trigger = function(eventName){\r
         var listeners = this.getListeners();\r
         if(eventName in listeners){\r
             var callbacks = listeners[eventName];\r
-            for(var i=0; i<callbacks.length; i++){\r
-                callbacks[i](extraParameters);\r
+            var i = 0;\r
+            if(eventName == 'ok'){\r
+                var data = this.getFormData();\r
+                for(i=0; i<callbacks.length; i++){\r
+                    callbacks[i](data);\r
+                }\r
+                if(arguments.length>1 && arguments[1]){\r
+                    //workaround to remove listeners on close:\r
+                    if('close' in listeners){\r
+                        var v = listeners['close'];\r
+                        delete listeners['close'];\r
+                        this.close();\r
+                        listeners['close'] = v;\r
+                    }else{\r
+                        this.close();\r
+                    }\r
+\r
+                }\r
+            }else{\r
+                for(i=0; i<callbacks.length; i++){\r
+                    callbacks[i]();\r
+                }\r
             }\r
         }\r
-    }\r
+    };\r
 \r
-    p.addButton = function(onTop, caption, classNames, callback){\r
-        var $J = this.$J;\r
-        var div = $J($J(this.getDiv()).children()[onTop ? 0 : 2]);\r
-        var a = $J('<a/>').html(caption).addClass(classNames).attr('href','#').click(function(evt){\r
-            callback(evt);\r
-            return false;\r
-        });\r
-        div.append(a);\r
-        return a;\r
-    }\r
-    //adds a cancel button to the bottom of the popupdiv\r
-    //addCancelButton(caption) adds a cancel button which HIDES the popup\r
-    //addCancelButton(caption, true) adds a cancel button which REMOVES the popup\r
-    p.addCancelButton = function(caption, removeOnClick){\r
-        var me = this;\r
-        addButton(false,caption,this.cancelButtonClass, removeOnClick ? function(){\r
-            me.remove()\r
-        } : function(){\r
-            me.hide()\r
-        });\r
-    }\r
-    //adds a ok button to the bottom of the popupdiv\r
-    //addOkButton(caption,callback) adds a cancel button which HIDES the popup AND EXECUTES\r
-    //addCancelButton(caption, true) adds a cancel button which REMOVES the popup\r
-    p.addOkButton = function(caption, callbackOnClick, removeOnClick){\r
-        addButton(false,caption,this.okButtonClass, callbackOnClick);\r
-    }\r
-    p.find = function(argumentAsInJQueryFind){\r
-        return this.$J(this.getDiv().children[1]).find(argumentAsInJQueryFind);\r
-    }\r
-    \r
-    p.setFocusable = function(value){\r
+    p.setContent = function(content){\r
+        var div = this.getDiv();\r
+        var container =   $($(div).children()[1]);\r
+        //div.appendTo('body'); //necessary to properly display the div size\r
+        container.empty();\r
+        consolelog('emptying');\r
+        if(content instanceof $){\r
+            container.append(content);\r
+        }else if(content instanceof Array){\r
+            var jQ = $;\r
+            var me = this;\r
+            var name = this.getListItemName();\r
+            var input = $('<input/>').attr('type','hidden').attr('name','value');\r
+            for(var h=0; h<content.length; h++){\r
+                var a = $('<a/>').attr('href','#').attr('name',name).html(content[h]).click(function(){\r
+                    input.val(jQ(this).html());\r
+                    me.trigger('ok',true);\r
+                }).focus(function(){ //focus because we need to\r
+                    input.val(jQ(this).html());\r
+                });\r
+                container.append(a);\r
+            }\r
+            container.append(input);\r
+        }else if(content && content.constructor == Object){\r
+            var leftElements = $([]);\r
+            var rightElements = $([]);\r
+            var maxw = [0,0];\r
+            var insert = function(e1,e2){\r
+                var lineDiv = $('<div/>');\r
+                if(!e2){\r
+                    e2=e1;\r
+                    e1 = $('<span/>');\r
+                }\r
+                rightElements = rightElements.add(e2);\r
+                leftElements = leftElements.add(e1);\r
+                container.append(lineDiv.append(e1).append(e2));\r
+                return lineDiv;\r
+            }\r
+            var title, component;\r
+\r
+            var max = Math.max; //instantiate once\r
+            var lineDiv = undefined;\r
+            var lineDivs = $([]);\r
+            for(var k in content){\r
+                var val = content[k];\r
+                if(typeof val == 'string' || typeof val == 'number'){\r
+                    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
+                    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
+                    if(val){\r
+                        title.attr('checked','checked');\r
+                    }else{\r
+                        title.removeAttr('checked');\r
+                    }\r
+                    component = $('<label/>').attr('for',id).html(k);\r
+                    maxw[1] = max(maxw[1],k.length);\r
+                    lineDivs = lineDivs.add(insert($('<span/>').append(title),component));\r
+                }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
+                    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
+                    }\r
+                    lineDivs = lineDivs.add(insert(title,component));\r
+                }\r
+                if(lineDiv){\r
+                    lineDiv.css('marginBottom','1ex');\r
+                }\r
+            }\r
+            lineDivs.css({\r
+                'white-space': 'nowrap',\r
+                'marginBottom':'0.5ex'\r
+            });\r
+            //last div erase marginBottom\r
+            $(lineDivs[lineDivs.length-1]).css('marginBottom','');\r
+\r
+\r
+            //display: inline-block below assures that width are properly set\r
+            //IE 6/7 accepts the value only on elements with a natural display: inline.\r
+            //(see http://www.quirksmode.org/css/display.html#t03)\r
+            //span and anchors are among them\r
+            //(see http://www.maxdesign.com.au/articles/inline/)\r
+            leftElements.add(rightElements).css({\r
+                'display':'inline-block',\r
+                'margin':'0px',\r
+                'padding':'0px'\r
+            });\r
+            leftElements.css({\r
+                'textAlign':'right',\r
+                'marginRight':'0.5ex',\r
+                '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
+            }); //might be zero if default values are all ""\r
+        }\r
+\r
+    };\r
+\r
+   \r
+\r
+//    p.setInvoker = function(invoker){\r
+//        var focusAttr = this.getFocusAttr();\r
+//        var invk = this.invoker;\r
+//        var clickNameSpace = "click."+this.getId();\r
+//        if(this.isClickElement(invk)){\r
+//            invk.unbind(clickNameSpace); //.removeAttr('tabindex').removeAttr(focusAttr);\r
+//        }\r
+//\r
+//        if(this.isClickElement(invoker)){\r
+//            var me = this;\r
+//            //me.setFocusable(true);\r
+//            invoker.unbind(clickNameSpace).bind(clickNameSpace,function(evt){\r
+//                //let the invoker have focus and let it be recognized as an element which does not blur the popup:\r
+//                //invoker.attr('tabindex',0).attr(focusAttr,'true');\r
+//                var popupDiv = me.getDiv();\r
+//\r
+//                if(popupDiv.length && popupDiv.is(':visible')){\r
+//                    var v = me.getFirstFocusableElement();\r
+//                    if(v){\r
+//                        me.getFirstFocusableElement().focus();\r
+//                    }\r
+//                    return false;\r
+//                }\r
+//                me.show.apply(me);\r
+//                return false;\r
+//            });\r
+//        }\r
+//        if(!invoker || !(invoker instanceof $)){\r
+//            delete this.invoker; //so we'll call the prorotype invoker\r
+//            return;\r
+//        }\r
+//        this.invoker = invoker;\r
+//    //        invk = invoker;\r
+//    }\r
+\r
+\r
+    p.setFocusCycleRoot = function(value){\r
+        //var value = this.focusable;\r
         var popup = this.getDiv();\r
-        var $J = this.$J;\r
-        var focusAttr =this.getFocusAttr();\r
+        var focusAttr = this.getFocusAttr();\r
+        var invokerIsClickable = this.isClickElement(this.invoker);\r
+        var children_ = popup.children();\r
+        var topDiv = $(children_[0]);\r
+        var centralDiv = $(children_[1]);\r
+        var bottomDiv = $(children_[2]);\r
+        var elementsWithFocus =  centralDiv.find('input[type!=hidden],select,textarea,a'); //input:not(:hidden),select,textarea,a,\r
+\r
+        var ret = elementsWithFocus.length ? $(elementsWithFocus[0]) : popup;\r
+        if(this.showclose){\r
+            elementsWithFocus =elementsWithFocus.add(topDiv.find('a'));\r
+        }\r
+        if(this.showok){\r
+            elementsWithFocus = elementsWithFocus.add(bottomDiv.find('a'));\r
+        }\r
+        elementsWithFocus = elementsWithFocus.add(popup);\r
+        var focusNameSpace = "blur."+this.getId();\r
         if(!value){\r
-            popup = popup.add($J(popup).find('*'));\r
-            popup.each(function(i,elm){\r
-                $J(elm).removeAttr('tabindex').removeAttr(focudid);\r
+            elementsWithFocus.each(function(i,elm){\r
+                $(elm).unbind(focusNameSpace).removeAttr('tabindex').removeAttr(focusAttr);\r
             });\r
             this.getFirstFocusableElement = function(){\r
                 return undefined;\r
             }\r
+            if(invokerIsClickable){\r
+                this.invoker.removeAttr('tabindex').removeAttr(focusAttr);\r
+            }\r
             return;\r
         }\r
+         if(invokerIsClickable){\r
+                this.invoker.attr('tabindex',0).attr(focusAttr,'true');\r
+            }\r
+        var doc_ = d_; //closure (see nested function below)\r
         \r
-        popup.attr('tabindex',0);\r
-        var elementsWithFocus = $J(popup).find('textarea,a,input,select');\r
-        var doc = document;\r
-        var ret = elementsWithFocus.length ? $J(elementsWithFocus[0]) : popup;\r
-        elementsWithFocus = elementsWithFocus.add(popup);\r
-        //build the attribute focus to recognize subelement of popup\r
+        //now all elements (including header and footer)\r
         \r
         var me = this;\r
         //bind the blur to each focusable element:\r
         elementsWithFocus.each(function(i,e){\r
-            var ee = $J(e);\r
-            ee.attr(focusAttr,'true'); //makes sense?\r
+            var ee = $(e);\r
+            ee.attr(focusAttr,'true');\r
             ee.attr('tabindex',i+1);\r
-            ee.unbind('blur').blur(function(){\r
+            ee.unbind(focusNameSpace).bind(focusNameSpace,function(){\r
                 //wait 250msec to see if the focus has been given to another popup focusable element: if yes, do nothing\r
                 //otherwise execute callback\r
                 setTimeout(function(){\r
-                    var v = doc.activeElement;\r
-                    //consolelog(v);\r
-                    if(v && $J(v).attr(focusAttr)){\r
+                    var v = doc_.activeElement;\r
+                    consolelog(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
                         return;\r
                     }\r
-                    me.trigger('blur');\r
+                    \r
                     me.close();\r
                 },200)\r
             }); //set here another time delay. 300 seems to be the good compromise between visual hide and safetiness that\r
@@ -1417,18 +1402,112 @@ return element && element.length && element instanceof this.$J && element[0] !==
     };\r
     p.getFirstFocusableElement = function(){\r
         return undefined;\r
-    }\r
+    };\r
     p.show = function(){\r
         var div = this.getDiv();\r
         var me = this;\r
+        \r
\r
+        var cssModified = (this.popupClass || this.popupCss);\r
+        if(this.popupClass){\r
+            //which might be the prototype\r
+            div.removeClass().addClass(this.popupClass);\r
+            this.popupClass = ''; //override prototype property\r
+        }\r
+        if(this.popupCss){\r
+            //which might be the prototype\r
+            div.css(this.popupCss);\r
+            this.popupCss = ''; //override prototype property\r
+        }\r
+        //css modified, restore properties we need to be restored:\r
+        if(cssModified){\r
+            div.css({\r
+                'position':'absolute',\r
+                'zIndex':this.zIndex,\r
+                'margin':'0px',\r
+                'overflow':'hidden'\r
+            });\r
+        }\r
+\r
+        //if we have elements of type listitem, add the specified class\r
+        var name = this.getListItemName();\r
+        var elms = this.find('a[name='+name+']');\r
+        if(this.listItemClass){\r
+            elms.removeClass().addClass(this.listItemClass);\r
+            this.listItemClass = "";\r
+        }\r
+        elms.css('display','block');\r
+        \r
 \r
-        this.setSizable(true);\r
+        this.setFocusCycleRoot(this.focusable);\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
-       \r
         var subdiv = div.children();\r
-        var $J= me.$J;\r
+\r
+        //configure buttons. Text and classes are added here cause might have been changed\r
+        var topDiv = $(subdiv[0]);\r
+        var titleInput = topDiv.find(':text'); //$(':text') is equivalent to $('[type=text]') (selects all <input type="text"> elements)\r
+        var closeBtn = topDiv.find('a');\r
+        //if title doesn't exist or is hidden, set them to undefined (same for closeBtn).\r
+        //to check visibility, we dont use is(:visible) cause apparently\r
+        //width and height as zero mean hidden (I think that is the cause):\r
+        titleInput = titleInput.length ? $(titleInput.get(0)) : undefined;\r
+        closeBtn = closeBtn.length ? $(closeBtn.get(0)) : undefined;\r
+        if(this.showclose || this.title){\r
+            topDiv.css('paddingBottom','0.5ex').show(); //add padding to bottom\r
+            //is(.. return true if at least one of these elements matches the given arguments.\r
+            if(closeBtn){\r
+                if(this.closeButtonClass){\r
+                    closeBtn.addClass(this.closeButtonClass);\r
+                }\r
+                if(this.closeButtonTitle){\r
+                    closeBtn.html(this.closeButtonTitle);\r
+                }\r
+                closeBtn.css({\r
+                    'display':'inline-block'\r
+                }); //in order to set width and height on the element\r
+            }\r
+            if(titleInput){\r
+                titleInput.val(this.title).css({\r
+                    'display':'inline-block',\r
+                    'padding':'0',\r
+                    'margin':'0',\r
+                    'border':'0',\r
+                    'backgroundColor':'transparent',\r
+                    'marginRight' : '1ex'\r
+                }).attr('readonly','readonly');\r
+            }\r
+        }else{\r
+            topDiv.css('padding','0px');\r
+        }\r
+\r
+        var bottomDiv = $(subdiv[2]);\r
+        //do the same as above, ok must exist and be visible, otherwise is undefined\r
+        var okButton = bottomDiv.find('a');\r
+        okButton = okButton.length ? $(okButton.get(0)) : undefined;\r
+        \r
+        //see note above about why we dont use okButton.is(':visible')\r
+        if(this.showok){\r
+            bottomDiv.css('paddingTop','0.5ex').show(); //add padding to bottom\r
+            //is(.. return true if at least one of these elements matches the given arguments.\r
+            if(okButton){\r
+                if(this.okButtonClass){\r
+                    okButton.addClass(this.okButtonClass);\r
+                }\r
+                if(this.okButtonTitle){\r
+                    okButton.html(this.okButtonTitle);\r
+                }\r
+                okButton.css('display','inline-block'); //in order to set width and height on the element\r
+            }\r
+        }else{\r
+            bottomDiv.css('paddingTop','0px');\r
+        }\r
+\r
+        var centralDiv = $(subdiv[1]);\r
         //reset properties of the central div\r
-        $J(subdiv[1]).css({\r
+        centralDiv.css({\r
             'maxHeight':'',\r
             'maxWidth':'',\r
             'minHeight':'',\r
@@ -1437,41 +1516,81 @@ return element && element.length && element instanceof this.$J && element[0] !==
             'width':''\r
         });\r
 \r
-        var invoker = this.getInvoker();\r
-            \r
+        \r
+        var invoker = this.invoker;\r
+        \r
+        var sizeAsPopup = false;\r
         if(this.isClickElement(invoker)){\r
-            this.setBoundsAsPopup(invoker);\r
-            consolelog('sbap');\r
+            this.setBoundsAsPopup(invoker, true);\r
+            sizeAsPopup = true;\r
+            //storing click events, when showing clicking on an event must give the focus to the popup\r
+            //old handlers will be restored in close()\r
+            this['_tmpHandlers'+this.getId()] = undefined;\r
+            var focusElm = this.getFirstFocusableElement();\r
+            if(focusElm){\r
+            var oldHandlers = [];\r
+            var type = 'click';\r
+            var clickEvents =invoker.data("events")[type];\r
+            $.each(clickEvents, function(key, value) {\r
+                oldHandlers.push(value);\r
+            })\r
+            invoker.unbind(type); //remove (temporarily) the binding to the event.\r
+            //for instance, if we show the popup by clicking invoker, when the popup is shown do nothing\r
+            //on clicking invoker until popup.hide is called\r
+\r
+            this['_tmpHandlers'+this.getId()] = oldHandlers;\r
+            invoker.unbind(type).bind(type,function(evt){\r
+                //let the invoker have focus and let it be recognized as an element which does not blur the popup:\r
+                //invoker.attr('tabindex',0).attr(focusAttr,'true');\r
+                if(div.length && div.is(':visible')){\r
+                       focusElm.focus();\r
+                    return false;\r
+                }\r
+                //something wrong: close the popup and restore the hanlers\r
+                me.close.apply(me);\r
+                return false;\r
+            });\r
+            }\r
+\r
         }else{\r
-            this.setBoundsInside(invoker, this.getBoundsOfInvoker());\r
+            this.setBoundsInside(invoker, this.bounds, this.boundsexact, true);\r
         }\r
-        //this.callbackPreShow();\r
 \r
-        //            consolelog('maxHeight: '+ (div.height()-$J(subdiv[0]).outerHeight()-$J(subdiv[2]).outerHeight()-\r
-        //                ($J(subdiv[1]).outerHeight(true)-$J(subdiv[1]).height())));\r
-        //            consolelog('height: '+$J(subdiv[1]).height());\r
+        \r
 \r
         //set central div max height ONLY IF NECESSARY:\r
-        var maxHeight = (div.height()-$J(subdiv[0]).outerHeight()-$J(subdiv[2]).outerHeight()-\r
-            ($J(subdiv[1]).outerHeight(true)-$J(subdiv[1]).height()));\r
-        var height = $J(subdiv[1]).height();\r
-        if(maxHeight<height){\r
-            //alert('setting height');\r
-            $J(subdiv[1]).css('maxHeight',maxHeight+'px');\r
+        var maxHeight = (div.height()-topDiv.outerHeight()-bottomDiv.outerHeight()-\r
+            (centralDiv.outerHeight(true)-centralDiv.height()));\r
+        var height = centralDiv.height();\r
+        if(sizeAsPopup && maxHeight<height){\r
+            centralDiv.css('maxHeight',maxHeight+'px');\r
+        }else{\r
+            centralDiv.css({\r
+                'maxHeight': maxHeight+'px',\r
+                'minHeight': maxHeight+'px'\r
+            });\r
         }\r
-            \r
         //set central div max width ONLY IF NECESSARY:\r
         var maxWidth = div.width();\r
-        var width = $J(subdiv[1]).outerWidth(true);\r
-        if(maxWidth<width){\r
-            //alert('setting width');\r
-            $J(subdiv[1]).css('maxHeight',maxHeight+'px');\r
+        var width = $(subdiv[1]).outerWidth(true);\r
+        if(sizeAsPopup && maxWidth<width){\r
+            centralDiv.css('maxWidth',maxWidth+'px');\r
+        }else{\r
+            centralDiv.css({\r
+                'maxWidth': maxWidth+'px',\r
+                'minWidth':maxWidth+'px'\r
+            });\r
         }\r
-      \r
 \r
-       \r
-        //TODO: avoid clone and empty?\r
-        var shadow = div.clone(true,true).empty().css({\r
+        //set title and close button to span whole width, if necessary\r
+        if(titleInput || closeBtn){\r
+            var titleW = topDiv.width() - (closeBtn ? closeBtn.outerWidth(true) : 0) - (titleInput ? titleInput.outerWidth(true)-titleInput.width() : 0);\r
+            if(titleInput){\r
+                titleInput.css('width',titleW+'px');\r
+            }\r
+        }\r
+\r
+        var shadow = div.clone(false,false).empty().css({\r
             'backgroundColor':'#000',\r
             'borderColor':'#000',\r
             'visibility':'visible',\r
@@ -1482,32 +1601,33 @@ return element && element.length && element instanceof this.$J && element[0] !==
 \r
         \r
         var postShowFcn = function(){\r
+            me.trigger('show');\r
             var rect = me.getBounds.apply(me);\r
             shadow.css({\r
                 'left':(rect.x + me.shadowOffset)+'px',\r
                 'top':(rect.y + me.shadowOffset)+'px',\r
                 'width':(rect.width)+'px',\r
                 'height':(rect.height)+'px'\r
-            }).fadeTo(me.defaultFadeTime,me.shadowOpacity, function(){\r
+            }).fadeTo(me.fadInTime,me.shadowOpacity, function(){\r
                 var v = me.getFirstFocusableElement();\r
                 if(v){\r
                     v.focus();\r
                 }\r
             });\r
-\r
         }\r
 \r
-        div.hide().css('visibility','visible').show(this.defaultFadeTime,function(){\r
+        div.hide().css('visibility','visible').show(this.fadInTime,function(){\r
+            \r
             postShowFcn();\r
-            me.trigger('show');\r
+            \r
+            \r
         });\r
     };\r
     \r
-    p.setBoundsAsPopup = function(popupInvoker){\r
+    p.setBoundsAsPopup = function(popupInvoker, isSizable){\r
         var invoker = popupInvoker;\r
         var div = this.getDiv();\r
-        var wdw = this.$J(window);\r
-        var oldCss= this.isSizable() ?  undefined : this.setSizable(true);\r
+        var oldCss= isSizable ?  undefined : this.setSizable();\r
         \r
         var windowRectangle = this.getBoundsOf(wdw); //returns the window rectangle\r
 \r
@@ -1520,16 +1640,16 @@ return element && element.length && element instanceof this.$J && element[0] !==
         this.setMaxSize({\r
             height : spaceAbove>spaceBelow ? spaceAbove : spaceBelow,\r
             width: wdw.scrollLeft()+wdw.width()-invokerOffset.left\r
-        }); //width will be ignored (for the moment)\r
+        },isSizable); //width will be ignored (for the moment)\r
+        \r
         \r
-\r
         //setting the minimum size to the invoker width, minheight the same as maxHeight (see above)\r
         this.setMinSize({\r
             width: invoker.outerWidth()+this.shadowOffset //workaround to NOT consider the shadow, as offset below substracts the shadow\r
         //height : spaceAbove>spaceBelow ? spaceAbove : spaceBelow //why this? because if we click the popup a\r
         //computed height CH seems to be set. At subsequent popup show, CH will be the same UNLESS a new maxHeight lower than CH is set\r
         //however, we want CH to change even if a new maxHeight greater than CH is set\r
-        });\r
+        },isSizable);\r
 \r
         //setting the top and left. This must be done at last because popupDiv.outerHeight(true)\r
         //must have been computed according to the height set above...\r
@@ -1537,9 +1657,8 @@ return element && element.length && element instanceof this.$J && element[0] !==
             'left': invokerOffset.left,\r
             'top': (spaceAbove > spaceBelow ? invokerOffset.top -  div.outerHeight(true) :\r
                 invokerOffset.top + invokerOuterHeight)\r
-        });\r
+        },isSizable);\r
         if(oldCss){\r
-            this.setSizable(false);\r
             div.css({\r
                 'display':oldCss['display'],\r
                 'visibility':oldCss['visibility']\r
@@ -1551,27 +1670,29 @@ return element && element.length && element instanceof this.$J && element[0] !==
     //padding={top:0.25,left:0.25,bottom:0.25,right:0.25} will place the popupdiv at the center of parent\r
     //padding={top:25,left:25,bottom:25,right:25} will place the popupdiv at distances 25 px from parent sides\r
     //in other words, padding keys lower or euqals to 1 will be conbsidered as percentage, otherwise as absolute measures in px\r
-    p.setBoundsInside = function(parent, padding){\r
+    p.setBoundsInside = function(parent, pd, boundsExact, isSizable){\r
+\r
         var div = this.getDiv();\r
-        var oldCss = this.isSizable() ?  undefined : this.setSizable(true);\r
+        var oldCss = isSizable ?  undefined : this.setSizable();\r
 \r
         var bounds = this.getBoundsOf(parent);\r
+        \r
         var x=bounds.x;\r
         var y = bounds.y;\r
         var w = bounds.width\r
         var h = bounds.height;\r
         var pInt = parseInt;\r
         //rebuilding:\r
-        if(!padding){\r
-            padding = {\r
-                top:0,\r
-                left:0,\r
-                bottom:0,\r
-                right:0\r
-            };\r
-        }\r
+        \r
+        var padding = {\r
+            top: pd['top'],\r
+            left:pd['left'],\r
+            bottom:pd['bottom'],\r
+            right:pd['right']\r
+        };\r
+        \r
         for(var k in padding){\r
-            if(padding[k]<0){\r
+            if(padding[k]<=0){\r
                 padding[k]=0;\r
             }else if(padding[k]<=1){\r
                 padding[k] = k=='top' || k =='bottom' ? h*padding[k] : w*padding[k];\r
@@ -1579,16 +1700,49 @@ return element && element.length && element instanceof this.$J && element[0] !==
                 padding[k] = pInt(padding[k]);\r
             }\r
         }\r
-        this.setSize({\r
-            'width':w-padding['left']-padding['right'],\r
-            'height':w-padding['top']-padding['bottom']\r
-        });\r
-        this.offset({\r
-            'left':padding['left'],\r
-            'top': padding['top']\r
-        });\r
+\r
+        var maxSize = {\r
+            'width':w-padding['left']-padding['right']+this.shadowOffset,\r
+            'height':h-padding['top']-padding['bottom']+this.shadowOffset\r
+        };\r
+            \r
+        var vvvv ={\r
+            width:maxSize.width,\r
+            height:maxSize.height\r
+        };\r
+        this._convertSize(div, vvvv);\r
+           \r
+        if(boundsExact){\r
+            this.setMinSize({\r
+                width:maxSize.width,\r
+                height:maxSize.height\r
+            },isSizable); //a copy cause the argument will be modified\r
+            this.setMaxSize({\r
+                width:maxSize.width,\r
+                height:maxSize.height\r
+            }, isSizable); //a copy cause the argument will be modified\r
+            \r
+            this.offset({\r
+                'left':x + padding['left'],\r
+                'top': y + padding['top']\r
+            },isSizable);\r
+        }else{\r
+            this.setMaxSize({\r
+                width:maxSize.width,\r
+                height:maxSize.height\r
+            },isSizable); //a copy cause the argument will be modified\r
+            var spanLeft = maxSize.width - div.outerWidth(true);\r
+            var spanTop = maxSize.height - div.outerHeight(true);\r
+            this.offset({\r
+                'left':x + padding['left'] + (spanLeft > 0 ? spanLeft/2 : 0),\r
+                'top': y + padding['top'] +(spanTop > 0 ? spanTop/2 : 0)\r
+            },isSizable);\r
+\r
+        }\r
+        //convert to percentage in order to keep same dimensions when zooming\r
+        \r
+\r
         if(oldCss){\r
-            this.setSizable(false);\r
             div.css({\r
                 'display':oldCss['display'],\r
                 'visibility':oldCss['visibility']\r
@@ -1597,7 +1751,7 @@ return element && element.length && element instanceof this.$J && element[0] !==
     };\r
     p.getBounds = function(){\r
         return this.getBoundsOf(this.getDiv());\r
-    },\r
+    };\r
     //TODO: change argument\r
     p.getBoundsOf = function(jQueryElement){\r
         var ret = {\r
@@ -1606,11 +1760,10 @@ return element && element.length && element instanceof this.$J && element[0] !==
             width:0,\r
             height:0\r
         };\r
-        var w = window;\r
-        if(!jQueryElement){\r
-            jQueryElement = this.$J(w);\r
+        if(!jQueryElement || !(jQueryElement instanceof $)){\r
+            jQueryElement = wdw;\r
         }\r
-        if(jQueryElement[0] === w){\r
+        if(jQueryElement[0] === w_){\r
             ret.x = jQueryElement.scrollLeft();\r
             ret.y = jQueryElement.scrollTop();\r
         }else{\r
@@ -1621,11 +1774,11 @@ return element && element.length && element instanceof this.$J && element[0] !==
         ret.width = jQueryElement.width();\r
         ret.height = jQueryElement.height();\r
         return ret;\r
-    }\r
+    };\r
 \r
-    p.setMaxSize = function(size){\r
+    p.setMaxSize = function(size, isSizable){\r
         var div = this.getDiv();\r
-        var oldCss= this.isSizable() ?  undefined : this.setSizable(true);\r
+        var oldCss = isSizable ?  undefined : this.setSizable();\r
 \r
         this._convertSize(div, size);\r
         var css = {};\r
@@ -1639,7 +1792,6 @@ return element && element.length && element instanceof this.$J && element[0] !==
             div.css(css);\r
         }\r
         if(oldCss){\r
-            this.setSizable(false);\r
             div.css({\r
                 'display':oldCss['display'],\r
                 'visibility':oldCss['visibility'],\r
@@ -1649,9 +1801,9 @@ return element && element.length && element instanceof this.$J && element[0] !==
         }\r
         return size;\r
     };\r
-    p.setMinSize = function(size){\r
+    p.setMinSize = function(size, isSizable){\r
         var div = this.getDiv();\r
-        var oldCss= this.isSizable() ?  undefined : this.setSizable(true);\r
+        var oldCss= isSizable ?  undefined : this.setSizable();\r
 \r
         this._convertSize(div, size);\r
         var css = {};\r
@@ -1665,7 +1817,6 @@ return element && element.length && element instanceof this.$J && element[0] !==
             div.css(css);\r
         }\r
         if(oldCss){\r
-            this.setSizable(false);\r
             div.css({\r
                 'display':oldCss['display'],\r
                 'visibility':oldCss['visibility'],\r
@@ -1674,7 +1825,7 @@ return element && element.length && element instanceof this.$J && element[0] !==
             });\r
         }\r
         return size;\r
-    },\r
+    };\r
     //div must be display!=hidden. size is a dict with at least one of the fields 'width' and 'height'\r
     //TODO: check if div is sizable????\r
     p._convertSize = function(div, size){\r
@@ -1689,32 +1840,15 @@ return element && element.length && element instanceof this.$J && element[0] !==
         if('height' in size){\r
             size.height -= (eD.height + this.shadowOffset);\r
         }\r
-    },\r
-\r
-    p.setSize = function(size){\r
-        var div = this.getDiv();\r
-        var oldCss= this.isSizable() ?  undefined : this.setSizable(true);\r
-\r
-        this.setMaxSize(size);\r
-        this.setMinSize(size);\r
-        if(oldCss){\r
-            this.setSizable(false);\r
-            div.css({\r
-                'display':oldCss['display'],\r
-                'visibility':oldCss['visibility'],\r
-                'top':oldCss['top'],\r
-                'left':oldCss['left']\r
-            });\r
-        }\r
     };\r
 \r
-    p.offset = function(offs){\r
+    p.offset = function(offs, isSizable){\r
         var div = this.getDiv();\r
-        var oldCss= this.isSizable() ?  undefined : this.setSizable(true);\r
+        var oldCss= isSizable?  undefined : this.setSizable();\r
+        //offset does NOT consider margins. Do we have top and left?\r
         \r
         this.getDiv().offset(offs);\r
         if(oldCss){\r
-            this.setSizable(false);\r
             div.css({\r
                 'display':oldCss['display'],\r
                 'visibility':oldCss['visibility'],\r
@@ -1726,117 +1860,103 @@ return element && element.length && element instanceof this.$J && element[0] !==
         }\r
     };\r
 \r
+    p.isClosing = false;\r
     p.close = function(){\r
+        this.isClosing = true;\r
+        this.setFocusCycleRoot(false);\r
         var div = this.getDiv();\r
-        var $J = this.$J;\r
-        var shadow = $J('#'+this.getShadowDivId());\r
-        //        $J.each(div, function(i,e){\r
-        //            shadow = shadow.add($J('#'+$J(e).attr('id')+'_shadow'));\r
-        //        });\r
+        var shadow = $('#'+this.getShadowDivId());\r
         shadow.remove();\r
-        if(this.getCloseOperation() == 'remove'){\r
-            div.remove(this.defaultFadeOutTime);\r
-        }else{\r
-            div.hide(this.defaultFadeOutTime);\r
+        var me = this;\r
+        var remove = this.defaultCloseOperation == 'remove';\r
+        div.hide(this.fadeOutTime, function(){\r
+            \r
+            if(remove){\r
+                div.remove();\r
+                \r
+            //this is because all bindings will be removed, including blur events\r
+            //we remove this.getFocusAttr() to reupdate focus cycle root when calling show again\r
+            }\r
+            \r
+            //restore event data on invoker, if any\r
+            var id = '_tmpHandlers'+me.getId();\r
+            if(me[id]){\r
+                var oldHandlers = me[id];\r
+                delete  me[id];\r
+                me.invoker.unbind('click');\r
+                for(var k =0; k< oldHandlers.length; k++){\r
+                    var h = oldHandlers[k];\r
+                    me.invoker.bind(h.type+(h.namespace ? "."+h.namespace : ""),h.handler);\r
+                }\r
+            }\r
+\r
+            me.isClosing = false;\r
+            me.trigger('close');\r
+        });\r
+        \r
+    };\r
+\r
+\r
+    p.setSizable = function(){\r
+        //if false, just update the flag\r
+        var div = this.getDiv();\r
+\r
+        if(!div.parent().length){\r
+            div.appendTo('body');\r
+        }\r
+        var keys = ['display','visibility','left','top','maxWidth','maxHeight','minWidth','minHeight'];\r
+        var css = {};\r
+        for(var i=0; i<keys.length; i++){\r
+            css[keys[i]] = div.css(keys[i]);\r
         }\r
-        this.setSizable(false);\r
-        this.trigger('close');\r
+        div.offset({\r
+            'left':wdw.scrollLeft(),\r
+            'top':wdw.scrollTop()\r
+        });\r
+        //set the div invisible but displayable to calculate the size (callbackPreShow)\r
+        div.css({\r
+            'visibility':'hidden',\r
+            'maxWidth':'',\r
+            'maxHeight':'',\r
+            'minWidth':'',\r
+            'minHeight':'',\r
+            'height':'',\r
+            'width':''\r
+        }).show();\r
+\r
+\r
+        return css;\r
+    }\r
+    p.getShadowDivId = function(){\r
+        return this.getId()+"_shadow";\r
+    }\r
+\r
+    p.getFocusAttr = function(){\r
+        return this.getId()+"_focus";\r
+    }\r
+\r
+    p.getListItemName = function(){\r
+        return this.getId()+"_listitem";\r
     }\r
 \r
     \r
 })(PopupDiv.prototype);\r
 \r
+//default PopupDiv properties in telemeta\r
+PopupDiv.listItemClass = 'component_icon list_item icon_playlist';\r
+PopupDiv.shadowOffset = 4;\r
+PopupDiv.popupClass = 'control component';\r
+PopupDiv.popupCss = {\r
+    'border':'1px solid #666',\r
+    'padding':'1ex'\r
+};\r
+PopupDiv.okButtonTitle =  'Ok';\r
+PopupDiv.okButtonClass =  'component_icon button icon_ok';\r
+PopupDiv.closeButtonTitle =  '';\r
+PopupDiv.closeButtonClass =  'markersdivDelete';\r
+PopupDiv.fadInTime = 'fast',\r
+    PopupDiv.fadeOutTime = 0,\r
+    PopupDiv.shadowOpacity = 0.3;\r
+\r
+\r
 \r
-//p.hide = function(){\r
-//        var div = this.getDiv();\r
-//        var $J = this.$J;\r
-//        var shadow = $J([]);\r
-//        $J.each(div, function(i,e){\r
-//            shadow = shadow.add($J('#'+$J(e).attr('id')+'_shadow'));\r
-//        });\r
-//        var both = div.add(shadow);\r
-//        //calling hide with the specified arguments:\r
-//        var removeShadow = new function(){\r
-//            shadow.remove();\r
-//        };\r
-//        var args = [];\r
-//        for(var i=1; i<arguments.length; i++){\r
-//            args.push(arguments[i]);\r
-//        }\r
-//        if(args.length<1 || !(args[args.length-1] instanceof Function)){\r
-//            args.push(removeShadow);\r
-//        }else{\r
-//            var f = args[args.length-1];\r
-//            var newf = function(){\r
-//                removeShadow();\r
-//                f();\r
-//            }\r
-//            args[args.length-1] = newf;\r
-//        }\r
-//        both.hide.apply(both, args);\r
-//        this.setSizable(false);\r
-//    };\r
-//\r
-//    p.remove = function(){\r
-//        var div = this.getDiv();\r
-//        var shadow = $J('#'+div.attr('id')+'_shadow');\r
-//        var both = div.add(shadow);\r
-//        both.remove();\r
-//        this.setSizable(false);\r
-//    };\r
-\r
-\r
-//default private functions not accessible from outside (memeory leaks? dont think so)\r
-//    var setAsPopupOf = function(popupDiv, invoker){\r
-////        if(!(invoker.is('a') || invoker.is('input[type=button]') || invoker.is('button') ||\r
-////            invoker.is('input[type=submit]'))){\r
-////            return;\r
-////        }\r
-//\r
-//        invoker.attr('tabindex',0).attr(this.focusId,'true');\r
-//        //invoker.attr(this.getFocusId(),'true');\r
-//        var me =this;\r
-//        this.callbackPreShow = function(){\r
-//            me.setBoundsAsPopup.apply(me,[invoker]);\r
-//        };\r
-//        this.callbackPostShow = function(){\r
-//            var fcn = removeOnBlur ? me.remove : me.hide;\r
-//            me.setFocusable.apply(me);\r
-//            var elm = me.getFirstFocusableElement();\r
-//            elm.focus();\r
-//        };\r
-//\r
-//        var popupDiv = this.getDiv();\r
-//        invoker.unbind('click').bind('click',function(evt){\r
-//            if(popupDiv.length && popupDiv.is(':visible')){\r
-//                me.getFirstFocusableElement().focus();\r
-//                return false;\r
-//            }\r
-//            me.show.apply(me);\r
-//            return false;\r
-//        });\r
-//    };\r
-//\r
-//    p.setAsWindowDialog = function(timeInMsec, padding){\r
-//\r
-//        var me =this;\r
-//        this.callbackPreShow = function(){\r
-//            me.setBoundsInside.apply(me,[padding]);\r
-//        }\r
-//\r
-//        if(timeInMsec){\r
-//            this.callbackPostShow = function(){\r
-//                setTimeout(timeInMsec, function(){\r
-//                    me.remove.apply(me);\r
-//                });\r
-//            }\r
-//        }else{\r
-//            this.callbackPostShow = function(){\r
-//                var elm = me.setFocusable.apply(me,function(){\r
-//                    me.remove.apply(me);\r
-//                });\r
-//                elm.focus();\r
-//            };\r
-//        }\r
-//    };\r
-//
\ No newline at end of file
index b22f5fca616ee7e8b0bdde901657257866a5fe7b..24a9dcf74735ec7b9306aa816bca6a06d50b6bc0 100644 (file)
@@ -147,9 +147,11 @@ var MarkerMapDiv = TimesideArray.extend({
         var me = this;
         div.find('.markersdivDescription').unbind('focus').focus(function(){
             me.setFocus(index,true);
+            me.fire('focus', {'index': index});
         });
         div.find('.markersdivTitle').unbind('focus').focus(function(){
             me.setFocus(index,true);
+            me.fire('focus', {'index': index});
         });
         div.find('.markersdivEdit').unbind('click').click( function(){
             me.setEditMode(index);
@@ -239,6 +241,7 @@ var MarkerMapDiv = TimesideArray.extend({
         }
         
         var me = this;
+
         e_deleteButton.unbind('click').click( function(){
             if(!(marker.isSavedOnServer) || confirm(gettrans('delete the marker permanently?'))){
                 me.fire('remove',{
@@ -264,11 +267,16 @@ var MarkerMapDiv = TimesideArray.extend({
             return false; //avoid scrolling of the page on anchor click
         });
 
-        //            if(isEditing){
-        //                startEdit();
-        //            }else{
-        //                this.updateTitleWidth();
-        //            }
+
+        e_titleText.keydown(function(event){
+           if(e_okButton.is(':visible')){
+               if (event.keyCode == '13') {
+                    event.preventDefault();
+                    e_okButton.trigger('click');
+                }
+           }
+        });
+
         return div;
     }
 
index ece27fada398f2cff83780123d5f95d54c485cb7..b1de828bb83a38f3ab1f23d7dff295ae47f3b36a 100644 (file)
@@ -645,6 +645,17 @@ var Player = TimesideClass.extend({
                 rulerRemove.apply(ruler, [data.index]);
             });
 
+            //finally, focus events (WHEN the user CLICKS on a textinput or a textarea on a markerdiv)
+            mapUI.bind('focus', function(data){
+                if(data && 'index' in data){
+                    if(data.index>=0 && data.index<map.length){
+                        var offset = map.toArray()[data.index].offset;
+                        player.setSoundPosition(offset);
+                        player.getRuler().movePointer(offset);
+                    }
+                }
+            });
+
             jQuery('#loading_span').empty().remove();
             //TODO: move this in load_player?
             //                    setUpPlayerTabs([jQuery('#tab_analysis'), jQuery('#tab_markers')],
index 70cb940603230f6052f2e3596eb33c3494b32783..ef217a0732432f4a3eb77b920ac01198664a07d5 100644 (file)
@@ -65,6 +65,29 @@ var playlistUtils = {
         return popup.show(content,event);
     },
 
+
+    bindToNewPlaylistAction: function(anchorElement){
+
+      var t = gettrans('title');
+        var d = gettrans('description');
+        var dd = {};
+        dd[t]='';
+        dd[d]='';
+        var playlist = this;
+          var ppp_ = new PopupDiv({'content':dd,
+          focusable:true,  invoker:anchorElement, showclose:true, showok:true, ok:function(data){
+              if(!data[t] && !data[d]){
+                  return;
+              }
+              //convert language
+              playlist.add({'title':data[t],'description':data[d]});
+          } });
+consolelog(anchorElement);
+      anchorElement.unbind('click').click(function(){ppp_.show();});
+//        p.okButtonTitle = 'A';
+//        ppp_.show();
+    },
+
     add : function(dictionary){
 
         if(dictionary.public_id===undefined){
index 72f46cd3d9f9faa1c51af2fc9311b247c8e8ede3..aa3cd5f44975ffde7ca0f3b67b89712ca334463b 100644 (file)
@@ -5,11 +5,13 @@
 {% block extra_javascript %}
 <script src="{% url telemeta-timeside "src/playlist.js" %}" type="text/javascript"></script>
 <script>
-    jQuery(document).ready(function(){
-        jQuery('#_new_playlist').bind("click.bla",function(e){var p = popup;
-            return p.show(p.createDivDialog({'title':'','description':''}, function(data){playlistUtils.add(data)}),e);
-        });
+    jQuery(window).ready(function(){
+//        jQuery('#_new_playlist').bind("click.bla",function(e){var p = popup;
+//            return p.show(p.createDivDialog({'title':'','description':''}, function(data){playlistUtils.add(data)}),e);
+//        });
+ playlistUtils.bindToNewPlaylistAction(jQuery('#_new_playlist'));
     });
+   
 </script>
 {% endblock %}
 
index bf0997422f8f6afa761d37a07762b6037b97a8df..bee81e25d193aac6e2d51b04431ee665ca2e7fa1 100644 (file)
         }
     });
 
-    jQuery(document).ready(function(){
-//        var ar = [];
-//        for(var i=0; i<100; i++){
-//            ar.push('<a href=#>'+i+'</a>');
-//        }
-//        var p = new PopupDiv(ar.join('<br/>'));
-//        p.getDiv().find('a').each(function(i,aa){
-//                jQuery(aa).click(function(){alert(jQuery(aa).html());p.hide();return false;});
-//            });
-
-        var p = new PopupDiv({'close me and see what you can get':function(){p.hide();}});
-//        var p = new PopupDiv({'close me and see what you can get':function(){p.hide();},'options':['ferrari','maserati','bmw'],'inputa':'default','liar':true});
-        var a = jQuery('<a/>').attr('href','#').html('clickme');
-
-        p.setInvoker(a);
-        jQuery('body').append(a);
-    });
 </script>
 <!--item.approx_duration-->