1$(document).ready( function() { cms_init();}); 2$(document).ajaxComplete( function(event,jqXHR,options) { cms_init(/*event,jqXHR,options*/) }); 3 4$.fn.loadOuter = function( url, callback ) { 5 var outer = $(this); 6 $("body").data("href",url); // put the latest url request in the page's body, so it can be used for other actions (ex: export) 7 $.get(url, function( data, status, jqXHR ) { 8 contentType=jqXHR.getResponseHeader('content-type') 9 if (contentType.indexOf("json")>-1) 10 cms_return(outer, data); 11 else if (contentType.indexOf("html")>-1) 12 outer.replaceWith(data) 13 else alert("Undefined content-type received [455]") 14 //setTimeout(function(){alert(outer.find('[autofocus]').length);outer.find('[autofocus]').focus()},1000) 15 //alert(outer.find('[autofocus]').length) 16 }); 17} 18 19$.fn.equaWidth = function( arr, reset ) { 20 context=$(this) 21 if (reset) arr.forEach(function(o,i){$(o,context).css({width:"auto"})}) // we reset the width 22 var obj={current:0,total:0,width:[],percent:[]} 23 arr 24 .map(function(o){return o+":visible"}) // we filter only visible items 25 .forEach(function(o,i){ // we calculate all width 26 obj.current=$(o,context).map(function(){return $(this).outerWidth()}).sort(function(a, b){return b-a})[0]||0 27 obj.width.push(obj.current) 28 obj.total+=obj.current 29 }) 30 obj.width.forEach(function(o,i){obj.percent.push(o/obj.total*100)}) 31 arr.forEach(function(o,i){$(o,context).css({width:obj.percent[i]+"%"})}) 32} 33 34$.initchange = function( arg ) { 35 // ex: $.initchange({name:"login",value:"empty",callback:function(){alert(this.value)}}) will: 1:alert("empty"), 2:if input[name='login'] changes will alert(#value#) 36 arg.self=$("input[name='"+arg.name+"']") 37 arg.callback(arg) // callback is done even if arg.self.length=0, important! 38 arg.self.on("change",function(e){ 39 if (arg.self.length>1) { 40 arg.value=arg.self.filter(function(){return this.checked && ! this.disabled}).map(function(){return this.value}).toArray() 41 } else { 42 arg.value=arg.self.val() 43 } 44 arg.callback(arg) 45 }) 46} 47 48var editable_field_file = function(div) { // base on self.editable of cbyInpufile, here to a specific tag 49 div.find("li").eq(0).addClass("icon fontello icon-edit fright").on("click",function(){ 50 var json=JSON.parse($(this).closest("div").find("input[type=hidden]").val()) // {name:"example.with.dot.gif",file:"tsdsdjfg.gif,...} 51 var parts=[json.name.split(".").slice(0,-1).join("."),json.name.split(".").pop()] // ["example.with.dot","gif"] 52 var width=$(this).width() 53 $(this).hide().after($("<input/>").css({minWidth:width}).val(parts[0]).on("blur",function(){ 54 json.name=[$(this).val(),parts[1]].join(".") 55 $(this).closest("div").find("input[type=hidden]").val(JSON.stringify(json)) 56 $(this).prev().text(json.name).show() 57 $(this).remove() 58 })) 59 $(this).next().focus() 60 }) 61} 62function cms_return(obj, data) { 63 // All ajax request should return (success) here (edit/view/save/...), obj is a jQuery object 64 65 /* first, set a min height to the parent to avoid "jump" if the content's height decreases */ 66 var parent=obj.closest("div.dataset").parent(); 67 //if (parent.length && parent.closest('#cbybox').length==0 && (parseInt(parent.css("min-height"))<parent.height()) ) parent.css("min-height",parent.height()+"px") 68 //if (obj.closest("div.dataset").hasClass("metaform-forms")) $(window).scrollTop(0) 69 if (typeof data=="object") { 70 if (data.xreferer) { 71 document.cookie="xreferer="+encodeURIComponent(data.xreferer)+"; path= /;" 72 } 73 if (data.message) if($.covr) $.covr.open(data.message.toString()); else alert(data.message.toString()); 74 // if data.jsc, eval this string. Note: the "context" (this) is set by $.ajax as the button clicked before the ajax request (see 75 if (data.jsc) eval(data.jsc) 76 switch (data.status) { 77 case 1: // normal behaviour -> just replace obj with data.html 78 obj.replaceWith( data.html||"Empty data [432]" ); 79 return; 80 case 2: // error (error on posted fiels, ...) -> show the message data.errors 81 if (data.errors) data.errors=data.errors.toString() 82 if ($('div.ds-form-errors',obj).length) { 83 $('div.ds-form-errors',obj).show().html( data.errors||"Empty data [432]"); 84 } else { 85 data.errors=data.errors.replace(/(<([^>]+)>)/ig,"")||"Empty data [433]" 86 if($.covr) $.covr.open(data.errors); else alert(data.errors); 87 } 88 return; 89 case 3: // return from a save -> replace the all dataset with new one 90 if (obj.closest("div.dataset").length && data.location && data.target!="top") { 91 obj.closest("div.dataset").loadOuter(data.location) 92 } else
93 document.location.href=data.location||(document.location.href.split("#")[0]); 94 //obj.parent().replaceWith( data.html||"Empty data [434]" ); 95 return; 96 case 4: // javascript reload (without the hash wich may cause problem by "jumping" into the page) 97 // always try to reload "top" (if frame), except if top:false is in the data 98 data.document=top||self 99 if (data.top===false) data.document=self 100 data.document.location=data.document.location.pathname+(data.document.location.search||"") 101 return; 102 case 5: // just do nothing, used in combinaison of data.message or data.jsc 103 return; 104 break; 105 default: 106 alert("Error reading response:\n"+JSON.stringify(data,null,2)); 107 return; 108 } 109 } 110 alert("Error reading response:\n"+JSON.stringify(data,null,2)); 111} 112 113 114function cms_init(context) { 115 context=context||document 116 var iframe=(window !== window.parent) 117 if (iframe) $("html").css({"overflow-y":"auto"}) 118 /*$("img.converting").css("background-image","url(/img/converting.gif)").on("load",function(){$(this).css("background-image","none")}) 119 $("img",context).error(function() { 120 var self=this 121 $(self).attr("data-src",$(self).attr("src")).attr("src","data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7") 122 var image=new Image() 123 image.onerror=function(){setTimeout(reload,5000)} 124 image.onload=function(){self.src=image.src} 125 var reload=function(){ 126 image.src=$(self).attr("data-src") 127 } 128 setTimeout(reload,5000) 129 //$(this).hide(); 130 });*/ 131 /*$('[data-xreferer]',context).onFirst("click",function(){ 132 xreferer=$(this).attr('data-xreferer');document.cookie="xreferer="+encodeURIComponent(xreferer)+"; path=/" 133 })*/ 134 135 // Move openclose button 136 $("div.dataset a.ds-button.openclose",context).each(function(){ 137 var icon=$(this).find("i");$(this).html("").removeClass("ds-button").append(icon); 138 var head=$(this).closest('div.ds-form').find('div.ds-form-head'); 139 // If head is only text (!& is not text -> also test on contents), transform as a <span>#text</span> with a click acting like clicking on the icon (to make the text clikable) 140 if (head.text()==head.html() || head.contents().length==1) head.html($("<span/>").css({cursor:"pointer"}).text(head.text()).click(function(){$(this).prev().click()})) 141 head.prepend($(this).show()) // .show() because in css ds-button.openclose are display:none to avoid flicking 142 }); 143 144 var plugins= 145 { "data-clone":{position:"before",clone:"prev",on:"click"} 146 , "data-dropdown":{fn:"cbyDropdown"} 147 , "data-sort":{} 148 , "data-tabsize":{} 149 , "data-pagination":{dico:"entrée(s)"} 150 , "data-selection":{} 151 , "data-target":{keepafter:true} 152 , "data-inputfile":{fn:"cbyInputfile"} 153 , "data-redactor":{fn:"redactor",hide:true,loadsync:["/jsc/redactor/redactor.js","/jsc/redactor/redactor-memo.js","/jsc/redactor/redactor.css"]} 154 , "data-redactor3":{fn:"redactor",hide:false,loadsync:["/lib/redactor-317/redactor.js","/lib/redactor-317/plugins.js","/lib/redactor-317/redactor.css"]} 155 , "data-geturl":{} 156 , "data-hidemailto":{} 157 , "data-cookieconsent":{name: "cookieconsent",path: "/",domain: "",expires: 92,text:["This website uses cookies to ensure you get the best experience on our website.","Got it!"]} 158 , "data-cycl":{} 159 , "data-rich":{} 160 , "data-scrollto":{} 161 , "data-scrollmem":{} 162 , "data-textcomplete":{} 163 , "data-canvasjs":{loadsync:["/jsc/jquery.canvasjs.min.js?v1"]} 164 , "data-signature":{loadsync:["/jsc/jSignature.js"]} 165 , "data-memofs":{fn:"cbyMemofs",keepafter:false} 166 , "data-yaml":{fn:"cbyYaml",loadsync:["/jsc/jquery.yaml.js"]} 167 , "data-chat":{fn:"cbyChat", loadsync:["/jsc/jquery.cbyChat.js","/jsc/socket.io-1.2.0.js"]} 168 , "data-nanogallery2":{hide:true,fn:"nanogallery2", loadhead:["/lib/nanogallery2-2.3.0/dist/css/nanogallery2.min.css"], loadsync:["/lib/nanogallery2-2.3.0/dist/jquery.nanogallery2.min.js"]} 169 } 170// $(".data",context).each(function(index) { // maybe make for (var plugin in plugins) before $(".data",context).each... to see (before not working but because var plugin was missing) */ 171// var options={} 172// for (var plugin in plugins) { 173 var options={} 174 for (var plugin in plugins) { 175 $(".data["+plugin+"]",context).each(function(index) { // really faster than $(".data").filter("["+plugin+"]") 176 // to see which plugin take more time: console.log("cms_init for "+plugin+" in "+(new Date())) 177 var options=false // changed 201709: added var to have local scope... to check! 178 if (options=$(this).attr(plugin)) { 179 if (plugins[plugin].hide) $(".data["+plugin+"]",context).hide(); // used when loadsync is there to avoid "flick". do it on all same objects as loadsync will "block" only the first one 180 if (plugins[plugin].debug) alert("DEBUG: plugin '"+plugin+"' with raw options: "+options) 181 if (options[0]=="{") { 182 options=JSON.parse(options); 183 } else { 184 options={} 185 options[plugin.replace("data-","")]=$(this).attr(plugin); // ex: data-target="form" -> options={target:"form"} 186 } 187 if (plugins[plugin]) options=$.extend({},plugins[plugin],options) // add a {} to avoid plugin option to be changed 188 if (plugins[plugin].debug) alert("DEBUG: plugin '"+plugin+"' with json options: \n"+JSON.stringify(options,null,2)) 189 if (plugins[plugin].loadsync) { 190 plugins[plugin].loadsync.forEach(function(o){loadsync(o)}) 191 delete plugins[plugin].loadsync 192 } 193 if (plugins[plugin].loadhead) {
194 plugins[plugin].loadhead.forEach(function(o){loadhead(o)}) 195 delete plugins[plugin].loadhead 196 } 197 if (plugins[plugin].fn) { 198 $.fn[plugins[plugin].fn].apply($(this), [options]); 199 if (plugins[plugin].hide) $(this).show(); 200 } else { 201 switch (plugin) { 202 case "data-clone": 203 // TODO: make other possibilities (after, on change, ...) 204 $(this).data("clone",$(this).prev().clone(true)) 205 if (options.remove) $(this).prev().remove() 206 $(this).on(options.on,function(){$(this).before($(this).data("clone").clone(true));cms_init($(this).parent())}) 207 break; 208 case "data-target": 209 var tag=this.tagName.toUpperCase(); 210 // next line: if only one input type=[text], broser will submit the form with "enter" key -> suppress this 211 if ($(this).closest("form").find("input[type=text]").length==1) $(this).closest("form").append($("<input/>",{type:"text"}).hide()) 212 switch (options.target) { 213 case "form": // In general, this changes "view", "edit",... buttons to load content with ajax 214 switch (tag) { 215 case "FORM":$(this).unbind("submit.target").on("submit.target",function(e){$(this).closest("div.ds-form").loadOuter(this.action+"?"+$(this).serialize());return false});break 216 default:$(this).unbind("click.target").on("click.target",function(){$(this).closest("div.ds-form").loadOuter($(this).attr("href"));return false;});break; 217 } 218 break; 219 case "metaform": // Never used...? 220 switch (tag) { 221 case "FORM":$(this).unbind("submit.target").on("submit.target",function(e){$(this).closest("div.metaform").loadOuter(this.action+"?"+$(this).serialize());return false});break; 222 default:$(this).unbind("click.target").on("click.target",function(){$(this).closest("div.metaform").loadOuter($(this).attr("href"));return false;});break; 223 } 224 break; 225 case "cbybox": 226 $(this).cbybox({ 227 cssouter:{width:"80%"},cssinner:{padding:0}, 228 onclose:function(){document.location.href=document.location.href;return true} 229 }); 230 break; 231 default: // allow non-A tag to be clickable 232 if (tag!=="A") $(this).unbind("click.target").on("click.target",function(){document.location.href=$(this).attr("href");}) 233 break; 234 } 235 break; 236 case "data-sort": 237 // Note: for dates, direct in node, and here: dd=new Date(options.date) 238 switch (options.current) { 239 case 1:icon="icon-sort-up";break; 240 case -1:icon="icon-sort-down";break; 241 default:icon="icon-sort icon-disabled";break; 242 } 243 var icon=$("<i/>").addClass("icon "+icon).css({marginLeft:"0.5em"}) 244 $(this).css({cursor:"pointer",position:"relative"/*,paddingRight:"1em"*/}).addData({target:"form"}).attr("href",options.href).append(icon) 245 break; 246 case "data-tabsize": // $(this) is a textarea 247 var tab=options 248 if (options.tabsize && options.tabsize=="true") tab={type:"auto", offset:4, slice:1} // if just "true", set to auto (slice: do not use the "slice" last column to calculate the max 249 if (options.tabsize && /^\d+$/.test(options.tabsize)) tab={type:"fixed", size:parseInt(options.tabsize,10)} // if number set to fixed 250 var max=function(val){ // val is a string - textarea value - with \n and \t, calculate the "max number of chars" of all virtual columns (except last) 251 val=val.split(/\n/g).map(function(o){return o.split(/\t/g)}) 252 var max=val.reduce(function(r,o,i){return o.length>r?o.length:r},0) // max number of columns - used to remove (.slice) the last colum from the calcul 253 return val.map(function(o){return o.slice(0,max-tab.slice)}).reduce(function(r,o,i){r=r.concat(o);return r},[]).reduce(function(r,o,i){return o.length>r?o.length:r},0) 254 } 255 // some default css 256 $(this).css({whiteSpace:"pre",width:"100%",minHeight:"10em",fontFamily:"monospace, 'courier new'"}) 257 if (options.css) $(this).css(options.css) 258 // change "tab" key behaviour to allow inserting tab 259 $(this).on("keydown",function(e){if(e.keyCode===9){var v=this.value,s=this.selectionStart,e=this.selectionEnd;this.value=v.substring(0, s)+'\t'+v.substring(e);this.selectionStart=this.selectionEnd=s+1;return false;}}) 260 if (tab.type=="fixed") $(this).css({tabSize:""+tab.size}) 261 if (tab.type=="auto") $(this).css({tabSize:""+(max($(this).val())+tab.offset)}).on("keyup",function(){$(this).css({tabSize:""+(max($(this).val())+tab.offset)})}) 262 break; 263 case "data-pagination": 264 //alert(JSON.stringify(options)) 265 //options.maxp=parseInt(options.count+1/options.maxi) 266 var lis=[],input 267 //content.push($("<span></span>").html([options.count,options.dico,options.page+" / "+options.maxp].join(" "))) 268 if (options.search) { 269 input=$("<input/>",{name:options.search,type:"text",autofocus:"autofocus",placeholder:"search",value:pipe.query(options.search)}).data("base",options.base).on("keyup",function(){ 270 $(this).closest("div.ds-form").loadOuter($(this).data("base")+"&"+$(this).serialize()) 271 }.debounce(300)) 272 lis.push($("<li/>").append(input)) 273 } 274 lis.push($("<li></li>").html([options.count,options.dico].join(" "))); 275 if (options.allowed && options.allowed.length>1) { 276 html=$("<div></div>") 277 $(options.allowed||[10,50,250]).each(function(i,maxi){html.append($("<a></a>").text(maxi+" / page").addClass((maxi==options.maxi)?"strong":"").addData({target:"form"}).attr("href",options.curr+"&safe.p=1&safe.maxi="+maxi))}) 278 279 var data={dropdown:{layout:"html",html:html.html()}} 280 lis.push($("<li></li>") 281 .append($("<a></a>").css("padding","0 0.5em") 282 .html(((options.page-1)*options.maxi+1)+"-"+Math.min(options.count,((options.page)*options.maxi))) 283 .addData(data))) 284 } 285 // add a hidden li to reload current page, ex: used in action to reload current view at current page 286 lis.push($("<li class='none reload icon icon-cw'></li>").css({cursor:"pointer"}).addData({target:"form"}).attr("href",options.curr)) 287 if (options.page>1) 288 lis.push($("<li class='icon icon-left-dir'></li>").css({cursor:"pointer"}).addData({target:"form"}).attr("href",options.prev)) 289 else 290 lis.push($("<li class='icon icon-left-dir icon-disabled'></li>")) 291 if (options.page*options.maxi<options.count) 292 lis.push($("<li class='icon icon-right-dir'></li>").css({cursor:"pointer"}).addData({target:"form"}).attr("href",options.next)) 293 else 294 lis.push($("<li class='icon icon-right-dir icon-disabled'></li>")) 295 var ul=$("<ul></ul>").addClass("ds-pagination").append(lis) 296 297 /*if (this.tagName.toUpperCase()=="TABLE") { 298 var colspan=$(this).find("tr").eq(0).find("td").length 299 var tr=$("<tr></tr>").addClass("ds-pagination").append($("<td></td>").attr("colspan",colspan).append(ul)) 300 $(this).append($("<tfoot/>").append(tr.clone())) 301 } 302 if (this.tagName.toUpperCase()=="UL") { 303 var li=$("<li></li>").addClass("ds-pagination").append(ul) 304 $(this).append(li.clone()) 305 } 306 if (this.tagName.toUpperCase()=="DIV") { 307 $(this).after(ul) 308 }*/ 309 // TODO: check position: always after(ul?) 310 $(this).parent().after(ul) 311 cms_init(ul) 312 if (input) input.focus().data("val",input.val()).val("").val(input.data("val")) 313 //alert(parent.html()) 314 315 break; 316 case "data-selection": 317 //alert(JSON.stringify(options)) 318 var checkbox=function(options,multi,checked){ 319 /* multi: 0/false = it's a single item 320 "all" = it's a "multi-select" of the all selection 321 "current" = it's a "multi-select" of the current list selection 322 */ 323 var obj=$("<a></a>").attr("href","#") // we construct a checkbox (icon) with some attribute coming from options 324 .data("multi",multi) 325 .data("id",options.id) 326 .addClass("icon icon-checkbox"+(checked?" checked":"")) 327 // if it's a checkbox for a single line, add a data-item-id to be able to find() them later 328 if (!multi) obj.attr("data-item-id",options.id).css({marginRight:"5px"}); else obj.css({marginLeft:"5px"}) 329 obj.click(function(e){
330 var ul=$(this).nearest("ul.ds-selection"); // look for selection container (above the table in general), it contains "data" for later 331 var self=$(this); 332 var last=ul.data("parent").find(".last[data-item-id]"); 333 self.toggleClass("checked"); // toggle the checkbox 334 var checked=self.hasClass("checked"); // get the checked value from it 335 var id=[]; // will be the list of id to send to server 336 if (ul.data("url")) { 337 var list=ul.data("parent").find("[data-item-id]"); // contains all the "single" checkbox 338 if ($(this).data("multi")) { // we clicked on the "multi" checkbox (to select current visible item or all session list) 339 list.each(function(i,o){$(o).removeClass("checked").addClass((checked?"checked":""))}) 340 id=list.map(function(i,o){return $(o).data("id")}).toArray().join(",") 341 } else if (e.shiftKey && last.length) { // we click with Shift key -> if we have a ".last" item -> make the selection between last and clicked items 342 var inside=-1; // simple trick to filter the list to get all items between last and clicked (ex: [-1,-1,-1,1(=last),1,1,-1(current),1,1,1] -> filter on "==1" or itself 343 list=list.filter(function(i,o){if($(o).is(last)||$(o).is(self)) inside=-inside; return (inside==1||$(o).is(self))}) 344 list.each(function(i,o){$(o).removeClass("checked").addClass((checked?"checked":""))}) 345 id=list.map(function(i,o){return $(o).data("id")}).toArray().join(",") 346 } else { 347 list.removeClass("last") 348 $(this).addClass("last") 349 id=$(this).data("id") 350 } 351 // ajax to modify selection, like ?safe.id:1000,1001,1002&safe.checked=1&safe.multi=all -> will set id [1000,1001,1002] to "selected" 352 $.ajax( { url:ul.data("url") 353 , data:{"safe.id":id,"safe.checked":(checked)?1:0,"safe.multi":($(this).data("multi"))?$(this).data("multi"):0} 354 , success:function(data){ // adding class "data" and "data-selection" attribute on the ul, so, as ajaxComplete will be fired, the cms_init() will be called 355 ul.data("parent").addData({selection:data.selection}) 356 } 357 }) 358 } 359 return false; 360 }) 361 return obj; 362 } 363 if (options.single) { // on a single row 364 $(this).children().eq(0).css({whiteSpace:"nowrap"}).prepend(checkbox(options,false,options.checked)) 365 } else { // on the table itself -> show result 366 var ul=$("<ul></ul>").addClass("ds-selection").data("url",options.url).data("parent",$(this)) 367 .append($("<li></li>").append(checkbox(options,"current",options.current))) 368 if (options.count) ul.append($("<li></li>").css({whiteSpace:"nowrap"}).addClass("ds-selected").append(["Sélection: ",options.count,checkbox(options,"all",options.count>0)])) 369 if (!options.count) ul.append($("<li></li>").css({whiteSpace:"nowrap"}).text("Sélection: 0")) 370 371 ul.append((options.actions||[]).map(function(o,i){ 372 var a=false; 373 if (o.button) { 374 a=o.button; 375 } else { 376 var a=$("<a class='ds-button'></a>").append($("<div></div>").text(o.title))//.addData({target:"form"}) 377 if (o.icon) a.prepend($("<i/>").addClass(o.icon)) 378 if (o.confirm) a.attr("data-confirm",o.confirm) 379 if (o.ajax!=false) { 380 a.addClass("pointer").attr("data-href",o.href); // Hide href 381 a.on("click",function(){ 382 var confirmed=($(this).attr("data-confirm"))?(confirm($(this).attr("data-confirm"))):true 383 // Note: we setup context:this to allow cms_return to have a this pointing to this "a" 384 if (confirmed) $.ajax( {url:$(this).attr("data-href"), context:this, success:function(data){cms_return($(this),data)}, error:function(data){alert("Error reading response #4315"+data)}}) 385 return false; 386 }) 387 } else { 388 a.attr("href",o.href); // Simple href to allow "SaveAs" 389 if (o.confirm) a.attr("onclick","return confirm($(this).attr('data-confirm'));") 390 } 391 } 392 return $("<li></li>").addClass("appear").append(a) 393 })); 394 $(this).parent().next(".ds-selection").remove() 395 $(this).parent().after(ul) 396 if (!$(this).data("appear") || $(this).data("appear")!=$(this).next().find(".appear").length) { 397 $(this).data("appear",$(this).next().find(".appear").length).next().find(".appear").hide().fadeIn() 398 } 399 cms_init(ul); 400 } 401 break; 402 case "data-geturl": 403 $(this).click(function(){ 404 if (!$(this).attr("id")) $(this).attr("id","id_"+Math.floor(Math.random()*99999999)) 405 var id=$(this).attr("id") 406 var lis=[$("<li><input/></li>") 407 , $("<li>") 408 .append($("<a>get</a>").attr("onclick","$(this).closest('ul').find('input').eq(0).val($(this).closest('ul').find('iframe')[0].contentWindow.location.href)")) 409 .append($("<a>set</a>").attr("onclick","$('#"+id+"').val($(this).closest('ul').find('input').eq(0).val())")) 410 , $("<li/>").append("<iframe src='/cms/' />") 411 ] 412 $.cbybox.open($("<ul/>").addClass("iframe").append(lis),{cssouter:{width:"80%",height:"80%"},cssinner:{height:"100%"}}) 413 }) 414 break; 415 case "data-hidemailto": 416 var e=options.hidemailto.replace('#','@').split('').reverse().join('') 417 $(this).attr("href","mailto:"+e) 418 if ($(this).text()=="mailto:") $(this).text(e) 419 break; 420 case "data-cookieconsent": 421 if (pipe.cookie.get(options.name)!="agree") { 422 options.agree=function(){ 423 pipe.cookie.set(options.name,"agree",options.expires,options.domain,options.path) 424 $(this).parent().remove() 425 } 426 $("body").append( 427 $("<div/>",{class:"c-cookieconsent"}).append( 428 $("<div/>",{class:"c-cookieconsent-left"}).append(options.text[0]), 429 (options.text[2])?$("<div/>",{class:"c-cookieconsent-middle"}).append(options.text[2]):"", 430 $("<div/>",{class:"c-cookieconsent-right"}).addClass("u-pointer").append(options.text[1]).on("click",options.agree) 431 ) 432 ) 433 } 434 break; 435 case "data-cycl": 436 var me=$(this), item=$(".o-cycl-item",me) 437 if (item.length==1) {$(".o-cycl-next, .o-cycl-prev",me).remove();item.eq(0).after(item.eq(0).clone());return false;} // only 1 -> disabled 438 if (item.length==2) {item.eq(1).after(item.clone());item=$(".o-cycl-item",me)} // only 2 -> make it 4 to allow cycling 439 var next=function(){item.eq(item.length-1).after(item.eq(0));item=$(".o-cycl-item",me);
439$('.c-cycl-news-body').slideUp()} 440 var prev=function(){item.eq(0).before(item.eq(item.length-1));item=$(".o-cycl-item",me);$('.c-cycl-news-body').slideUp()} 441 var close=function(){me.hide()} 442 $(".o-cycl-next",me).on("click",next) 443 $(".o-cycl-prev",me).on("click",prev) 444 $(".o-cycl-close",me).on("click",close) 445 break; 446 case "data-rich-light": 447 var dom={} 448 dom.text = $(this), 449 dom.wrap = dom.text.hide().wrap($("<div/>",{class:"o-rich"})).parent().attr("tabindex",1) 450 dom.html = $("<div/>",{class:"o-rich-html",contenteditable:!dom.text[0].disabled}).html(dom.text.val()||"\n").appendTo(dom.wrap) // content editable 451 dom.tool = $("<div/>",{class:"o-rich-tool"}).css({fontFamily:"courier"}).toggle(!dom.text[0].disabled).appendTo(dom.wrap) // content control 452 var events={ 453 exec : function(){var e=$.extend({},$(this).data("control"));if (e.arg && e.arg[0]=="prompt") e.arg=prompt(e.arg[1],e.arg[2])||false;if (e.arg!==false) document.execCommand(e.exec,false,e.arg)}, 454 focus : function(){dom.wrap.addClass("is-focus")}, 455 blur : function(){dom.wrap.removeClass("is-focus");events.update()}, 456 paste : function(e){e.preventDefault();var text = (e.originalEvent || e).clipboardData.getData('text/plain');window.document.execCommand('insertText', false, text)}, 457 html2text : function(){dom.text.val(dom.html.html().replace(/(<\/li>|<br>|<ul>)/gi,"$1\n").replace(/\n+/g, '\n'))}, 458 text2html : function(){dom.html.html(dom.text.val()||"\n")}, 459 update : function(){if(source) events.text2html(); else events.html2text()} 460 } 461 var source=false // are we in source mode? 462 463 dom.tool.append([ 464 {exec:"bold", html:"<b>b</b>"}, 465 {exec:"italic", html:"<i>i</i>"}, 466 {exec:"underline", html:"<u>u</u>"}, 467 {exec:"insertUnorderedList", html:"<span>â¢</span>", name:"insert list"}, 468 {exec:"createLink", html:"<span>_</span>", name:"create link", arg:["prompt","Enter URL","http://"]}, 469 {name:"view source", html:"<span><></span>", mousedown:function(){events.update();source=!source;dom.text.css({height:dom.html.height()}).toggle(source);dom.html.toggle(!source);}} 470 ].map(function(o){return $(o.html).addClass("o-rich-exec").attr("title",o.name||o.exec).data("control",o).on("mousedown",o.mousedown||events.exec)})) 471 472 dom.html.on("focus",events.focus).on("blur",events.blur).on("paste",events.paste) 473 dom.text.on("focus",events.focus).on("blur",events.blur) 474 break; 475 case "data-rich": 476 var me=$.extend(true,{ 477 self:this, // the textarea 478 tool:{ // rich-tools 479 box: {name:"box style", html:"<span>Box<i class='icon icon-down-dir'></i></span>", drop:1, mousedown:function(){$(this).parent().find(".js-style").toggle();return false;}}, 480 p: {exec:"formatBlock", html:"<span>P - normal</span>", drop:-1, arg:"p",class:""}, 481 //p2: {exec:"formatBlock", html:"<span>P - large</span>", drop:-1, arg:"p",class:"u-text--xl"}, 482 h1: {exec:"formatBlock", html:"<span>H1</span>", drop:-1, arg:"h1"}, 483 h2: {exec:"formatBlock", html:"<span>H2</span>", drop:-1, arg:"h2"}, 484 h3: {exec:"formatBlock", html:"<span>H3</span>", drop:-1, arg:"h3"}, 485 bold: {exec:"bold", html:"<b>b</b>"}, 486 italic: {exec:"italic", html:"<i>i</i>"}, 487 under: {exec:"underline", html:"<u>u</u>"}, 488 li: {exec:"insertUnorderedList", html:"<span>â¢</span>", name:"insert list", keep:true}, 489 code: {name:"view source", html:"<span style='float:right'>%</span>", mousedown:function(){me.fct.update();source=!source;me.dom.text.css({height:me.dom.html.outerHeight()-3 /* box-shadow */}).toggle(source);me.dom.html.toggle(!source);(source)?me.dom.text.focus():me.dom.html.focus()}}, 490 insert: {name:"insert", html:"<span>+</span>", mousedown:function(){me.fct.range(0);$.covr.open(me.dom.covr,{clone:true,foot:{ok:""}})}}, 491 }, 492 hidetool:false, // auto hide tool when not focus 493 dom:{}, // will contains all dom-related objects 494 css:{ // css for dom elements 495 wrap:{maxWidth:700,background:"white"}, 496 html:{maxHeight:"50vh"} 497 }, 498 pics:[], docs:[], // images and documents cas be passed for "insert" action 499 range:false, // save/restor the current range 500 fct:{ // all events functions 501 exec : function(e){
502 if ($.covr.is("open")) {me.fct.range(1);$.covr.close()} 503 var c=$.extend({},$(this).data("control")); 504 if (c.exec && c.arg!==false) document.execCommand(c.exec,false,c.arg); 505 //console.log(c.class , me.range , me.range.commonAncestorContainer , me.range.commonAncestorContainer.parentNode) 506 if (c.exec=="formatBlock") me.fct.attr(me.fct.closest(document.getSelection().focusNode,c.arg),"class",c.class) 507 e.preventDefault(); 508 }, 509 normalize : function(){ 510 //me.dom.html.contents().each(function(){if(this.nodeType==3) {$(this).next("br").remove();$(this).wrap($("<p/>"))}}) 511 //me.dom.html.find("ul").filter(function(){return $(this).find("li").length==0}).remove() 512 //me.dom.html.find("p").filter(function(){return $(this).find("*").length==0 && $(this).text().trim()==""}).html(" ") 513 me.dom.html.find("img").each(function(){if($(this).parent().prop("tagName").toLowerCase()!="figure") $(this).wrap($("<figure/>"))});me.fct.html2text() 514 }, 515 focus : function(){me.dom.wrap.addClass("is-focus");if (me.hidetool) me.dom.tool.slideDown(100)}, 516 blur : function(e){ 517 me.dom.wrap.removeClass("is-focus");me.fct.update();if (me.hidetool && !me.dom.wrap.hasClass("is-focus")) me.dom.tool.slideUp(100) 518 }, 519 paste : function(e){e.preventDefault();var text = (e.originalEvent || e).clipboardData.getData('text/plain');window.document.execCommand('insertText', false, text)}, 520 html2text : function(){me.dom.text.val(me.dom.html.html().replace(/(<\/li>|<\/p>|<br>|<ul>)/gi,"$1\n").replace(/\n+/g, '\n'))}, 521 text2html : function(){me.dom.html.html(me.dom.text.val()||"\n")}, 522 update : function(){if(source) me.fct.text2html(); else me.fct.html2text()}, 523 closest : function(elm,tag) {while (elm.nodeType==3 || elm.tagName.toLowerCase()!=tag.toLowerCase()) {elm=elm.parentNode;}; return elm||[]}, 524 attr : function(elm,att,val) {if(elm) (val)?elm.setAttribute(att,val):elm.removeAttribute(att)}, 525 range : function(flag){ // flag: 0|false = save current range in me.range, 1|true: restore me.range to current editor 526 if (!window.getSelection || !window.getSelection().rangeCount) return false; 527 var sel = window.getSelection(); 528 switch(flag) { 529 case 0: /* save current range */ me.range=sel.getRangeAt(0);break; 530 case 1: /* re-set saved range */ sel.removeAllRanges(); if (me.range) {sel.addRange(me.range);}break; 531 case 2: return sel.getRangeAt(0);break; 532 } 533 } 534 }, 535 insert:{ 536 link: [ 537 $("<div/>",{class:"u-grid-2"}).text("Link"), 538 $("<input/>",{class:"u-grid-8",placeholder:"http://www.google.ch"}).on("change",function(e){$(this).next().data("control").arg=this.value;}), 539 $("<a/>",{class:"u-grid-1 u-text--center u-pointer icon icon-ok"}).data("control",{exec:"createLink",arg:false}).click(function(){me.fct.exec.apply(this)}), 540 $("<a/>",{class:"u-grid-1 u-text--right u-pointer icon icon-cancel"}).click(function(){$.covr.close()}) 541 ], 542 mods: [ 543 $("<div/>",{class:"u-grid-2"}).text("Modules") 544 ], 545 docs: [ 546 $("<div/>",{class:"u-grid-2"}).text("Documents") 547 ], 548 pics: [] 549 }, 550 code:{} /* mode : view source code ? */ 551 },options); 552 553 document.execCommand('defaultParagraphSeparator', false, 'p'); 554 555 me.dom.text = $(this).addClass("o-rich-text").css({display:"block"}), 556 me.dom.wrap = $("<div/>",{class:"o-rich o-rich-wrap",tabindex:1}).css(me.css.wrap) 557 me.dom.html = $("<div/>",{class:"o-rich-html",contenteditable:!me.dom.text[0].disabled}).css(me.css.html).html(me.dom.text.val()||"\n") // content editable 558 me.dom.drop = "" // used to create dropdown of tool 559 me.dom.tool = $("<div/>",{class:"o-rich-tool"}).toggle(!me.dom.text[0].disabled).append(Object.keys(me.tool).map(function(o){ // content control 560 o=me.tool[o] 561 if (o.drop && o.drop>0) me.dom.drop=$("<div/>",{class:"o-rich-drop"}).data("drop",o.drop); else me.dom.drop="" 562 return $(o.html).addClass("o-rich-exec").attr("title",o.name||o.exec).data("c
562ontrol",o).on("mousedown",o.mousedown||me.fct.exec).addClass(o.drop?"o-rich-drop-"+o.drop:"").append(me.dom.drop) 563 })) 564 me.dom.tool.find(".o-rich-drop").each(function(){$(this).append(me.dom.tool.find(".o-rich-drop--"+$(this).data("drop")))}) 565 me.dom.covr = $("<div/>",{class:"o-rich-insert"}).append(Object.keys(me.insert).map(function(o){ 566 if (o=="mods" && me.mods.length) me.insert[o].push($("<select/>",{class:"u-grid-10 t-icon"}).append($("<option/>").text("")).append(me.mods.map(function(p){ 567 return $("<option/>").text(p).data("control",{exec:"insertHTML",arg:$("<div/>",{class:"o-rich-mods",title:p}).text(p).wrap($("<div/>")).parent().html()}).click(me.fct.exec) 568 }))); 569 if (o=="docs" && me.docs.length) me.insert[o].push($("<select/>",{class:"u-grid-10 t-icon"}).append($("<option/>").text("")).append(me.docs.map(function(p){ 570 return $("<option/>").text(p.name).data("control",{exec:"insertHTML",arg:$("<a/>",{href:p.path+p.file}).text(p.name).wrap($("<div/>")).parent().html()}).click(me.fct.exec) 571 }))); 572 if (o=="pics" && me.pics.length) me.insert[o].push($("<div/>").append(me.pics.map(function(p){ 573 return $("<div/>",{class:"o-rich-insert-pics-item"}).css({backgroundImage:"url("+p.path+p.file+")"}).data("control",{exec:"insertImage",arg:p.path+p.file}).click(me.fct.exec) 574 }))); 575 return $("<div/>",{class:"o-rich-insert-"+o}).append(me.insert[o]) 576 })) 577 578 me.dom.text.hide().wrap(me.dom.wrap).before(me.dom.tool).after(me.dom.html); 579 me.dom.tool.find(".o-rich-drop").each(function(){$(this).css({top:$(this).parent().outerHeight(),minWidth:$(this).parent().outerWidth()})}) 580 if (me.hidetool) me.dom.tool.hide() 581 me.fct.normalize() 582 //events.range(0);dom.covr.prepend($("<div/>",{class:"u-grid-2"}).text("Range"),$("<div/>",{class:"u-grid-10"}).text(JSON.stringify(dom.range))) 583 584 var source=false // are we in source mode? 585 586 me.dom.html.on("focus",me.fct.focus).on("blur",me.fct.blur).on("paste",me.fct.paste).on("mouseup",function(){ 587 me.fct.range(0);var p=me.range.commonAncestorContainer 588 while (p.nodeType==3) {p=p.parentNode} 589 p=$(p) 590 console.log(p) 591 }) 592 me.dom.text.on("focus",me.fct.focus).on("blur",me.fct.blur) 593 break; 594 case "data-canvasjs": 595 var self=this 596 597 self.options=options 598 setTimeout(function(){ 599 $(self) 600 //.wrap($("<div/>").css({width:"100%"/*,maxWidth:800*/,padding:10,margin:"1em 0 3em 0",boxShadow:"1px 1px 3px #000"})) 601 .css({width:"100%",height:300}) 602 .CanvasJSChart(self.options) 603 } 604 ,(((self.options.animationDuration||1200)+100))*index 605 ) 606 break; 607 case "data-scrollto": 608 var scrollto=false 609 switch (options.scrollto) { 610 case "self": scrollto=$(this).offset().top-Math.min($(this).height(),$(window).height());break; 611 case "bottom": scrollto=$("body").height();break; 612 } 613 if (scrollto!==false) window.scrollTo(0,scrollto); 614 break; 615 case "data-scrollmem": 616 // stores the obj's scrollTop value to re-set it after reload. Used on the obj which may scroll (a ul) by adding onclick on <a> children, ex: 617 // <ul class='data' data-scroll='whatever or options'><li><a>1</a></li><a>2</a></li></ul> -> clicking on a <a> will store scrollTop if not zero 618 // if options.id, take this id as localStorage id, otherwaise take obj'id or obj'className 619 if (!localStorage) return 620 var obj=$(this), id=options.id || obj.attr("id") || (this.tagName.toLowerCase()+" "+this.className).replace(/ /g,".") 621 if (localStorage.getItem(id)) {obj.scrollTop(parseInt(localStorage.getItem(id)))} 622 obj.find(options.selector || "a").on("click",{id:id,obj:obj},function(e){ 623 if (e.data.obj.scrollTop()) localStorage.setItem(e.data.id,e.data.obj.scrollTop()); else if (localStorage.getItem(e.data.id)) localStorage.removeItem(e.data.id) 624 }) 625 break; 626 case "data-textcomplete": 627 var strategy={ 628 href:options.href, 629 match: (options.regexp)?eval(options.regexp):/^(.{2,}
629)$/, // eval because regexp will be .toString(), by default: at least 2 chars 630 search: function (term, callback, match) { 631 $.getJSON(this.href||document.location.href, { "safe.q": term }) 632 .done(function (resp) {callback(resp);}) 633 .fail(function () {callback([]);}); 634 }, 635 replace: function (value) {return value.text}, 636 template: function (value) {return value.text}, 637 index: 1 638 } 639 if (options.action==1) {strategy.replace=function(value){document.location.href=value.value;return "loading..."}} 640 strategies=[strategy] 641 if (options.sift) strategies.unshift({ 642 match: /^\{(.*)/, // eval because regexp will be .toString(), by default: at least 2 chars 643 search: function (term, callback, match) {/*console.log(this.el.value);*/term=[{isjson:this.isjson(this.el.value),text:this.el.value}];callback(term)}, 644 replace: function (value) {if (!value.isjson) return undefined; else {document.location.search+="&safe.sift="+encodeURIComponent(value.text);return "loading...."}}, 645 template: function (value) {return $("<div>").append($("<div>").text(value.text).css({fontSize:"1.5em",margin:"-2px -5px",padding:"2px 10px",background:"white",color:value.isjson?"green":"red"})).html()}, 646 isjson: function(str){try {eval("["+str+"]");} catch (e) {return false;}return true;}, 647 index: 1 648 }) 649 //console.log(strategies) 650 $(this).attr("type","text").textcomplete(strategies,{placement:"left",noResultsMessage:"not found"}) 651 break; 652 case "data-signature": 653 var signature=$(this).wrap($("<div/>")).jSignature(), 654 parent=signature.parent() 655 parent.css({position:"relative",border:"1px solid #999",background:"#fff",paddingBottom:"25%" /* jSignature has a ration 1/4 */}) 656 if (options.val) signature.jSignature("setData","data:image/jsignature;base30," + options.val) 657 if (options.mode=="edit") { 658 signature.css({position:"absolute",left:1,right:1,top:1,bottom:1,zIndex:1}).after([ 659 $("<input/>").attr("type","text").css({position:"absolute",left:0,right:0,bottom:0,zIndex:-1}).attr("name",options.name).prop("required",options.mandatory), 660 $("<div/>").addClass("validation").css({position:"absolute",left:0,right:0,top:0,bottom:0,zIndex:0}), 661 $("<a href='#'/>").addClass("icon icon-arrows-cw").css({position:"absolute",right:0,top:0,zIndex:1}).click(function(){signature.jSignature("clear");return false}) 662 ]).bind("change",function(e){signature.next().val(signature.jSignature("getData","base30"))}) 663 } else { 664 parent.html($("<img />").css({position:"absolute",display:"block",left:0,top:0,width:"100%",margin:0}).attr("src",signature.jSignature('getData', 'default'))); 665 } 666 break; 667 } 668 } 669 if (!options.keepafter) $(this).removeAttr(plugin) 670 } 671 }) 672 } 673 674 $(".o-tipr-trigger[title]",context).tipr(); 675 676 if (!$.fn.dragsort) $.fn.dragsort=function(){return false}
677 $('.dragsort-items:not(.dragsort-done)',context).addClass("dragsort-done clearfix").dragsort({ // generic dragsort (parent: .dragsort-items, dragSelector: .dragsort-selector) 678 dragSelector: ".dragsort-selector", dragBetween: false, placeHolderTemplate: "<li></li>",dragEnd: function() {} 679 }); 680 $('.dragsort-selector',context).cbyTouchmouse() 681 $('.dragsort-delete',context) 682 .css({cursor:"pointer"}) 683 .unbind("click") 684 .click(function(){$(this).closest(".dragsort-item").remove()}) 685/* $('.dragsort-items .dragsort-addOLD',context) 686 .css({cursor:"pointer"}) 687 .each(function(){$(this).attr("data-clone",$(this).closest(".dragsort-item").clone().wrap("<div/>").parent().html())}) 688 .unbind("click") 689 .click(function(){$(this).removeClass("dragsort-add").addClass("dragsort-delete").html("<i class='icon icon-cancel'/>");var parent=$(this).closest(".dragsort-items");if ($(this).attr("data-max")=="none" || parseInt($(this).attr("data-max"))>parent.children().length) {parent.append($(this).attr("data-clone"));cms_init(context)}})
690 $('.dragsort-items .dragsort-add2',context) 691 .css({cursor:"pointer"}) 692 .each(function(){$(this).attr("data-clone",$(this).closest(".dragsort-item").clone().wrap("<div/>").parent().html())}) 693 .unbind("click") 694 .click(function(){$(this).removeClass("dragsort-add").addClass("dragsort-delete").html("<i class='icon icon-cancel'/>");var parent=$(this).closest(".dragsort-items");if ($(this).attr("data-max")=="none" || parseInt($(this).attr("data-max"))>parent.children().length) {parent.append($(this).attr("data-clone"));cms_init(context)}}) 695 $('input.js-date',context).cbySelect({"type":"date"}); 696*/ 697 $('.js-group-children:not(.group-children-done)',context).addClass('group-children-done').each(function(){ // group a list of children in 1 child + a arrow to open the other children 698 if ($(this).children().length<2) return true; // true so each will continue 699 $(this).css({position:"relative"}) 700 var href=$(this).children().eq(0).attr("href") 701 $(this).children(':not(:eq(0))').filter(function(){return $(this).attr("href")==href}).addClass("selected"); // add a selected class on the hidden children which have the same href as the first 702 var div=$('<div/>').addClass('ds-popup ds-radius').css({display:"none"}); // makes a div to contain the hidden children 703 div.append($(this).children(':not(:eq(0))').css({display:"block",whiteSpace:"nowrap"})); // append all the children (except the first one) 704 $(this).append(div) 705 var open=$('<a href="#"><i class="icon icon-down-dir"></i></a>') // makes the a containing the open/close arrow 706 $(this).children().eq(0).after(open) // append it after the first child 707 open.click(function(){ 708 var padding=parseInt($(this).next().css("paddingLeft")) 709 $(this).next().toggle().css({top:-padding,left:-padding,paddingTop:$(this).prev().height()+2*padding,minWidth:$(this).prev().width()+$(this).width()+2*padding}); 710 $(this).prev().css({position:"relative",zIndex:1500}) 711 $(this).css({position:"relative",zIndex:1500}) 712 return false 713 }) // click event to open the hidden children 714 }) 715 // Shortcut add a label after <input class='collapse'>, used in next+next line 716 $('input.collapse').each(function(){if ($(this).next("label.collapse").length==0) $(this).after("<label class='toggle collapse'></label>")}) 717 $('input[type=checkbox] + label.toggle').each(function(){ // on a "<input type='checkbox' name='...'><label class='toggle ...'></label>" 718 if ( (ie=/MSIE (\d+)/.exec(navigator.userAgent)) && !(ie[1]<6 || ie[1]>8) ) return false; 719 var id=$(this).prev().attr("id")||"id_"+Math.floor(Math.random()*9999999) 720 $(this).prev().attr("id",id).hide() // add id (same if existing, see line before and hide it */ 721 $(this).attr("for",id) // add for to toggle the checkbox 722 .addClass("icon pointer") 723 }) 724 725 $('.wysiwyg').cbyWysiwyg(); 726 727 var hint=function(e){$(this).closest(".o-hint-item").toggleClass("is-hint",$(this).val()=="" && e.type!="focus")} 728 $(".o-hint-input, .o-hint-input input").filter(":input").on("focus blur change",hint).each(hint) 729 730 /* test open/close details */ 731 $(".remoded .dsd-folderlist .ds-dropdown").each(function(){ 732 a=$(this).prev() // <a> 733 var tr=$(this).closest("tr") 734 var div=$(this).removeClass("ds-dropdown").hide() 735 div.find("td").css("border",0) 736 a.unbind("click focus").bind("click",function(e){ 737 e.preventDefault() 738 var td=$("<td colspan='4' class='ds'></td>").append(div) 739 tr.after($("<tr><td class='ds'></td></tr>").append(td)) 740 tr.css("background","#f3f3f3").next().css("background","#f3f3f3") 741 div.slideToggle() 742 }) 743 }) 744 745 setTimeout(function(){$(".no-transition-onload").removeClass("no-transition-onload")},100) 746} 747/* jquery stick: if not done, set the oject position to "fixed" and append a fake div to simulate the height */ 748(function($) { 749 $.fn.stick = function(opts) { 750 opts=opts||{css:{}} 751 if (!$("body").data("stick-timeout")) $("body").data("stick-timeout",setInterval(function(){$(".fake-stick").each(function(){$(this).css({height:$(this).prev().outerHeight()})})},500)) 752 return this.filter(function(){return !$(this).hasClass("stick")}).addClass("stick").each(function() { 753 $(this) 754 .css({position:"fixed",zIndex:1,width:"100%"}).css(opts.css) 755 .after($("<div/>").addClass("fake-stick").css({height:$(this).outerHeight()})) 756 }); 757 }; 758})(jQuery); 759 760function cms_submit(obj,data,step) {
761 // data: An object containing extra data that should be submitted along with the form, ex: data: { key1: 'value1', key2: 'value2' } 762 // step: A form can have .ds-form-step objects, in this case, send form multiple time, every step with on .ds-form-step "un-disabled" 763 // 1. search for the form 764 if (obj.tagName.toUpperCase=="FORM") form=$(obj); else form=$(obj).closest('form'); 765 //if (form.attr("data-confirm") && confirm(form.attr("data-confirm"))!==true) return false 766 var progress={button:false,text:form.find(".ds-progress-text"),width:form.find(".ds-progress-width"),start:new Date()}; // all progress DOM object 767 // 2. if HTML5 "required" and "checkValidity" exists, use it (to simulate the HTML5 'errors tooltip', just create a submit button and click on it) 768 form.removeClass('invalid') 769 if (form.length && typeof(form[0].checkValidity)=="function" && !form[0].checkValidity()) { 770 form 771 .addClass('invalid') // As iOS does not show a warning, we set up css rules to display a "red" box-shadow around the "invalid" fields (see dataset.css) 772 .on('submit',function(e){e.preventDefault();return false;}) // as iOS does not show warning, avoid to submit the form with the following line (click) 773 $('<input type="submit">').hide().appendTo(form).click().remove(); // simulate a "submit" 774 form.off('submit'); // remove on 'submit' for data-target=document (normal submit()) 775 return false; 776 } 777 778 var uploadProgress=function(){return false;} 779 if (form.find("input[type=file]").length) uploadProgress = function(event,position,total,percentComplete) { 780 progress.second=(new Date()-progress.start)/1000 781 if (progress.second>0) progress.bitrate=position/progress.second 782 if (progress.button.length) progress.button.show().html(percentComplete+"%") 783 if (progress.text.length) progress.text.show().html(percentComplete+"%") 784 if (progress.width.length) progress.width.show().css({width:percentComplete+"%"}) 785 } 786 var steps=false,annex=form.find("input.ds-form-step-annex") 787 if ( (steps=form.find(".ds-form-step")) && steps.length>0) { 788 steps.each(function(){this.disabled=true}) 789 annex.each(function(){this.disabled=true}) // Annex to the file. Note: only one annex to each file 790 step=step||0 791 if (form.find("input[name='_mode']").val()!="add") { 792 // we are in an update -> 793 // first "step" (0) send all previous values in Json, following step send POST["_field"]=name that tell the server to only take care of this one 794 if (step>0) { 795 data=$.extend(data,{_step:step,_field:steps.get(step-1).name}) // note: _step is not used in server 796 form.find(":input").each(function(){this.disabled=true}) // disable all form elements 797 steps.get(step-1).disabled=false; // un-disable current's step element 798 if (annex.length) annex.get(step-1).disabled=false; 799 progress.start=new Date() 800 progress.text=steps.eq(step-1).nearest(".ds-progress-text"); 801 progress.width=steps.eq(step-1).nearest(".ds-progress-width"); 802 } 803 step++ 804 if (step==steps.length+1) step=0; // to end loop*/ 805 } else { 806 // we are in an insert (probably with a pivot!), just post every fields but steps files one by one 807 data=$.extend(data,{_step:step}) 808 steps.get(step).disabled=false; 809 if (annex.length) annex.get(step).disabled=false; 810 progress.start=new Date() 811 progress.text=steps.eq(step).nearest(".ds-progress-text"); 812 progress.width=steps.eq(step).nearest(".ds-progress-width"); 813 step++ 814 if (step==steps.length) step=0; // to end loop 815 } 816 } 817 818 if (form.attr('data-xreferer')) { 819 xreferer=form.attr('data-xreferer');document.cookie="xreferer="+encodeURIComponent(xreferer)+"; path=/" 820 } 821 822 switch ($(obj).attr("data-target")) { 823 case "document": 824 form.submit(); 825 break; 826 default: // submit, ... 827 if ($(obj).hasClass("ds-once") && $(obj).find("i.icon").length==0) $(obj).prepend($("<i class='icon'/>")) // if button is ds-once but don't have a icon, just a one 828 progress.button=$("<a href='#' />").addClass($(obj).attr("class")).html($(obj).html()); // clone the current button to avoid double click and to put a spinner 829 if ($(obj).find("i.icon").length) $(obj).hide().after(progress.button); 830 if (progress.button.find("i").hasClass("icon")) spin="icon icon-spinner icon-spin"; else if (progress.button.find("i").hasClass("mdi")) spin="mdi mdi-sync mdi-spin"; else spin="" 831 setTimeout(function(){progress.button.find("i").addClass(spin)},200) 832 833 form.ajaxSubmit({ 834 data:data, 835 dataType:"json", 836 uploadProgress: uploadProgress, 837 /*beforeSerialize: function(form,options) { 838 $(":input",form).each(function(){alert($(this).val()+" "+$(this).attr("data-value"));if ($(this).attr("data-value")!==undefined) {$(this).val($(this).attr("data-value"));alert($(this).val())}}) 839 },*/ 840 success: function(responseText, statusText, xhr, $form){ 841 progress.button.hide();$(obj).show(); 842 if (progress.text.length) progress.text.html("100%") 843 if (progress.width.length) progress.width.animate({width:"100%"}) 844 //alert('status: ' + statusText + '\n\nresponseText: \n' + responseText); 845 //alert("Error reading response:\n"+JSON.stringify(responseText,null,2)); 846 //document.location.href=document.location.href 847 if (step) { 848 cms_submit(obj,data,step); 849 } else { 850 cms_return($form,responseText) 851 } 852 }, 853 error: function(xhr){ 854 //alert(xhr.responseText||"Error, permission denied or session expired [5426]") 855 console.log(xhr.responseText||"Error, permission denied or session expired [5426]") 856 document.location.href=document.location.href 857 } 858 }); 859 break; 860 } 861} 862 863function js_keyup(event,obj) { 864 if (event && event.keyCode==13) $(obj).nearest("a.ds-submit").click() 865} 866 867var loadsync=function(src){ // will load a file (.js or .css) synchronously based on his extension and if not already loaded 868 if (document.querySelector && document.querySelector("[loadsync='"+src+"'], script[src='"+src+"'], link[href='"+src+"']")) return 869 var xhrObj = new XMLHttpRequest(),extension=(""+src).split("?")[0].split(".").pop(),dom=false; 870 xhrObj.open('GET', src, false); 871 xhrObj.send(''); 872 873 if(xhrObj.status!=200) { 874 alert("Error "+xhrObj.status+" reading: "+src) 875 } else { 876 switch (extension) { 877 case "css": 878 dom = document.createElement("style"); // warning: relative url will not work here, use loadhead 879 dom.type = "text/css" 880 if (dom.styleSheet) dom.styleSheet.cssText = xhrObj.responseText; 881 else dom.appendChild(document.createTextNode(xhrObj.responseText)); 882 break; 883 default: // .js 884 dom = document.createElement("script"); 885 dom.type = "text/javascript" 886 dom.text = xhrObj.responseText; 887 break; 888 } 889 if (dom) { 890 dom.setAttribute("loadsync",src) 891 document.getElementsByTagName('head')[0].appendChild(dom); 892 } 893 } 894} 895 896var loadhead=function(src){ // will load a file (.js or .css) by adding appropriate tag in <head>, generally use for .css file, not .js 897 // same job as loadsync, but as it's not sync: 898 // pros: do not show the warning "MLHttpRequest on the main thread is deprecated...", do all other loading in css file with relative url "src:url(relative/to/src)" 899 // cons: js function inside the src can't be call directly after loadhead() as they will not be ready (not sync)! 900 if (document.querySelector && document.querySelector("[loadsync='"+src+"'], script[src='"+src+"'], link[href='"+src+"']")) return 901 var extension=(""+src).split("?")[0].split(".").pop(),dom=false; 902 903 switch (extension) { 904 case "css": 905 dom = document.createElement("link"); 906 dom.rel = "stylesheet" 907 dom.href = src 908 break; 909 default: // .js 910 dom = document.createElement("script"); 911 dom.type = "text/javascript" 912 dom.src = src 913 break; 914 } 915 if (dom) { 916 document.getElementsByTagName('head')[0].appendChild(dom); 917 } 918} 919 920/* jQuery plugins 921 Copyright (c) 2013 Stéphane Carion, ComputedBy (www.computedby.c
921om) 922 923 Dual licensed under the MIT or GPL Version 2 licenses. 924 http://www.opensource.org/licenses/mit-license.php 925 http://www.opensource.org/licenses/gpl-2.0.php 926 927*/ 928 929/* cbySelect plugin */ 930;(function($){ 931 /* OO jquery based on http://www.virgentech.com/blog/2009/10/building-object-oriented-jquery-plugin.html */ 932 $.fn.cbySelect = function(options) { 933 return this.each(function() { 934 var element = $(this); 935 // Return early if this element already has a plugin instance 936 if (element.data('cbySelect')) return; 937 // pass options to plugin constructor 938 var cbySelect = new cbySelectClass(this, options); 939 // Store plugin object in this element's data 940 element.data('cbySelect', cbySelect); 941 }); 942 }; 943 944 var cbySelectClass = function(element,options) { 945 // Start declaration (don't forget to put 'var' before every variables/functions!) 946 // Default settings 947 var settings = jQuery.extend({ 948 type:"xselect", // xselect||date 949 mode:"popup", // popup||inline 950 value:"", 951 days:["di","lu","ma","me","je","ve","sa"], 952 range:[false,false] // use for date, range=[date1,date2] -> must be between date1 and date2 953 }, options); 954 var self=this; 955 var input=$(element); // The object 956 var container=input.parent(); 957 settings.value=input.val(); 958 959 self.pad = function(input,length) { 960 return (1e15+input+"").slice(-length||-2) 961 } 962 self.format = function(input,format) { 963 switch (format) { 964 case "dd.mm.yyyy":return self.pad(input.getDate())+"."+self.pad(input.getMonth()+1)+"."+input.getFullYear();break; 965 } 966 } 967 self.parse = function(text,format) { 968 switch (format) { 969 case "dd.mm.yyyy":return (text.split(".").length!=3)?new Date():new Date(text.split(".")[2], text.split(".")[1]-1, text.split(".")[0]);;break; 970 } 971 return new Date(); 972 } 973 974 self.daycell = function(mode,d) { // 0: outside the current month -> no number inside 975 if (mode==0) return [$("<span/>").attr("class","ds-name").text(settings.days[d]),$("<span/>").attr("class","ds-day").text()] 976 if (mode==1) return [$("<span/>").attr("class","ds-name").text(settings.days[d.getDay()]),$("<span/>").attr("class","ds-day").attr("data-date",self.format(d,"dd.mm.yyyy")).text(self.pad(d.getDate()))] 977 } 978 979 self.month = function(d) { // return the html of a month, in ul/li 980 if (!d) firstday=new Date(); else firstday=new Date(d); // clone d 981 firstday.setDate(1) // first day of month 982 var offset=(firstday.getDay()+6)%7; // offset of first day of month, monday as 0 983 var ulhead=$("<ul/>").attr("class","ds-head"); 984 var ulbody=$("<ul/>").attr("class","ds-body"); 985 var li=$("<li/>").attr("class","ds-cell"); 986 // data-nav: Year,Month,Day,... 987 ulhead 988 .append(li.clone().addClass("ds-nav ds-prevmonth").attr('data-nav','0,-1').text("<")) 989 .append(li.clone().addClass("ds-nav ds-prevyear").attr('data-nav','-1,0').text("<<")) 990 .append(li.clone().addClass("ds-nav ds-name").text(self.pad(d.getMonth()+1)+"."+d.getFullYear())) 991 .append(li.clone().addClass("ds-nav ds-nextyear").attr('data-nav','1,0').text(">>")) 992 .append(li.clone().addClass("ds-nav ds-nextmonth").attr('data-nav','0,1').text(">")); 993 for (var i=0;i<offset;i++) ulbody.append(li.clone().addClass("ds-week0").html(self.daycell(0,(i+1)%7))); 994 while (d.getMonth()==firstday.getMonth()) { 995 ulbody.append(li.clone().addClass("ds-week"+parseInt(i/7)+((self.format(dates.current,"dd.mm.yyyy")==self.format(firstday,"dd.mm.yyyy"))?" selected":"")).html(self.daycell(1,firstday))); 996 firstday=new Date(firstday.getTime()+86400000); 997 i++; 998 } 999 $('.ds-nav[data-nav]',ulhead).click(function(){ 1000 arr=$(this).attr('data-nav').split(','); 1001 dates.nav=new Date(dates.nav.getFullYear()+parseInt(arr[0],10),dates.nav.getMonth()+parseInt(arr[1],10),1); 1002 calendar.html(self.month(dates.nav)); 1003 }) 1004 $('.ds-day[data-date]',ulbody) 1005 .each(function(){ // add class if selected or today 1006 if ($(this).attr("data-date")==self.format((new Date()),"dd.mm.yyyy")) $(this).parent().addClass("ds-today") 1007 if ($(this).attr("data-date")==self.format(dates.current,"dd.mm.yyyy")) $(this).parent().addClass("selected") 1008 if (settings.range && settings.range[0] && settings.range[0].split(".").reverse().join("")>=$(this).attr("data-date").split(".").reverse().join("")) $(this).parent().addClass("disabled") 1009 if (settings.range && settings.range[1] && settings.range[1].split(".").reverse().join("")<$(this).attr("data-date").split(".").reverse().join("")) $(this).parent().addClass("disabled") 1010 }) 1011 .filter(function(){return !$(this).parent().hasClass("disabled")}) 1012 .click(function(){ // add the onclick event 1013 input.val($(this).attr("data-date")); 1014 dates.current=self.parse($(this).attr("data-date"),"dd.mm.yyyy") 1015 calendar.hide() 1016 }) 1017 return [ulhead,ulbody]; 1018 } 1019 1020 var dates={current:self.parse(settings.value,"dd.mm.yyyy"),nav:self.parse(settings.value,"dd.mm.yyyy")} 1021 1022 switch (settings.type) { 1023 case "date": 1024 var icon=$("<i class='icon icon-calendar'>") 1025 input.after(icon) 1026 //icon.css({marginLeft:-icon.width()}) 1027 input.attr("autocomplete","off").css({width:"7.5em"}) 1028 var calendar=$("<div/>").attr("class","ds-calendar ds-"+settings.mode); 1029 container.append(calendar); 1030 calendar.hide(); 1031 if (input.attr("data-range")) { 1032 settings.range=JSON.parse(input.attr("data-range")) 1033 for (i=0;i<settings.range.length;i++) if (settings.range[i]==1) settings.range[i]=self.format((new Date()),"dd.mm.yyyy") 1034 } 1035 input.click(function(){calendar.html(self.month(dates.current)).toggle()}) 1036 break; 1037 } 1038 } 1039})(jQuery); 1040 1041/* cbyDropdown plugin */ 1042(function($){ 1043 /* OO jquery based on http://www.virgentech.com/blog/2009/10/building-object-oriented-jquery-plugin.html */ 1044 $.fn.cbyDropdown = function(options) { 1045 return this.each(function() { 1046 var element = $(this); 1047 // Return early if this element already has a plugin instance 1048 if (element.data('cbyDropdown')) return; 1049 // pass options to plugin constructor 1050 var cbyDropdown = new cbyDropdownClass(this, options); 1051 // Store plugin object in this element's data 1052 element.data('cbyDropdown', cbyDropdown); 1053 }); 1054 }; 1055 1056 var cbyDropdownClass = function(element,params) { 1057 // Start declaration (don't forget to put 'var' before every variables/functions!) 1058 var $el=$(element) 1059 var self = jQuery.extend( 1060 { 1061 // first part, normally used to be changed in params 1062 mode: "edit" // "view"|"edit" 1063 , layout:"options" // options|date|datetime|html|file|ajax 1064 , source:"array" 1065 , array:["One","Two","Three","Four","Five"] // example of array 1066 , multiple:false // true, false, "post", {}, obj: {"drag":true,"delete":true,...} 1067 , free:false // "edit": allow text input (if not false, this must be the name of the input) 1068 , minchar:0 // min char before open dropdown 1069 , maxitem:0 // max item displayed 1070 , values:{real:false,text:"",selected:[]} // the values real value, text value, selected: $(obj) containing selected obj(s) 1071 , days:["di","lu","ma","me","je","ve","sa"] // label for day name 1072 , group: {type:"count",after:" item(s)"}
1072 // manage what appear in the anchor or input 1073 /* {type:"count",after:" item(s)", before:""}: will count the selected items and add "item(s)" to this number 1074 {type:"data-resume"}: will count the different "data-resume", ex: "2 offices, 1 user" 1075 {type:"join", separator:","}: will array.join() the real values with separator 1076 */ 1077 , range:[false,false] // use for date, range=[date1,date2] -> must be between date1 and date2, ex: ["05.05.2015","25.06.2015"] 1078 , icon:"auto" // false to remove, $("<i class='...'>) to force 1079 , position:false // add some class to be on the right 1080 , highlight:false // when on options, add a input to filter (highlight) the list 1081 // second part, use internally but can also be override 1082 , wrap:false // the wrap div 1083 , input:false // the <input/> if existing 1084 , anchor:false // when no input (view mode), anchor will replace the input and be clickable 1085 , dropdown:false // the dropdown div 1086 , tmp:false 1087 , scroll:false // scroll dropdown options 1088 }, params); 1089 1090 // Third part, function used internally but can be overridden by settings 1091 self.pad = self.pad || function(text,length) { 1092 return (1e15+text+"").slice(-length||-2) 1093 } 1094 self.format = self.format || function(date,format) { 1095 switch (format) { 1096 case "dd.mm.yyyy hh:mm":return self.pad(date.getDate())+"."+self.pad(date.getMonth()+1)+"."+date.getFullYear()+" "+self.pad(date.getHours())+":"+self.pad(date.getMinutes());break; 1097 case "dd.mm.yyyy hh:00":return self.pad(date.getDate())+"."+self.pad(date.getMonth()+1)+"."+date.getFullYear()+" "+self.pad(date.getHours())+":00";break; 1098 case "dd.mm.yyyy":return self.pad(date.getDate())+"."+self.pad(date.getMonth()+1)+"."+date.getFullYear();break; 1099 case "yyyymmdd":return date.getFullYear()+self.pad(date.getMonth()+1)+self.pad(date.getDate());break; 1100 case "hh:mm":return self.pad(date.getHours())+":"+self.pad(date.getMinutes());break; 1101 } 1102 alert("self.format error on "+date+" - "+format) 1103 } 1104 self.parse = self.parse || function(text,format) { 1105 text=""+text 1106 switch (format) { 1107 case "dd.mm.yyyy": 1108 case "dd.mm.yyyy hh:mm": 1109 if (text.split(" ").length<2) text+=" 00:00" 1110 var parts=text.split(" "); // split datetime format 1111 if (!parts[0] || parts[0].split(".").length!=3) return new Date() 1112 var date=new Date(parts[0].split(".")[2], parts[0].split(".")[1]-1, parts[0].split(".")[0], parts[1].split(":")[0], parts[1].split(":")[1]); 1113 return date 1114 break; 1115 } 1116 alert("parse error on: "+text+" - "+format) 1117 } 1118 1119 self.reduce=function(arr) { 1120 // transform the array as : [["first","items[]","items[]"] -> ["first", "2 items"] 1121 return arr 1122 // first, reduce array as: [["first","items[]","items[]"] -> {pos:{"items(s)":2},arr:[[0,"first"],[2,"items[]"]]} 1123 .reduce(function(o,v,i){ 1124 if (v.substr(-2)=="[]") { 1125 //field.reduced=true // tell the field it has been reduced! 1126 if (o.pos[v]) o.arr[o.pos[v]-1][0]++; else {o.arr.push([1,v]);o.pos[v]=o.arr.length;} 1127 } else o.arr.push([0,v]) 1128 return o 1129 },{pos:{},arr:[]}) 1130 // only take the .arr property: [[0,"first"],[2,"items[]"]] 1131 .arr 1132 // sort the array as [0]=0 unchanged, then [0]>0 -> alphanumeric 1133 .sort(function(a,b){return (a[0]==0)?false:a[1]>b[1]}) 1134 // Second, map it to ["first", "2 items"] 1135 .map(function(o,i){return !o[0]?o[1]:[o[0],o[1].substr(0,o[1].length-2)].join(" ")}) 1136 } 1137 1138 self.resume = self.resume || function(arg){ // Only for layout=options 1139 //return false 1140 var resume=""; 1141 if (self.mode=="edit") { 1142 self.values.selected=self.dropdown.find("input").filter(function(){return (this.checked && !this.disabled)}) 1143 self.values.real=self.values.selected.toArray().map(function(o){return o.value}) 1144 } else { 1145 self.values.selected=self.dropdown.find("li").filter(function(){return ($(this).hasClass("checked") || this.hasAttribute("data-resume")) && this.hasAttribute("data-resume")}) 1146 } 1147 self.values.text=self.values.selected.toArray().map(function(o){return $(o).attr("data-resume")}).filter(function(o){return o}
1147) 1148 // try to group some value (those beginning with ##) 1149 /*self.values.groups={} 1150 self.values.text.forEach(function(label){if (label.indexOf("##")==0) self.values.groups[label]=(self.values.groups[label]||0)+1}) 1151 self.values.text.forEach(function(label,i){ 1152 if (self.values.groups[label]) { 1153 self.values.text[i]=(self.values.groups[label]!=-1)?label.replace("##",self.values.groups[label]):""; 1154 self.values.groups[label]=-1 1155 } 1156 }) 1157 self.values.text=self.values.text.filter(function(label){return label})*/ 1158 if (self.multiple.join) self.values.join=[].concat(self.multiple.join).concat(self.multiple.join); else self.values.join=[", ",", "] 1159 self.values.text=self.reduce(self.values.text) 1160 if (self.input && self.input.val()!=self.values.text.join(self.values.join[0])) // set the value only if different (to avoid :invalid on input when empty) 1161 self.input.val(self.values.text.join(self.values.join[0])) 1162 1163 self.values.text=self.values.text.join(self.values.join[1]) 1164 if (self.anchor) { 1165 self.anchor.html(self.values.text || "") 1166 if (params.anchor && params.placeholder && self.anchor.html()=="") self.anchor.html(params.placeholder) 1167 } 1168 } 1169 1170 self.select = self.select || function(obj,set) { 1171 if (!obj[0]) return false; 1172 self.values.selected=obj 1173 if (!self.multiple) { 1174 obj.closest('ul').children().removeClass("selected") 1175 obj.addClass("selected"); 1176 } 1177 if (self.scroll) { 1178 var d={y:parseInt(obj.position().top),h1:parseInt(obj.outerHeight()),h2:parseInt(self.scroll.height()),s:parseInt(self.scroll.scrollTop())} 1179 if (d.y+d.h1>d.h2) self.scroll.scrollTop(d.s+d.y-d.h2+d.h1) 1180 else if (d.y<0) self.scroll.scrollTop(d.s+d.y) 1181 } 1182 if (set) { 1183 switch (self.layout) { 1184 case "options": 1185 obj.find("input[type='radio']").click() 1186 self.resume(); 1187 if (self.input) self.input.change(); 1188 //self.dropdown.find("li").show() 1189 break; 1190 case "date": 1191 self.values.text=obj.attr("data-value"); 1192 self.values.real=self.parse(self.values.text,"dd.mm.yyyy") 1193 if (self.input) self.input.val(self.values.text).change(); 1194 self.hide(); 1195 break; 1196 case "datetime": 1197 self.values.test=(set===2 || set===3)?self.values.date+" "+obj.val():obj.attr("data-value")+" "+self.values.time 1198 if (isNaN(self.parse(self.values.test,"dd.mm.yyyy hh:mm"))) return false; 1199 self.values.text=self.values.test 1200 self.values.real=self.parse(self.values.text,"dd.mm.yyyy hh:mm") 1201 self.values.date=self.values.text.split(" ")[0] 1202 self.values.time=self.values.text.split(" ")[1] 1203 if (self.input) self.input.val(self.values.text); 1204 if (set===3) self.hide(); 1205 break; 1206 } 1207 1208 if (!self.multiple && !obj.hasClass("collapse") && (self.layout!="datetime" || obj.hasClass("datetime"))) { 1209 self.hide(); 1210 if (self.input) self.input.blur(); 1211 } else { 1212 //if (input) input.focus() // removed because of focus on initialisation put wrong focus 1213 } 1214 if (self.onchange) self.onchange(self,obj) 1215 //input.change() 1216 } 1217 } 1218 1219 self.fill = self.fill || false // will be replace by a function if needed for each settings.layout 1220 1221 self.OLDlist = function(value,regexp) { // return the html to put in the main div (should be a ul) 1222 var ul=$("<ul/>").addClass("ds-body").attr("tabindex","-1"); // tabindex because of bug in firefox when user press "tab" 1223 scroll=ul 1224 var count=0,found=-1 1225 for (i=0,maxi=options.all.length;i<maxi;i++) { 1226 if (!regexp || regexp.test(options.all[i][1])) { 1227 if (regexp) html=options.all[i][1].replace(regexp, "<mark>$&</mark>"); else html=options.all[i][1] 1228 li=$("<li/>").addClass("ds-option").attr("data-value",options.all[i][0]).html(html) 1229 li.addClass("enabled").click(function(){self.select($(this),true)}) 1230 ul.append(li); 1231 //if (options.all[i][0]==options.value0) found=count 1232 count++ 1233 } 1234 } 1235 if (count==0) wrap.removeClass("ds-open"); else wrap.addClass("ds-open"); 1236 //if (found) self.select(false,false) 1237 return ul 1238 } 1239 1240 self.calendar = self.calendar || function(d) { // return the html of a month, in ul/li 1241 var dates={
1242 current:new Date() 1243 , cursor:new Date() 1244 , text:"dd.mm.yyyy" 1245 , today:self.format((new Date()),"dd.mm.yyyy") 1246 } 1247 if (self.values.real instanceof Date) dates.current=new Date(self.values.real); 1248 if (d instanceof Date) dates.current=new Date(d); 1249 dates.cursor=new Date(dates.current); // a day to play with (clone with new Date(current)) 1250 dates.cursor.setDate(1) // first day of month 1251 var offset=(dates.cursor.getDay()+6)%7; // offset of first day of month, monday as 0 1252 var ulhead=$("<ul/>").attr("class","ds-head"); 1253 var ulbody=$("<ul/>").attr("class","ds-body"); 1254 var ultime=false; // only if type=datetime 1255 var litpl=$("<li/>").attr("class","ds-cell"); // template for all li's 1256 // add item for navigation (next month,...) and title 1257 ulhead 1258 .append(litpl.clone().addClass("ds-nav ds-prevmonth").attr('data-nav','0,-1').text("<")) 1259 .append(litpl.clone().addClass("ds-nav ds-prevyear").attr('data-nav','-1,0').text("«")) 1260 .append(litpl.clone().addClass("ds-nav ds-name").text(self.pad(dates.current.getMonth()+1)+"."+dates.current.getFullYear())) 1261 .append(litpl.clone().addClass("ds-nav ds-nextyear").attr('data-nav','1,0').text("»")) 1262 .append(litpl.clone().addClass("ds-nav ds-nextmonth").attr('data-nav','0,1').text(">")); 1263 // add event to navigation 1264 $('.ds-nav[data-nav]',ulhead).click(function(){ 1265 arr=$(this).attr('data-nav').split(','); 1266 dates.nav=new Date(dates.current.getFullYear()+parseInt(arr[0],10),dates.current.getMonth()+parseInt(arr[1],10),1,dates.current.getHours(),dates.current.getMinutes()); 1267 self.dropdown.html(self.calendar(dates.nav)); 1268 return false; 1269 }) 1270 1271 // add item for days in previous month 1272 for (var i=0;i<offset;i++) ulbody.append(litpl.clone().addClass("ds-week0").html("<span class='ds-name'>"+self.days[(i+1)%7]+"</span>")); 1273 1274 // add item for curent month 1275 var li=false,inrange=true 1276 while (dates.current.getMonth()==dates.cursor.getMonth()) { 1277 dates.text=self.format(dates.cursor,"dd.mm.yyyy") 1278 li=litpl.clone().addClass("ds-week"+parseInt(i/7)).attr("data-value",dates.text) 1279 if (dates.text==dates.today) li.addClass("ds-today") 1280 if (dates.text==self.values.text) li.addClass("selected"); 1281 li.html("<span class='ds-name'>"+self.days[(i+1)%7]+"</span><span class='ds-day'>"+dates.cursor.getDate()+"</span>"); 1282 inrange=true; 1283 if (inrange && self.range && self.range[0] && self.range[0]>=dates.text.split(".").reverse().join("")) inrange=false 1284 if (inrange && self.range && self.range[1] && self.range[1]<dates.text.split(".").reverse().join("")) inrange=false 1285 if (inrange) { 1286 li.addClass("enabled").click(function(){ 1287 self.select($(this),true) 1288 }) 1289 } else { 1290 li.addClass("disabled") 1291 } 1292 ulbody.append(li); 1293 dates.cursor.setDate(dates.cursor.getDate()+1); // add one day. do not use dates.cursor=new Date(dates.cursor.getTime()+86400000); because of summer/winter time! 1294 i++; 1295 } 1296 1297 if (self.layout=="datetime") { 1298 ultime=$("<ul/>").attr("class","ds-time") 1299 ultime.append($("<li/>").text("hh:mm")) 1300 ultime.append($("<li/>").append($("<input tabindex='-1'/>").val(self.format(dates.current,"hh:mm")).change(function(){self.select($(this),2)}))) 1301 ultime.append($("<li/>").addClass("icon icon-ok pointer").click(function(){self.select($(this).nearest('input'),3)})) 1302 } 1303 return [ulhead,ulbody,ultime]; 1304 } 1305 1306 if (!self.wrap) self.wrap=$el.wrap("<div></div>").parent().addClass("ds-dropdown-wrap"); 1307 else if ($("#"+self.wrap).length) self.wrap=$("#"+self.wrap); 1308 else { 1309 self.wrap=$("<div/>").attr("id",self.wrap);$("dody").append(self.wrap) 1310 } 1311 1312 switch (self.layout) { 1313 case "options": 1314 if ($el.prop("tagName")!="UL") { 1315 alert("dropdown 'options' on a non-UL tag not implemented") 1316 return false; 1317 } 1318 // Check that there is no problem with radio button (multiple groups) 1319 self.tmp=$el.find("input[type='radio']").attr("name") 1320 if (self.tmp && $el.find("input[type='radio'][name='"+self.tmp+"']").length != $("input[type='radio'][name='"+self.tmp+"']").length) { //
1321 alert("Warning, radio buttons with name "+self.tmp+" are not unique on the page") 1322 } 1323 1324 1325 if (self.icon=="auto") self.icon=$("<i class='icon icon-down-dir'>") 1326 1327 if (!self.anchor) { 1328 if (self.mode=="edit") { 1329 if (self.wrap.next().prop("tagName")=="INPUT") self.input=self.wrap.next(); 1330 else if (self.wrap.prev().prop("tagName")=="INPUT") self.input=self.wrap.prev(); 1331 else self.input=self.wrap.next(); 1332 self.wrap.prepend(self.input); 1333 if (self.input && !self.input.attr("type")) self.input.attr("type","text") 1334 } else { 1335 self.anchor=$("<a href='#'/>").addClass("anchor"); 1336 self.wrap.prepend(self.anchor) 1337 } 1338 } 1339 1340 // here, we calculate the depth of the li > li > li. 1=only one level 1341 self.depth=0//Math.max.apply(Math, $el.find('li').map(function(){return $(this).parentsUntil($el,'li').length})) 1342 self.dropdown=$el.wrap("<div/>").parent().addClass("ds-dropdown ds-options"); 1343 if (self.highlight) self.dropdown.prepend($("<input/>",{type:"text",placeholder:"filter", style:"position:relative;border:1px solid #ddd;margin:2px;width:calc(100% - 4px);",onfocus:"$(this).cbyHighlight('li',$(this).next())"})) 1344 if (self.free && self.input) self.input.attr("name",self.free) 1345 self.dropdown.find("input").attr("tabindex","-1"); // unreachable by "tab" 1346 self.dropdown.find("input[type='checkbox']").change(function(){self.select($(this),true)}); 1347 self.dropdown.find("input[type='radio']").click(function(){self.select($(this),true)}); 1348 self.dropdown.find("input[indeterminate='indeterminate']").prop("indeterminate","indeterminate") // allow to set "indeterminate" attribute (not possible in html!) 1349 if (self.dropdown.find("input[type='radio']:checked").length) self.values.selected=[].concat(self.dropdown.find("input[type='radio']:checked")); 1350 self.dropdown.find("input + label").css({cursor:"pointer"}).each(function(i){ // set label clickable with "for" attribute 1351 var r="random"+Math.floor(999999*Math.random())+"_"+i 1352 $(this).attr("for",r).prev().attr("id",r) 1353 }) 1354 if (self.dropdown.find("li li").length==0) self.dropdown.find("li").not(".head").addClass("enabled") // allow up/down key if not multi level 1355 //if (self.dropdown.find("input:checked").length) self.resume() 1356 1357 if (self.multiple) self.resume({init:true}); 1358 // NOTE: do not set values in javascript directly, set the correct input:checked with javascript 1359 /*if (self.values && self.values.real && self.values.real.length) self.dropdown.find("input").each(function(i,o){ 1360 if(self.values.real.indexOf(o.value)>-1 || self.values.real.indexOf(parseInt(o.value,10))>-1) o.checked=true 1361 })*/ 1362 if (self.input && !self.multiple && !self.free) self.input.on("keydown",function(e){ return false}) // TODO check this and next line! problem: show all options after user select 1363 if (self.input && !self.multiple && self.free) self.input.on("keyup",function(e){ 1364 var regexp=false,collapse=false,textnode=false 1365 self.dropdown.find("li").show() 1366 if ($.trim(self.input.val())!="") regexp=RegExp(self.input.val().replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"),"i"); 1367 self.dropdown.find("li").not(".collapse").each(function(){ 1368 if (regexp && !regexp.test($(this).text())) { // also search inside children! 1369 $(this).hide(); 1370 } else { 1371 if (collapse=$(this).closest("li").find(".collapse")) collapse.eq(0).prop("checked",true) // only work for a double level, see for more 1372 textnode=$(this).find("label").eq(0);//.contents().filter(function(i,o){return o.nodeType==3}).wrap("<span/>") 1373 if (textnode[0].nodeType==3) textnode.html(regexp?textnode.text().replace(regexp, "<mark>$&</mark>"):textnode.text()) 1374 //else textnode.html(regexp?textnode.text().replace(regexp, "<mark>$&</mark>"):textnode.text()) 1375 } 1376 }) 1377 if (!regexp) self.dropdown.find("mark").unwrap() 1378 }) 1379 break; 1380 case "html": 1381 if ($el.prop("tagName")=="INPUT") self.input=$el; else self.anchor=$el; 1382 if (self.delayed) { 1383 self.dropdown=$("<div/>").addClass("ds-dropdown ds-html"); 1384 $el.one("click focus",function(){self.dropdown.html(self.html);cms_init(self.dropdown)}) 1385 } else { 1386 self.dropdown=$("<div/>").addClass("ds-dropdown ds-html").html(self.html); 1387 cms_init(self.dropdown) 1388 } 1389 self.wrap.append(self.dropdown); 1390 break; 1391 case "ajax": 1392 self.anchor=$el 1393 self.dropdown=$("<div/>").text("loading...") 1394 self.wrap.addClass("ds-dropdown-wrap") 1395 if (self.url) self.load=function(){ 1396 self.wrap.find(".ds-form-head").addClass("icon icon-spin icon-spinner").html("") 1397 //self.wrap.html("loading...") 1398 if (self.json) { 1399 $.ajax({url:self.url,dataType:"json",success:function(data){if(data.status==1) self.wrap.html(data.html);cms_init(self.wrap)}}) 1400 } else self.wrap.load(self.url),function(){cms_init(self.wrap)}} 1401 break; 1402 case "date": 1403 case "datetime": 1404 if ($el.prop("tagName")!="INPUT") { 1405 alert("dropdown 'date' ot 'datetime' on a non-INPUT tag not implemented") 1406 return false; 1407 } 1408 self.input=$el; 1409 if (self.input.val()) self.input.val(self.input.val().replace("/","").replace(" "," ")) 1410 if (self.input.val()) self.values.text=self.input.val(); else self.values.text=self.format(new Date(),"dd.mm.yyyy hh:00") 1411 self.values.real=self.parse(self.values.text,"dd.mm.yyyy hh:mm") 1412 self.values.date=self.values.text.split(" ")[0] 1413 self.values.time=self.values.text.split(" ")[1] 1414 if (self.layout=="date") self.values.text=self.values.date 1415 if (self.icon=="auto") self.icon=$("<i class='icon icon-calendar'>"); 1416 1417 if (self.range[0]||self.range[1]) { 1418 for (i=0;i<self.range.length;i++) 1419 if (self.range[i]==1) // today 1420 self.range[i]=self.format((new Date()),"yyyymmdd"); 1421 else 1422 self.range[i]=self.format(self.parse(self.range[i],"dd.mm.yyyy"),"yyyymmdd"); 1423 } 1424 self.dropdown=$("<div/>").addClass("ds-dropdown ds-calendar"); 1425 self.wrap.append(self.dropdown); 1426 self.fill=self.calendar
1427 if (self.input) self.input.keyup=function(){ 1428 if (self.input.val()==values.real) return false; 1429 if (/^[0-9]{2}\.[0-9]{2}\.[0-9]{4}/.test(self.input.val())) self.dropdown.html(self.calendar(self.parse(self.input.val(),"dd.mm.yyyy"))) 1430 } 1431 break; 1432 case "next": 1433 self.anchor=$el 1434 self.dropdown=$("<div/>").addClass("ds-dropdown").append(self.wrap.next().show()); 1435 self.wrap.append(self.dropdown); 1436 break; 1437 default: 1438 alert("dropdown '"+settings.layout+"' not implemented") 1439 return false; 1440 } 1441 1442 if (self.position=="right" && self.dropdown) self.dropdown.addClass("dropright") 1443 1444 if (self.input && self.placeholder) self.input.attr("placeholder",self.placeholder) 1445 if (self.input && self.icon!==false && self.icon!="auto") self.input.css({paddingRight:"1.5em"}).after(self.icon) 1446 //if (input && settings.multiple) input.attr("readonly","true"); // do not open keyboard on mobile devices, note: removed because this interfer with "required" attribute not fired 1447 if (self.input && self.width) self.input.css({width:self.width}) 1448 1449 if (self.dropdown) { 1450 self.dropdown.addClass("ds-"+self.mode) 1451 //self.dropdown.on("mouseenter",function(){self.inside=true}).on("mouseleave",function(){self.inside=false}) 1452 } else { 1453 //alert("Warning: no dropdown!") 1454 } 1455 1456 self.show = self.show || function(){ 1457 if (self.input && self.layout!="date" && self.layout!="datetime") self.dropdown.css({minWidth:self.input.outerWidth()}); 1458 self.wrap.addClass("ds-open"); 1459 //self.dropdown.removeClass("dropright"); 1460 //if(self.dropdown.offset().left+self.dropdown.width()>$(window).width()) self.dropdown.addClass("dropright"); 1461 } 1462 1463 self.hide = self.hide || function(){self.wrap.removeClass("ds-open");} 1464 1465 self.toggle = self.toggle || function(){self.wrap.toggleClass("ds-open");} 1466 1467 self.cbybox = self.cbybox || function(){$.cbybox.open(dropdown.removeClass('ds-dropdown'),{cssouter:{width:"auto"}})} 1468 1469 // Manage opening dropdown 1470 if (self.open===true) self.show() 1471 if (self.anchor) self.anchor.css({cursor:"pointer"}).attr("tabindex",self.tabindex||"1") 1472 if (self.position!="cbybox") { 1473 self.skipevent=false; 1474 (self.input||self.anchor).on("click focus",function(e){ 1475 if (! (self.skipevent=!self.skipevent)) return false; // avoid double events (focus+click or double click) 1476 setTimeout(function(){self.skipevent=false},300); 1477 if (self.wrap.hasClass("ds-open")) {self.hide();return false} 1478 if (self.fill) self.dropdown.html(self.fill()); 1479 if (self.load) self.load(); 1480 self.show(); 1481 e.preventDefault(); 1482 }) 1483 } else { 1484 (self.input||self.anchor).on("click",function(e){ 1485 self.cbybox(); 1486 e.preventDefault() 1487 }) 1488 } 1489 return self 1490 } 1491 // Manage closing dropdown 1492 $(document).on('mousedown.dropdown keyup.dropdown', function(e) { 1493 //console.log(e.target,$(".ds-dropdown-wrap.ds-open").length) 1494 var target=$(e.target) 1495 $(".ds-dropdown-wrap.ds-open").filter(function(){return !$(this).has(target).length}).removeClass("ds-open") 1496 }) 1497})(jQuery); 1498 1499/* cbyInputfile plugin */ 1500(function($){ 1501 /* OO jquery based on http://www.virgentech.com/blog/2009/10/building-object-oriented-jquery-plugin.html */ 1502 $.fn.cbyInputfile = function(options) { 1503 return this.each(function() { 1504 var element = $(this); 1505 // Return early if this element already has a plugin instance 1506 if (element.data('cbyInputfile')) return; 1507 // pass options to plugin constructor 1508 var cbyInputfile = new cbyInputfileClass(this, options); 1509 // Store plugin object in this element's data 1510 element.data('cbyInputfile', cbyInputfile); 1511 }); 1512 }; 1513 1514 var cbyInputfileClass = function(element,options) { 1515 // Start declaration (don't forget to put 'var' before every variables/functions!) 1516 // Default settings 1517 var self=this; 1518 var input=$(element); // The object 1519 var isIE = /(MSIE|Trident\/|Edge\/)/i.test(navigator.userAgent); 1520 var mode="edit" 1521 if (element.tagName.toLowerCase()!="input") mode="view" 1522 var multiple={ 1523 attr:input.attr("multiple"), // Is the input multiple (in the xml) 1524 support:input.multiple // Is the multiple supported in the browser? 1525 } 1526 var settings = jQuery.extend(true,{ 1527 placeholder:( (multiple.attr||options.large) && !options.small)? 1528 {text:"Click or drag",icon:"icon icon-upload",css:{fontSize:"2em",padding:"1em 0",textAlign:"center",color:"#aaa",border:"4px dashed #aaa",borderRadius:"5px"}}: 1529 {text:"Browse...",icon:"icon icon-upload",css:{padding:"2px 10px 4px", textAlign:"left",border:"1px solid #999",borderRadius:"3px",display:"inline-block"}}, 1530 inputcss:{maxWidth:"none",position:"absolute",opacity:0.01,width:"100%",height:"100%",zIndex:1,cursor:"pointer"}, 1531 //limit:{maxsize:40000000,maxfiles:100,extensions:[]}, 1532 layout:1, 1533 annex:false /* used to add some other field, ex: ["desc"]*/ 1534 }, options); 1535 var count={maxfiles:0} 1536 var name=input.attr("name") 1537 var wrap=input.wrap("<div></div>").parent(); 1538 var placeholder=$("<div></div>
1538").addClass("validation").css(settings.placeholder.css).html(settings.placeholder.text) 1539 wrap.on("dragover",function(){placeholder.css({borderColor:"#1e8cbe"})}).on("dragleave",function(){placeholder.css({borderColor:"#aaaaaa"})}) 1540 1541 if (settings.placeholder.icon) placeholder.prepend($("<i></i>").addClass(settings.placeholder.icon)) 1542 wrap.css({position:"relative"}).append(placeholder) 1543 input.css(settings.inputcss) 1544 var dropdown=$("<div></div>").addClass("ds-dropdown").css({position:"relative",minHeight:"2em",paddingTop:"0.5em",zIndex:"inherit"}).hide() 1545 var uldropdown=$("<ul></ul>").addClass("dragsort-items") 1546 wrap.after(dropdown.append(uldropdown)) 1547 //cms_init(dropdown) 1548 input.on("change",function(){self.change(this,"input")}); 1549 // For IE, we must catch the dragover to avoid going to the images and must watch the drop on the originalEvent (dataTransfer contains "files" property) 1550 if (isIE) input.on("drop",function(event){self.change(event.originalEvent.dataTransfer,"input")}).on("dragover",function(event){event.preventDefault()}) 1551 1552 self.filesize = function(a,b,c,d,e){return (a==0)?"0 Byte":(b=Math,c=b.log,d=1024,e=b.min(c(a)/c(d),'kMGTPEZY'.length)|0,a/b.pow(d,e)).toFixed(2)+' '+(e?'kMGTPEZY'[--e]+'B':'Bytes')} 1553 1554 self.checkextension = function(name) { 1555 var ext="."+name.split('.').pop().toLowerCase(); 1556 var extensions= 1557 { allowed:(settings.limit.extensions||[]).filter(function(v){return v[0]=="+"}).map(function(v){return v.replace("+",".").toLowerCase()}) 1558 , denied:(settings.limit.extensions||[]).filter(function(v){return v[0]=="-"}).map(function(v){return v.replace("-",".").toLowerCase()}) 1559 , error:0 1560 } 1561 if (extensions.allowed.length && extensions.allowed.indexOf(ext)==-1) extensions.error="extension not allowed (allowed: "+extensions.allowed.join(", ")+")" 1562 if (extensions.denied.length && extensions.denied.indexOf(ext)>-1) extensions.error="extension not allowed (denied: "+ext+")" 1563 return extensions.error 1564 } 1565 self.checklimit = function(text,number) { // text: maxsize (one by file), maxfiles (number of file) 1566 error=0 1567 if (settings.limit[text] && number>settings.limit[text]) error=text+" exceeded"; 1568 if (text=="maxsize" && number==0) error=text+" empty"; 1569 return error 1570 } 1571 self.change = function(obj,from) { /* obj.files comes from input.files OR options.files */ 1572 dropdown.show().parent().addClass("ds-open") 1573 var total=0,fake=false,li=false; 1574 if (!multiple.attr) uldropdown.html("") 1575 switch(settings.layout) { 1576 case 1: // input.files splitted in lines, can be moved and deleted 1577 for (var i=0;i<obj.files.length;i++) { 1578 li=$("<li></li>").css({padding:"0 0.5em 0.5em 1em"}).addClass("clearfix"); 1579 count={maxfiles:1} 1580 uldropdown.find(".ds-form-step").each(function(i,v){count.maxfiles++;}) 1581 var error=self.checkextension(obj.files[i].name) || self.checklimit("maxsize",obj.files[i].size) || self.checklimit("maxfiles",count.maxfiles) 1582 if (error===0) { 1583 if (from!="options") { 1584 fake=$("<input/>").attr("type","file").attr("name",name) // we add a fake input[type=file] used by jquery.form.js 1585 if (multiple.attr) fake.addClass("ds-form-step") // if multiple, add a class to tell cms_submit we have a pivot in the form 1586 fake.hide() 1587 fake.get(0).cbyfiles={files:obj.files,index:i} // as we can't set specific input.files, we copy all files and tell which index it is 1588 } else { 1589 fake=$("<input/>").attr("type","hidden").attr("name",name).val(JSON.stringify(obj.files[i])) // we add a fake input[type=hidden] for previous values 1590 } 1591 } else { 1592 fake=$("<div></div>").css({paddingLeft:"1em",color:"#f00",fontSize:"0.9em"}).html(error) 1593 } 1594 li.append($("<span></span>").text(obj.files[i].name)) 1595 if (from=="options" && obj.files[i].path) { 1596 a=$("<a/>").attr("target","_blank").attr("href",obj.files[i].path+obj.files[i].file) 1597 if (obj.files[i].type && (obj.files[i].type.indexOf("image")==0 || obj.files[i].type.indexOf("vimeo")==0)) a.attr("data-covr",obj.files[i].path+obj.files[i].file) 1598 li.children(0).wrapInner(a) 1599 } 1600 li.append($("<span></span>").addClass("right").html( 1601 [ self.filesize(obj.files[i].size) 1602 , (from!="options")?$("<span></span>").css({padding:"0 0.5em"}).addClass("ds-progress-text").html(""):"" 1603 , $("<i></i>
1603").addClass("icon icon-sort pointer dragsort-selector") 1604 , $("<i></i>").addClass("icon icon-cancel right pointer").click(function(){$(this).closest("li").remove()}) 1605 ])) 1606 if (settings.annex) li.append($("<div/>").addClass("annex").append(settings.annex)) 1607 if (from!="options") li.append($("<div></div>").addClass("ds-progress-width").hide().css({width:0,height:3,backgroundColor:"#0f0"})) 1608 li.append(fake) 1609 if (!multiple.attr) { 1610 li.find("i.icon-sort").remove() 1611 li.find("i.icon-cancel").unbind("click").click(function(){ 1612 $(this).closest("li").find("input").remove() 1613 $(this).closest("li").append($("<input/>").attr("type","hidden").val("{}").attr("name",name)) 1614 $(this).closest("li").find("> span").eq(0).css({textDecoration:"line-through"}) 1615 }) 1616 } 1617 li.find("[data-covr]").on("click",function(){$.covr.open($("<img/>",{src:$(this).attr("data-covr")}));return false}) 1618 uldropdown.append(li) 1619 } 1620 input.hide().get(0).disabled=true // tel jquery.form.js to skip this input 1621 break; 1622 case 2: // input.files stay in "block", blockes can be deleted, TODO: size+ext check 1623 for (var i=0;i<obj.files.length;i++) total+=obj.files[i].size 1624 li=$("<li></li>").css({padding:"0 0.5em 0.5em 1em"}).addClass("clearfix") 1625 li.append($("<span></span>").text(obj.files.length+" fichier(s)")) 1626 .append($("<i></i>").addClass("icon icon-down-dir pointer").click(function(){$(this).toggleClass("icon-down-dir").toggleClass("icon-right-dir").nearest("ul").toggle()})) 1627 .append($("<span></span>").addClass("right").html([self.filesize(total),$("<i></i>").addClass("icon icon-cancel right pointer").click(function(){$(this).closest("li").remove()})])) 1628 var ul=$("<ul></ul>").css({fontSize:"0.8em",color:"#999",paddingLeft:"1.5em"}) 1629 for (var i=0;i<obj.files.length;i++) { 1630 var file=obj.files[i] 1631 ul.append($("<li></li>").css({listStyle:"circle",paddingBottom:"0.2em"}).text(file.name+" - "+self.filesize(file.size))) 1632 } 1633 li.append(ul) 1634 li.append(input.attr("name",name).hide()) // real input are moved in the li, so containing all "files" in one input 1635 uldropdown.append(li) 1636 break; 1637 } 1638 // Create a new input with same attr but different name 1639 input=$("<input/>").attr("type","file").attr("name","tmp."+name).css(settings.inputcss).on("change",function(){self.change(this)}) 1640 if (isIE) input.on("drop",function(event){self.change(event.originalEvent.dataTransfer,"input")}).on("dragover",function(event){event.preventDefault()}) 1641 if (multiple.attr) input.attr("multiple","multiple") 1642 wrap.prepend(input) 1643 1644 } 1645 1646 self.vimeo=function(){ 1647 var vid=prompt("Vimeo ID, ex:39206630") 1648 if (!vid) return false 1649 if (!/^[0-9]+$/.test(vid)) {alert("Wrong video ID");return false;} 1650 $.get("https://vimeo.com/api/v2/video/"+vid+".json").then(function(data){ 1651 // [{"id":39206630,"title":"MAMCO, Museum of Contemporary Art of Geneva. Ad.","description":"","url":"https://vimeo.com/39206630","upload_date":"2012-03-26 11:56:31","mobile_url":"https://vimeo.com/39206630","thumbnail_small":"https://i.vimeocdn.com/video/270295514_100x75.jpg","thumbnail_medium":"https://i.vimeocdn.com/video/270295514_200x150.jpg","thumbnail_large":"https://i.vimeocdn.com/video/270295514_640.jpg","user_id":583391,"user_name":"Base Design","user_url":"https://vimeo.com/basedesign","user_portrait_small":"https://i.vimeocdn.com/portrait/6445559_30x30","user_portrait_medium":"https://i.vimeocdn.com/portrait/6445559_75x75","user_portrait_large":"https://i.vimeocdn.com/portrait/6445559_100x100","user_portrait_huge":"https://i.vimeocdn.com/portrait/6445559_300x300","stats_number_of_likes":4,"stats_number_of_plays":215,"stats_number_of_comments":0,"duration":15,"width":1280,"he
1651ight":720,"tags":"MAMCO, BaseMotion, BaseDesign, GVA STudio, Art, Museum, Spot, Humor, Still image","embed_privacy":"anywhere"}] 1652 if (data && data[0] && data[0]["thumbnail_large"]) { 1653 var fake=$("<input/>",{type:"hidden",name:name,val:JSON.stringify({request:data[0]["thumbnail_large"],name:data[0].title+".jpg",type:"vimeo",xtra:vid})}) 1654 var li=$("<li>").css({padding:"0 0.5em 0.5em 1em"}).addClass("clearfix").append( 1655 $("<span/>").append($("<a/>",{href:"#","data-covr":data[0]["thumbnail_large"]}).text(data[0].title+".jpg")), 1656 $("<span/>",{class:"right"}).html([ 1657 fake, 1658 $("<i></i>").addClass("icon icon-sort pointer dragsort-selector"), 1659 $("<i></i>").addClass("icon icon-cancel right pointer").click(function(){$(this).closest("li").remove()}) 1660 ]) 1661 ) 1662 li.find("[data-covr]").on("click",function(){$.covr.open($("<img/>",{src:$(this).attr("data-covr")}));return false}) 1663 uldropdown.append(li) 1664 } else div.text("Error loading vimeo....") 1665 }) 1666 } 1667 if (settings.vimeo) wrap.css({display:"inline-block",width:"80%"}).after( 1668 $("<div/>").css({display:"inline-block",width:"15%",float:"right"}) 1669 .append(placeholder.clone().text("Vimeo")).css({cursor:"pointer"}).on("click",self.vimeo) 1670 ) 1671 1672 // Init with current values. Note, if options.files is empty it may be [{}], so check also the first files[0] to have a .name key 1673 if (options.files && options.files.length && options.files[0].name) { 1674 dropdown.css({opacity:1,transition:"none 0s"}) // no transition if already filled with something 1675 self.change(options,"options") 1676 } 1677 1678 } 1679})(jQuery); 1680 1681/* 1682* jQuery.bind-first library v0.2.3 1683* Copyright (c) 2013 Vladimir Zhuravlev 1684* 1685* Released under MIT License 1686* @license 1687* 1688* Date: Thu Feb 6 10:13:59 ICT 2014 1689**/ 1690(function(t){function e(e){return u?e.data("events"):t._data(e[0]).events}function n(t,n,r){var i=e(t),a=i[n];if(!u){var s=r?a.splice(a.delegateCount-1,1)[0]:a.pop();return a.splice(r?0:a.delegateCount||0,0,s),void 0}r?i.live.unshift(i.live.pop()):a.unshift(a.pop())}function r(e,r,i){var a=r.split(/\s+/);e.each(function(){for(var e=0;a.length>e;++e){var r=t.trim(a[e]).match(/[^\.]+/i)[0];n(t(this),r,i)}})}function i(e){t.fn[e+"First"]=function(){var n=t.makeArray(arguments),i=n.shift();return i&&(t.fn[e].apply(this,arguments),r(this,i)),this}}var a=t.fn.jquery.split("."),s=parseInt(a[0]),f=parseInt(a[1]),u=1>s||1==s&&7>f;i("bind"),i("one"),t.fn.delegateFirst=function(){var e=t.makeArray(arguments),n=e[1];return n&&(e.splice(0,2),t.fn.delegate.apply(this,arguments),r(this,n,!0)),this},t.fn.liveFirst=function(){var e=t.makeArray(arguments);return e.unshift(this.selector),t.fn.delegateFirst.apply(t(document),e),this},u||(t.fn.onFirst=function(e,n){var i=t(this),a="string"==typeof n;if(t.fn.on.apply(i,arguments),"object"==typeof e)for(type in e)e.hasOwnProperty(type)&&r(i,type,a);else"string"==typeof e&&r(i,e,a);return i})})(jQuery); 1691 1692/* 1693 cbyTouchmouse plugin (simulate mouse[events] from touch[event], ex: for drag&drop, use as $('document').cbyTouchmouse(), or $('div.touch').cbyTouchmouse() 1694 2013 - Stéphane Carion 1695 * Based on work by Shaun Inman 1696 * http://ross.posterous.com/2008/08/19/iphone-touch-events-in-javascript/ 1697*/ 1698 1699(function($) { 1700 $.fn.cbyTouchmouse = function(options) { 1701 var settings = { 1702 }; 1703 if(options) { 1704 $.extend(settings, options); 1705 }; 1706 var container = $(this); 1707 return this.each(function() { 1708 var touchHandler = function(event) { 1709 var touch = event.changedTouches[0]; 1710 1711 var simulatedEvent = document.createEvent("MouseEvent"); 1712 simulatedEvent.initMouseEvent({ 1713 touchstart: "mousedown", 1714 touchmove: "mousemove", 1715 touchend: "mouseup" 1716 }[event.type], true, true, window, 1, 1717 touch.screenX, touch.screenY, 1718 touch.clientX, touch.clientY, false, 1719 false, false, false, 0, null); 1720 1721 touch.target.dispatchEvent(simulatedEvent); 1722 event.preventDefault(); 1723 } 1724 1725 this.addEventListener("touchstart", touchHandler, true); 1726 this.addEventListener("touchmove", touchHandler, true); 1727 this.addEventListener("touchend", touchHandler, true); 1728 this.addEventListener("touchcancel", touchHandler, true); 1729 }) 1730 } 1731})(jQuery); 1732 1733(function($) { 1734 $.fn.cbyWysiwyg = function(options) { 1735 if(options) { 1736 $.extend(settings, options); 1737 }; 1738 var container = $(this);
1739 var makeiteditable = function(obj,arg) { 1740 arg=arg||{} 1741 obj.attr("contenteditable","true") 1742 1743 if (arg.oneline) { 1744 obj.bind("keydown",function(e){ // disallow <return> 1745 var code = null; 1746 code = (e.keyCode ? e.keyCode : e.which); 1747 return (code == 13) ? false : true; 1748 }) 1749 obj.bind("paste",function(e){ // on paste, juste take the first line 1750 var data = e.originalEvent.clipboardData.getData('Text'); 1751 insertHtml(data.split(/\r\n|\r|\n/g)[0]); 1752 return false; 1753 }) 1754 } else { 1755 obj.bind("paste",function(e){ 1756 var data = e.originalEvent.clipboardData.getData('Text'); 1757 insertHtml(data.replace(/\r\n|\r|\n/g,"<br>")); 1758 return false; 1759 }) 1760 } 1761 var eventname="mouseup" 1762 if (window.chrome) eventname="mousedown mouseup" // both mouseup and mousedown needed for Chrome 1763 switch (arg.exec||"full") { 1764 case "full": 1765 obj.addClass("exec execfull") 1766 obj.bind(eventname,function(e){ 1767 if (!window.getSelection().isCollapsed) { 1768 var a=["bold","italic","underline","forecolor_#ff0000","forecolor_#00ff00","removeFormat_foreColor"]; 1769 //var a=["bold","italic","underline","forecolor_#ff0000","insertunorderedlist","removeFormat_foreColor"]; 1770 var position={imgw:150,imgh:30,x:e.offsetX-parseInt($(this).css("padding-left"),10),y:$(this).height()-e.offsetY} 1771 position.index=parseInt(position.x/position.imgw*a.length) 1772 console.log(position) 1773 if(position.y<position.imgh && position.index < a.length){ 1774 document.execCommand(a[position.index].split("_")[0],false,a[position.index].split("_")[1]) 1775 document.getSelection().removeAllRanges() 1776 } 1777 } 1778 $(this).toggleClass("execon",!window.getSelection().isCollapsed) 1779 }) 1780 break; 1781 case "simple": 1782 obj.addClass("exec execsimple") 1783 obj.bind(eventname,function(e){ 1784 if (!window.getSelection().isCollapsed) { 1785 var a=["forecolor_#ff0000","forecolor_#00ff00","removeFormat_foreColor"]; 1786 var position={imgw:75,imgh:30,x:e.offsetX-parseInt($(this).css("padding-left"),10),y:$(this).height()-e.offsetY} 1787 position.index=parseInt(position.x/position.imgw*a.length) 1788 if(position.y<position.imgh && position.index < a.length){ 1789 document.execCommand(a[position.index].split("_")[0],false,a[position.index].split("_")[1]) 1790 document.getSelection().removeAllRanges() 1791 } 1792 } 1793 $(this).toggleClass("execon",!window.getSelection().isCollapsed) 1794 }) 1795 break; 1796 } 1797 } 1798 1799 // paste after caret position 1800 var insertHtml=function(html) { 1801 var sel, range; 1802 if (window.getSelection) { 1803 sel = window.getSelection(); 1804 if (sel.getRangeAt && sel.rangeCount) { 1805 range = sel.getRangeAt(0); 1806 range.deleteContents(); 1807 var el = document.createElement("div"); 1808 el.innerHTML = html; 1809 var frag = document.createDocumentFragment(), node, lastNode; 1810 while ( (node = el.firstChild) ) { 1811 lastNode = frag.appendChild(node); 1812 } 1813 range.insertNode(frag); 1814 if (lastNode) { 1815 range = range.cloneRange(); 1816 range.setStartAfter(lastNode); 1817 range.collapse(true); 1818 sel.removeAllRanges(); 1819 sel.addRange(range); 1820 } 1821 } 1822 } else { 1823 if (document.selection && document.selection.type != "Control") document.selection.createRange().pasteHTML(html); 1824 } 1825 } 1826 1827 //Clear all character inside word document and other 1828 var cleanWordPaste=function(input) { 1829 var tmp = document.createElement("DIV"); 1830 tmp.innerHTML = input; 1831 var newString = tmp.textContent||tmp.innerText; 1832 newString = newString.replace(/\n\n/g, "<p />").replace(/.*<!--.*-->/g,""); 1833 for ( i=0; i<10; i++ ) { 1834 if ( newString.substr(0,6)=="<br />" ) { 1835 newString = newString.replace("<br />", ""); 1836 } 1837 } 1838 return newString; 1839 } 1840 1841 $('body').on('focus', '.execwatch[contenteditable]', function() { 1842 var $this = $(this); 1843 $this.data('before', $this.html()); 1844 return $this; 1845 }).on('blur paste', '.execwatch[contenteditable]', function(e) { 1846 //console.log(e.type) 1847 var $this = $(this); 1848 if ($this.data('before') !== $this.html()) { 1849 $this.data('before', $this.html()); 1850 1851 $this.prev().val($this.data('before')) 1852 //console.log($this.html()) 1853 $this.trigger('change'); 1854 } 1855 return $this; 1856 }); 1857 1858 return this.each(function() { 1859 var self=$(this) 1860 if ($(this).prop("tagName").toLowerCase()=="textarea") { 1861 $(this).wrap($("<div></div>").addClass("ds-inner"))//css({padding:"0.2em",border:"1px solid #999"})) 1862 self=$("<div></div>").addClass("execwatch").html($(this).val()||"<br>"); 1863 $(this).after(self).hide() 1864 } 1865 makeiteditable(self,"full"); 1866 }) 1867 1868}})(jQuery); 1869 1870/* simple ping, ex: $.fn.ping(); or $.fn.ping(false), timeout is set to 55 min as session are 60 minutes */ 1871jQuery.fn.ping = function(flag){ 1872 if (flag===false) {clearTimeout($("html").data("ping"));$("html").data("ping",false);return} 1873 var ping=function(){$.get("/ping/"+$("html").data("ping"))} 1874 $("html").data("ping",$("html").data("ping")||setInterval(ping,1000*60*55)) 1875} 1876 1877/* jquery addData, add a class "data" and an attribute "data-key" with JSON.encode string of value */ 1878jQuery.fn.addData = function(data) { 1879 $(this).addClass("data"); 1880 for (key in data) $(this).attr("data-"+key,($.type(data[key]) === "string")?data[key]:JSON.stringify(data[key])) 1881 return $(this); 1882}; 1883/* jquery field, find the input[name='#name#'] in the nearest form */ 1884jQuery.fn.field = function(name) { 1885 return $(this).nearest("form").find(":input").filter(function(){return name=="" || $(this).attr("name")==name}); 1886}; 1887 1888/* 1889 cbyTouchmouse plugin (simulate mouse[events] from touch[event], ex: for drag&drop, use as $('document').cbyTouchmouse(), or $('div.touch').cbyTouchmouse() 1890 2013 - Stéphane Carion 1891 * Based on work by Shaun Inman 1892 * http://ross.posterous.com/2008/08/19/iphone-touch-events-in-javascript/ 1893 NOTE: warning: scrolling with finger will be unavailable on the object! 1894*/ 1895 1896(function($) { 1897 $.fn.cbyTouchmouse = function(options) { 1898 var settings = { 1899 }; 1900 if(options) { 1901 $.extend(settings, options); 1902 }; 1903 var container = $(this); 1904 return this.each(function() { 1905 var touchHandler = function(event) { 1906 var touch = event.changedTouches[0]; 1907 1908 var simulatedEvent = document.createEvent("MouseEvent"); 1909 simulatedEvent.initMouseEvent({ 1910 touchstart: "mousedown", 1911 touchmove: "mousemove", 1912 touchend: "mouseup" 1913 }[event.type], true, true, window, 1, 1914 touch.screenX, touch.screenY, 1915 touch.clientX, touch.clientY, false, 1916 false, false, false, 0, null); 1917 1918 touch.target.dispatchEvent(simulatedEvent); 1919 event.preventDefault(); 1920 } 1921 1922 this.addEventListener("touchstart", touchHandler, true); 1923 this.addEventListener("touchmove", touchHandler, true); 1924 this.addEventListener("touchend", touchHandler, true); 1925 this.addEventListener("touchcancel", touchHandler, true); 1926 }) 1927 } 1928})(jQuery); 1929 1930/* jquery nearest, from https://github.com/fusionbox/jquery-nearest */ 1931/* add by cby: just return the first match (.eq(0)) */ 1932(function($) { 1933 $.fn.nearest = function(find_child, closest_parent) { 1934 if ( typeof closest_parent == 'undefined' ) { 1935 if ( $(document).find(find_child).length === 0 ) return $([]); 1936 1937 var current = $(this); 1938 var child = null; 1939 while ( current.length !== 0 ) { 1940 child = current.find(find_child); 1941 if ( child.length ) return child.eq(0); 1942 1943 if ( current.parent() == current ) break; 1944 current = current.parent(); 1945 } 1946 //return an empty set: 1947 return $([]); 1948 } 1949 var closest = $(this).closest(closest_parent); 1950 if ( closest.filter(find_child).length ) return closest.filter(find_child).eq(0); 1951 return closest.find(find_child).eq(0); 1952 } 1953})(jQuery); 1954 1955(function($) { 1956 $.fn.bgi=function(uri,anim){ 1957 // correct way the set a background image (even if uri is complexe - spaces, quote, slashes), ex: $("div.bg").bgi("/img/space éèà .gif") 1958 // note: if uri has a scheme, "contain:"|"cover:" use it to set full background property 1959 var self=$(this) 1960 uri=uri.split(":") 1961 if (["contain","cover","initial"].indexOf(uri[0])>-1) { 1962 self.css({backgroundSize:uri.splice(0,1),backgroundRepeat:"no-repeat",backgroundPosition:"center"}) 1963 } 1964 var url="url("+uri[0].split("/").map(function(o){return encodeURIComponent(o)}).join("/")+")" 1965 if (anim) { 1966 self.parent().css({overflow:"hidden"}) 1967 var clone=self.clone().empty().css({position:"absolute",width:self.width(),left:anim/4+"px"}).offset(self.offset()) 1968 self.after(clone.animate({left:(anim>0)?"100%":"-100%"},400,function(){$(this).remove()})) 1969 } 1970 return self.css({backgroundImage:url}) 1971 } 1972})(jQuery); 1973 1974(function($) { 1975 $.fn.cbyHighlight = function(arg, path, regex) { 1976 // Ex: <input type="text" placeholder="Search" onfocus="$(this).cbyHighlight('.o-highlight-item')"> 1977 // or $("input.o-highlight").cbyHighlight(".o-highlight-item") 1978 // or $('body').cbyHighlight(true,"text") 1979 var firsttime=true,visible=true 1980 function innerHighlight(node, path, regex) { 1981 var skip = 0; 1982 if (node.nodeType == 3) { 1983 var pos=node.data.search(regex) 1984 if (pos >= 0) { 1985 var mark = document.createElement('mark'); 1986 var middlebit = node.splitText(pos); 1987 var endbit = middlebit.splitText(path.length); 1988 var middleclone = middlebit.cloneNode(true); 1989 mark.appendChild(middleclone); 1990 middlebit.parentNode.replaceChild(mark, middlebit); 1991 skip = 1; 1992 } 1993 } else if (node.nodeType == 1 && node.childNodes && !/(script|style|mark)/i.test(node.tagName)) { 1994 for (var i = 0; i < node.childNodes.length; ++i) { 1995 i += innerHighlight(node.childNodes[i], path, regex); 1996 } 1997 } 1998 return skip; 1999 } 2000 if (arg === true || arg[0]===true) { // arg=[true] means path is an array of str
2000ing 2001 return this.length && path && path.length ? this.each(function() { 2002 if (arg[0]===true){ 2003 for (var i=0;i<path.length;i++) innerHighlight(this,path[i],regex[i]); 2004 }else{ 2005 innerHighlight(this,path,regex); 2006 } 2007 }) : this; 2008 } else if (arg === false) { 2009 return this.find("mark").each(function() { 2010 this.parentNode.firstChild.nodeName; 2011 with(this.parentNode) { 2012 replaceChild(this.firstChild, this); 2013 normalize(); 2014 } 2015 }).end(); 2016 } else this 2017 .filter(function(){return $(this).is("input") && !$(this).data("cbyhighlights")}) 2018 .data("cbyhighlights", $(arg||".o-highlight-item",path)) 2019 .on("keyup", function(e) { 2020 //if (firsttime) {firsttime=false;$(this).data("cbyhighlights").find("*").append(" ")} // add a space to all node to avoid text() to return joined string (<p>aa</p><p>bb</p>).text() -> aabb and not aa bb 2021 if (firsttime) visible=$(this).data("cbyhighlights").eq(0).is(":visible"); // will show/hide as initial state when keyword="" 2022 firsttime=false 2023 console.log($(this).data("cbyhighlights-delimiter")||" ") 2024 $(this).data("cbyhighlights").hide() 2025 var keyword = $(this).val().toLowerCase().trim().replace(/\s\s+/g, ' ') 2026 ,keywords = keyword.split($(this).data("cbyhighlights-delimiter")||" ") 2027 ,count = 0 2028 if(keywords.length>1) 2029 var regex=keywords.map(function(r){ 2030 return pipe.regsafe(r) 2031 }) 2032 else 2033 var regex=pipe.regsafe(keyword) 2034 2035 if (keyword == "") 2036 $(this).data("cbyhighlights").toggle(visible).parent().cbyHighlight(false) 2037 else { 2038 $(this).data("cbyhighlights").hide().parent().cbyHighlight(false) 2039 2040 if(keywords.length>1) { 2041 $(this).data("cbyhighlights").each(function(){ 2042 var and=true 2043 ,tr=this 2044 regex.map(function(r){ 2045 if($(tr).text().search(r)==-1) 2046 and=false 2047 }) 2048 if(and){ 2049 count++ 2050 $(this).show().cbyHighlight([true], keywords, regex) 2051 } 2052 }) 2053 if(count==0){ 2054 var or=new RegExp((pipe.regsafe(keywords.join('---'))).toString().replace(/---/gi,'|').slice(1,-3),'gi') 2055 2056 $(this).data("cbyhighlights").each(function(){ 2057 if ($(this).text().search(or)!=-1) 2058 $(this).show().cbyHighlight([true], keywords, regex) 2059 }) 2060 } 2061 }else{ 2062 $(this).data("cbyhighlights").each(function(){ 2063 if ($(this).text().search(regex)!=-1) 2064 $(this).show().cbyHighlight(true, keyword ,regex) 2065 }) 2066 } 2067 } 2068 }) 2069 2070 return this; 2071 }; 2072})(jQuery); 2073 2074;(function($, window){ 2075 var dom = {} 2076 dom.self = $(this); // window or element which trigger the call to covr 2077 dom.back = $("<div/>",{class:"o-covr o-covr-back"}).hide(); 2078 dom.main = $("<div/>",{class:"o-covr-main"}).appendTo(dom.back); 2079 dom.scrl = $("<div/>",{class:"o-covr-scrl"}).appendTo(dom.main); 2080 ;["head.u-text--l","body","foot"].forEach(function(key){ 2081 dom[key.split(".")[0]] = $("<div/>",{class:"o-covr-"+key.replace(/\./g," ")}).appendTo(dom.main) 2082 }) 2083 var conf = { speed:100, foot: {"ok":function(){$.covr.close();}}} 2084 dom.back.on("click",function(e){ 2085 var target=$(e.target); 2086 if (!dom.back.hasClass("js-modal") && !target.hasClass("o-covr-main") && target.closest(".o-covr-main").length==0) $.covr.close() 2087 }) 2088 $.covr = { 2089 open: function(html,opts,event){ 2090 if (event) dom.self = $(event.target) 2091 dom.focus = $(":focus").blur() 2092 opts=$.extend(true,{},conf,opts) 2093 dom.back.appendTo($("body")).toggleClass("js-modal",!!opts.modal) 2094 html={head:"",body:html,split:[]} 2095 if ($.type(html.body)=="string" && (html.split=html.body.split("|")) && html.split.length>1) { 2096 html.head=html.split[0] 2097 html.body=html.split[1] 2098 if (html.split.length>2) {opts.foot[html.split[2]]=opts.foot.ok;delete opts.foot.ok} 2099 } 2100 dom.head.empty().append(html.head) 2101 dom.body.empty().append(html.body) 2102 dom.foot.empty().append(Object.keys($.extend({},opts.foot)).filter(function(key){return opts.foot[key]}).map(function(key){ 2103 return $("<a/>",{class:"o-button u-pointer"}).text(key).on("click",$.proxy(opts.foot[key],dom)) 2104 })) 2105 if (opts.close) dom.main.prepend($("<div/>",{class:"o-covr-close u-pointer icon icon-cancel"}).on("click",function(){$.covr.close();return false;})) 2106 if (opts.scrl) dom.scrl.append(dom.head,dom.body,dom.foot) 2107 if (opts.wrap) dom.back.append(opts.wrap.append(dom.main)) 2108 dom.back[0].className="o-covr o-covr-back "+(opts.class||"") 2109 dom.back.fadeIn(conf.speed) 2110 if (opts.scrl) dom.scrl.css({paddingRight:dom.scrl[0].offsetWidth-dom.scrl[0].clientWidth}
2110) 2111 return dom.back 2112 }, 2113 close: function(){ 2114 dom.foot.empty() 2115 dom.back.fadeOut(conf.speed); 2116 dom.focus.focus() 2117 }, 2118 load: function(url,opts,event){ 2119 if (event) dom.self = $(event.target) 2120 $.ajax({url:url,success:function(html){$.covr.open(html,opts)}}) 2121 return false; 2122 }, 2123 is: function(mode) { 2124 if (mode==1 || mode=="open") return dom.back.is(":visible"); 2125 if (mode==0 || mode=="close") return !dom.back.is(":visible"); 2126 } 2127 } 2128 $.fn.covr = function(html,opts){return $.covr.open($(this))} 2129})(jQuery, this); 2130 2131/* tipr plugin */ 2132;(function($, window){ 2133 var dom = { 2134 self: $(this), // window or element which trigger the call to tipr 2135 main: $("<div/>",{class:"o-tipr"}), 2136 html: "Info", 2137 timeout: false, 2138 pos: {w:0,h:0,x:0,y:0,d:"nw"}, // position: width, height, x, y and direction 2139 all: "o-tipr-nw o-tipr-ne o-tipr-sw o-tipr-se" 2140 } 2141 var conf = { speed:100 } 2142 $("body").on("click.tipr",function(e){ 2143 var target=$(e.target); 2144 if (!target.hasClass("o-tipr-main") && target.closest(".o-tipr-main").length==0) $.tipr.close() 2145 }) 2146 $.tipr = { 2147 open: function(opts,event){ 2148 if (event) dom.self = $(event.target) 2149 opts=$.extend(true,{},conf,opts) 2150 dom.html=dom.self.data("tipr-html")||dom.self.attr("title") 2151 dom.self.data("tipr-html",dom.html);dom.self.removeAttr("title") 2152 if ((""+dom.html).trim()=="") return 2153 dom.pos.w=dom.self.outerWidth(); dom.pos.h=dom.self.outerHeight() 2154 dom.pos.x=dom.self.offset().left+dom.pos.w/2;dom.pos.y=dom.self.offset().top+dom.pos.h/2 2155 dom.pos.d=[(dom.pos.y>$("html").scrollTop()+$(window).height()/2)?"s":"n",(dom.pos.x>$("html").scrollLeft()+$(window).width()/2)?"e":"w"].join("") 2156 dom.main.empty().append(dom.html).appendTo($("body")).removeClass(dom.all).addClass("o-tipr-"+dom.pos.d).css({ 2157 top: dom.pos.d[0]=="n"?dom.pos.y+dom.pos.h/2:"auto", 2158 left: dom.pos.d[1]=="w"?dom.pos.x:"auto", 2159 bottom: dom.pos.d[0]=="s"?$(window).height()-dom.pos.y+dom.pos.h/2:"auto", 2160 right: dom.pos.d[1]=="e"?$(window).width()-dom.pos.x:"auto" 2161 }).fadeIn(conf.speed) 2162 return dom.main 2163 }, 2164 close: function(){ 2165 dom.main.fadeOut(conf.speed); 2166 }, 2167 delay: function(flag,opts){ 2168 clearTimeout(dom.timeout) 2169 var func=function(){} 2170 if (flag=="on") func=function(){$.tipr.open(opts)} 2171 else func=function(){$.tipr.close()} 2172 dom.timeout = setTimeout(func,conf.speed) 2173 } 2174 } 2175 $.fn.tipr = function(opts){ 2176 return this.each(function() { 2177 $(this).hover( 2178 function(){dom.self=$(this);$.tipr.delay("on")}, 2179 function(){$.tipr.delay("off")} 2180 ) 2181 }) 2182 } 2183})(jQuery, this); 2184 2185// debounce and throttle prototypes 2186Function.prototype.debounce=function(delay, immediate) { 2187 // Ex: $input.on("keyup",function(){console.log(this.value)}.debounce(false)}) 2188 // Ex: $input.on("change blur",function(){console.log(this.value)}.debounce(true)}) 2189 // Warning: if immediate=true, the last event may not be fired! 2190 if (delay===true||delay===false) {immediate=delay;delay=false} 2191 var timeout,func=this; 2192 return function() { 2193 var context = this, args = arguments, delayed = function() { 2194 timeout = null; 2195 if (!immediate) func.apply(context, args); 2196 }; 2197 var callNow = immediate && !timeout; 2198 clearTimeout(timeout); 2199 timeout = setTimeout(delayed, delay || 250); 2200 if (callNow) func.apply(context, args); 2201 }; 2202}; 2203Function.prototype.throttle = function(delay){ 2204 // Ex: $(window).on("resize",function(){console.log($(this).width())}.throttle(250)) 2205 var skip, func = this, clear = function() { 2206 skip = false; 2207 }; 2208 return function() { 2209 if (!skip) { 2210 func.apply(this, arguments); 2211 setTimeout(clear, delay || 250); 2212 skip = true; 2213 }; 2214 } 2215}; 2216 2217var pipe={ 2218 test: function() { 2219 console.log(pipe.gettype({test:1}),pipe.gettype(/$me^/)) 2220 console.log(pipe.escape("this is a <i>italic</i>\n this is <bold>")) 2221 console.log(pipe.regsafe("c'est l'été!")) 2222 console.log(pipe.sanitize("Sanitize this à é$ string")) 2223 console.log(pipe.filesize(43274983)) 2224 }, 2225 gettype: function(obj){ // returns the type of the objet "boolean","number","string","array","object","regexp" 2226 return ({}).toString.call(obj).slice(8,-1).toLowerCase(); 2227 }, 2228 escape: function(s,br) { // returns the xml escaped string of input ("<" becomes "<"). Only 5 characters must be replaced - if br is not false, also replace "\n" with "<br />" 2229 return (""+s) 2230 .replace(pipe._escape[0], function (ch) {return pipe._escape[1][ch];}) 2231 .replace((br===false)?pipe._escape[2]:pipe._escape[3],'<br />') 2232 }, 2233 sanitize: function(s,lower) { // returns a "sanitized" version of the string, ex: "This is an éà $" -> "this is an ea-"
2234 if (pipe.gettype(s)!="string") return ""; 2235 if (lower) s=s.toLowerCase(); 2236 return s.replace(pipe._sanitize[0],function(a){return pipe._sanitize[1][a.toLowerCase()]||"-"}).replace(pipe._sanitize[2],"-"); 2237 }, 2238 regsafe: function(s,check) { // returns a RegExp with escaped's chars and make it case insentitive and accent insensitive, if check is true, the string s may be a regexp already -> check it! 2239 s=""+s 2240 var parts = s.split('/'); 2241 if (check && parts.length > 1 && parts[0]=="") { 2242 try {return new RegExp(parts[1], parts[parts.length-1]);} 2243 catch(e) {return pipe.regsafe(s,false)} 2244 } 2245 // 1. remove all special meaning regexp char (. -> \.) 2246 s=s.replace(pipe._regsafe[0], "\\$1") 2247 // 2. replace all accent with non-accent (été -> ete) 2248 for (key in pipe._regsafe[1]) if (pipe._regsafe[1].hasOwnProperty(key)) s=s.replace(new RegExp(pipe._regsafe[1][key], 'g'),key) 2249 // 3. prepare new regexp, add key to regexp (e:[èéêë] -> e:[eèéêë]) 2250 for (key in pipe._regsafe[1]) if (pipe._regsafe[1].hasOwnProperty(key)) pipe._regsafe[1][key]="[" + key + pipe._regsafe[1][key].slice(1); 2251 // 4. replace all possible accented char with regexp equivalent (ete -> [èéêë]t[eèéêë]) 2252 for (key in pipe._regsafe[1]) if (pipe._regsafe[1].hasOwnProperty(key)) s=s.replace(new RegExp(key, 'g'),pipe._regsafe[1][key]) 2253 return new RegExp(s,"gi") 2254 }, 2255 filesize: function(n,arg) { 2256 arg=arg||pipe._filesize 2257 return function(a,b,c,d,e){return (a==0)?arg.zero:(b=Math,c=b.log,d=1024,e=b.min(c(a)/c(d),arg.suffix[1].length)|0,a/b.pow(d,e)).toFixed(arg.decimal)+arg.separator+(e?arg.suffix[1][--e]+'B':arg.suffix[0])}(n) 2258 }, 2259 delimiter: function(number,chr) { // 1000000.12345 -> 1'000'000.12345 2260 return number.toString().split(".").map(function(o,i){return (i>0)?o:o.replace(pipe._delimiter[0], "$1"+(chr||"'"))}).join(".") 2261 }, 2262 pad: function(number,len,chr){ 2263 var number=""+number,chr=chr||"0" 2264 while (number.length<len) number=chr+number 2265 return number; 2266 }, 2267 date: { 2268 format: function(d,format){ // pipe.date.format(#date#,"DD.MM.YYYY") => "25.12.2016", allowed tag: Y,M,D,H,h,m,s 2269 var d=d||new Date(),self={Y:d.getFullYear(),M:d.getMonth()+1,D:d.getDate(),H:d.getHours(),h:d.getHours(),m:d.getMinutes(),s:d.getSeconds()} 2270 if (format===true) return self 2271 return (format||pipe._date.format||"DD.MM.YYYY").match(pipe._date.match) // returns ["DD","HH","YYYY",...] 2272 .map(function(o){return self.hasOwnProperty(o[0])?pipe.pad(self[o[0]],o.length):o}).join("") 2273 }, 2274 parse: function(s,format){ 2275 var d={},format=format||pipe._date.parse||"DD.MM.YYYY hh:mm:ss" 2276 var m=format.match(pipe._date.match).filter(function(o){return "DMYHhms".indexOf(o[0])!=-1}) 2277 s.match(/\d+/g).forEach(function(o,i){d[m[i][0]]=parseInt(o,10)}) 2278 return new Date(d.Y||0,d.M-1||0,d.D||0,Math.min(d.H||d.h||0,24),Math.min(d.m||0,60),Math.min(d.s||0,60)) 2279 } 2280 }, 2281 cookie: { 2282 get:function (name) { 2283 var t = "; " + document.cookie, 2284 i = t.split("; " + name + "="); 2285 return 2 != i.length ? void 0 : i.pop().split(";").shift() 2286 }, 2287 set:function (name, val, expires, domain, path) { 2288 var s = new Date; 2289 s.setDate(s.getDate() + (expires || 365)); 2290 var r = [name + "=" + val, "expires=" + s.toUTCString(), "path=" + (path || "/")]; 2291 domain && r.push("domain=" + domain), 2292 document.cookie = r.join(";") 2293 } 2294 }, 2295 query: function (name,href) { // pipe.query("safe.q") -> the query_string ?safe.q=test -> "test" (note: href may be $("body").data("href") in some case) 2296 var match = RegExp('[?&]' + name + '=([^&]*)').exec(href||$("body").data("href")||window.location.search); 2297 return match && decodeURIComponent(match[1].replace(/\+/g, ' ')); 2298 }, 2299 schr: function(n) { // special characters - return &#n; - if n is a string, returns some prefefined char, ex: "euro", "nbsp" 2300 if (typeof n=="string") n={"euro":8364/*â¬*/, "copy":169/*©*/, "trade":174/*®*/, "nbsp":160/*NonBreakingSpace= */, "zwsp":8203/*ZeroWidthSpace*/}[n]||63/*?*/ 2301 return String.fromCharCode(n); // zero width space 2302 }, 2303 dotget: function(obj, path, alt) { /* Search and return the nested property of an object, ex: var o={name:{first:"Jean",last:"Dupond"}} -> pipe.dotget(o,"name.first","Luc")=="Jean" */ 2304 if (!obj) return alt; 2305 path = path.split('.'); 2306 for (var i=0, maxi=path.length; i<maxi; i++) { 2307 if (!obj) return alt; 2308 if (obj.hasOwnProperty(path[i])) 2309 obj=obj[path[i]]; 2310 else if (match = /(.+)\[(\d+)\]/.exec(path[i])) { 2311 obj = (obj.hasOwnProperty(match[1]))?obj[match[1]][parseInt(match[2])]:alt; 2312 } else obj=alt 2313 } 2314 return obj;
2315 }, 2316 2317 _escape:[/[<>&"']/g,{'<': '<', '>': '>', '&': '&', '"': '"', "'": '''},/^[]/,/\r?\n/], 2318 _sanitize:[/[^a-zA-Z0-9\/]/g,{"á":"a","à ":"a","â":"a","ç":"c","é":"e","è":"e","ê":"e","î":"i","ô":"o","ù":"u","û":"u"},/-+/g], 2319 _regsafe:[/([.*+?^=!:${}()|\[\]\/\\])/g,{a:"[à áâãäå]", c:"[ç]", e:"[èéêë]", i:"[ìÃîï]", n:"[ñ]", o:"[òóôõö]", u:"[ùúûü]", y:"[ýÿ]", Y:"[ß]", A:"[ÃÃÃÃÃà ]", C:"[Ã]", E:"[ÃÃÃÃ]", I:"[ÃÃÃÃ]", N:"[Ã]", O:"[ÃÃÃÃÃ]", U:"[ÃÃÃÃ]"}], 2320 _filesize:{zero:"0 Byte",decimal:2,separator:" " /*Alt-0160*/,suffix:["Bytes","kMGTPEZY"]}, 2321 _delimiter:[/(\d)(?=(\d{3})+(?!\d))/g], 2322 _date:{format:"DD.MM.YYYY",parse:"DD.MM.YYYY hh:mm:ss",match:/(Y+|M+|D+|H+|h+|m+|s+|[^YMDHhms]+)/g}, 2323 2324 url:{ 2325 queryvalue:function(name,url) { 2326 var match = RegExp('[?&]' + name + '=([^&]*)').exec(url||((window && window.location)?(window.location.search||window.location.href):"")); 2327 return match && decodeURIComponent(match[1].replace(/\+/g, ' ')); 2328 } 2329 }, 2330 /* JSON extensions (to use with: JSON.stringify(obj,pipe.json.encode) and JSON.parse(obj,pip.json.decode)) : encode/decode functions and regexps 2331 Ex: JSON.stringify({r:/test/i,f:function(){a=2}},pipe.json.encode) -> '{"r":"__regexp /test/i","f":"__function (){a=2}"}"' */ 2332 json: { 2333 encode:function(key, value) { 2334 if (value instanceof RegExp) value="__regexp " + value.toString(); 2335 if (value instanceof Function) value="__"+value.toString(); 2336 return value; 2337 }, 2338 decode:function(key, value) { 2339 if (typeof value=="string" && value.indexOf("__") == 0) { 2340 if (value.indexOf("__function")==0) value=eval("("+value.substring(2)+")") 2341 else if (value.indexOf("__regexp ") == 0) { 2342 var m = value.split("__regexp ")[1].match(/\/(.*)\/(.*)?/); 2343 if (m) value = new RegExp(m[1], m[2] || ""); 2344 } 2345 } 2346 return value; 2347 }, 2348 unflatten: function(data) { 2349 if (Object(data) !== data || Array.isArray(data)) 2350 return data; 2351 var result = {}, cur, prop, idx, last, temp; 2352 for(var p in data) { 2353 cur = result, prop = "", last = 0; 2354 do { 2355 idx = p.indexOf(".", last); 2356 temp = p.substring(last, idx !== -1 ? idx : undefined); 2357 cur = cur[prop] || (cur[prop] = (!isNaN(parseInt(temp)) ? [] : {})); 2358 prop = temp; 2359 last = idx + 1; 2360 } while(idx >= 0); 2361 cur[prop] = data[p]; 2362 } 2363 return result[""]; 2364 }, 2365 flatten: function(data,last) { 2366 // last: if key "last" exist and is string, return it directly, (used for language selection) ex: 2367 // flatten({first:{fr:"Premier",en:"First"},other:{fr:"Un",en:"One"}}) -> {"first.fr":"premier","first.en":"First","other.fr":"Un","other.en":One"} 2368 // flatten({first:{fr:"Premier",en:"First"},other:{fr:"Un",en:"One"}},"fr") -> {first:"premier",other:"Un"} 2369 var result = {}; 2370 function recurse (cur, prop) { 2371 if (Object(cur) !== cur) { 2372 result[prop] = cur; 2373 } else if (Array.isArray(cur)) { 2374 for(var i=0, l=cur.length; i<l; i++) 2375 recurse(cur[i], prop ? prop+"."+i : ""+i); 2376 if (l == 0) 2377 result[prop] = []; 2378 } else { 2379 if( last && cur.hasOwnProperty(last) && typeof cur[last]=="string") { 2380 result[prop]=cur[last]; 2381 } else { 2382 var isEmpty = true; 2383 for (var p in cur) { 2384 isEmpty = false; 2385 recurse(cur[p], prop ? prop+"."+p : p); 2386 } 2387 if (isEmpty) 2388 result[prop] = {}; 2389 } 2390 } 2391 } 2392 recurse(data, ""); 2393 return result; 2394 } 2395 }, 2396 2397 /* reduce functions. Note: function(previousValue,currentValue,index,array) */ 2398 max:function(p,c,i,a){ return (c>p)?c:p; }, // [1,2,3,4,5,1].reduce(pipe.max) => 5 2399 min:function(p,c,i,a){ return (c<p)?c:p; }, // [1,2,3,4,5,1].reduce(pipe.min) => 1 2400 sum:function(p,c,i,a){ return c+p; }, // [1,2,3,4,5,1].reduce(pipe.sum) => 16 2401 normalize:function(p,c,i,a){ // [1,2,3,4,5,1].reduce(pipe.normalize,[]) => [0.0625, 0.125, 0.1875, 0.25, 0.3125, 0.0625] 2402 if (i==1) {var s=a.reduce(pipe.sum);for (var i=0,l=a.length;i<l;i++) a[i]/=s;} 2403 return a 2404 }, 2405 unique:function(p,c,i,a){ // ex: [1,2,3,4,5,3,2].reduce(pipe.unique,[]) => [1,2,3,4,5] 2406 if(p.indexOf(c)==-1) p.push(c); 2407 return p 2408 }, 2409 shuffle:function(p,c,i,a){ // [1,2,3,4,5,6].reduce(pipe.shuffle,[]) => [5,3,2,1,6,4] (note: the real shuffle is done once on i==1, so not optimized but easy for chaining) 2410 if (i==1) for(var j, x, i = a.length; i; j = Math.floor(Math.random() * i), x = a[--i], a[i] = a[j], a[j] = x); 2411 return a 2412 } 2413}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.