1/* 2# Copyright (c) 2003-2005, Jannis Hermanns (on behalf the Serendipity Developer Team) 3# All rights reserved. See LICENSE file for licensing details 4*/ 5 6(function(serendipity, $, undefined ) { 7 // Fires functions which are generated dynamically in backend PHP files 8 // (i.e. include/functions_entries_admin.inc.php) which load the various 9 // WYSIWYG editors in entries editor, HTML nuggets etc. 10 serendipity.spawn = function() { 11 if (self.Spawnextended) { 12 Spawnextended(); 13 } 14 15 if (self.Spawnbody) { 16 Spawnbody(); 17 } 18 19 if (self.Spawnnugget) { 20 Spawnnugget(); 21 } 22 } 23 24 // Generic function to set cookies 25 serendipity.SetCookie = function(name, value) { 26 var today = new Date(); 27 var expire = new Date(); 28 expire.setTime(today.getTime() + (60*60*24*30*1000)); 29 // get array like or simple string argument items 30 if (name.indexOf("[") != -1) { 31 document.cookie = 'serendipity' + name + '=' + escape(value) + ';expires=' + expire.toGMTString(); 32 } else { 33 document.cookie = 'serendipity[' + name + ']=' + escape(value) + ';expires=' + expire.toGMTString(); 34 } 35 } 36 37 serendipity.GetCookie = function(name) { 38 var nameEQ = name + "="; 39 var ca = document.cookie.split(';'); 40 for(var i=0;i < ca.length;i++) { 41 var c = ca[i]; 42 while (c.charAt(0)==' ') c = c.substring(1,c.length); 43 if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); 44 } 45 return null; 46 } 47 48 /** 49 * Based upon code written by chris wetherell 50 * http://www.massless.org 51 * chris [THE AT SIGN] massless.org 52 */ 53 54 // Returns "position" of selection in textarea 55 // Used internally by wrapSelectionWithLink() 56 serendipity.getSelection = function($txtarea) { 57 var start = $txtarea[0].selectionStart; 58 var end = $txtarea[0].selectionEnd; 59 return $txtarea.val().substring(start, end); 60 } 61 62 // Used by non-wysiwyg editor toolbar buttons to wrap selection 63 // in a element associated with toolbar button 64 serendipity.wrapSelection = function(txtarea, openTag, closeTag) { 65 scrollPos = false; 66 67 if (txtarea.scrollTop) { 68 scrollPos = txtarea.scrollTop; 69 } 70 71 // http://stackoverflow.com/questions/1712417/jquery-wrap-selected-text-in-a-textarea 72 var $txtarea = $(txtarea); 73 74 if (!$txtarea.length) { 75 return; 76 } 77 78 var len = $txtarea.val().length; 79 var start = $txtarea[0].selectionStart; 80 var end = $txtarea[0].selectionEnd; 81 var selectedText = $txtarea.val().substring(start, end); 82 var replacement = openTag + selectedText + closeTag; 83 $txtarea.val($txtarea.val().substring(0, start) + replacement + $txtarea.val().substring(end, len)); 84 85 $txtarea[0].selectionStart = start + replacement.length; 86 $txtarea[0].selectionEnd = start + replacement.length; 87 88 if (scrollPos) { 89 txtarea.focus(); 90 txtarea.scrollTop = scrollPos; 91 } 92 } 93 94 // Used by non-wysiwyg editor toolbar buttons to wrap selection 95 // in <a> element (only) 96 serendipity.wrapSelectionWithLink = function(txtarea) { 97 var my_link = prompt("Enter URL:","http://"); 98 99 if (my_link) { 100 if (serendipity.getSelection($(txtarea) ) == "") { 101 var my_desc = prompt("Enter Description", ''); 102 } 103 var my_title = prompt("Enter title/tooltip:", ""); 104 } 105 106 html_title = ""; 107 108 if (my_title != "" && my_title != null) { 109 html_title = ' title="' + my_title + '"'; 110 } 111 112 if (my_link != null) { 113 lft = "<a href=\"" + my_link + "\"" + html_title + ">"; 114 115 if (my_desc != null && my_desc != "") { 116 rgt = my_desc + "</a>"; 117 } else { 118 rgt = "</a>"; 119 } 120 121 serendipity.wrapSelection(txtarea, lft, rgt); 122 } 123 124 return; 125 } 126 /* end chris w. script */ 127 128 // Adds img element to selected text 129 // Used internally by wrapInsImage() 130 serendipity.insertText = function(txtarea, str) { 131 $txtarea = $(txtarea); 132 var selLength = $txtarea.val().length; 133 var selStart = $txtarea[0].selectionStart; 134 var selEnd = $txtarea[0].selectionEnd; 135 136 if (selEnd==1 || selEnd==2) { 137 selEnd=selLength; 138 } 139 140 var before = $txtarea.val().substring(0,selStart); 141 var after = $txtarea.val().substring(selStart); 142 143 $txtarea.val(before + str + after); 144 145 $txtarea[0].selectionStart = selStart + str.length 146 $txtarea[0].selectionEnd = selStart + str.length 147 } 148 149 // Used by non-wysiwyg editor toolbar buttons to wrap selection 150 // in <img> element (only); does not really "wrap", merely inserts 151 // an <img> element before selected text 152 serendipity.wrapInsImage = function(txtarea) { 153 var loc = prompt('Enter the image location: '); 154 155 if (loc) { 156 var alttxt = prompt('Enter alternative text for this image: '); 157 serendipity.insertText(txtarea,'<img src="'+ loc + '" alt="' + alttxt + '">'); 158 } 159 } 160 /* end Better-Editor functions */ 161 162 // Switches preview of image selected from media db 163 serendipity.change_preview = function(input, output) { 164 var filename = document.getElementById(input).value; 165 var $target = $('#' + output + '_preview > img'); 166 $target.attr('src', filename); 167 } 168 169 // Opens media db image selection in new window 170 serendipity.choose_media = function(id) { 171 serendipity.openPopup('serendipity_admin.php?serendipity[adminModule]=media&serendipity[noBanner]=true&serendipity[noSidebar]=true&serendipity[noFooter]=true&serendipity[showMediaToolbar]=false&serendipity[showUpload]=true&serendipity[htmltarget]=' + id + '&serendipity[filename_only]=true'); 172 } 173 174 // "Transfer" value from media db popup to form element, used for example for selecting a category-icon 175 serendipity.serendipity_imageSelector_addToElement = function(str, id) { 176 id = serendipity.escapeBrackets(id); 177 var $input = $('#' + id); 178 $input.val(str); 179 180 if ($input.attr('type') != 'hidden') { 181 $input.focus(); // IE would generate an error when focusing an hidden element 182 } 183 184 // calling the change-event for doing stuff like generating the preview-image 185 $input.change(); 186 } 187 188 // Escape [ and ] to be able to use the string as selector 189 // jQuery fails to select the input when the selector contains unescaped [ or ] 190 serendipity.escapeBrackets = function(str) { 191 str = str.replace(/\[/g, "\\["); 192 str = str.replace(/\]/g, "\\]"); 193 return str; 194 } 195 196 // Add another (image) keyword 197 serendipity.AddKeyword = function(keyword) { 198 s = document.getElementById('keyword_input').value; 199 document.getElementById('keyword_input').value = (s != '' ? s + ';' : '') + keyword; 200 } 201 202 // "Transfer" value from media db popup to textarea, including wysiwyg 203 // This gets textarea="body"/"extended" and tries to insert into the textarea 204 // named serendipity[body]/serendipity[extended] 205 serendipity.serendipity_imageSelector_addToBody = function(str, textarea) { 206 var oEditor; 207 if (typeof(FCKeditorAPI) != 'undefined') { 208 oEditor = FCKeditorAPI.GetInstance('serendipity[' + textarea + ']') ; 209 210 if (oEditor.EditMode == FCK_EDITMODE_WYSIWYG) { 211 oEditor.InsertHtml(str); 212 return; 213 } 214 } else if(typeof(xinha_editors) != 'undefined') { 215 if (typeof(xinha_editors['serendipity[' + textarea + ']']) != 'undefined') { 216 oEditor = xinha_editors['serendipity['+ textarea +']']; 217 } 218 219 if (oEditor) { 220 oEditor.insertHTML(str); 221 return; 222 } 223 } else if(typeof(HTMLArea) != 'undefined') { 224 if (textarea == 'body' && typeof(editorbody) != 'undefined') { 225 oEditor = editorbody; 226 } else if (textarea == 'extended' && typeof(editorextended) != 'undefined') { 227 oEditor = editorextended; 228 } else if (typeof(htmlarea_editors) != 'undefined' && typeof(htmlarea_editors[textarea]) != 'undefined') { 229 oEditor = htmlarea_editors[textarea]; 230 } 231 232 if (oEditor._editMode != 'textmode') { 233 oEditor.insertHTML(str); 234 return; 235 } 236 } else if(typeof(TinyMCE) != 'undefined') { 237 // for the TinyMCE editor we do not have a text mode insert 238 tinyMCE.execInstanceCommand('serendipity[' + textarea + ']', 'mceInsertContent', false, str); 239 return; 240 } else if (typeof(CKEDITOR) != 'undefined') { 241 oEditor = (typeof(isinstance) == 'undefined') ? CKEDITOR.instances[textarea] : isinstance; 242 if (typeof(oEditor) == 'undefined') oEditor = popupEditorInstance; 243 if (oEditor.mode == "wysiwyg") { 244 oEditor.insertHtml(str); 245 return; 246 } 247 } 248 249 serendipity.noWysiwygAdd(str, textarea); 250 } 251 252 // The noWysiwygAdd JS function is the vanila serendipity_imageSelector_addToBody js function 253 // which works fine in NO WYSIWYG mode 254 // NOTE: the serendipity_imageSelector_addToBody could add any valid HTML string to the textarea 255 serendipity.noWysiwygAdd = function(str, textarea) { 256 escapedElement = serendipity.escapeBrackets(textarea); 257 if ($('#' + escapedElement).length) { 258 // Proper ID was specified (hopefully by plugins) 259 } else { 260 // Let us try the serendipity[] prefix 261 escapedElement = serendipity.escapeBrackets('serendipity[' + textarea + ']'); 262 263 if (!$('#' + escapedElement).length) { 264 console.log("Serendipity plugin error: " + escapedElement + " not found."); 265 } 266 } 267 268 serendipity.wrapSelection($('#'+escapedElement), str, ''); 269 } 270 271 // Inserting media db img markup including s9y-specific container markup 272 serendipity.serendipity_imageSelector_done = function(textarea) { 273 var insert = ''; 274 var img = ''; 275 var src = ''; 276 var alt = ''; 277 var title = ''; 278 279 var f = document.forms['serendipity[selForm]'].elements; 280 281 img = f['imgName'].value; 282 var imgWidth = f['imgWidth'].value; 283 var imgHeight = f['imgHeight'].value; 284 if (f['serendipity[linkThumbnail]'] && f['serendipity[linkThumbnail]'][0].checked == true) { 285 img = f['thumbName'].value; 286 imgWidth = f['imgThumbWidth'].value; 287 imgHeight = f['imgThumbHeight'].value; 288 } 289 290 if (parent.self.opener == undefined) { 291 // in iframes, there is no opener, and the magnific popup is wrapped 292 parent.self = window.parent.parent.$.magnificPopup; 293 parent.self.opener = window.parent.parent; 294 } 295 296 if (f['serendipity[filename_only]']) { 297 // this part is used when selecting only the image without further markup (-> category-icon) 298 var starget = f['serendipity[htmltarget]'] ? f['serendipity[htmltarget]'].value : 'serendipity[' + textarea + ']'; 299 300 switch(f['serendipity[filename_only]'].value) { 301 case 'true': 302 parent.self.opener.serendipity.serendipity_imageSelector_addToElement(img, f['serendipity[htmltarget]'].value); 303 parent.self.close(); 304 return true; 305 case 'id': 306 parent.self.opener.serendipity.serendipity_imageSelector_addToElement(f['imgID'].value, starget); 307 parent.self.close(); 308 return true; 309 case 'thumb': 310 parent.self.opener.serendipity.serendipity_imageSelector_addToElement(f['thumbName'].value, starget); 311 parent.self.close(); 312 return true; 313 case 'big': 314 parent.self.opener.serendipity.serendipity_imageSelector_addToElement(f['imgName'].value, starget); 315 parent.self.close(); 316 return true; 317 } 318 } 319 320 alt = f['serendipity[alt]'].value.replace(/"/g, """); 321 title = f['serendipity[title]'].value.replace(/"/g, """); 322 323 var imgID = 0; 324 if (f['imgID']) { 325 imgID = f['imgID'].value; 326 } 327 328 var floating = $(':input[name="serendipity[align]"]:checked').val(); 329 if (floating == "") { 330 floating = "center"; 331 } 332 img = "<!-- s9ymdb:" + imgID + " --><img class=\"serendipity_image_"+ floating +"\" width=\"" + imgWidth + "\" height=\"" + imgHeight + '" src="' + img + "\" " + (title != '' ? 'title="' + title + '"' : '') + " alt=\"" + alt + "\">"; 333 334 if ($(':input[name="serendipity[isLink]"]:checked').val() == "yes") { 335 // wrap the img in a link to the image. TODO: The label in the media_chooser.tpl explains it wrong 336 var targetval = $('#select_image_target').val(); 337 338 var prepend = ''; 339 var ilink = f['serendipity[url]'].value; 340 var itarget = ''; 341 342 switch (targetval) { 343 case 'js': 344 var itarget = ' onclick="F1 = window.open(\'' + f['serendipity[url]'].value + '\',\'Zoom\',\'' 345 + 'height=' + (parseInt(f['imgHeight'].value) + 15) + ',' 346 + 'width=' + (parseInt(f['imgWidth'].value) + 15) + ',' 347 + 'top=' + (screen.height - f['imgHeight'].value) /2 + ',' 348 + 'left=' + (screen.width - f['imgWidth'].value) /2 + ',' 349 + 'toolbar=no,menubar=no,location=no,resize=1,resizable=1,scrollbars=yes\'); return false;"'; 350 break; 351 case '_blank': 352 var itarget = ' target="_blank"'; 353 break; 354 case 'plugin': 355 var itarget = ' id="s9yisphref' + imgID + '" onclick="javascript:this.href = this.href + \'&serendipity[from]=\' + self.location.href;"'; 356 prepend = '<a title="' + ilink + '" id="s9yisp' + imgID + '"></a>'; 357 ilink = f['baseURL'].value + 'serendipity_admin_image_selector.php?serendipity[step]=showItem&serendipity[image]=' + imgID; 358 break; 359 } 360 361 var img = prepend + "<a class=\"serendipity_image_link\" " + (title != '' ? 'title="' + title + '"' : '') + " href='" + ilink + "'" + itarget + ">" + img + "</a>"; 362 } 363 364 if ($('#serendipity_imagecomment').val() != '') { 365 var comment = f['serendipity[imagecomment]'].value; 366 367 var img = '<figure class="serendipity_imageComment_' + floating + '" style="width: ' + imgWidth + 'px">' 368 + '<div class="serendipity_imageComment_img">' + img + '</div>' 369 + '<figcaption class="serendipity_imageComment_txt">' + comment + '</figcaption>' 370 + '</figure>'; 371 } 372 373 if (parent.self.opener.serendipity == undefined) { 374 // in iframes, there is no opener, and the magnific popup is wrapped 375 parent.self = window.parent.parent.$.magnificPopup; 376 parent.self.opener = window.parent.parent; 377 } 378 parent.self.opener.serendipity.serendipity_imageSelector_addToBody(img, textarea); 379 parent.self.close(); 380 } 381 382 // Toggle extended entry editor 383 serendipity.toggle_extended = function(setCookie) { 384 if ($('#toggle_extended').length == 0) { 385 // this function got called on load of the editor 386 var toggleButton = '#toggle_extended'; 387 $('#extended_entry_editor').parent().find('label').first().wrap('<button id="toggle_extended" class="icon_link" type="button"></button>'); 388 $(toggleButton).prepend('<span class="icon-down-dir" aria-hidden="true"></span> '); 389 $(toggleButton).click(function(e) { 390 e.preventDefault(); 391 serendipity.toggle_extended(true); 392 }); 393 if (localStorage !== null && localStorage.show_extended_editor == "true") { 394 // the editor is visible by default - note the string, as bool is not supported yet in localStorage 395 return; 396 } 397 } 398 399 if ($('#extended_entry_editor:hidden').length > 0) { 400 $('#extended_entry_editor').show(); // use name selector instead of id here; id does not work 401 $('#tools_extended').show(); 402 $('#toggle_extended').find('> .icon-right-dir').removeClass('icon-right-dir').addClass('icon-down-dir'); 403 if (localStorage !== null) { 404 localStorage.show_extended_editor = "true"; 405 } 406 } else { 407 $('#extended_entry_editor').hide(); 408 $('#tools_extended').hide(); 409 $('#toggle_extended').find('> .icon-down-dir').removeClass('icon-down-dir').addClass('icon-right-dir'); 410 if (localStorage !== null) { 411 localStorage.show_extended_editor = "false"; 412 } 413 } 414 if (setCookie) { 415 document.cookie = 'serendipity[toggle_extended]=' + (($('#extended_entry_editor:hidden').length == 0) ? "true" : "") + ';'; 416 } 417 } 418 419 // Collapses/expands the category selector 420 var categoryselector_stored_categories = null; 421 serendipity.toggle_category_selector = function(id) { 422 if ($('#toggle_' + id).length == 0) { 423 // this function got called on load of the editor 424 var toggleButton = '#toggle_' + id; 425 426 $('#'+id).before('<button id="toggle_' + id + '" class="button_link" type="button" href="#' + id + '"><span class="icon-right-dir" aria-hidden="true"></span><span class="visuallyhidden"> {$CONST.TOGGLE_ALL}</span></button>'); 427 428 $(toggleButton).click(function(e) { 429 e.preventDefault(); 430 $(this).toggleClass('active'); 431 serendipity.toggle_category_selector(id); 432 }); 433 $('#'+id).change(function(e) { 434 categoryselector_stored_categories = null; 435 }); 436 437 if ($('#'+id).children('*[selected="selected"]').length > 1) { 438 // when loading the page new for the preview and more than one category was 439 // selected, collapsing the category-selector would lose those categories 440 $('#'+id).attr("size", $('#'+id).children().size); 441 $('#toggle_' + id).find('> .icon-right-dir').removeClass('icon-right-dir').addClass('icon-down-dir'); 442 return 443 } 444 445 } 446 447 if ($('#'+id).attr("multiple")) { 448 if ($('#'+id).children(':selected').filter('[value!="0"]').length > 1) { 449 // when collapsing, all multiple selection needs to be saved to be restoreable if the click was a mistake 450 var selected_categories = ''; 451 $('#'+id).children(':selected').filter('[value!="0"]').each(function(i, child) { 452 selected_categories += child.value + ',' 453 }); 454 categoryselector_stored_categories = selected_categories; 455 } 456 $('#'+id).removeAttr("multiple"); 457 $('#'+id).removeAttr("size"); 458 $('#toggle_' + id).find('> .icon-down-dir').removeClass('icon-down-dir').addClass('icon-right-dir'); 459 460 } else { 461 $('#'+id).attr("multiple", ""); 462 $('#'+id).attr("size", $('#'+id).children().size); 463 $('#toggle_' + id).find('> .icon-right-dir').removeClass('icon-right-dir').addClass('icon-down-dir'); 464 465 var selected_categories = categoryselector_stored_categories; 466 if (selected_categories != null) { 467 selected_categories = selected_categories.split(','); 468 selected_categories.forEach(function(cat_id) { 469 if(cat_id) { 470 $('#'+id).find('[value="'+ cat_id +'"]').attr('selected', 'selected'); 471 } 472 }); 473 } 474 475 } 476 } 477 478 // save in the cookie which options were selected when inserting a image from the media db 479 serendipity.rememberMediaOptions = function() { 480 $('#imageForm :input').each(function(index, element) { 481 if (! (element.type == 'radio' && element.checked == false)) { 482 serendipity.SetCookie(element.name.replace(/\[/g, '_').replace(/\]/g, ''), $(element).val()); 483 } 484 }); 485 } 486 487 // Rescale image 488 serendipity.rescale = function(dim, newval) { 489 var ratio = $('#serendipityScaleImg').attr('data-imgheight')/$('#serendipityScaleImg').attr('data-imgwidth'); 490 var trans = new Array(); 491 trans['width'] = new Array('serendipity[height]', ratio); 492 trans['height'] = new Array('serendipity[width]', 1/ratio); 493 494 if ($('#resize_keepprops').is(':checked')) { 495 document.serendipityScaleForm.elements[trans[dim][0]].value=Math.round(trans[dim][1]*newval); 496 } 497 } 498 499 // Rename file in media db 500 serendipity.rename = function(id, fname) { 501 var newname; 502 var media_rename = '{$CONST.ENTER_NEW_NAME}'; 503 if (newname = prompt(media_rename + fname, fname)) { 504 var media_token_url = $('input[name*="serendipity[token]"]').val(); 505 $.ajax({ 506 type: 'POST', 507 url: '?serendipity[adminModule]=images&serendipity[adminAction]=rename&serendipity[fid]='+ escape(id) +'&serendipity[newname]='+ escape(newname) +'&serendipity[token]='+ media_token_url, 508 async: true, 509 cache: false, 510 success: function(response) { 511 $response = (response.trim() == '') 512 ? '<p>{$CONST.DONE}!</p>\ 513 <button id="rename_ok" class="button_link state_submit" type="button" >{$CONST.GO}</button>\ 514 ' 515 : response + '\ 516 <input class="go_back" type="button" onClick="$.magnificPopup.close();" value="{$CONST.BACK}">\ 517 '; 518 $.magnificPopup.open({ 519 items: { 520 type: 'inline', 521 src: $('<div id="rename_msg">\ 522 <h4>{$CONST.MEDIA_RENAME}</h4>\ 523 '+ $response +'\ 524 </div>') 525 }, 526 type: 'inline', 527 midClick: true, 528 callbacks: { 529 open: function() { 530 this.content.on('click', '#rename_ok', function() { 531 window.parent.parent.location.href= '?serendipity[adminModule]=images&serendipity[adminAction]=default'; 532 }); 533 }, 534 } 535 }); 536 }, 537 error: function(XMLHttpRequest, textStatus, errorThrown) { 538 $.magnificPopup.open({ 539 items: { 540 type: 'inline', 541 src: $('<div id="rename_msg">\ 542 <h4>{$CONST.MEDIA_RENAME}</h4>\ 543 <p>"Status: " + textStatus</p>\ 544 '+ errorThrown +'\ 545 <button id="rename_error" class="button_link state_submit" type="button" >{$CONST.GO}</button>\ 546 </div>') 547 }, 548 type: 'inline', 549 midClick: true, 550 callbacks: { 551 open: function() { 552 this.content.on('click', '#rename_error', function() { 553 window.parent.parent.location.href= '?serendipity[adminModule]=images&serendipity[adminAction]=default'; 554 }); 555 }, 556 } 557 }); 558 } 559 }); 560 } 561 } 562 563 // Delete file from ML 564 serendipity.deleteFromML = function(id, fname) { 565 if (confirm('{$CONST.DELETE}?')) { 566 var media_token_url = $('input[name*="serendipity[token]"]').val(); 567 $.post('?serendipity[adminModule]=images&serendipity[adminAction]=doDelete&serendipity[fid]='+ escape(id) +'&serendipity[token]='+ media_token_url) 568 .done(function(jqXHR, textStatus) { 569 if (textStatus == 'success') { 570 $.magnificPopup.open({ 571 items: { 572 type: 'inline', 573 src: $('<div id="delete_msg">\ 574 <h4>{$CONST.MEDIA_DELETE}</h4>\ 575 '+ jqXHR + '\ 576 <button id="delete_ok" class="button_link state_submit" type="button" >{$CONST.GO}</button>\ 577 </div>') 578 }, 579 type: 'inline', 580 midClick: true, 581 callbacks: { 582 open: function() { 583 this.content.on('click', '#delete_ok', function() { 584 window.parent.parent.location.href= '?serendipity[adminModule]=images&serendipity[adminAction]=default'; 585 }); 586 }, 587 } 588 }); 589 } 590 }) 591 .fail(function(jqXHR, textStatus, errorThrown) { 592 if (textStatus != null) { // what could that be ? "timeout", "error", "abort", "parsererror" ? 593 $.magnificPopup.open({ 594 items: { 595 type: 'inline', 596 src: $('<div id="delete_msg">\ 597 <h4>{$CONST.MEDIA_DELETE}</h4>\ 598 '+ jqXHR + '\ 599 <p>"Status: " + textStatus</p>\ 600 '+ errorThrown +'\ 601 <button id="delete_error" class="button_link state_submit" type="button" >{$CONST.GO}</button>\ 602 </div>') 603 }, 604 type: 'inline', 605 midClick: true, 606 callbacks: { 607 open: function() { 608 this.content.on('click', '#delete_error', function() { 609 window.parent.parent.location.href= '?serendipity[adminModule]=images&serendipity[adminAction]=default'; 610 }); 611 }, 612 } 613 }); 614 } 615 }); 616 } 617 } 618 619 // Collapse/expand tree view in media db choose img popup window 620 var tree_toggle_state = 'expand'; 621 622 serendipity.treeToggleAll = function() { 623 if (tree_toggle_state == 'expand') { 624 tree_toggle_state = 'collapse'; 625 tree.expandAll(); 626 } else { 627 tree_toggle_state = 'expand'; 628 tree.collapseAll(); 629 coreNode.expand(); 630 } 631 } 632 633 // Used by media_upload.tpl to ..? 634 serendipity.getfilename = function(value) { 635 re = /^.+[\/\\]+?(.+)$/; 636 return value.replace(re, "$1"); 637 } 638 639 var inputStorage = new Array(); 640 641 serendipity.checkInputs = function() { 642 upload_fieldcount = $('.uploadform_userfile').length; 643 644 for (i = 1; i <= upload_fieldcount; i++) { 645 if (!inputStorage[i]) { 646 serendipity.fillInput(i, i); 647 } else if (inputStorage[i] == document.getElementById('target_filename_' + i).value) { 648 serendipity.fillInput(i, i); 649 } 650 } 651 } 652 653 serendipity.fillInput = function(source, target) { 654 sourceval = serendipity.getfilename(document.getElementById('userfile_' + source).value); 655 656 if (sourceval.length > 0) { 657 document.getElementById('target_filename_' + target).value = sourceval; 658 inputStorage[target] = sourceval; 659 } 660 } 661 662 // check that the entry is validated for saving, used mainly by serendipity_event_entrycheck 663 serendipity.checkSave = function() { 664 {serendipity_hookPlugin hook='backend_entry_checkSave' hookAll='true'} 665 return true; 666 } 667 668 // set a category to checked 669 serendipity.enableCategory = function(catNumber) { 670 $("#" + "serendipity_category_" + catNumber).prop("checked", true); 671 } 672 673 // is no category enabled? 674 serendipity.hasNoCategoryEnabled = function() { 675 var $source = $('#edit_entry_category'); 676 var $selected = $source.find('input:checkbox:checked'); 677 678 if ($selected.length > 0) { 679 return false; 680 } 681 else { 682 return true; 683 } 684 } 685 686 // save in which directory the first uploaded files is stored (the default when only inserting one file) 687 serendipity.rememberUploadOptions = function() { 688 serendipity.SetCookie("addmedia_directory", $('#target_directory_1').val()); 689 } 690 691 // Clones the upload form template 692 serendipity.addUploadField = function() { 693 upload_fieldcount = $('.uploadform_userfile').length + 1; 694 695 var $fields = $('#uploads > div:last-child').clone(true); 696 $fields.attr('id', 'upload_form_' + upload_fieldcount); 697 698 var userfile = $('.uploadform_userfile', $fields); 699 var userfile_label = $('.uploadform_userfile_label', $fields); 700 var targetfilename = $('.uploadform_target_filename', $fields); 701 var targetfilename_label = $('.uploadform_target_filename_label', $fields); 702 var targetdir = $('.uploadform_target_directory', $fields); 703 var targetdir_label = $('.uploadform_target_directory_label', $fields); 704 705 userfile.attr('id', 'userfile_' + upload_fieldcount); 706 userfile.attr('name', 'serendipity[userfile][' + upload_fieldcount + ']'); 707 userfile_label.attr('for', 'userfile_' + upload_fieldcount); 708 709 targetfilename.attr('id', 'target_filename_' + upload_fieldcount); 710 targetfilename.attr('name', 'serendipity[target_filename][' + upload_fieldcount + ']'); 711 targetfilename.val(''); 712 targetfilename_label.attr('for', 'target_filename_' + upload_fieldcount); 713 714 targetdir.attr('id', 'target_directory_' + upload_fieldcount); 715 targetdir.attr('name', 'serendipity[target_directory][' + upload_fieldcount + ']'); 716 // This looks weird, but works. If anyone can improve this, by all means do so. 717 targetdir.val($($('#target_directory_' + (upload_fieldcount - 1))).val()); 718 targetdir_label.attr('for', 'target_directory_' + upload_fieldcount); 719 720 $fields.appendTo('#uploads'); 721 } 722 723 // Inverts a selection of checkboxes 724 serendipity.invertSelection = function() { 725 $('#formMultiDelete .multidelete').each(function() { 726 var $box = $(this); 727 var boxId = $box.attr('id'); 728 if($box.is(':checked')) { 729 $(boxId).prop('checked', false); 730 } else { 731 $(boxId).prop('checked', true); 732 } 733 $box.trigger('click'); 734 }); 735 } 736 737 // Highlight/dehighlight elements in lists 738 serendipity.highlightComment = function(id, checkvalue) { 739 $('#' + id).toggleClass('multidel_selected'); 740 } 741 742 serendipity.closeCommentPopup = function() { 743 {if $use_backendpopups || $force_backendpopups.comments} 744 parent.self.close(); 745 {else} 746 window.parent.parent.$.magnificPopup.close(); 747 {/if} 748 } 749 750 serendipity.openPopup = function(url) { 751 {if $use_backendpopups || $force_backendpopups.images} 752 window.open(url, 753 'ImageSel', 754 'width=800,height=600,toolbar=no,scrollbars=1,scrollbars,resize=1,resizable=1'); 755 {else} 756 $.magnificPopup.open({ 757 items: { 758 src: url 759 }, 760 type: 'iframe' 761 }); 762 {/if} 763 764 }; 765 766 serendipity.reloadImage = function(img) { 767 $(img).attr('src', $(img).attr('src')+'?'+Math.random()); 768 } 769 770 serendipity.catsList = function() { 771 var $source = $('#edit_entry_category'); 772 var $target = $('#cats_list > ul'); 773 var $selected = $source.find('input:checkbox:checked'); 774 775 $target.empty(); 776 777 if ($selected.length > 0) { 778 $selected.each(function() { 779 var catText = $(this).next('label').text(); 780 catText = $('<span>').text(catText).html(); 781 $('<li class="selected">'+ catText +'</li>').appendTo($target); 782 }); 783 } else { 784 $('<li>{$CONST.NO_CATEGORIES}</li>').appendTo($target); 785 } 786 } 787 788 serendipity.tagsList = function() { 789 var $source = $('#properties_freetag_tagList').val(); 790 var $target = $('#tags_list > ul'); 791 792 if (typeof $source !== 'undefined') { 793 var tagged = $source.split(','); 794 $target.empty(); 795 796 if (tagged == '') { 797 $('<li>{$CONST.EDITOR_NO_TAGS}</li>').appendTo($target); 798 } else { 799 $.each(tagged, function(key, tag) { 800 $('<li class="selected">'+ tag +'</li>').appendTo($target); 801 }); 802 } 803 } 804 } 805 806 serendipity.liveFilters = function(input, target, elem) { 807 var currentInput = $(input).val().toLowerCase(); 808 809 if (currentInput == '') { 810 $(target).toggle(true); 811 } else { 812 $(target).each(function() { 813 var $el = $(this); 814 815 if ($el.find(elem).html().toLowerCase().indexOf(currentInput) > -1) { 816 $el.toggle(true); 817 } else { 818 $el.toggle(false); 819 } 820 }); 821 } 822 } 823 824 if(Modernizr.indexeddb && {$use_autosave}) { 825 serendipity.startEntryEditorCache = function() { 826 if ($('textarea[name="serendipity[body]"]').val() == "") { 827 serendipity.getCached("serendipity[body]", function(res) { 828 if (res && res != null && res != "null") { 829 $('textarea[name="serendipity[body]"]').text(res); 830 } 831 }); 832 serendipity.getCached("serendipity[extended]", function(res) { 833 if (res && res != null && res != "null") { 834 if ($('textarea[name="serendipity[extended]"]').val() == "") { 835 $('textarea[name="serendipity[extended]"]').text(res); 836 if (! $('textarea[name="serendipity[extended]"]').is(':visible')) { 837 serendipity.toggle_extended(); 838 } 839 } 840 } 841 }); 842 } 843 844 $('textarea[name="serendipity[body]"]').one('keyup', function() { 845 setInterval(function() { 846 serendipity.cache("serendipity[body]", $('textarea[name="serendipity[body]"]').val()) 847 }, 5000); 848 }); 849 $('textarea[name="serendipity[extended]"]').one('keyup', function() { 850 setInterval(function() { 851 serendipity.cache("serendipity[extended]", $('textarea[name="serendipity[extended]"]').val()); 852 }, 5000); 853 }); 854 } 855 856 serendipity.eraseEntryEditorCache = function() { 857 serendipity.cache("serendipity[body]", ""); 858 serendipity.cache("serendipity[extended]", ""); 859 } 860 861 var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; 862 863 serendipity.cache = function (id, data) { 864 if (typeof indexedDB !== 'undefined') { 865 var request = indexedDB.open("cache", 1); 866 request.onupgradeneeded = function (event) { 867 event.target.result.createObjectStore("cache"); 868 }; 869 request.onsuccess = function(event) { 870 event.target.result.transaction(["cache"], 'readwrite').objectStore("cache").put(data, id); 871 }; 872 } 873 } 874 875 serendipity.getCached = function(id, success) { 876 if (typeof indexedDB !== 'undefined') { 877 var request = indexedDB.open("cache", 1); 878 request.onupgradeneeded = function (event) { 879 event.target.result.createObjectStore("cache"); 880 }; 881 request.onsuccess = function(event) { 882 event.target.result.transaction(["cache"], 'readwrite').objectStore("cache").get(id).onsuccess = function (event) { 883 success(event.target.result); 884 }; 885 }; 886 } 887 } 888 } 889 890 serendipity.toggle_collapsible = function(toggler, target, stateClass, stateIcon, stateOpen, stateClosed) { 891 // argument defaults 892 stateClass = stateClass || 'additional_info'; 893 stateIcon = stateIcon || '> span'; 894 stateOpen = stateOpen || 'icon-down-dir'; 895 stateClosed = stateClosed || 'icon-right-dir'; 896 897 var $toggleIcon = $(toggler).find(stateIcon); 898 var toggleState = $toggleIcon.attr('class'); 899 900 // if toggler does not have an id, do not store state 901 var togglerId = $(toggler).attr('id'); 902 if (togglerId !== undefined) { 903 var storageKey = 'show_' + $(toggler).attr('id'); 904 } 905 906 if(toggleState == stateOpen) { 907 $toggleIcon.removeClass(stateOpen).addClass(stateClosed); 908 if (togglerId !== undefined && localStorage !== null) { 909 localStorage.setItem(storageKey, "false"); 910 } 911 } else { 912 $toggleIcon.removeClass(stateClosed).addClass(stateOpen); 913 if (togglerId !== undefined && localStorage !== null) { 914 localStorage.setItem(storageKey, "true"); 915 } 916 } 917 918 $(target).toggleClass(stateClass); 919 } 920 921 serendipity.sync_heights = function() { 922 if($('.equal_heights').length > 0) { 923 if($('html').hasClass('lt-ie9')) { 924 $('.equal_heights').syncHeight({ 925 updateOnResize: false 926 }); 927 } else { 928 $('.equal_heights').syncHeight({ 929 updateOnResize: true 930 }); 931 } 932 } 933 } 934 935 serendipity.skipScroll = function(target, time) { 936 time = typeof time !== 'undefined' ? time : 250; 937 938 $('html, body').animate({ 939 scrollTop: $(target).offset().top 940 }, time); 941 } 942 943 serendipity.updateAll = function() { 944 var $overlay = $('<div id="overlay" />'); 945 $.get('?serendipity[adminModule]=plugins&serendipity[adminAction]=renderOverlay') 946 .done(function(data) { 947 $overlay.append(data); 948 $overlay.appendTo(document.body); 949 $('#updateProgress').attr('max', $('.plugin_status').length); 950 serendipity.updateNext(); 951 }); 952 } 953 954 serendipity.updateNext = function() { 955 $('#updateMessage').text("Updating " + $('.plugins_installable > li:visible h4').first().text()); 956 $.get($('.plugin_status .button_link:visible').first().attr('href')) 957 .done(function(messages) { 958 $('.plugins_installable > li:visible').first().fadeOut(); 959 $('#updateProgress').attr('value', parseInt($('#updateProgress').attr('value')) + 1); 960 if ($('.plugins_installable > li:visible').length > 0) { 961 serendipity.updateNext(); 962 } else { 963 $('#overlay').fadeOut("normal", function () { 964 window.location = $('#back').attr('href') + '&serendipity[updateAllMsg]=true'; 965 }); 966 } 967 }) 968 .fail(function(data) { 969 $('#content').prepend(data.responseText); 970 $('#updateAll').hide(); 971 $('#overlay').fadeOut(); 972 }); 973 } 974 975}( window.serendipity = window.serendipity || {}, jQuery )) 976 977$(function() { 978 // Breakpoints for responsive JS 979 var mq_small = Modernizr.mq('(min-width:640px)'); 980 // IE 8 should always be larger than mq_small 981 if($('html').hasClass('lt-ie9')) { mq_small = true; } 982 983 // Fire responsive nav 984 if($('#main_menu').length > 0) { 985 $('#nav-toggle').click(function(e) { 986 var $el = $(this); 987 var $target = $('body'); 988 var $icon = $el.find('span:first-child'); 989 $($target).toggleClass('active_nav'); 990 if($($target).hasClass('active_nav')) { 991 $icon.removeClass('icon-menu').addClass('icon-cancel'); 992 } else { 993 $icon.removeClass('icon-cancel').addClass('icon-menu'); 994 } 995 e.preventDefault(); 996 }); 997 } 998 999 // Fire details polyfill 1000 $('html').addClass($.fn.details.support ? 'details' : 'no-details'); 1001 $('details').details(); 1002 1003 // Fire WYSIWYG editor(s) 1004 serendipity.spawn(); 1005 1006 // Fire a11y helper script 1007 AccessifyHTML5({ 1008 header: '#top', 1009 footer: '#meta' 1010 }); 1011 1012 // Layout helpers for IE < 9 1013 if($('html').hasClass('lt-ie9')) { 1014 if($('#dashboard').length > 0) { 1015 // For some reason, .addClass() does not work here 1016 $('.dashboard_widget:nth-child(odd)').css('clear', 'left'); 1017 $('.dashboard_widget:nth-child(even)').css('margin', '0 0 1em 2%'); 1018 } 1019 } 1020 1021 // Editor-area 1022 if($('#serendipityEntry').length > 0) { 1023 serendipity.catsList(); 1024 serendipity.tagsList(); 1025 serendipity.toggle_category_selector('categoryselector'); 1026 serendipity.toggle_extended(); 1027 } 1028 1029 // Form submit events 1030 $('#uploadform').submit(function() { 1031 serendipity.rememberUploadOptions(); 1032 }); 1033 1034 $('#imageForm').submit(function() { 1035 serendipity.serendipity_imageSelector_done(); 1036 }); 1037 1038 $('#serendipityEntry').submit(function() { 1039 return serendipity.checkSave(); 1040 }); 1041 1042 // Click events 1043 // 1044 // Make the timestamp readable in browser not supporting datetime-local. 1045 // Has no effect in those supporting it, as the timestamp is invalid in HTML5 1046 if($('#serendipityEntry').length > 0) { 1047 if(!Modernizr.inputtypes.date) { 1048 $('#serendipityNewTimestamp').val($('#serendipityNewTimestamp').val().replace("T", " ")); 1049 } 1050 if(Modernizr.indexeddb && {$use_autosave}) { 1051 serendipity.startEntryEditorCache(); 1052 } 1053 } 1054 1055 // Set entry timestamp 1056 $('#reset_timestamp').click(function(e) { 1057 $('#serendipityNewTimestamp').val($(this).attr('data-currtime')); 1058 if(!Modernizr.inputtypes.date) { 1059 $('#serendipityNewTimestamp').val($('#serendipityNewTimestamp').val().replace("T", " ")); 1060 } 1061 e.preventDefault(); 1062 // Inline notification, we might want to make this reuseable 1063 $('<span id="msg_timestamp" class="msg_notice"><span class="icon-info-circled" aria-hidden="true"></span>{$CONST.TIMESTAMP_RESET} <a class="remove_msg" href="#msg_timestamp"><span class="icon-cancel" aria-hidden="true"></span><span class="visuallyhidden">{$CONST.HIDE}</span></a></span>').insertBefore('#edit_entry_title'); 1064 // Remove timestamp msg 1065 $('.remove_msg').click(function(e) { 1066 e.preventDefault(); 1067 var $target = $(this).parent(); 1068 $target.fadeOut(250, function() { $target.remove(); }); 1069 }); 1070 // Automagic removal after 5 secs 1071 setTimeout(function() { 1072 $('#msg_timestamp').fadeOut(250).remove(); 1073 }, 5000); 1074 }); 1075 1076 // Switch entry status 1077 $('#switch_entry_status').click(function(e) { 1078 var $el = $(this); 1079 var oldState = $el.attr('title'); 1080 var newState = $el.attr('data-title-alt'); 1081 var entryState = $('#entry_status option'); 1082 var stateIcon = $el.find("[class^='icon']"); 1083 1084 $(entryState).filter(function() { 1085 return $(this).html() == oldState; 1086 }).prop('selected', false); 1087 1088 $(entryState).filter(function() { 1089 return $(this).html() == newState; 1090 }).prop('selected', true); 1091 1092 $el.attr({ 1093 'title': newState, 1094 'data-title-alt': oldState 1095 }).find('> .visuallyhidden').text(newState); 1096 1097 if(stateIcon.hasClass('icon-toggle-on')) { 1098 stateIcon.removeClass('icon-toggle-on').addClass('icon-toggle-off'); 1099 } else { 1100 stateIcon.removeClass('icon-toggle-off').addClass('icon-toggle-on'); 1101 } 1102 1103 // Inline notification, we might want to make this reuseable 1104 $('<span id="msg_entrystatus" class="msg_notice"><span class="icon-info-circled" aria-hidden="true"></span>{$CONST.ENTRY_STATUS}: ' + newState + ' <a class="remove_msg" href="#msg_entrystatus"><span class="icon-cancel" aria-hidden="true"></span><span class="visuallyhidden">{$CONST.HIDE}</span></a></span>').insertBefore('#edit_entry_title'); 1105 // Remove entrystatus msg 1106 $('.remove_msg').click(function(e) { 1107 e.preventDefault(); 1108 var $target = $(this).parent(); 1109 $target.fadeOut(250, function() { $target.remove(); }); 1110 }); 1111 // Automagic removal after 5 secs 1112 setTimeout(function() { 1113 $('#msg_entrystatus').fadeOut(250).remove(); 1114 }, 5000); 1115 1116 e.preventDefault(); 1117 }); 1118 1119 // Matching change event 1120 $('#entry_status').change(function() { 1121 $('#switch_entry_status').trigger('click'); 1122 }); 1123 1124 // Editor tools 1125 $('.wrap_selection').click(function() { 1126 var $el = $(this); 1127 var $tagOpen = $el.attr('data-tag-open'); 1128 var $tagClose = $el.attr('data-tag-close'); 1129 //var target = document.forms['serendipityEntry']['serendipity[' + $el.attr('data-tarea') + ']']; 1130 var target = $('#'+serendipity.escapeBrackets($el.attr('data-tarea'))); 1131 if ($el.hasClass('lang-html')) { 1132 var open = '<' + $tagOpen + '>'; 1133 var close = '</' + $tagClose + '>'; 1134 } else { 1135 var open = $tagOpen; 1136 var close = $tagClose; 1137 } 1138 serendipity.wrapSelection(target, open, close); 1139 }); 1140 1141 $('.wrap_insimg').click(function() { 1142 var target = $('#'+serendipity.escapeBrackets($(this).attr('data-tarea'))); 1143 serendipity.wrapInsImage(target); 1144 }); 1145 1146 $('.wrap_insurl').click(function() { 1147 var target = $('#'+serendipity.escapeBrackets($(this).attr('data-tarea'))); 1148 serendipity.wrapSelectionWithLink(target); 1149 }); 1150 1151 $('.wrap_insmedia').click(function() { 1152 serendipity.openPopup('serendipity_admin.php?serendipity[adminModule]=media&serendipity[noBanner]=true&serendipity[noSidebar]=true&serendipity[noFooter]=true&serendipity[showMediaToolbar]=false&serendipity[showUpload]=true&serendipity[textarea]=' + $(this).attr('data-tarea')); 1153 }); 1154 1155 // Entry metadata 1156 if($('#edit_entry_metadata').length > 0) { 1157 $('#toggle_metadata').click(function() { 1158 serendipity.toggle_collapsible($(this), '#meta_data'); 1159 }); 1160 if (localStorage !== null && localStorage.getItem("show_toggle_metadata") == "true") { 1161 $('#toggle_metadata').click(); 1162 } 1163 } 1164 1165 // Show category selector 1166 {if $use_backendpopups || $force_backendpopups.categories} 1167 if($('#serendipityEntry').length > 0) { 1168 $('#select_category').click(function(e) { 1169 e.preventDefault(); 1170 1171 if ($('#meta_data').hasClass('additional_info')) { 1172 $('#toggle_metadata').click(); 1173 } 1174 1175 serendipity.skipScroll($(this).attr('href')); 1176 }); 1177 } 1178 {else} 1179 $('#meta_data #edit_entry_category').addClass('mfp-hide'); 1180 1181 if($('#serendipityEntry').length > 0) { 1182 var btnText = '{$CONST.DONE}'; 1183 1184 $('#select_category').magnificPopup({ 1185 type: "inline", 1186 closeMarkup: '<button title="%title%" class="mfp-close" type="button">'+ btnText +'</button>', 1187 callbacks: { 1188 open: function() { 1189 // Accessibility helper 1190 $('#edit_entry_category .form_check input[type="checkbox"]').attr('aria-hidden', 'true'); 1191 if(localStorage !== null && localStorage.cat_view_state == "compact") { 1192 $('.mfp-content').addClass('compact_categories'); 1193 $('#toggle_cat_view').find('.icon-th').removeClass('icon-th').addClass('icon-th-list'); 1194 } 1195 }, 1196 afterClose: function() { 1197 // Accessibility helper 1198 $('#edit_entry_category .form_check input[type="checkbox"]').attr('aria-hidden', 'false'); 1199 serendipity.catsList(); 1200 } 1201 } 1202 }); 1203 1204 $('#cats_list').on('click', 'h3, li', function() { 1205 $('#select_category').trigger('click'); 1206 }); 1207 } 1208 {/if} 1209 1210 // Switch category view 1211 if($('#serendipityEntry').length > 0) { 1212 $('#toggle_cat_view').click(function() { 1213 var $el = $(this); 1214 var $target = $('.mfp-content'); 1215 1216 if($target.hasClass('compact_categories')) { 1217 $target.removeClass('compact_categories'); 1218 $el.find('.icon-th-list').removeClass('icon-th-list').addClass('icon-th'); 1219 if (localStorage !== null) { 1220 localStorage.cat_view_state = "hierarchical"; 1221 } 1222 } else { 1223 $target.addClass('compact_categories'); 1224 $el.find('.icon-th').removeClass('icon-th').addClass('icon-th-list'); 1225 if (localStorage !== null) { 1226 localStorage.cat_view_state = "compact"; 1227 } 1228 } 1229 }); 1230 }; 1231 1232 // Show tag selector 1233 {if $use_backendpopups || $force_backendpopups.tags} 1234 if($('#serendipityEntry').length > 0) { 1235 $('#select_tags').click(function(e) { 1236 e.preventDefault(); 1237 1238 if ($('#adv_opts').hasClass('additional_info')) { 1239 $('#toggle_advanced').click(); 1240 } 1241 1242 serendipity.skipScroll($(this).attr('href')); 1243 }); 1244 } 1245 {else} 1246 $('#adv_opts #edit_entry_freetags').addClass('mfp-hide'); 1247 1248 if($('#serendipityEntry').length > 0) { 1249 var btnText = '{$CONST.DONE}'; 1250 1251 $('#select_tags').magnificPopup({ 1252 type: "inline", 1253 closeMarkup: '<button title="%title%" class="mfp-close" type="button">'+ btnText +'</button>', 1254 callbacks: { 1255 afterClose: function() { 1256 serendipity.tagsList(); 1257 } 1258 } 1259 }); 1260 1261 $('#backend_freetag_list > a').click(function(e) { 1262 e.preventDefault(); 1263 }); 1264 1265 $('#tags_list').on('click', 'h3, li', function() { 1266 $('#select_tags').trigger('click'); 1267 }); 1268 } 1269 {/if} 1270 1271 // Category live filter 1272 $('#categoryfilter').keyup(function() { 1273 serendipity.liveFilters($(this), '#edit_entry_category .form_check', 'label'); 1274 }); 1275 1276 // Oldie helper for selecting categories 1277 $('#edit_entry_category .form_check input').change(function(e) { 1278 var $el = $(this); 1279 1280 if($el.is(":checked")) { 1281 $el.siblings('label').addClass('selected'); 1282 } else { 1283 $el.siblings('label').removeClass('selected'); 1284 } 1285 }); 1286 1287 // Plugins live filter 1288 $('#pluginfilter').keyup(function() { 1289 serendipity.liveFilters($(this), '.plugins_installable > li', '.plugin_features'); 1290 }); 1291 1292 // Reset button for live filters 1293 $('.reset_livefilter').click(function() { 1294 var target = '#' + $(this).attr('data-target'); 1295 $(target).val('').keyup(); 1296 }); 1297 1298 // Advanced options 1299 if($('#advanced_options').length > 0) { 1300 $('#toggle_advanced').click(function() { 1301 serendipity.toggle_collapsible($(this), '#adv_opts'); 1302 }); 1303 if (localStorage !== null && localStorage.getItem("show_toggle_advanced") == "true") { 1304 $('#toggle_advanced').click(); 1305 } 1306 } 1307 1308 // Entry preview 1309 $('.entry_preview').click(function() { 1310 document.forms['serendipityEntry'].elements['serendipity[preview]'].value='true'; 1311 }); 1312 1313 // Collapsible configuration elements 1314 if($('#serendipity_config_options, #serendipity_category, #image_directory_edit_form').length > 0) { 1315 var optsCollapsed = true; 1316 1317 $('.show_config_option').click(function(e) { 1318 var $el = $(this); 1319 if ($el.attr('href')) { 1320 var $toggled= $el.attr('href'); 1321 } else { 1322 var $toggled = $el.data('href'); 1323 } 1324 1325 serendipity.toggle_collapsible($el, $toggled); 1326 e.preventDefault(); 1327 }); 1328 1329 $('#show_config_all').click(function(e) { 1330 if ($(this).attr('href')) { 1331 var $container = $(this).attr('href'); 1332 } else { 1333 var $container = $(this).data('href'); 1334 } 1335 var $toggleIcon = $(this).find('span:first-child'); 1336 var $toggleIcons = $($container).find('.show_config_option > span'); 1337 var $toggleOption = $($container).find('.config_optiongroup'); 1338 if(optsCollapsed) { 1339 $toggleIcons.removeClass('icon-right-dir').addClass('icon-down-dir'); 1340 $toggleOption.removeClass('additional_info'); 1341 $toggleIcon.removeClass('icon-right-dir').addClass('icon-down-dir'); 1342 optsCollapsed = false; 1343 } else { 1344 $toggleIcons.removeClass('icon-down-dir').addClass('icon-right-dir'); 1345 $toggleOption.addClass('additional_info'); 1346 $toggleIcon.removeClass('icon-down-dir').addClass('icon-right-dir'); 1347 optsCollapsed = true; 1348 } 1349 $(this).toggleClass('active'); 1350 e.preventDefault(); 1351 }); 1352 1353 $('.show_config_option:not(.show_config_option_now)').click(); 1354 } 1355 1356 $('.change_preview').change(function() { 1357 serendipity.change_preview($(this).attr('id'), $(this).attr('data-configitem')); 1358 }); 1359 1360 $('.choose_media').click(function() { 1361 var configitem = $(this).parent().find('.change_preview').attr('id'); 1362 serendipity.choose_media(configitem); 1363 }); 1364 1365 $('.customfieldMedia').click(function() { 1366 var configitem = $(this).parent().find('textarea').attr('id'); 1367 serendipity.choose_media(configitem); 1368 }); 1369 1370 $('#tree_toggle_all').click(function(e) { 1371 e.preventDefault(); 1372 serendipity.treeToggleAll(); 1373 }); 1374 1375 // Comments 1376 $('.comments_delete, .comments_multidelete, .build_cache').click(function() { 1377 var $msg = $(this).attr('data-delmsg'); 1378 return confirm($msg); 1379 }); 1380 1381 $('.comments_reply').click(function(e) { 1382 e.preventDefault(); 1383 serendipity.openPopup($(this).attr('href')); 1384 }); 1385 1386 // Selection for multidelete 1387 $('.multidelete, .multiinsert').click(function() { 1388 var $el = $(this); 1389 serendipity.highlightComment($el.attr('data-multidelid'), $el.attr('checked')); 1390 var selectionAmount = $('.multidelete:checked, .multiinsert:checked').length; 1391 if (selectionAmount > 0) { 1392 $('#media_galleryinsert').fadeIn(); 1393 } else { 1394 $('#media_galleryinsert').fadeOut(); 1395 } 1396 }); 1397 1398 // Also marks checkbox when header is clicked 1399 $('.media_file h3').on('click', function() { 1400 $(this).parent().find('.multiinsert').click(); 1401 }); 1402 1403 // When clicking the 'Insert all' button, check whether only one or multiple 1404 // images are selected 1405 $('#media_galleryinsert .image_insert').on('click', function(e) { 1406 var selectionAmount = $('.multidelete:checked, .multiinsert:checked').length; 1407 if (selectionAmount == 0) { 1408 e.preventDefault(); 1409 return false; 1410 } 1411 1412 // Actually do a single insert 1413 if (selectionAmount == 1) { 1414 e.preventDefault(); 1415 var actualTargetElement = $('.multidelete:checked, .multiinsert:checked').closest('.media_file').find('.media_file_preview a').first(); 1416 // This below is a hack. Triggering actualTargetElement.click() does not work. Probably because MFP overrides click events within a modal popup. 1417 // So we need to do something dirty and directly access the location href. Don't tell my mom. 1418 location.href = actualTargetElement.attr('href'); 1419 return false; 1420 } 1421 }); 1422 1423 // hide gallery insert button until an image is selected 1424 $('#media_galleryinsert').hide(); 1425 1426 // Invert checkboxes 1427 $('.invert_selection').click(function() { 1428 serendipity.invertSelection(); 1429 }); 1430 1431 // Go back one step 1432 $('.go_back').click(function() { 1433 history.go(-1); 1434 }); 1435 1436 // Add media db upload field 1437 $('#add_upload').click(function(e) { 1438 e.preventDefault(); 1439 serendipity.addUploadField(); 1440 }); 1441 1442 // Check media db inputs 1443 $('.check_input').change(function() { 1444 serendipity.checkInputs(); 1445 }); 1446 1447 $('.check_inputs').click(function() { 1448 serendipity.checkInputs(); 1449 }); 1450 1451 // Extra function for media db download 1452 $('#imageurl').change(function() { 1453 sourceval = serendipity.getfilename(document.getElementById('imageurl').value); 1454 1455 if (sourceval.length > 0) { 1456 document.getElementById('imagefilename').value = sourceval; 1457 } 1458 }); 1459 1460 // Dashboard bookmarklet hint 1461 $('.s9y_bookmarklet').click(function(e) { 1462 e.preventDefault(); 1463 alert('{$CONST.FURTHER_LINKS_S9Y_BOOKMARKLET_DESC}'); 1464 }); 1465 1466 // Show media file info, template info, label info or filters 1467 $('.media_show_info, .template_show_info, .filters_toolbar li > a, .toggle_info').click(function(e) { 1468 var $el = $(this); 1469 if ($el.attr('href')) { 1470 $($el.attr('href')).toggleClass('additional_info'); 1471 } else { 1472 $($el.data('href')).toggleClass('additional_info'); 1473 } 1474 if (mq_small) { 1475 $el.closest('.has_info').toggleClass('info_expanded'); 1476 } 1477 $el.toggleClass('active'); 1478 e.preventDefault(); 1479 }); 1480 1481 // Show further links 1482 {if $use_backendpopups || $force_backendpopups.links} 1483 if($('#dashboard').length > 0) { 1484 $('.toggle_links').click(function(e) { 1485 $('#s9y_links').toggleClass('mfp-hide'); 1486 1487 e.preventDefault(); 1488 serendipity.skipScroll($(this).attr('href')); 1489 }); 1490 } 1491 {else} 1492 if($('#dashboard').length > 0) { 1493 $('.toggle_links').magnificPopup({ type: "inline" }); 1494 } 1495 {/if} 1496 1497 // Media file actions 1498 {if $use_backendpopups || $force_backendpopups.images} 1499 $('.media_fullsize').click(function(e) { 1500 e.preventDefault(); 1501 var $el = $(this); 1502 var filepath = $el.attr('href'); 1503 var pwidth = $el.attr('data-pwidth'); 1504 var pheight = $el.attr('data-pheight'); 1505 var ptop = (screen.height - pheight)/2; 1506 var pleft = (screen.width - pwidth)/2; 1507 window.open(filepath, 'Zoom', 'height='+pheight+',width='+pwidth+',top='+ptop+',left='+pleft+',toolbar=no,menubar=no,location=no,resize=1,resizable=1,scrollbars=yes'); 1508 }); 1509 {else} 1510 if ($('.media_fullsize').length > 0) { 1511 $('.media_fullsize').magnificPopup({ type:'image' }); 1512 } 1513 {/if} 1514 1515 $('.media_rename').click(function(e) { 1516 e.preventDefault(); 1517 var $el = $(this); 1518 serendipity.rename($el.attr('data-fileid'), $el.attr('data-filename')); 1519 }); 1520 1521 $('.media_delete').click(function(e) { 1522 e.preventDefault(); 1523 var $el = $(this); 1524 serendipity.deleteFromML($el.attr('data-fileid'), $el.attr('data-filename')); 1525 }); 1526 1527 1528 $('#media_crop').click(function(e) { 1529 window.open($(this).attr('href'), 'ImageCrop', 'width=800,height=600,toolbar=no,scrollbars=1,scrollbars,resize=1,resizable=1').focus(); 1530 e.preventDefault(); 1531 }); 1532 1533 $('.add_keyword').click(function(e) { 1534 serendipity.AddKeyword($(this).attr('data-keyword')); 1535 e.preventDefault(); 1536 }); 1537 1538 // Confirm media scale 1539 $('.image_scale').click(function() { 1540 if (confirm('{$CONST.REALLY_SCALE_IMAGE}')) document.serendipityScaleForm.submit(); 1541 }); 1542 1543 // Media scale change events 1544 $('#resize_width').change(function() { 1545 serendipity.rescale('width' , $(this).val()); 1546 }); 1547 1548 $('#resize_height').change(function() { 1549 serendipity.rescale('height' , $(this).val()); 1550 }); 1551 1552 // Show extended comment 1553 $('.toggle_comment_full').click(function(e) { 1554 var $el = $(this); 1555 if ($el.attr('href')) { 1556 var $toggled = $($el.attr('href')); 1557 } else { 1558 var $toggled = $($el.data('href')); 1559 } 1560 1561 serendipity.toggle_collapsible($el, $toggled); 1562 1563 $toggled.prev().toggleClass('additional_info'); 1564 e.preventDefault(); 1565 }); 1566 1567 // MediaDB-Filter-Buttons should react instantly 1568 $('input[name="serendipity[filter][fileCategory]"]').on('change', function() { 1569 $('#media_library_control').submit(); 1570 }); 1571 1572 // Clone form submit buttons 1573 $('#sort_entries > .form_buttons').clone().appendTo('#filter_entries'); 1574 $('#media_pane_sort > .form_buttons').clone().appendTo('#media_pane_filter'); 1575 1576 // Clone pagination - this could become a function, which should also 1577 // check if the cloned pagination already exists 1578 $('.media_pane .pagination').clone().prependTo('.media_pane'); 1579 $('.comments_pane .pagination').clone().prependTo('.comments_pane'); 1580 $('.entries_pane .pagination').clone().prependTo('.entries_pane'); 1581 $('.karma_pane .pagination').clone().prependTo('.karma_pane'); 1582 1583 // close comment reply on button click 1584 if ($('#comment_replied').length > 0) { 1585 $('#comment_replied').click(function() { 1586 serendipity.closeCommentPopup(); 1587 }); 1588 } 1589 1590 // UI-flow when selecting multiple images in ML upload 1591 if ($('.uploadform_userfile').length > 0) { 1592 $('.uploadform_userfile').change(function() { 1593 if ($(this).get(0).files.length > 1) { 1594 $(this).parent().siblings(':first').fadeOut(); 1595 $(this).parent().siblings(':first').find('input').val(''); 1596 $(this).attr('name', $(this).attr('name') + '[]'); 1597 } 1598 if ($(this).get(0).files.length == 1) { 1599 $(this).parent().siblings(':first').fadeIn(); 1600 } 1601 }); 1602 } 1603 1604 // update all button in plugin upgrade menu 1605 if ($('#updateAll').length > 0) { 1606 $('#updateAll').click(function() { 1607 serendipity.updateAll(); 1608 }); 1609 } 1610 1611 // minify images before upload, approach taken from https://github.com/joelvardy/javascript-image-upload/ 1612 {if {serendipity_getConfigVar key='uploadResize'} && ({serendipity_getConfigVar key='maxImgWidth'} > 0 || {serendipity_getConfigVar key='maxImgHeight'} > 0)} 1613 if ($('#uploadform').length > 0) { 1614 $('input[name="go_properties"]').hide(); 1615 var progressIcon = document.createElement('span'); 1616 progressIcon.className = 'uploadIcon icon-info-circled'; 1617 errorIcon = document.createElement('span'); 1618 errorIcon.className = 'uploadIcon icon-attention-circled'; 1619 successIcon = document.createElement('span'); 1620 successIcon.className = 'uploadIcon icon-ok-circled'; 1621 $('#uploadform').submit(function(event) { 1622 if (! $('#imageurl').val()) { 1623 event.preventDefault(); 1624 $('#uploadform .check_inputs').attr('disabled', true); 1625 var sendDataToML = function(data, progressContainer, progress) { 1626 $.ajax({ 1627 type: 'post', 1628 url: $('#uploadform').attr('action'), 1629 data: data, 1630 cache: false, 1631 processData: false, 1632 contentType: false, 1633 xhr: function() { 1634 var xhr = $.ajaxSettings.xhr(); 1635 xhr.upload.onprogress = function(e) { 1636 if (e.lengthComputable) { 1637 progress.value = e.loaded / e.total * 100; 1638 } 1639 }; 1640 return xhr; 1641 } 1642 }).done(function(data) { 1643 progress.value = 100; 1644 progressContainer.className = "msg_success"; 1645 $(progressContainer).find('.uploadIcon').replaceWith(successIcon.cloneNode(true)); 1646 }).fail(function(data) { 1647 progressContainer.className = "msg_error"; 1648 progress.disabled = true; 1649 progressContainer.innerHTML += "{$CONST.ERROR_UNKNOWN_NOUPLOAD}"; 1650 $(progressContainer).find('.uploadIcon').replaceWith(errorIcon.cloneNode(true)); 1651 }).always(function() { 1652 if ($('#ml_link').length == 0) { 1653 var mlLink = document.createElement('a'); 1654 mlLink.id = "ml_link"; 1655 mlLink.className = "button_link"; 1656 mlLink.href = $('#uploadform').attr('action'); 1657 mlLink.innerHTML = "{$CONST.MEDIA_LIBRARY}"; 1658 $(mlLink).hide(); 1659 $('.form_buttons').prepend(mlLink); 1660 $(mlLink).fadeIn(); 1661 } 1662 $('#uploadform .check_inputs').removeAttr('disabled'); 1663 }); 1664 }; 1665 $('.uploadform_userfile').each(function() { 1666 var files = this.files; 1667 for (var i = 0; i < files.length; i++) { 1668 var reader = new FileReader(); 1669 reader.file = files[i]; 1670 reader.onload = function(readerEvent) { 1671 var image = new Image(); 1672 var file = this.file; 1673 var type = file.type; 1674 var data = new FormData(); 1675 data.append('serendipity[action]', 'admin'); 1676 data.append('serendipity[adminModule]', 'media'); 1677 data.append('serendipity[adminAction]', 'add'); 1678 data.append('serendipity[token]', $('input[name*="serendipity[token]"]').val()); 1679 data.append('serendipity[target_filename][1]', $('input[name*="serendipity[target_filename][1]"]').val()); 1680 data.append('serendipity[target_directory][1]', $('select[name*="serendipity[target_directory][1]"]').val()); 1681 var progress = document.createElement('progress'); 1682 var progressContainer = document.createElement('span'); 1683 progressContainer.className = 'msg_notice'; 1684 progress.max = 100; 1685 progress.value = 0; 1686 $(progressContainer).append(progressIcon); 1687 progressContainer.innerHTML += file.name + ": " 1688 $(progressContainer).append(progress); 1689 $('.form_buttons').append(progressContainer); 1690 if (type.substring(0, 6) == "image/") { 1691 image.onload = function (imageEvent) { 1692 var canvas = document.createElement('canvas'), 1693 max_width = {if {serendipity_getConfigVar key='maxImgWidth'}}{serendipity_getConfigVar key='maxImgWidth'}{else}0{/if}, 1694 max_height = {if {serendipity_getConfigVar key='maxImgHeight'}}{serendipity_getConfigVar key='maxImgHeight'}{else}0{/if}, 1695 width = image.width, 1696 height = image.height; 1697 1698 if (max_width > 0 && width > max_width) { 1699 height *= max_width / width; 1700 width = max_width; 1701 } 1702 if (max_height > 0 && height > max_height) { 1703 width *= max_height / height; 1704 height = max_height; 1705 } 1706 1707 canvas.width = width; 1708 canvas.height = height; 1709 canvas.getContext('2d').drawImage(image, 0, 0, width, height); 1710 1711 if (type == "image/bmp") { 1712 {* bmp is not supported *} 1713 type = "image/png"; 1714 data.append('serendipity[target_filename][1]', file.name.replace('.bmp', '.png')); 1715 } 1716 canvas.toBlob(function(blob) { 1717 data.append('serendipity[userfile][1]', blob, file.name); 1718 sendDataToML(data, progressContainer, progress); 1719 }, type); 1720 } 1721 image.src = readerEvent.target.result; 1722 } else { 1723 data.append('serendipity[userfile][1]', file, file.name); 1724 sendDataToML(data, progressContainer, progress); 1725 } 1726 } 1727 reader.readAsDataURL(reader.file); 1728 } 1729 }); 1730 } 1731 }); 1732 } 1733 {/if} 1734 1735 if ($('#serendipity_only_path').length > 0) { 1736 $('#serendipity_only_path').change(function() { 1737 serendipity.SetCookie('serendipity_only_path', $('#serendipity_only_path').val()); 1738 }); 1739 } 1740 1741 if ($('.image_move').length > 0) { 1742 $('.image_move').removeClass('hidden'); 1743 $('.image_move').magnificPopup({ 1744 type: 'inline', 1745 }); 1746 $('#move-popup form').submit(function(e) { 1747 e.preventDefault(); 1748 $('#newDir').val($('#move-popup form select').val()); 1749 $.magnificPopup.close(); 1750 $('input[name="toggle_move"]').click(); 1751 }); 1752 } 1753 1754 // reopen detail element after spamblock action 1755 if ($('#serendipity_comments_list').length > 0 && window.location.hash && $('#' + window.location.hash.replace('#', '')).length > 0) { 1756 $('#' + window.location.hash.replace('#', '')).find(".toggle_info").click(); 1757 } 1758 1759 // ajaxify image rotate, solving cache issue 1760 $('.media_rotate_right,.media_rotate_left').click(function(e) { 1761 e.preventDefault(); 1762 var $rotateButton = $(this) 1763 $.get($rotateButton.attr('href'), function() { 1764 serendipity.reloadImage($rotateButton.closest('.media_file').find('img')); 1765 }); 1766 }) 1767 1768 // Tabs 1769 if($('.tabs').length > 0) { 1770 var currTabText = '{$CONST.CURRENT_TAB}'; 1771 1772 $('.tabs').accessibleTabs({ 1773 wrapperClass: 'tabcontent', 1774 currentClass: 'on', 1775 tabhead: 'h3', 1776 tabheadClass: 'visuallyhidden', 1777 tabbody: '.panel', 1778 fx: 'fadeIn', 1779 currentInfoText: currTabText, 1780 currentInfoClass: 'visuallyhidden', 1781 syncheights: false, 1782 saveState: true 1783 }); 1784 } 1785 1786 // Drag 'n' drop 1787 if (! Modernizr.touch){ 1788 function getDragdropConfiguration(group) { 1789 return { 1790 containerSelector: '.pluginmanager_container', 1791 group: group, 1792 handle: '.pluginmanager_grablet', 1793 1794 onDrop: function ($item, container, _super) { 1795 var placement = $item.parents('.pluginmanager_container').data("placement"); 1796 $item.find('select[name$="placement]"]').val(placement); 1797 $item.removeClass('dragged').removeAttr('style'); 1798 $('body').removeClass('dragging'); 1799 $.autoscroll.stop(); 1800 }, 1801 onDragStart: function ($item, container, _super) { 1802 $.autoscroll.init(); 1803 $item.css({ 1804 height: $item.height(), 1805 width: $item.width() 1806 }); 1807 $item.addClass('dragged'); 1808 $('body').addClass('dragging'); 1809 } 1810 } 1811 } 1812 1813 $('.pluginmanager_sidebar .pluginmanager_container').sortable(getDragdropConfiguration('plugins_sidebar')); 1814 $('.pluginmanager_event .pluginmanager_container').sortable(getDragdropConfiguration('plugins_event')); 1815 $('.configuration_group .pluginmanager_container').sortable(getDragdropConfiguration('plugins_event')); 1816 } 1817 1818 // Equal Heights 1819 $(window).load(function() { 1820 if(!Modernizr.flexbox) { 1821 if (mq_small) { 1822 serendipity.sync_heights(); 1823 } 1824 } 1825 }); 1826 1827 // Make sure plugin list heights are recalculated when switching tabs 1828 $('#pluginlist_tabs a').click(function() { 1829 if(!Modernizr.flexbox) { 1830 if (mq_small) { 1831 serendipity.sync_heights(); 1832 } 1833 } 1834 }); 1835}); 1836 1837// This is kept for older plugins. Use of $(document).ready() is encouraged. 1838// At some point, these will be removed. 1839addLoadEvent = function(func) { 1840 var oldonload = window.onload; 1841 if (typeof window.onload != 'function') { 1842 window.onload = func; 1843 } else { 1844 window.onload = function() { 1845 oldonload(); 1846 func(); 1847 } 1848 } 1849} 1850 1851// Several plugins use this in the global scope. Those API functions are 1852// vital, so they reference to our new serendipity scope. This global 1853// scope is deprecated and subject to removal in the future. 1854serendipity_imageSelector_addToBody = function(block, textarea) { 1855 return serendipity.serendipity_imageSelector_addToBody(block, textarea); 1856} 1857 1858serendipity_imageSelector_done = function(textarea) { 1859 return serendipity.serendipity_imageSelector_done(textarea); 1860} 1861 1862serendipity_imageSelector_addToElement = function(str, id) { 1863 return serendipity.serendipity_imageSelector_addToElement(str, id); 1864} 1865