return new String(d.getTime() + '' + Math.floor(Math.random() * 1000000)).substr(0, 18);\r
};\r
\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
- display: 'none',\r
- border: '1px solid #e1e1e1',\r
- zIndex:1000\r
- });\r
- if(this.className){\r
- div.addClass(this.className);\r
- }\r
- return div;\r
- },\r
- className: 'component',\r
- // mouseDownNamespace : "mousedown.popup__",\r
- // keyDownNamespace : "keydown.popup__",\r
-\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 = "keyup.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
- isShowing: function(){\r
- return this._cfg_.divsToDelete ? true : false;\r
- },\r
-\r
-\r
- hide: function(){\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
-\r
- show:function(content, optionalEvent){\r
- //if showing, hide\r
- if(this.isShowing()){\r
- this.hide();\r
- }\r
-\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
- //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
- }\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
- 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 = wdow.scrollTop()+ (windowH-size.height)/2;\r
- position.left = wdow.scrollLeft()+(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
- '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 = {\r
- left: div.outerWidth()-div.width(),\r
- top:div.outerHeight()-div.height()\r
- }; //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
- //the shadow in the background will be created according to the actual div size\r
- //However, since we do not specify neither width nor height, the calculation of the div size\r
- //works if maxWidth and maxHeight do set a width and height. In order to do so, they\r
- //must be lower or equal to the actual div width and height. That's why the "min" here below:'\r
- div.css({\r
- 'maxWidth': Math.min(div.width(), maxSize.width-divPadding.left),\r
- 'maxHeight': Math.min(div.height(), maxSize.height-divPadding.top)\r
- });\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
- //now we can build the divShadow\r
- var divShadow = div.clone(false,false).empty().css({\r
- 'zIndex':999,\r
- 'borderColor':'#000',\r
- 'display':'none',\r
- 'backgroundColor':'#000'\r
- }).insertAfter(div);\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(){ //basically in between fast (200) and slow (600)\r
- //position div shadow:\r
- divShadow.show();\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
- divShadow.fadeTo(0,0.4, function(){\r
- divShadow.css({\r
- 'top': (position.top+shadowOffset),\r
- 'left': (position.left+shadowOffset),\r
- 'width': div.outerWidth(true),\r
- 'height': div.outerHeight(true)\r
- });\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
- 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
- \r
- var onOk= function(){\r
- if(callbackOnOk){\r
- var ret = {};\r
- var inputs = table.find("input");\r
- $J.each(inputs, function(key,value){\r
- var v = $J(value);\r
- ret[v.attr('name')] = v.val();\r
- });\r
- callbackOnOk(ret);\r
- return false;\r
- }else{\r
- return onCancel();\r
- }\r
- };\r
- var subdiv = $J('<div/>').css({\r
- 'padding':'1ex',\r
- 'float':'right'\r
- }).\r
- append(\r
- $J('<a/>').\r
- html('Ok').\r
- addClass('component_icon').\r
- addClass('button').\r
- addClass('icon_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
- addClass('component_icon').\r
- addClass('button').\r
- addClass('icon_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
/**\r
* Loads scripts asynchronously\r
* can take up to four arguments:\r
\r
}\r
\r
+\r
(function(p){\r
//private static variables\r
var $ = jQuery;\r
\r
//in the functions below, this refers to the new Popup instance, not to the prototype\r
\r
- \r
+\r
\r
p.isClickElement = function(element){\r
return element && element.length==1 && element instanceof $ && element[0] !== w_ && element[0] !== d_ &&\r
return div.attr('id');\r
};\r
\r
- \r
+\r
//default properties which can be overridden\r
p.shadowOffset = 4;\r
p.invoker = wdw;\r
p.shadowOpacity = 0.25;\r
p.zIndex = 10000;\r
// p.listItemClass = '';\r
- \r
+\r
p.getFormData = function(){\r
var elms = this.find('input,select,textarea');\r
var ret = {};\r
}\r
}\r
};\r
- \r
+\r
p.trigger = function(eventName){\r
var listeners = this.getListeners();\r
var me = this;\r
var container = $($(div).children()[1]);\r
//div.appendTo('body'); //necessary to properly display the div size\r
container.empty();\r
- \r
+\r
if(content instanceof $){\r
container.append(content);\r
}else if(content instanceof Array){\r
this.invoker.attr('tabindex',0).attr(focusAttr,'true');\r
}\r
var doc_ = d_; //closure (see nested function below)\r
- \r
+\r
//now all elements (including header and footer)\r
- \r
+\r
var me = this;\r
//bind the blur to each focusable element:\r
elementsWithFocus.each(function(i,e){\r
//timeout should execute\r
return;\r
}\r
- \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
p.show = function(){\r
var div = this.getDiv();\r
var me = this;\r
- \r
- \r
+\r
+\r
var cssModified = (this.popupClass || this.popupCss);\r
if(this.popupClass){\r
//which might be the prototype\r
// this.listItemClass = "";\r
// }\r
// elms.css('display','block');\r
- \r
+\r
\r
this.setFocusCycleRoot(this.focusable);\r
this.setSizable();//this means the popupdiv is display: !none and visibility:hidden, so every element\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
+\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
'width':''\r
});\r
\r
- \r
+\r
var invoker = this.invoker;\r
- \r
+\r
var sizeAsPopup = false;\r
if(this.isClickElement(invoker)){\r
this.setBoundsAsPopup(invoker, true);\r
this.setBoundsInside(invoker, this.bounds, this.boundsexact, true);\r
}\r
\r
- \r
+\r
\r
//set central div max height ONLY IF NECESSARY:\r
var maxHeight = (div.height()-topDiv.outerHeight(true)-bottomDiv.outerHeight(true)-\r
attr('id',this.getShadowDivId()) //for use in hide\r
.insertAfter(div);\r
\r
- \r
+\r
var postShowFcn = function(){\r
me.trigger('show');\r
var rect = me.getBounds.apply(me);\r
}\r
\r
div.hide().css('visibility','visible').show(this.fadInTime,function(){\r
- \r
+\r
postShowFcn();\r
- \r
- \r
+\r
+\r
});\r
};\r
- \r
+\r
p.setBoundsAsPopup = function(popupInvoker, isSizable){\r
var invoker = popupInvoker;\r
var div = this.getDiv();\r
var oldCss= isSizable ? undefined : this.setSizable();\r
- \r
+\r
var windowRectangle = this.getBoundsOf(wdw); //returns the window rectangle\r
\r
var invokerOffset = invoker.offset();\r
var invokerOuterHeight = invoker.outerHeight();\r
\r
+ //first set the maxwidth,so that we can compute the height according to it:\r
+ this.setMaxSize({\r
+ width: wdw.scrollLeft()+wdw.width()-invokerOffset.left\r
+ },isSizable);\r
+\r
+\r
var spaceAbove = invokerOffset.top - windowRectangle.y;\r
var spaceBelow = windowRectangle.height - invokerOuterHeight - spaceAbove;\r
\r
+ var placeAbove = spaceAbove > spaceBelow && div.outerHeight(true) > spaceBelow;\r
+ //note that div.outerHeight() should be == div.outerHeight(true), as we set margins =0\r
+\r
+// alert(div.outerHeight(true)+' '+spaceAbove+' '+spaceBelow);\r
+// div.css('visibility','');\r
+// return;\r
+\r
this.setMaxSize({\r
- height : spaceAbove>spaceBelow ? spaceAbove : spaceBelow,\r
- width: wdw.scrollLeft()+wdw.width()-invokerOffset.left\r
+ height : (placeAbove ? spaceAbove : spaceBelow)\r
},isSizable); //width will be ignored (for the moment)\r
- \r
- \r
+ //decrement of one pixel cause when the popup has to be reduced and the shadows bounds "touch" the window right or bottom sides,\r
+ //the window scrolls (and it shouldn't)\r
+\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
//must have been computed according to the height set above...\r
this.offset({\r
'left': invokerOffset.left,\r
- 'top': (spaceAbove > spaceBelow ? invokerOffset.top - div.outerHeight(true) :\r
+ 'top': (placeAbove ? invokerOffset.top - div.outerHeight(true) :\r
invokerOffset.top + invokerOuterHeight)\r
},isSizable);\r
if(oldCss){\r
var oldCss = isSizable ? undefined : this.setSizable();\r
\r
var bounds = this.getBoundsOf(parent);\r
- \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
- \r
+\r
var padding = {\r
top: pd['top'],\r
left:pd['left'],\r
bottom:pd['bottom'],\r
right:pd['right']\r
};\r
- \r
+\r
for(var k in padding){\r
if(padding[k]<=0){\r
padding[k]=0;\r
'width':w-padding['left']-padding['right']+this.shadowOffset,\r
'height':h-padding['top']-padding['bottom']+this.shadowOffset\r
};\r
- \r
+\r
var vvvv ={\r
width:maxSize.width,\r
height:maxSize.height\r
};\r
this._convertSize(div, vvvv);\r
- \r
+\r
if(boundsExact){\r
this.setMinSize({\r
width:maxSize.width,\r
width:maxSize.width,\r
height:maxSize.height\r
}, isSizable); //a copy cause the argument will be modified\r
- \r
+\r
this.offset({\r
'left':x + padding['left'],\r
'top': y + padding['top']\r
\r
}\r
//convert to percentage in order to keep same dimensions when zooming\r
- \r
+\r
\r
if(oldCss){\r
div.css({\r
'width': div.outerWidth(true)-div.width(),\r
'height':div.outerHeight(true)-div.height()\r
};\r
- \r
+\r
if('width' in size){\r
size.width -= (eD.width + this.shadowOffset);\r
}\r
var div = this.getDiv();\r
var oldCss= isSizable? undefined : this.setSizable();\r
//offset does NOT consider margins. Do we have top and left?\r
- \r
+\r
this.getDiv().offset(offs);\r
if(oldCss){\r
div.css({\r
var me = this;\r
var remove = this.defaultCloseOperation == 'remove';\r
div.hide(this.fadeOutTime, function(){\r
- \r
+\r
if(remove){\r
div.remove();\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
+\r
//restore event data on invoker, if any\r
var id = '_tmpHandlers'+me.getId();\r
if(me[id]){\r
me.isClosing = false;\r
me.trigger('close');\r
});\r
- \r
+\r
};\r
\r
\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
+})(PopupDiv.prototype);
\ No newline at end of file