');
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('
')
.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
* @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 += '' + $gp.mod_keys[k] + ' + ';
});
return '' + html + '';
};
/**
* 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);
}
$('
')
.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");
}
},
};
/**
* 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
* @param string drag_area
* @param string positioning (absolute,relative,fixed)
* @param function callback_done function to call once the drag 'n drop is done
*/
function SimpleDrag(selector, drag_area, positioning, callback_done){
var tolerance = -10;
var $drag_area = $(drag_area);
//dragging
$gp.$doc.off('mousedown.sdrag',selector).on('mousedown.sdrag',selector,function(e){
if( e.which != 1 ){
return;
}
var box, click_offsetx, click_offsety;
e.preventDefault();
if( $drag_area.length < 1 ){
return;
}
init();
function init(){
var pos = $drag_area.offset();
click_offsetx = e.clientX - pos.left + $gp.$win.scrollLeft();
click_offsety = e.clientY - pos.top + $gp.$win.scrollTop();
}
$gp.$doc.on('mousemove.sdrag',function(e){
//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;
});
$gp.$doc.off('mouseup.sdrag').on('mouseup.sdrag',function(e){
var newposleft,newpostop,pos_obj;
$gp.$doc.off('mousemove.sdrag mouseup.sdrag');
if( !box ){
return false;
}
e.preventDefault();
//clean
box.remove();
box = false;
//new
newposleft = e.clientX - click_offsetx;
newpostop = e.clientY - click_offsety;
//newposleft = Math.max(0,e.clientX - click_offsetx);
//newpostop = Math.max(0,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,pos_obj,e);
}
$drag_area.trigger('dragstop');
return false;
});
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){
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);
}
}
$gp.$win.on('resize', function(){
$('.keep_viewable').each(function(){
KeepViewable($(this),false);
});
});
}
/**
* 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;
}
};