From: riccardo Date: Fri, 25 Mar 2011 14:39:58 +0000 (+0100) Subject: popup working (hopefully) X-Git-Tag: 1.1~331 X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=887d68e5f436b75a10187f9eb47dff5e77fe3eb6;p=telemeta.git popup working (hopefully) --- diff --git a/telemeta/htdocs/css/telemeta.css b/telemeta/htdocs/css/telemeta.css index 29cd0bcb..66940834 100644 --- a/telemeta/htdocs/css/telemeta.css +++ b/telemeta/htdocs/css/telemeta.css @@ -987,8 +987,8 @@ a.image-link { padding:4px 8px 4px 26px; /*top right bottom left - last value depends on the icon size (default=16)*/ border-top: 1px solid #DDD; border-left: 1px solid #DDD; - border-bottom: 1px solid #666; - border-right: 1px solid #666; + border-bottom: 1px solid #999; + border-right: 1px solid #999; background-color: #f9f9f9; /*#626262;*/ color:#444; font-weight: bold; @@ -1040,3 +1040,32 @@ a.image-link { .mediaitem_button_ok{ background-image: url('/images/ok.png'); } +.mediaitem_button_csv{ + background-image: url('/images/csv.png'); +} +.mediaitem_button_playlist{ + background-image: url('/images/playlist.png'); +} + +a.listItem, a.listItem:visited, a.listItem:link{ + display:block; + border:0px; + font-weight: normal; + color:#6A0307; + background-color: ''; + text-decoration: none; +} + +a.listItem:hover,a.listItem:link:hover, a.listItem:visited:hover{ + background-color: #6A0307; + color:white; + text-decoration: none; +} + +.addToPlaylist { + margin:0.5ex; + position: absolute; + display:none; + left: 0; + top: 0; +} \ No newline at end of file diff --git a/telemeta/htdocs/images/cancel.png b/telemeta/htdocs/images/cancel.png index 03b23670..0ad2eb21 100644 Binary files a/telemeta/htdocs/images/cancel.png and b/telemeta/htdocs/images/cancel.png differ diff --git a/telemeta/htdocs/images/csv.png b/telemeta/htdocs/images/csv.png new file mode 100644 index 00000000..c9012665 Binary files /dev/null and b/telemeta/htdocs/images/csv.png differ diff --git a/telemeta/htdocs/images/playlist.png b/telemeta/htdocs/images/playlist.png new file mode 100644 index 00000000..7330bc5b Binary files /dev/null and b/telemeta/htdocs/images/playlist.png differ diff --git a/telemeta/htdocs/js/application.js b/telemeta/htdocs/js/application.js index bc0a49d7..ff1787f3 100644 --- a/telemeta/htdocs/js/application.js +++ b/telemeta/htdocs/js/application.js @@ -174,190 +174,326 @@ var json = function(param,method,onSuccessFcn,showAlertOnError){ details="\nThe server responded witha status of "+jqXHR.status+" ("+ jqXHR.statusText+")\n\nDetails (request responseText):\n"+jqXHR.responseText; } - alert("ERROR: Failed to save marker"+details); + alert("ERROR: Failed to save"+details); } } }); }; -uniqid = function() { +var uniqid = function() { var d = new Date(); return new String(d.getTime() + '' + Math.floor(Math.random() * 1000000)).substr(0, 18); -} -popupDialog = function(invokerElement,divContent,callbackOnOk){ - var $J = jQuery; - var div = $J("
") - var divShadow = $J('
') - // var topDiv = $J('
') - // .append($J('').html(dialogTitle ? dialogTitle : " ")) - // .append($J(''). - // css({'float':'right','padding':'1ex','backgroundImage':'url("/images/del_marker.png")', - // 'backgroundRepeat':'no-repeat'}) - // .attr('href','#').bind('click',function(){div.remove();})); - - var okB = $J('') - .addClass('mediaitem_button') - .addClass('mediaitem_button_ok') - .attr('href',"#") - .html("Ok") - .css({ - 'float':'right', - 'marginLeft':'0.5ex' - }) - .bind('click',function(){ - div.remove(); - divShadow.remove(); - if(callbackOnOk){ - callbackOnOk(); - } - return false; - }) - var cancelB = okB.clone(true,true) - .html('Cancel') - .removeClass('mediaitem_button_ok') - .addClass('mediaitem_button_cancel') - .unbind('click').bind('click',function(){ - div.fadeOut('fast', function() { - div.remove(); - divShadow.remove(); - }); - return false; - }) +}; - var bottomDiv = $J('
').css({ - 'marginTop':'0.5ex' - }).append(cancelB).append(okB); +var popup={ + _cfg_:{ + jQuery:jQuery, + div: function(){ + var div = this.jQuery('
').css({ //this is _cfg_ + position: 'absolute', + overflow:'auto', //necessary to properly display the content + border: '1px solid #DDD', + backgroundColor:'#f9f9f9', //same as mediaitem_button (see telemeta.css) + padding:'1ex', + margin: '0', + display: 'none', + zIndex:1000 + }); + if(this.className){ + div.addClass(this.className); + } + return div; + }, + className: undefined, + divShadow: function(){ + return this.jQuery('
').css({ //this is _cfg_ + position: 'absolute', + display: 'none', + overflow:'visible', + backgroundColor:'#000', + zIndex:999 + }); + }, + // mouseDownNamespace : "mousedown.popup__", + // keyDownNamespace : "keydown.popup__", - div.append(divContent).append(bottomDiv); + //namespace: 'popup__', //used for namespaces when binding click to document + handlersToRestore: [], + event: null, + divsToDelete:null, + toggleBind: function(element, functionE){ + var clickNamespace = "click.popup__"; + var keydownNamespace = "keydown.popup__"; + element.unbind(clickNamespace); + element.unbind(keydownNamespace); + if(functionE){ + element.bind(clickNamespace, functionE); + element.bind(keydownNamespace,functionE); + } + } + }, - var pos = invokerElement.position(); - var top = (invokerElement.outerHeight(true)+pos.top); - var left = pos.left; - div.css({ - padding: '1ex', - border: '1px solid #DDD', - display: 'none', - position: 'absolute', - left: pos.left + 'px', - top:top+"px", - zIndex:1000, - backgroundColor:'#eee' + isShowing: function(){ + return this._cfg_.divsToDelete ? true : false; + }, + - }); - div.insertBefore(invokerElement); - divShadow.css({ - 'backgroundColor':'#000', - position:'absolute', - zIndex:900, - width:div.outerWidth(), - height:div.outerHeight(), - left: (left + 5)+'px', - top:(top+5)+"px" - }); - div.fadeIn('fast', function() { - divShadow.insertAfter(div); - divShadow.fadeTo(0,0.4); - cancelB.focus(); - }); -} -popup={ - id: '_popup_id__', - isFocused:false, hide: function(){ - var $J = jQuery; - $J(document).unbind('click'); - $J(document).unbind('keydown'); - var popupdiv = $J(this.id); - if(popupdiv){ - popupdiv.remove(); - this.isFocused = false; + var toggleBind = this._cfg_.toggleBind; + + var $J = this._cfg_.jQuery; + + toggleBind($J(document)); + if(this._cfg_.divsToDelete){ + for(var i=0; i < this._cfg_.divsToDelete.length; i++){ + this._cfg_.divsToDelete[i].empty().remove(); + } + } + if(this._cfg_.event && this._cfg_.handlersToRestore){ + var type = this._cfg_.event.type; //which should be the same as h.type below, without namespaces? + var invokerElement = this._cfg_.event.target; + if(invokerElement){ + var e = $J(invokerElement); + toggleBind(e); + if(type){ + //e.unbind(type); + for(var i=0; i0){ + namespace="."+namespace; + } + var what = h.type+ namespace; + e.bind(what, functionCode); + } + } + } } + this._cfg_.event=null; + this._cfg_.handlersToRestore=null; }, - show:function(invokerElement,divContent){ - var popupId = this.id; - var createDiv = function(){ - return jQuery("
").append(jQuery("
").css({ - 'backgroundColor':'#000', - position:'absolute', - bottom:0, - right:0, - top:'5px', - left:'5px' - })) - .append( - jQuery("
").css({ - position: 'absolute', - top:0, - left:0, - padding: '1ex', - border: '1px solid #DDD', - backgroundColor:'#eee' - })).attr('id',popupId).css({ - display: 'none', - position: 'absolute', - zIndex:1000 - }); + + show:function(content, optionalEvent){ + //if showing, hide + if(this.isShowing()){ + this.hide(); } - var $J = jQuery; - var div = createDiv() - //adding - div.insertBefore(invokerElement); - - var mainDiv = $J(div.children()[1]).append(divContent); - var me = this; - var hide = this.hide; + var $J = this._cfg_.jQuery; + var div = this._cfg_.div(); + //toggleBind sets the functions to hiding/keep shown the popup when clicking or + //using the keyboard keys + var toggleBind = this._cfg_.toggleBind; - var children = $J(divContent).find('*'); - $(children).each(function(){ - $J(this).focus(function(){ - me.isFocused = true; + //remove the callback on invoker so that clicking on invoker does nothing + //moreover, toggleBind on invoker so that clicking invoker doesn't hide the popup + this.oldCallback = undefined; + var oldHandlers=[]; + var invokerElement = optionalEvent && optionalEvent.target ? $J(optionalEvent.target) : undefined; + if(invokerElement){ + optionalEvent.stopPropagation(); //othewrwise the popup hides immediately + //cause the event is catched from the document click (added later, see below) + // but apparently as soon as we add it it catches even the current event) + var type = optionalEvent.type; + var clickEvents =invokerElement.data("events")[type]; + $J.each(clickEvents, function(key, value) { + oldHandlers.push(value); + }) + invokerElement.unbind(type); //remove (temporarily) the binding to the event. + //for instance, if we show the popup by clicking invoker, when the popup is shown do nothing + //on clicking invoker until popup.hide is called + toggleBind(invokerElement,function(e){ //add bindings to stop cancel the popup in case the invoker is clicked again + e.stopPropagation(); + return false; }); - $J(this).blur(function(){ - me.isFocused = false; + } + //store the functions removed from invoker, if any, to restore them in this.hide + this._cfg_.handlersToRestore = oldHandlers; + this._cfg_.event = optionalEvent; + + //toggleBind on each child of content so that clicking and pressing keys on + //a child doesn't hide the popup + var children = $J(content).find('*'); + $J(children).each(function(){ + toggleBind($(this),function(e){ + e.stopPropagation(); + return false; }); }); + //showing + var doc = $J(document); + $J('body').append(div); - //setting positions: - var pos = invokerElement.position(); - var top = (invokerElement.outerHeight(true)+pos.top); - var left = pos.left; + content.css('position','static'); //this is really important to place the content in the normal flow + //within the div. static is the default + content.show(); //in case the div is display:none + div.append(content); + + //positioning div: center of the screen if no invoker, below the invoker otherwise + var wdow = $J(window); //reference the window object (doing it once speeds up a bit performances) + var windowH = wdow.height(); + var windowW = wdow.width(); + var position = div.offset(); + var shadowOffset=5; + var size = { + width:div.outerWidth(true)+shadowOffset, + height:div.outerHeight(true)+shadowOffset + }; + if(invokerElement){ + position = invokerElement.offset(); + position.top+= invokerElement.outerHeight(true); + }else{ + position.top = (windowH-size.height)/2; + position.left = (windowW-size.width)/2; + } + //position div. This must be done immediately cause here below we want to get the div offset + //(div position in absolute - ie, document's - coordinates) div.css({ - left: left + 'px', - top:top+"px" + 'top': position.top, + 'left': position.left, + 'right': 'auto', //in case right has been set by some css class rule + 'bottom': 'auto' //see above... }); + //set the maximum size + //due to overflow:auto a scrollbar will automatically appear + var max = Math.max; //reference max immediately (speeds up performances a bit) + var maxSize = { + width: max(20,windowW + wdow.scrollLeft() -position.left-shadowOffset), + height: max(20, (windowH + wdow.scrollTop() -position.top- shadowOffset)) + } + //position div and size: + var divPadding = {left: div.outerWidth()-div.width(), top:div.outerHeight()-div.height()}; //setting width on a div means the width(), + //but calculations here are made according to outerWidth(true), so we need this variable (se below) - - //showing - div.fadeIn('fast', function() { - //now that is displayed, set the parent div size (which affects the shadow, too) - var w = mainDiv.outerWidth(); - var h = mainDiv.outerHeight(); - div.css({ - width:(w+5)+'px', - height:(h+5)+'px' - }); - //show the shadow - $J(div.children()[0]).fadeTo(0,0.4); - var inputs = $J(divContent).find(':input'); - me.isFocused=false; + div.css({ + 'maxWidth': maxSize.width-divPadding.left, + 'maxHeight': maxSize.height-divPadding.top + }); + //last thing: if invoker element exist, set width at least invoker element width + if(invokerElement){ + var iEw = invokerElement.outerWidth(); //no margins considered + if(iEwdiv.outerWidth()){ + div.css({ + 'minWidth':iEw-divPadding.left + }); + } + } + var divShadow = this._cfg_.divShadow().insertAfter(div); + // //position div shadow: + // var divShadow = this._cfg_.divShadow().css({ + // 'top': (position.top+shadowOffset), + // 'left': (position.left+shadowOffset), + // 'width': div.outerWidth(true), + // 'height': div.outerHeight(true) + // }).insertAfter(div).fadeTo(0,0.4); + // + // //set focus to the first input component, if any. Otherwise try with anchors, otherwise do nothing + // var inputs = $J(div).find(':input'); + // if(inputs && inputs[0]){ + // inputs[0].focus(); + // }else{ + // inputs = $J(div).find('a'); + // if(inputs && inputs[0]){ + // inputs[0].focus(); + // } + // } + // + //store the divs to be removed + this._cfg_.divsToDelete = [div,divShadow]; + //add a listener to the document. If one of the content children is clicked/keypressed, + //we won't come here. Otherwise hide popup + var me = this; + var hide = this.hide; + toggleBind(doc,function(e){ + hide.apply(me); + e.stopPropagation(); + }); + div.show(300, function(){ //400: basically in between fast (200) and slow (600) + //position div shadow: + divShadow.css({ + 'top': (position.top+shadowOffset), + 'left': (position.left+shadowOffset), + 'width': div.outerWidth(true), + 'height': div.outerHeight(true) + }).fadeTo(0,0.4); + + //set focus to the first input component, if any. Otherwise try with anchors, otherwise do nothing + var inputs = $J(div).find(':input'); if(inputs && inputs[0]){ inputs[0].focus(); - //me.isFocused=true; - } - jQuery(document).bind('click', function(){ - if(me.isFocused){ - return; - } - hide.apply(me); - }); - jQuery(document).bind('keydown', function(){ - if(me.isFocused){ - return; + }else{ + inputs = $J(div).find('a'); + if(inputs && inputs[0]){ + inputs[0].focus(); } - hide.apply(me); - }); + } }); + return false; //to avoid scrolling if we clicked on an anchor + }, + + //field must be a dictionary of label:defaultValues (both strings) + //callbackOnOk is the callback to be executed on ok, if null ok will simply hide the dialog + //otherwise it must be a function accepting + createDivDialog : function(field,callbackOnOk){ + + var $J = this._cfg_.jQuery; + var table = $J(''); + var fieldElms = {}; + for(var label in field){ + var input = $('') + .attr('type','text').val(field[label]).attr("name",label); + table.append($J('') + .append($J('
').html(label)) + .append($J('').append(input))); + fieldElms[label]=input; + } + + var p = this; + var onCancel= function(){ + p.hide(); + return false; + }; + var onOk= function(){ + if(callbackOnOk){ + var ret = {}; + var inputs = table.find("input"); + for(var ipt in inputs){ + var i = $(ipt); + ret[i.attr('name')] = i.val(); + } + callbackOnOk(ret); + return false; + }else{ + return onCancel(); + } + }; + var subdiv = $J('
').append( + $J(''). + html('Ok'). + css('float','right'). + addClass('mediaitem_button'). + addClass('mediaitem_button_ok'). + attr('href','#'). + click(function(){ + return onOk(); + }) + ); + if(callbackOnOk){ + subdiv.append( + $J(''). + html('Cancel'). + css('float','right'). + addClass('mediaitem_button'). + addClass('mediaitem_button_cancel'). + attr('href','#'). + click(function(){ + return onCancel(); + }) + ); + } + //popupDialog(element,table,onOk); + return $J('
').append(table).append(subdiv); } } diff --git a/telemeta/htdocs/timeside/src/playlist.js b/telemeta/htdocs/timeside/src/playlist.js index 0a280f3c..92e33f4d 100644 --- a/telemeta/htdocs/timeside/src/playlist.js +++ b/telemeta/htdocs/timeside/src/playlist.js @@ -1,42 +1,105 @@ var playlist = { - add : function(element){ - var $J = jQuery; - - var dText = $('') - .attr('type','text').val(""); - var tText = $('') - .attr('type','text').val(""); - - var table = $J('') - .append($J('') - .append($J('') - .append($J('
').html('title')) - .append($J('').append(tText))) - .append($J('
').html('description')) - .append($J('').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 = $('') + // .attr('type','text').val(""); + // var tText = $('') + // .attr('type','text').val(""); + // + // var table = $J('') + // .append($J('') + // .append($J('') + // .append($J(' - + {% endfor %}
').html('title')) + // .append($J('').append(tText))) + // .append($J('
').html('description')) + // .append($J('').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('
').append( + // $J(''). + // html('Cancel'). + // css('float','right'). + // addClass('mediaitem_button'). + // addClass('mediaitem_button_cancel'). + // attr('href','#'). + // click(function(){ + // return onCancel(); + // }) + // ).append( + // $J(''). + // 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('
').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('
-

{% trans "Playlists" %}

+

{% trans "Playlists" %}

+
{% trans "Add" %} {% for playlist in playlists %}

{{ playlist.playlist.title }}

- CSV + CSV {% trans "Delete" %} @@ -109,7 +118,9 @@ yes {% endif %}
{% trans "Delete" %} + {% trans "Delete" %} +
diff --git a/telemeta/templates/telemeta_default/mediaitem_detail.html b/telemeta/templates/telemeta_default/mediaitem_detail.html index a470e9ce..56f2b3fb 100644 --- a/telemeta/templates/telemeta_default/mediaitem_detail.html +++ b/telemeta/templates/telemeta_default/mediaitem_detail.html @@ -16,6 +16,7 @@ + {% endblock %} @@ -40,17 +44,15 @@ {% endif %} {% if user.is_authenticated %} - - - - {% endif %} {% trans "Previous" %}