details="\nThe server responded witha status of "+jqXHR.status+" ("+\r
jqXHR.statusText+")\n\nDetails (request responseText):\n"+jqXHR.responseText;\r
}\r
- alert("ERROR: Failed to save marker"+details);\r
+ alert("ERROR: Failed to save"+details);\r
}\r
}\r
});\r
\r
};\r
-uniqid = function() {\r
+var uniqid = function() {\r
var d = new Date();\r
return new String(d.getTime() + '' + Math.floor(Math.random() * 1000000)).substr(0, 18);\r
-}\r
-popupDialog = function(invokerElement,divContent,callbackOnOk){\r
- var $J = jQuery;\r
- var div = $J("<div/>")\r
- var divShadow = $J('<div/>')\r
- // var topDiv = $J('<div/>')\r
- // .append($J('<span/>').html(dialogTitle ? dialogTitle : " "))\r
- // .append($J('<a/>').\r
- // css({'float':'right','padding':'1ex','backgroundImage':'url("/images/del_marker.png")',\r
- // 'backgroundRepeat':'no-repeat'})\r
- // .attr('href','#').bind('click',function(){div.remove();}));\r
- \r
- var okB = $J('<a/>')\r
- .addClass('mediaitem_button')\r
- .addClass('mediaitem_button_ok')\r
- .attr('href',"#")\r
- .html("Ok")\r
- .css({\r
- 'float':'right',\r
- 'marginLeft':'0.5ex'\r
- })\r
- .bind('click',function(){\r
- div.remove();\r
- divShadow.remove();\r
- if(callbackOnOk){\r
- callbackOnOk();\r
- }\r
- return false;\r
- })\r
- var cancelB = okB.clone(true,true)\r
- .html('Cancel')\r
- .removeClass('mediaitem_button_ok')\r
- .addClass('mediaitem_button_cancel')\r
- .unbind('click').bind('click',function(){\r
- div.fadeOut('fast', function() {\r
- div.remove();\r
- divShadow.remove();\r
- });\r
- return false;\r
- })\r
+};\r
\r
- var bottomDiv = $J('<div/>').css({\r
- 'marginTop':'0.5ex'\r
- }).append(cancelB).append(okB);\r
+var popup={\r
+ _cfg_:{\r
+ jQuery:jQuery,\r
+ div: function(){\r
+ var div = this.jQuery('<div/>').css({ //this is _cfg_\r
+ position: 'absolute',\r
+ overflow:'auto', //necessary to properly display the content\r
+ border: '1px solid #DDD',\r
+ backgroundColor:'#f9f9f9', //same as mediaitem_button (see telemeta.css)\r
+ padding:'1ex',\r
+ margin: '0',\r
+ display: 'none',\r
+ zIndex:1000\r
+ });\r
+ if(this.className){\r
+ div.addClass(this.className);\r
+ }\r
+ return div;\r
+ },\r
+ className: undefined,\r
+ divShadow: function(){\r
+ return this.jQuery('<div/>').css({ //this is _cfg_\r
+ position: 'absolute',\r
+ display: 'none',\r
+ overflow:'visible',\r
+ backgroundColor:'#000',\r
+ zIndex:999\r
+ });\r
+ },\r
+ // mouseDownNamespace : "mousedown.popup__",\r
+ // keyDownNamespace : "keydown.popup__",\r
\r
- div.append(divContent).append(bottomDiv);\r
+ //namespace: 'popup__', //used for namespaces when binding click to document\r
+ handlersToRestore: [],\r
+ event: null,\r
+ divsToDelete:null,\r
+ toggleBind: function(element, functionE){\r
+ var clickNamespace = "click.popup__";\r
+ var keydownNamespace = "keydown.popup__";\r
+ element.unbind(clickNamespace);\r
+ element.unbind(keydownNamespace);\r
+ if(functionE){\r
+ element.bind(clickNamespace, functionE);\r
+ element.bind(keydownNamespace,functionE);\r
+ }\r
+ }\r
+ },\r
\r
- var pos = invokerElement.position();\r
- var top = (invokerElement.outerHeight(true)+pos.top);\r
- var left = pos.left;\r
- div.css({\r
- padding: '1ex',\r
- border: '1px solid #DDD',\r
- display: 'none',\r
- position: 'absolute',\r
- left: pos.left + 'px',\r
- top:top+"px",\r
- zIndex:1000,\r
- backgroundColor:'#eee'\r
+ isShowing: function(){\r
+ return this._cfg_.divsToDelete ? true : false;\r
+ },\r
+\r
\r
- });\r
- div.insertBefore(invokerElement);\r
- divShadow.css({\r
- 'backgroundColor':'#000',\r
- position:'absolute',\r
- zIndex:900,\r
- width:div.outerWidth(),\r
- height:div.outerHeight(),\r
- left: (left + 5)+'px',\r
- top:(top+5)+"px"\r
- });\r
- div.fadeIn('fast', function() {\r
- divShadow.insertAfter(div);\r
- divShadow.fadeTo(0,0.4);\r
- cancelB.focus();\r
- });\r
-}\r
-popup={\r
- id: '_popup_id__',\r
- isFocused:false,\r
hide: function(){\r
- var $J = jQuery;\r
- $J(document).unbind('click');\r
- $J(document).unbind('keydown');\r
- var popupdiv = $J(this.id);\r
- if(popupdiv){\r
- popupdiv.remove();\r
- this.isFocused = false;\r
+ var toggleBind = this._cfg_.toggleBind;\r
+ \r
+ var $J = this._cfg_.jQuery;\r
+\r
+ toggleBind($J(document));\r
+ if(this._cfg_.divsToDelete){\r
+ for(var i=0; i < this._cfg_.divsToDelete.length; i++){\r
+ this._cfg_.divsToDelete[i].empty().remove();\r
+ }\r
+ }\r
+ if(this._cfg_.event && this._cfg_.handlersToRestore){\r
+ var type = this._cfg_.event.type; //which should be the same as h.type below, without namespaces?\r
+ var invokerElement = this._cfg_.event.target;\r
+ if(invokerElement){\r
+ var e = $J(invokerElement);\r
+ toggleBind(e);\r
+ if(type){\r
+ //e.unbind(type);\r
+ for(var i=0; i<this._cfg_.handlersToRestore.length; i++){\r
+ var h = this._cfg_.handlersToRestore[i];\r
+ var functionCode = h.handler;\r
+ var namespace = ""+h.namespace;\r
+ if(namespace.length>0){\r
+ namespace="."+namespace;\r
+ }\r
+ var what = h.type+ namespace;\r
+ e.bind(what, functionCode);\r
+ }\r
+ }\r
+ }\r
}\r
+ this._cfg_.event=null;\r
+ this._cfg_.handlersToRestore=null;\r
},\r
- show:function(invokerElement,divContent){\r
- var popupId = this.id;\r
- var createDiv = function(){\r
- return jQuery("<div/>").append(jQuery("<div/>").css({\r
- 'backgroundColor':'#000',\r
- position:'absolute',\r
- bottom:0,\r
- right:0,\r
- top:'5px',\r
- left:'5px'\r
- }))\r
- .append(\r
- jQuery("<div/>").css({\r
- position: 'absolute',\r
- top:0,\r
- left:0,\r
- padding: '1ex',\r
- border: '1px solid #DDD',\r
- backgroundColor:'#eee'\r
- })).attr('id',popupId).css({\r
- display: 'none',\r
- position: 'absolute',\r
- zIndex:1000\r
- });\r
+\r
+ show:function(content, optionalEvent){\r
+ //if showing, hide\r
+ if(this.isShowing()){\r
+ this.hide();\r
}\r
- var $J = jQuery;\r
- var div = createDiv()\r
\r
- //adding\r
- div.insertBefore(invokerElement);\r
- \r
- var mainDiv = $J(div.children()[1]).append(divContent);\r
- var me = this;\r
- var hide = this.hide;\r
+ var $J = this._cfg_.jQuery;\r
+ var div = this._cfg_.div();\r
+ //toggleBind sets the functions to hiding/keep shown the popup when clicking or\r
+ //using the keyboard keys\r
+ var toggleBind = this._cfg_.toggleBind;\r
\r
- var children = $J(divContent).find('*');\r
- $(children).each(function(){\r
- $J(this).focus(function(){\r
- me.isFocused = true;\r
+ //remove the callback on invoker so that clicking on invoker does nothing\r
+ //moreover, toggleBind on invoker so that clicking invoker doesn't hide the popup\r
+ this.oldCallback = undefined;\r
+ var oldHandlers=[];\r
+ var invokerElement = optionalEvent && optionalEvent.target ? $J(optionalEvent.target) : undefined;\r
+ if(invokerElement){\r
+ optionalEvent.stopPropagation(); //othewrwise the popup hides immediately\r
+ //cause the event is catched from the document click (added later, see below)\r
+ // but apparently as soon as we add it it catches even the current event)\r
+ var type = optionalEvent.type;\r
+ var clickEvents =invokerElement.data("events")[type];\r
+ $J.each(clickEvents, function(key, value) {\r
+ oldHandlers.push(value);\r
+ })\r
+ invokerElement.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
+ toggleBind(invokerElement,function(e){ //add bindings to stop cancel the popup in case the invoker is clicked again\r
+ e.stopPropagation();\r
+ return false;\r
});\r
- $J(this).blur(function(){\r
- me.isFocused = false;\r
+ }\r
+ //store the functions removed from invoker, if any, to restore them in this.hide\r
+ this._cfg_.handlersToRestore = oldHandlers;\r
+ this._cfg_.event = optionalEvent;\r
+ \r
+ //toggleBind on each child of content so that clicking and pressing keys on\r
+ //a child doesn't hide the popup\r
+ var children = $J(content).find('*');\r
+ $J(children).each(function(){\r
+ toggleBind($(this),function(e){\r
+ e.stopPropagation();\r
+ return false;\r
});\r
});\r
+ //showing\r
+ var doc = $J(document);\r
+ $J('body').append(div);\r
\r
- //setting positions:\r
- var pos = invokerElement.position();\r
- var top = (invokerElement.outerHeight(true)+pos.top);\r
- var left = pos.left;\r
+ content.css('position','static'); //this is really important to place the content in the normal flow\r
+ //within the div. static is the default\r
+ content.show(); //in case the div is display:none\r
+ div.append(content);\r
+\r
+ //positioning div: center of the screen if no invoker, below the invoker otherwise\r
+ var wdow = $J(window); //reference the window object (doing it once speeds up a bit performances)\r
+ var windowH = wdow.height();\r
+ var windowW = wdow.width();\r
+ var position = div.offset();\r
+ var shadowOffset=5;\r
+ var size = {\r
+ width:div.outerWidth(true)+shadowOffset,\r
+ height:div.outerHeight(true)+shadowOffset\r
+ };\r
+ if(invokerElement){\r
+ position = invokerElement.offset();\r
+ position.top+= invokerElement.outerHeight(true);\r
+ }else{\r
+ position.top = (windowH-size.height)/2;\r
+ position.left = (windowW-size.width)/2;\r
+ }\r
+ //position div. This must be done immediately cause here below we want to get the div offset\r
+ //(div position in absolute - ie, document's - coordinates)\r
div.css({\r
- left: left + 'px',\r
- top:top+"px"\r
+ 'top': position.top,\r
+ 'left': position.left,\r
+ 'right': 'auto', //in case right has been set by some css class rule\r
+ 'bottom': 'auto' //see above...\r
});\r
+ //set the maximum size\r
+ //due to overflow:auto a scrollbar will automatically appear\r
+ var max = Math.max; //reference max immediately (speeds up performances a bit)\r
+ var maxSize = {\r
+ width: max(20,windowW + wdow.scrollLeft() -position.left-shadowOffset),\r
+ height: max(20, (windowH + wdow.scrollTop() -position.top- shadowOffset))\r
+ }\r
+ //position div and size:\r
+ var divPadding = {left: div.outerWidth()-div.width(), top:div.outerHeight()-div.height()}; //setting width on a div means the width(),\r
+ //but calculations here are made according to outerWidth(true), so we need this variable (se below)\r
\r
- \r
- //showing\r
- div.fadeIn('fast', function() {\r
- //now that is displayed, set the parent div size (which affects the shadow, too)\r
- var w = mainDiv.outerWidth();\r
- var h = mainDiv.outerHeight();\r
- div.css({\r
- width:(w+5)+'px',\r
- height:(h+5)+'px'\r
- });\r
- //show the shadow\r
- $J(div.children()[0]).fadeTo(0,0.4);\r
- var inputs = $J(divContent).find(':input');\r
- me.isFocused=false;\r
+ div.css({\r
+ 'maxWidth': maxSize.width-divPadding.left,\r
+ 'maxHeight': maxSize.height-divPadding.top\r
+ });\r
+ //last thing: if invoker element exist, set width at least invoker element width\r
+ if(invokerElement){\r
+ var iEw = invokerElement.outerWidth(); //no margins considered\r
+ if(iEw<maxSize.width && iEw>div.outerWidth()){\r
+ div.css({\r
+ 'minWidth':iEw-divPadding.left\r
+ });\r
+ }\r
+ }\r
+ var divShadow = this._cfg_.divShadow().insertAfter(div);\r
+ // //position div shadow:\r
+ // var divShadow = this._cfg_.divShadow().css({\r
+ // 'top': (position.top+shadowOffset),\r
+ // 'left': (position.left+shadowOffset),\r
+ // 'width': div.outerWidth(true),\r
+ // 'height': div.outerHeight(true)\r
+ // }).insertAfter(div).fadeTo(0,0.4);\r
+ //\r
+ // //set focus to the first input component, if any. Otherwise try with anchors, otherwise do nothing\r
+ // var inputs = $J(div).find(':input');\r
+ // if(inputs && inputs[0]){\r
+ // inputs[0].focus();\r
+ // }else{\r
+ // inputs = $J(div).find('a');\r
+ // if(inputs && inputs[0]){\r
+ // inputs[0].focus();\r
+ // }\r
+ // }\r
+ //\r
+ //store the divs to be removed\r
+ this._cfg_.divsToDelete = [div,divShadow];\r
+ //add a listener to the document. If one of the content children is clicked/keypressed,\r
+ //we won't come here. Otherwise hide popup\r
+ var me = this;\r
+ var hide = this.hide;\r
+ toggleBind(doc,function(e){\r
+ hide.apply(me);\r
+ e.stopPropagation();\r
+ });\r
+ div.show(300, function(){ //400: basically in between fast (200) and slow (600)\r
+ //position div shadow:\r
+ divShadow.css({\r
+ 'top': (position.top+shadowOffset),\r
+ 'left': (position.left+shadowOffset),\r
+ 'width': div.outerWidth(true),\r
+ 'height': div.outerHeight(true)\r
+ }).fadeTo(0,0.4);\r
+\r
+ //set focus to the first input component, if any. Otherwise try with anchors, otherwise do nothing\r
+ var inputs = $J(div).find(':input');\r
if(inputs && inputs[0]){\r
inputs[0].focus();\r
- //me.isFocused=true;\r
- }\r
- jQuery(document).bind('click', function(){\r
- if(me.isFocused){\r
- return;\r
- }\r
- hide.apply(me);\r
- });\r
- jQuery(document).bind('keydown', function(){\r
- if(me.isFocused){\r
- return;\r
+ }else{\r
+ inputs = $J(div).find('a');\r
+ if(inputs && inputs[0]){\r
+ inputs[0].focus();\r
}\r
- hide.apply(me);\r
- });\r
+ }\r
});\r
+ return false; //to avoid scrolling if we clicked on an anchor\r
+ },\r
+\r
+ //field must be a dictionary of label:defaultValues (both strings)\r
+ //callbackOnOk is the callback to be executed on ok, if null ok will simply hide the dialog\r
+ //otherwise it must be a function accepting\r
+ createDivDialog : function(field,callbackOnOk){\r
+\r
+ var $J = this._cfg_.jQuery;\r
+ var table = $J('<table/>');\r
+ var fieldElms = {};\r
+ for(var label in field){\r
+ var input = $('<input/>')\r
+ .attr('type','text').val(field[label]).attr("name",label);\r
+ table.append($J('<tr/>')\r
+ .append($J('<td/>').html(label))\r
+ .append($J('<td/>').append(input)));\r
+ fieldElms[label]=input;\r
+ }\r
+\r
+ var p = this;\r
+ var onCancel= function(){\r
+ p.hide();\r
+ return false;\r
+ };\r
+ var onOk= function(){\r
+ if(callbackOnOk){\r
+ var ret = {};\r
+ var inputs = table.find("input");\r
+ for(var ipt in inputs){\r
+ var i = $(ipt);\r
+ ret[i.attr('name')] = i.val();\r
+ }\r
+ callbackOnOk(ret);\r
+ return false;\r
+ }else{\r
+ return onCancel();\r
+ }\r
+ };\r
+ var subdiv = $J('<div/>').append(\r
+ $J('<a/>').\r
+ html('Ok').\r
+ css('float','right').\r
+ addClass('mediaitem_button').\r
+ addClass('mediaitem_button_ok').\r
+ attr('href','#').\r
+ click(function(){\r
+ return onOk();\r
+ })\r
+ );\r
+ if(callbackOnOk){\r
+ subdiv.append(\r
+ $J('<a/>').\r
+ html('Cancel').\r
+ css('float','right').\r
+ addClass('mediaitem_button').\r
+ addClass('mediaitem_button_cancel').\r
+ attr('href','#').\r
+ click(function(){\r
+ return onCancel();\r
+ })\r
+ );\r
+ }\r
+ //popupDialog(element,table,onOk);\r
+ return $J('<div/>').append(table).append(subdiv);\r
}\r
\r
}\r
var playlist = {
- add : function(element){
- var $J = jQuery;
-
- var dText = $('<input/>')
- .attr('type','text').val("");
- var tText = $('<input/>')
- .attr('type','text').val("");
-
- var table = $J('<table/>')
- .append($J('<tr/>')
- .append($J('<td/>').html('title'))
- .append($J('<td/>').append(tText)))
- .append($J('<tr/>')
- .append($J('<td/>').html('description'))
- .append($J('<td/>').append(dText)));
-
- var onOk= function(){
- var pl = [{
- "public_id":uniqid(),
- "title":tText.val(),
- "description":dText.val(),
- user:CURRENT_USER_NAME
- }];
- json(pl,'telemeta.add_playlist',function(){
- window.location.reload();
- },true);
- };
- //popupDialog(element,table,onOk);
- popup.show(element,table);
- },
+
+ // add : function(event){
+ //
+ // var $J = jQuery;
+ //
+ // var dText = $('<input/>')
+ // .attr('type','text').val("");
+ // var tText = $('<input/>')
+ // .attr('type','text').val("");
+ //
+ // var table = $J('<table/>')
+ // .append($J('<tr/>')
+ // .append($J('<td/>').html('title'))
+ // .append($J('<td/>').append(tText)))
+ // .append($J('<tr/>')
+ // .append($J('<td/>').html('description'))
+ // .append($J('<td/>').append(dText)));
+ //
+ // var onOk= function(){
+ // var pl = [{
+ // "public_id":uniqid(),
+ // "title":tText.val(),
+ // "description":dText.val(),
+ // user:CURRENT_USER_NAME
+ // }];
+ // json(pl,'telemeta.add_playlist',function(){
+ // window.location.reload();
+ // },true);
+ // };
+ // var onCancel= function(){
+ // popup.hide();
+ // return false;
+ // };
+ // var subdiv = $J('<div/>').append(
+ // $J('<a/>').
+ // html('Cancel').
+ // css('float','right').
+ // addClass('mediaitem_button').
+ // addClass('mediaitem_button_cancel').
+ // attr('href','#').
+ // click(function(){
+ // return onCancel();
+ // })
+ // ).append(
+ // $J('<a/>').
+ // html('Ok').
+ // css('float','right').
+ // addClass('mediaitem_button').
+ // addClass('mediaitem_button_ok').
+ // attr('href','#').
+ // click(function(){
+ // return onOk();
+ // })
+ // );
+ // //popupDialog(element,table,onOk);
+ // popup.show($J('<div/>').append(table).append(subdiv), event);
+ // },
+
+ add : function(dictionary){
+
+ if(dictionary.public_id===undefined){
+ dictionary.public_id = uniqid();
+ }
+ if(dictionary.user===undefined){
+ dictionary.user = CURRENT_USER_NAME;
+ }
+
+ json(dictionary,'telemeta.add_playlist',function(){
+ window.location.reload();
+ },true);
+
+ },
remove: function(id){
json([id],'telemeta.del_playlist',function(){
- window.location.reload();
- },true);
+ window.location.reload();
+ },true);
+ },
+
+ removeResource: function(id){
+ json([id],'telemeta.del_playlist_resource',function(){
+ window.location.reload();
+ },true);
+ },
+ //resourceType can be: 'collection', 'item', 'marker'
+ addToPlaylist: function(elementInvoker, playlistId,resourceType,objectId){
+ var send = {
+ 'public_id':uniqid(),
+ 'resource_type':resourceType,
+ 'resource_id':objectId
+ };
+ json([playlistId,send],'telemeta.add_playlist_resource',function(){
+ var p = popup;
+ p.show(jQuery('<div/>').html('<a style="border:0" class="mediaitem_button mediaitem_button_ok">Ok</span>'));
+ setTimeout(function(){p.hide()},600);
+ },true);
}
+
+
// ,add:function(title){
// if(title instanceof String)
//