/*global $gp:false, gpui:false, gplinks:false, gpinputs:false isadmin:false, gpBase:false, strip_from:false, gpRem:false, gpBLink:false */ /*jshint forin:true, noarg:true, noempty:true, eqeqeq:true, bitwise:true, strict:true, undef:true, unused:true, curly:true, browser:true, jquery:true, indent:4, maxerr:100, newcap:false, white:false*/ //"use strict"; var gp_editor = false; $gp.curr_edit_id = null; $gp.interface = []; // storage for editing interfaces $gp.cached = {}; $gp.defaults = {}; $gp.editors = []; // storage for editing objects /** * Get the coordinates for positioning editable area overlays * */ $gp.Coords = function(area){ if( area.hasClass('inner_size') ){ area = area.children().first(); } var loc = area.offset(); loc.w = area.outerWidth(); loc.h = area.outerHeight(); return loc; }; /** * Create a <div> in the #gp_admin_html space * */ $gp.div = function(id,div_class){ var div = $('#'+id); div_class = div_class || ''; if( div.length === 0 ){ div = $('<div id="'+id+'" class="'+div_class+'"></div>').appendTo('#gp_admin_html'); } return div; }; /** * Dynamically load inline editing * */ $gp.links.inline_edit_generic = function(evt,arg){ evt.preventDefault(); var area_id = $gp.AreaId( $(this) ); $gp.LoadEditor(this.href, area_id, arg); //show editor when a edit link is clicked in the var $target = $(evt.target); if( $target.closest('.panel_tabs').length && typeof(gp_editing) != 'undefined' ){ if( $target.data('mode') == 'extra' ){ gp_editing.is_extra_mode = true; }else{ gp_editing.is_extra_mode = false; } gp_editing.ShowEditor(); } } $gp._loadingEditor = false; $gp.LoadEditor = function(href, area_id, arg){ area_id = area_id || 0; if( area_id === $gp.curr_edit_id ){ return; } if( $gp._loadingEditor ){ console.log('editor still loading'); return; } $gp._loadingEditor = true; //first time editing, get default $gp.links, $gp.inputs, $gp.response if( typeof(gp_editing) == 'undefined' ){ $gp.defaults['links'] = $gp.Properties($gp.links); $gp.defaults['inputs'] = $gp.Properties($gp.inputs); $gp.defaults['response'] = $gp.Properties($gp.response); } $gp.CacheInterface(function(){ //set the current editing interface aside so the new one can be created if( typeof(gp_editing) !== 'undefined' ){ if( gp_editing.RestoreCached(area_id) ){ $gp._loadingEditor = false; return; } }else{ $gp.LoadStyle('/include/css/inline_edit.css'); $gp.LoadStyle('/include/css/manage_sections.css'); // $gp.LoadStyle('/include/css/manage_sections_compact.css'); // alternative compact style } $gp.curr_edit_id = area_id; var $edit_div = $gp.CurrentDiv(); $gp.DefinedObjects(); $gp.loading(); //legacy inline editing support //can also be used for development/troubleshooting if( typeof(gplinks[arg]) === 'function' ){ gplinks[arg].call(this,arg,evt); $gp._loadingEditor = false; return; } var script = strip_from(href,'#'); script += '&gpreq=json&defined_objects='+$gp.DefinedObjects(); if( arg != 'manage_sections' ){ script += '&cmd=inlineedit&area_id='+area_id+'§ion='+$edit_div.data('gp-section'); } //get the new editor $.getScript( script,function(data){ if( data === 'false' ){ alert($gp.error); $gp.loaded(); $gp._loadingEditor = false; return; } if( typeof(gp_editor.wake) == 'function' ){ gp_editor.wake(); } $gp._loadingEditor = false; }); }); }; /** * Get object properties * */ $gp.Properties = function(obj){ var properties = []; for( var i in obj ){ if( obj.hasOwnProperty(i) ){ properties.push(i); } } return properties; } /** * Get the current editing div * */ $gp.CurrentDiv = function(){ return $('#ExtraEditArea'+$gp.curr_edit_id); } /** * Cache the current editing interface * */ $gp.CacheInterface = function(callback){ $gp.CurrentDiv().removeClass('gp_edit_current'); //if gp_editing is not defined then we don't have anything to cache yet if( typeof(gp_editing) == 'undefined' ){ callback.call(); return; } //only continue if we can save gp_editing.SaveChanges(function(){ if( typeof(gp_editor.sleep) == 'function' ){ gp_editor.sleep(); } $gp.interface[$gp.curr_edit_id] = $('#ck_area_wrap').children().detach(); $gp.editors[$gp.curr_edit_id] = gp_editor; //cache $gp.links that were defined by the current gp_editor $gp.cached[$gp.curr_edit_id] = {}; $gp.CacheObjects( 'links' ); $gp.CacheObjects( 'inputs' ); $gp.CacheObjects( 'response' ); $('.cktabs .ckeditor_control.selected').removeClass('selected'); callback.call(); }); } /** * Cache $gp.links, $gp.inputs and $gp.Response * ?? gpresponse, gplinks, gpinputs ?? */ $gp.CacheObjects = function(type, cache_loc){ var from = $gp[type]; $gp.cached[$gp.curr_edit_id][type] = {}; for( var i in from ){ if( !from.hasOwnProperty(i) ){ continue; } if( $gp.defaults[type].indexOf(i) > -1 ){ continue; } $gp.cached[$gp.curr_edit_id][type][i] = from[i]; } } /** * Restore $gp.links, $gp.inputs and $gp.Response * ?? gpresponse, gplinks, gpinputs ?? */ $gp.RestoreObjects = function(type, id){ var from = $gp.cached[id][type]; for( var i in from ){ if( !from.hasOwnProperty(i) ){ continue; } $gp[type][i] = from[i]; } } /** * Send to the server which javascript objects are already defined * */ $gp.defined_objects = []; $gp.DefinedObjects = function(){ //get all objects the first time if( typeof(gp_editing) == 'undefined' ){ for( var i in window ) { if( typeof(window[i]) != 'object' ){ continue; } $gp.defined_objects.push(i); } } //compare with $gp.defined_objects var objects = []; for( var i in window ) { if( typeof(window[i]) != 'object' ){ continue; } if( $gp.defined_objects.indexOf(i) != -1 ){ continue; } objects.push(i); } return objects.join(','); } /** * Remote Browse * @param object evt Event object * */ $gp.links.remote = function(evt){ evt.preventDefault(); var src = $gp.jPrep(this.href,'gpreq=body'); //can remote install if( gpRem ){ var pathArray = window.location.href.split( '/' ); var url = pathArray[0] + '//' + pathArray[2]+gpBase; if( window.location.href.indexOf('index.php') > 0 ){ url += '/index.php'; } src += '&inUrl='+encodeURIComponent(url) + '&gpRem='+encodeURIComponent(gpRem); } //40px margin + 17px*2 border + 20px padding + 10 (extra padding) = approx 130 // var height = $gp.$win.height() - 130; var opts = {context:'iframe',width:780}; var iframe = '<iframe src="'+src+'" frameborder="0" />'; $gp.AdminBoxC(iframe,opts); }; /** * Add stylesheets to the current document * @param string file * @param bool already_prefixed */ $gp.LoadStyle = function(file, already_prefixed){ var time = req_time || new Date().getTime(); file = already_prefixed ? file : gpBase+file; file = file+'?t='+time; //already loaded? if( $('link[href="'+file+'"]').length ){ return; } //href set after appending to head so that it works properly in IE $('<link rel="stylesheet" type="text/css" />') .appendTo('head') .attr({'href':file}); }; /** * Show content (data) in #gp_admin_box * This is used instead of colorbox for admin content * - this box resizes without javascript calls (height) * - less animation */ $gp.AdminBoxC = function(data, options){ $gp.CloseAdminBox(); if( data === '' ){ return false; } if( typeof(options) == 'string' ){ options = {context:options}; }else if( typeof(options) == 'undefined' ){ options = {}; } options = $.extend({ context : '', width : 680, zIndex: 11000 }, options); /* var win_width = $gp.$win.width(); var box_width = Math.max(660, Math.round(win_width*0.70)); */ var box_width = options.width; $gp.div('gp_admin_box1') .css({ 'zIndex' : options.zIndex }) .stop(true,true) .fadeTo(0,0) //fade in from transparent .fadeTo((options.replaceBox ? 0 : 200), 0.2); $gp.div('gp_admin_box') .css({ 'zIndex' : options.zIndex, }) .stop(true,true) .fadeIn((options.replaceBox ? 0 : 400)) .html('<a class="gp_admin_box_close" data-cmd="admin_box_close"></a>' + '<div id="gp_admin_boxc" class="' + (options.context || '') + '" ' + 'style="width:' + box_width + 'px">' + '</div>') .find('#gp_admin_boxc') .html(data) .find('input:visible').first() .trigger('focus'); $('.messages').detach(); //close on escape key $gp.$doc.on('keyup.abox',function(e) { if( e.keyCode == 27 ){ $gp.CloseAdminBox(); } }); return true; }; /** * Close gp_admin_box * */ $gp.CloseAdminBox = function(evt){ if( evt ){ evt.preventDefault(); } $gp.$doc.off('keyup.abox'); $('#gp_admin_box1').fadeOut(); $('#gp_admin_box').fadeOut(300,function(){ //move contents back to document if they came from an inline element //remove other content var boxc = $('#gp_admin_boxc'); if( boxc.hasClass('inline') ){ $('#gp_admin_boxc').children().appendTo('#gp_hidden'); }else{ $('#gp_admin_boxc').children().remove(); } }); if( typeof($.fn.colorbox) !== 'undefined' ){ $.fn.colorbox.close(); } }; $gp.links.admin_box_close = $gp.inputs.admin_box_close = $gp.CloseAdminBox; /** * Save admin user settings * */ $gp.SaveGPUI = function(){ if( !isadmin ){ return; } var data = 'cmd=SaveGPUI'; $.each(gpui,function(i,value){ data += '&gpui_'+i+'='+value; }); var url = gpBLink+'/Admin/Preferences'; $gp.postC( url, data); }; /** * Drop down menus * */ $gp.links.dd_menu = function(evt){ evt.preventDefault(); evt.stopPropagation(); $('.messages').detach(); //remove messages since we can't set the z-index properly var that = this; var $list = $(this).parent().find('.dd_list'); //display the list and add other handlers $list.show(); //scroll to show selected var $selected = $list.find('.selected'); if( $selected.length ){ var $ul = $list.find('ul').first(); var pos = $list.find('.selected').prev().prev().prev().position(); if( pos ){ $ul.scrollTop( pos.top + $ul.scrollTop() ); } } //hide the list and remove handlers $('body').on('click.gp_select',function(evt){ $list.hide(); $list.off('.gp_select'); $('body').off('.gp_select'); //stop propogation if it's a click on the current menu so it will remain hidden if( $(evt.target).closest(that).length ){ evt.stopPropagation(); } }); }; /** * A simple tab method for switching content area visibility * */ $gp.links.tabs = function(evt){ evt.preventDefault(); var $this = $(this); $this.siblings('a').removeClass('selected').each(function(b,c){ if( c.hash ){ $(c.hash).hide() .find('input[type=submit],button[type=submit]').prop('disabled',true); } }); if( this.hash ){ $this.addClass('selected'); $(this.hash).show() .find('input[type=submit],button[type=submit]').prop('disabled',false); } }; /** * Use jQuery's Ajax functions to load javascripts and call callback when complete * @depredated 2.0.2 Keep for Simple Slideshow Plugin * */ $gp.Loaded = {}; $gp.LoadScripts = function(scripts,callback,relative_path){ var script_count = scripts.length, d=new Date(), t=d.getTime(), base=''; relative_path = relative_path||false; if( relative_path ){ base = gpBase; } //use $.each to prevent Array.prototype.xxxx from affecting the for loop $.each(scripts,function(i,script){ script = base+script; if( $gp.Loaded[script] ){ sload(); }else{ $gp.Loaded[script] = true; $.getScript( $gp.jPrep(script,'t='+t), function(){ sload(); }); } }); function sload(){ script_count--; if(script_count === 0){ if( typeof(callback) === 'function' ){ callback.call(this); } } } }; /** * Refresh the current page * ie doesn't handle href="" the same way as other browsers */ $gp.links.gp_refresh = function(evt){ evt.preventDefault(); $gp.Reload(); }; /** * Change the display of the admin toolbar * */ $gp.links.toggle_panel = function(evt){ var c,panel = $('#simplepanel'); evt.preventDefault(); var classes = ''; if( panel.hasClass('minb') ){ classes = ''; c = 0; }else if( panel.hasClass('compact') ){ classes = 'minb toggledmin'; c = 3; }else{ classes = 'compact'; c = 1; } if( !panel.hasClass('toggledmin') ){ panel.off('mouseenter touchstart').on('mouseenter touchstart',function(event){panel.off(event).removeClass('toggledmin');}); } panel.attr('class','keep_viewable '+classes); gpui.cmpct = c; $gp.SaveGPUI(); }; /** * Handle clicks on headers within the main admin toolbar * */ $gp.links.toplink = function(){ //must not be compact var $this = $(this); var $panel = $('#simplepanel'); if( $panel.hasClass('compact') ){ return; } var b = $this.next(); gpui.vis = !(b.is(':visible') && (b.height() > 0)); //hide visible areas $panel.find('.panelgroup2:visible').slideUp(300); if( gpui.vis ){ gpui.vis = $this.data('arg'); b.slideDown(300); } $gp.SaveGPUI(); }; /** * Collapsible area * */ $gp.links.collapsible = function(){ var area = $(this).parent(); //only show one if( area.hasClass('one') && area.hasClass('gp_collapsed') ){ area.parent().find('.head').addClass('gp_collapsed'); area.parent().find('.collapsearea').slideUp(300); area.removeClass('gp_collapsed').next().slideDown(300); //ability to show multiple }else{ area.toggleClass('gp_collapsed').next().slideToggle(300); } }; /** * Load content in #gp_admin_box * @deprecated 2.5, use data-cmd="gpabox" instead * */ $gp.links.ajax_box = $gp.links.admin_box = function(evt){ alert(' "ajax_box" and "admin_box" are deprecated link arguments. Use gpabox instead.'); evt.preventDefault(); $gp.loading(); var href = $gp.jPrep(this.href,'gpreq=flush'); $.get(href,'',function(data){ $gp.AdminBoxC(data); $gp.loaded(); },'html'); }; /** * Load content for #gp_admin_box * This method allows for other actions to be sent to the client in addition to admin_box content */ $gp.links.gpabox = function(evt){ evt.preventDefault(); $gp.loading(); var href = $gp.jPrep(this.href)+'&gpx_content=gpabox'; var this_context = this; $.getJSON(href,function(data,textStatus,jqXHR){ $gp.Response.call(this_context,data,textStatus,jqXHR); }); }; /** * Add a table row * */ $gp.links.add_table_row = function(evt){ var $tr = $(this).closest('tr'); var $new_row = $tr.closest('tbody').find('tr').first().clone(); $new_row.find('.class_only').remove(); $new_row.find('input').val('').attr('value',''); $new_row.find('textarea').val('').text(''); $tr.before($new_row); } /** * Remove a table row * */ $gp.links.rm_table_row = function(evt){ var $this = $(this); if( $this.closest('tbody').find('.rm_table_row').length < 2 ){ return; } $this.closest('tr').remove(); } /** * POST a link (without ajax) * */ $gp.links.post = function(evt){ evt.preventDefault(); var query = strip_to(this.search,'?'); var params = ParseQuery(query); params.verified = this.dataset.nonce; var form = document.createElement('form'); form.method = 'POST'; form.action = this.pathname; for( const [name, value] of Object.entries(params) ){ var element = document.createElement('input'); element.type = 'hidden'; element.name = name; element.value = value; form.appendChild(element); } document.body.appendChild(form); form.submit(); } function ParseQuery(queryString) { var query = {}; var pairs = (queryString[0] === '?' ? queryString.substr(1) : queryString).split('&'); for (var i = 0; i < pairs.length; i++) { var pair = pairs[i].split('='); query[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || ''); } return query; } /** * Post a gpabox request * */ $gp.inputs.gpabox = function(){ return $gp.post(this,'gpx_content=gpabox'); }; /** * Toggle the "checked" class on the parent of a checkbox when clicked * */ $gp.inputs.gpcheck = function(){ if( this.checked ){ $(this).parent().addClass('checked'); }else{ $(this).parent().removeClass('checked'); } }; /** * Check or uncheck all checkboxes in a form * */ $gp.inputs.check_all = function(){ $(this).closest('form').find('input[type=checkbox]').prop('checked',this.checked); }; /** * Send form using cookiecmd * */ $gp.inputs.cnreq = function(evt){ evt.preventDefault(); var query = $(this.form).serialize(); $gp.SetCookieCmd(query); //$gp.Cookie('cookie_cmd',encodeURIComponent(query),1); window.location = strip_from(strip_from(this.form.action,'#'),'?'); }; /** * Escape special html characters in a string similar to php's htmlspecialchars() function * */ $gp.htmlchars = function(str){ str = str || ''; return $('<a>').text(str).html(); }; /** * Redirect the user's browser to a url * */ $gp.response.location = function(obj){ window.setTimeout(function(){ window.location = obj.SELECTOR; },obj.CONTENT); window.setInterval(function(){ $('#redir-countdown').text($('#redir-countdown').text() - 1); }, 1000); }; /** * toggle the isPrivate class for the <html> element * obj.SELECTOR must evaluate as true or false * */ $gp.response.toggle_vis_class = function(obj){ $('html').toggleClass('isPrivate', !!obj.SELECTOR); }; /** * Get the edit area id * */ $gp.AreaId = function( $node ){ var area_id = $node.data('gp-area-id'); if( typeof(area_id) != 'undefined' ){ return parseInt(area_id); } //ExtraEditArea6 //ExtraEditLink6 var area_id = $node.attr('id'); if( typeof(area_id) != 'undefined' ){ return parseInt($node.attr('id').substr(13)); } } /** * Expand sub lists * */ $gp.links.expand = function(){ var list = $(this).siblings('ul'); if( list.css('display') == 'block' ){ return; } list.css('display','block'); $(document).one('click',function(evt){ list.css('display',''); }); } /** * Indicate if there's an extra area that is a draft * */ $gp.IndicateDraft = function(){ $('.gp_extra_edit').removeClass('msg_publish_draft'); $('.editable_area').each(function(){ if( $(this).data('draft') == 1 ){ $('.gp_extra_edit').addClass('msg_publish_draft'); return false; } }); } /** * Onload * */ $(function(){ $gp.$win = $(window); $gp.$doc = $(document); //add return value to form $gp.$doc.on('mousedown','form',function(){ var $this = $(this); if( $this.data('gpForms') === 'checked' ){ return; } if( typeof(this['return']) !== 'undefined' ){ console.log('return'); this['return'].value = window.location; //set the return path } $this.data('gpForms','checked'); }); if( !isadmin || (typeof(gp_bodyashtml) !== 'undefined') ){ return; } $('body, html').addClass('gpAdmin'); $gp.IndicateDraft(); window.setTimeout(function(){ EditOutlines(); UIEffects(); },1); /** * Update character counts * */ $gp.$doc.on('input', '.show_character_count textarea', function(){ var $span = $(this).parent().find('.character_count span'); $span.text(this.value.length); }); /** * Editable area outline * */ function EditOutlines(){ var timeout = false, overlay, lnk_span=false, edit_area, highlight_box, fixed_pos = false; overlay = $gp.div('gp_edit_overlay'); overlay.on('click', function(evt){ //if a link is clicked, prevent the overlay from being shown right away var target = $(evt.target); if( target.filter('a').length > 0 ){ if( target.hasClass('gp_overlay_close') ){ evt.preventDefault(); } if( edit_area){ edit_area.addClass('gp_no_overlay'); } } HideOverlay(); }).on('mouseleave touchend',function(){ StartOverlayHide(); }).on('mouseenter touchstart',function(){ if( timeout ){ window.clearTimeout(timeout); } }); //show the edit link when hovering over an editable area // using mouseenter to show link an area filled with an iframe $('.editable_area').on('mousemove.gp mouseenter.gp touchstart.gp',function(e){ if( timeout ){ window.clearTimeout(timeout); } var new_area = $(this); // don't show overlay // - for an area that is being edited // - if we've already shown it if( new_area.hasClass('gp_no_overlay') || new_area.hasClass('gp_editing') ){ return; } if( new_area.parent().closest('.editable_area').length > 0 ){ e.stopPropagation(); // trigger a substitute event, plugin JS can listen to new_area.trigger("admin:" + e.type); } //area han't changed, so just show the span if( lnk_span && edit_area && new_area.attr('id') === edit_area.attr('id') ){ lnk_span.show(); return; } rmNoOverlay(edit_area); edit_area = new_area; AreaOverlay(edit_area); }).on('mouseleave touchend',function(){ StartOverlayHide(); rmNoOverlay(edit_area); }); $gp.$win.on('scroll', function(){ SpanPosition(); }); function rmNoOverlay(edit_area){ if( !edit_area ){ return; } edit_area.removeClass('gp_no_overlay'); } /** * Make sure the span for the current edit area is within the viewable window * */ function SpanPosition(){ if( !lnk_span || fixed_pos ){ return; } var off = lnk_span.offset(), pos = lnk_span.position(), top = $gp.$win.scrollTop(), diff = Math.max(0,top - (off.top - pos.top)); lnk_span.stop(true,true).animate({'top':diff}); } function StartOverlayHide(){ if( timeout ){ window.clearTimeout(timeout); } timeout = window.setTimeout( function(){ HideOverlay(); },200); } function HideOverlay(){ //hide links if( lnk_span ){ lnk_span .stop(true,true) .hide(500,function(){ ResetMenu(); }); } fixed_pos = false; //hide the box var box = overlay.find('div'); box.stop(true,true).fadeOut(); } /** * Display the edit links and overlay that outlines an editable area * */ function AreaOverlay(edit_area){ var id,loc,width; id = edit_area.attr('id'); if( !id ){ return; } id = id.substr(13); //edit_area is always ExtraEditArea# //get the edit links var edit_links = $('#ExtraEditLnks'+id).children(); if( edit_links.length === 0 ){ edit_links = $('#ExtraEditLink'+id); if( edit_links.length === 0 ){ return; } } //edit area location loc = $gp.Coords(edit_area); overlay.show().css({'top':(loc.top-3),'left':(loc.left-2),'width':(loc.w+6)}); if( !lnk_span ){ lnk_span = $('<span>'); highlight_box = $('<div>'); overlay.html(highlight_box).append(lnk_span); }else{ lnk_span.stop(true,true).show().removeClass('gp_hover'); } highlight_box.stop(true,true).hide().css({'height':(loc.h+5),'width':(loc.w+4)}); SpanPosition(); //add the edit links edit_links = edit_links.clone(true) .removeClass('ExtraEditLink'); // lnk_span.html('<a class="gp_overlay_expand fa fa-pencil"></a>') .append(edit_links); ResetMenu(); } /** * Reset Context Menu * */ function ResetMenu(){ fixed_pos = false; lnk_span .css({'left':'auto','top':0,'right':0,'position':'absolute'}) .removeClass('gp_hover') .off('mouseenter touchstart') .one('mouseenter touchstart',function(){ if( edit_area.hasClass('gp_no_overlay') ){ return; } ShowMenu(); }); } /** * Display the editable area options * */ function ShowMenu(){ lnk_span .addClass('gp_hover') .stop(true,true) .show(); //show the overlay highlight_box.stop(true,true).fadeIn(); } /** * Left click to show menu * This may not always work. Some template/user js may cancel event bubbling * Clicking on links still works * */ $gp.$doc.on('click.gp','.editable_area, #gp_edit_overlay',function(evt){ if( ShowableMenu(evt) ){ MenuPos(evt); } }); /** * Position link at cursor * */ function MenuPos(evt){ fixed_pos = true; var left = evt.pageX-$gp.$win.scrollLeft(); var diff = left + lnk_span.width() - $gp.$win.width(); var top = evt.pageY - $gp.$win.scrollTop(); if( diff > 0 ){ left -= diff; } lnk_span.show().stop(true,true).css({'top':top,'left':left,'right':'auto','position':'fixed'}); } /** * Return true if we can show the Typesetter context menu * */ function ShowableMenu(evt){ if( evt.ctrlKey || evt.altKey || evt.shiftKey ){ return; } if( !edit_area || edit_area.hasClass('gp_editing') || edit_area.hasClass('gp_no_overlay') || !lnk_span ){ return; } return true; } } /* end EditOutlines */ function UIEffects(){ if( !$('html').hasClass('admin_body') ){ SimpleDrag('#simplepanel .toolbar, #simplepanel .toolbar a', '#simplepanel', 'fixed', function(newpos){ gpui.tx = newpos.left; gpui.ty = newpos.top; $gp.SaveGPUI(); },true); } //keep expanding areas within the viewable window $('.in_window').parent().on('mouseenter touchstart',function(){ var $this = $(this); var panel = $this.children('.in_window').css({'right':'auto','left':'100%','top':0}); window.setTimeout(function(){ var pos = panel.offset(); var right = pos.left + panel.width(); var bottom = pos.top + panel.height(); if( right > $gp.$win.width() + $gp.$win.scrollLeft() ){ panel.css({'right':'100%','left':'auto'}); } var winbottom = $gp.$win.height() + $gp.$win.scrollTop(); if( bottom > winbottom ){ var diff = winbottom + - bottom - 10; panel.css({'top':diff}); } },1); }); } /** * Reduce a list of titles by search criteria entered in gpsearch areas * */ $(document).on('keyup','input.gpsearch',function(){ var search = this.value.toLowerCase(); $(this.form).find('.gp_scrolllist > div > *').each(function(){ var $this = $(this); if( $this.text().toLowerCase().indexOf(search) == -1 ){ $this.addClass('filtered'); }else{ $this.removeClass('filtered'); } }); }); /** * Configuration -> Settings * Disable minifyjs when combinejs is unchecked * */ function CheckCombineJs(){ var checked = $('#admincontent_inner input[type="checkbox"][name="combinejs"]').prop("checked"); $('#admincontent_inner input[type="checkbox"][name="minifyjs"]').prop("disabled", !checked); } $('#admincontent_inner input[type="checkbox"][name="combinejs"]').on('change', CheckCombineJs); CheckCombineJs(); /** * Modifier key names based on UI language and OS * */ $gp.mod_keys = /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform) ? { // Apple ctrlKey: '˄ control', shiftKey: '⇑ shift', altKey: '⌥ option', metaKey: '⌘ command' } : { // others ctrlKey: gplang.ctrlKey, shiftKey: '⇑ ' + gplang.shiftKey, altKey: gplang.altKey, metaKey: 'Meta' }; /** * Get visual representation of modifier keys in a <span> * @param array of keys, possible values: ctrlKey, shiftKey, altKey, metaKey * @return html * */ $gp.GetModkeys = function(mod_keys){ if( !mod_keys.length ){ return ''; } var html = ''; $.each(mod_keys, function(i, k){ html += '<kbd class="keyboard-key">' + $gp.mod_keys[k] + '</kbd> + '; }); return '<span class="show_modkeys">' + html + '</span>'; }; /** * Insert modifier keys pepresentation to an element * @param stringa valid jQuery selector * @param string 'before' or 'after'' * @param array of keys, modifier keys and regular key, e.g. ['ctrlKey','H'], optional * */ $gp.InsertModkeys = function(selector, where, mod_keys){ $(selector).siblings('.show_modkeys').remove(); if( typeof(mod_keys) == 'undefined' ){ // get from hideAdminUIcfg var mod_keys = hideAdminUIcfg.hotkey_modkeys; } var modkeys_html = $gp.GetModkeys(mod_keys); if( where == 'before' ){ $(modkeys_html).insertBefore(selector); }else{ $(modkeys_html).insertAfter(selector); } }; /** * Get hotkey hint * @param array of keys, modifier keys and regular key, e.g. ['ctrlKey','H'] * @return string e.g. for title attr * */ $gp.GetHotkeyHint = function(keys){ var hint = ''; if( typeof(keys) == 'undefinded' || !keys.length ){ return ''; } $.each(keys, function(i, k){ switch(k){ case 'ctrlKey': case 'shiftKey': case 'altKey': case 'metaKey': hint += '[' + $gp.mod_keys[k] + ']+'; break; default: hint += '[' + k + ']'; break; } }); return hint; }; /* * Hide Admin UI * Configuration -> Settings * input capture hotkey combination */ $('#admin_ui_hotkey').on('focus', function(){ $(this).select(); }).on('keydown', function(evt){ var key_stroke = $.inArray(evt.key, ['Control', 'Shift', 'Alt', 'AltGraph', 'Meta']) != -1 ? '' : evt.key.toUpperCase(); var key_which = $.inArray(evt.key, ['Control', 'Shift', 'Alt', 'AltGraph', 'Meta']) != -1 ? '' : evt.which; var mod_keys = []; evt.ctrlKey && mod_keys.push('ctrlKey'); evt.shiftKey && mod_keys.push('shiftKey'); evt.altKey && mod_keys.push('altKey'); evt.metaKey && mod_keys.push('metaKey'); // show the modifier keys $gp.InsertModkeys('#admin_ui_hotkey', 'before', mod_keys); var key_code = (evt.ctrlKey ? 'ctrlKey+' : '') + (evt.shiftKey ? 'shiftKey+' : '') + (evt.altKey ? 'altKey+' : '') + (evt.metaKey ? 'metaKey+' : '') + key_which; if( key_stroke == '' || key_stroke == ' ' || key_stroke == 'DEAD' || key_stroke == 'DELETE' || key_stroke == 'BACKSPACE' ){ key_stroke = ''; key_code = ''; } $(this).val(key_stroke); $('#admin_ui_hotkey_code').val(key_code); evt.stopPropagation(); evt.preventDefault(); }).on('keyup', function(evt){ var code_val = $('#admin_ui_hotkey_code').val(); var has_modifier_key = /ctrlKey\+|shiftKey\+|altKey\+|metaKey\+/g.test(code_val); if( code_val == '' || !has_modifier_key ){ $(this).val(''); $('#admin_ui_hotkey_code').val(''); $gp.InsertModkeys('#admin_ui_hotkey', 'before', []); } }); // make the input smaller and show the modifier keys on load if( $('#admin_ui_hotkey').length ){ $('#admin_ui_hotkey').width(96); $gp.InsertModkeys('#admin_ui_hotkey', 'before'); } }); /* end on DOM ready */ /** * Hide Admin UI * */ $gp.HideAdminUI = { init: function(){ $gp.HideAdminUI.hotkey_hint = ''; if( hideAdminUIcfg.hotkey != '' && hideAdminUIcfg.hotkey_code != '' ){ var hotkey_arr = hideAdminUIcfg.hotkey_modkeys; hotkey_arr.push(hideAdminUIcfg.hotkey); $gp.HideAdminUI.hotkey_hint = ' ' + $gp.GetHotkeyHint(hotkey_arr); } $('<div class="show-admin-ui" ' + 'title="' + gplang.ShowAdminUI + $gp.HideAdminUI.hotkey_hint + '"' + '><i class="fa fa-window-restore"></i></div>') .on('click', function(){ $gp.HideAdminUI.toggle(false); }).appendTo('body'); $('.admin-link-hide-ui') .attr('title', $('.admin-link-hide-ui').attr('title') + $gp.HideAdminUI.hotkey_hint); if( hideAdminUIcfg.autohide_below ){ $gp.HideAdminUI.ww = $gp.$win.width(); $gp.$win.on('load', function(evt){ var ww = $gp.$win.width(); if( ww < hideAdminUIcfg.autohide_below ){ $gp.HideAdminUI.toggle(true); $gp.HideAdminUI.ww = ww; } }).on('resize', function(evt){ var ww = $gp.$win.width(); var threshold = hideAdminUIcfg.autohide_below; if( ww < threshold && $gp.HideAdminUI.ww >= threshold ){ $gp.HideAdminUI.toggle(true); $gp.HideAdminUI.ww = ww; }else if( ww >= threshold && $gp.HideAdminUI.ww < threshold ){ $gp.HideAdminUI.toggle(false); $gp.HideAdminUI.ww = ww; } }); } if( hideAdminUIcfg.hotkey_which != '' ){ $gp.$doc.on('keydown.hideAdminUI', function(evt){ var modkeys_pressed = true; $.each(hideAdminUIcfg.hotkey_modkeys, function(i, key){ if( evt[key] === false ){ modkeys_pressed = false; return false; } }); if( modkeys_pressed && evt.which == hideAdminUIcfg.hotkey_which ){ evt.preventDefault(); $gp.HideAdminUI.toggle(); } if( evt.which == 27 ){ /* 27 [Esc] key always exits hidden state */ $gp.HideAdminUI.toggle(false); } }); } }, toggle: function(show_hide){ if( typeof(show_hide) == 'boolean' ){ $("html").toggleClass("override_admin_style", show_hide); }else{ $("html").toggleClass("override_admin_style"); } }, }; (function() { // IIFE for scoping /** * A simple drag function for use with Typesetter admin areas * Works with absolute and fixed positioned elements * Different from other drag script in that the mouse will not trigger any mouseover/mousenter events because the drag box will be under the mouse * * @param {string} selector Selector for the element that triggers the drag (e.g., '.drag-handle') * @param {string} drag_area Selector for the element to be dragged (e.g., '#draggable-div') * @param {string} positioning 'absolute', 'relative', or 'fixed' * @param {function} callback_done Function to call once the drag 'n drop is done. Receives (element, position, event) */ window.SimpleDrag = function(selector, drag_area, positioning, callback_done) { // Making it a global function explicitly if (typeof jQuery === 'undefined') { console.error("SimpleDrag: jQuery is required but not loaded."); return; // Exit if jQuery is missing } if (typeof $gp === 'undefined' || !$gp.$doc || !$gp.$win || typeof $gp.div !== 'function') { console.error("SimpleDrag: $gp object is required and must have $doc, $win and div properties/methods."); return; // Exit if $gp is missing necessary properties } var tolerance = -10; var $drag_area = $(drag_area); var dragNamespace = '.simpleDrag_' + Math.random().toString(36).substring(7); // Unique namespace if ($drag_area.length === 0) { console.warn("SimpleDrag: No element found with selector '" + drag_area + "'. Drag functionality will not be enabled."); return; // Exit if no element to drag } // dragging $gp.$doc.off('mousedown' + dragNamespace, selector).on('mousedown' + dragNamespace, selector, function(e) { if (e.which !== 1) { return; // Only left mouse button } var box, click_offsetx, click_offsety; e.preventDefault(); init(); function init() { try { var pos = $drag_area.offset(); click_offsetx = e.clientX - pos.left + $gp.$win.scrollLeft(); click_offsety = e.clientY - pos.top + $gp.$win.scrollTop(); } catch (err) { console.error("SimpleDrag: Error in init function: ", err); return; } } $gp.$doc.on('mousemove' + dragNamespace, function(e) { try { // initiate the box if (!box) { var pos = $drag_area.offset(); var w = $drag_area.width(); var h = $drag_area.height(); box = $gp.div('admin_drag_box') .css({ 'top': pos.top, 'left': pos.left, 'width': w, 'height': h }); } box.css({ 'left': Math.max(tolerance, e.clientX - click_offsetx), 'top': Math.max(tolerance, e.clientY - click_offsety) }); e.preventDefault(); return false; } catch (err) { console.error("SimpleDrag: Error in mousemove handler: ", err); return false; // Stop propagation } }); $gp.$doc.off('mouseup' + dragNamespace).on('mouseup' + dragNamespace, function(e) { try { var newposleft, newpostop, pos_obj; $gp.$doc.off('mousemove' + dragNamespace + ' mouseup' + dragNamespace); // Remove both handlers if (!box) { return false; } e.preventDefault(); //clean box.remove(); box = false; //new newposleft = e.clientX - click_offsetx; newpostop = e.clientY - click_offsety; //add scroll back in for absolute position if (positioning === 'absolute') { newposleft += $gp.$win.scrollLeft(); newpostop += $gp.$win.scrollTop(); } newposleft = Math.max(tolerance, newposleft); newpostop = Math.max(tolerance, newpostop); pos_obj = { 'left': newposleft, 'top': newpostop }; $drag_area.css(pos_obj).data({ 'gp_left': newposleft, 'gp_top': newpostop }); if (typeof(callback_done) === 'function') { callback_done.call($drag_area, $drag_area, pos_obj, e); //Pass element as first param } $drag_area.trigger('dragstop'); return false; } catch (err) { console.error("SimpleDrag: Error in mouseup handler: ", err); return false; // Stop propagation } }); return false; }); if ($drag_area.css('position') === 'fixed' || $drag_area.parent().css('position') === 'fixed') { KeepViewable($drag_area.addClass('keep_viewable'), true); } function KeepViewable($elem, init) { try { if (!$elem.hasClass('keep_viewable')) { return; } var gp_left, css = {}, pos = $elem.position(); //move back to the right if $elem has been moved left if (init) { $elem.data({ 'gp_left': pos.left, 'gp_top': pos.top }); } else if (gp_left = $elem.data('gp_left')) { pos.left = css.left = gp_left; pos.top = css.top = $elem.data('gp_top'); } var width = $elem.width(); //keep the top of the area from being placed too high in the window var winbottom = $gp.$win.height(); if (pos.top < tolerance) { css.top = tolerance; //keep the top of the area from being placed too low } else if (pos.top > winbottom) { css.top = winbottom + 2 * tolerance; //tolerance is negative } //right var checkright = $gp.$win.width() - width - tolerance; if (pos.left > checkright) { css.left = checkright; } if (css.left || css.top) { $elem.css(css); } } catch (err) { console.error("SimpleDrag: Error in KeepViewable: ", err); } } $gp.$win.on('resize' + dragNamespace, function() { $('.keep_viewable').each(function() { KeepViewable($(this), false); }); }); }; // End SimpleDrag function })(); // End IIFE /** * Initialize functionality for the rename/details dialog * */ $gp.response.renameprep = function(){ var $form = $('#gp_rename_form'); var old_title = $('#old_title').val().toLowerCase(); var $new_title = $form.find('input.new_title').on('keyup change',ShowRedirect); var space_char = $('#gp_space_char').val(); $('input:disabled').each(function(a,b){ $(b).fadeTo(400,0.6); }); $('input.title_label').on('keyup change', SyncSlug).trigger('change'); $gp.links.showmore = function(){ $('#gp_rename_table tr').css('display','table-row'); $(this).parent().remove(); }; /** * Toggle synchronization/customization of a field * */ $gp.links.ToggleSync = function(evt){ var td = $(this).closest('td'); var vis = td.find('a:visible'); td.find('a').show(); vis.hide(); vis = td.find('a:visible'); if( vis.length ){ if( vis.hasClass('slug_edit') ){ td.find('input').addClass('sync_label').prop('readonly',true).fadeTo(400,0.6); SyncSlug(); }else{ td.find('input').removeClass('sync_label').prop('readonly',false).fadeTo(400,1); } } } /** * Show the redirct option if the new slug doesn't match the old slug * */ function ShowRedirect(){ var new_val = $new_title.val().replace(/ /g,space_char).toLowerCase(); if( new_val !== old_title ){ $('#gp_rename_redirect').show(500); }else{ $('#gp_rename_redirect').hide(300); } } /** * Update the value of the slug/url field with the title * */ function SyncSlug(){ var label = $('input.title_label').val(); $new_title.filter('.sync_label').val( LabelToSlug(label) ); $('input.browser_title.sync_label').val(label); ShowRedirect(); return true; } /** * Convert a label to a slug * */ function LabelToSlug(str){ // Remove control characters str = str.replace(/[\x00-\x1F\x7F]/g,''); //illegal characters //str = str.replace(/("|'|\?|\*|:|#)/g,''); str = str.replace(/(\?|\*|:|#)/g,''); //after removing tags, unescape special characters str = strip_tags(str); str = SlugSlashes(str); //all spaces should be underscores return str.replace(/ /g,space_char); } /** * Remove html tags from a string * */ function strip_tags(str){ return str.replace(/(<(\/?[a-zA-Z0-9][^<>]*)>)/ig,""); } /** * Take care of slashes and periods * */ function SlugSlashes(str){ //replace \ str = str.replace(/[\\]/g,'/'); //remove trailing "/." str = str.replace(/^\.+[\/\/]/,'/'); //remove trailing "/." str = str.replace(/[\/\/]\.+$/,'/'); //remove any "/./" str = str.replace(/[\/\/]\.+[\/\/]/g,'/'); //remove consecutive slashes str = str.replace(/[\/\/]+/g,'/'); if( str === '.' ){ return ''; } //left trim / str = str.replace(/^\/\/*/g,''); return str; } };