artabro/wire/templates-admin/scripts/main.js

545 lines
15 KiB
JavaScript
Raw Permalink Normal View History

2024-08-27 11:35:37 +02:00
/**
* ProcessWire Admin common javascript
*
* Copyright 2016 by Ryan Cramer
*
*/
var ProcessWireAdmin = {
/**
* Initialize all
*
*/
init: function() {
this.setupButtonStates();
this.setupTooltips();
this.setupDropdowns();
this.setupNotices();
},
setupNotices: function() {
$(".pw-notice-group-toggle").on('click', function() {
var $parent = $(this).closest('.pw-notice-group-parent');
var $children = $parent.nextUntil('.pw-notice-group-parent');
if($parent.hasClass('pw-notice-group-open')) {
$parent.removeClass('pw-notice-group-open');
$children.slideUp('fast');
} else {
$parent.addClass('pw-notice-group-open');
$children.slideDown('fast');
}
$parent.find('i[data-toggle]').each(function() {
$(this).toggleClass($(this).attr('data-toggle'));
});
return false;
});
},
/**
* Enable jQuery UI tooltips
*
*/
setupTooltips: function() {
$("a.tooltip, .pw-tooltip").tooltip({
position: {
my: "center bottom", // bottom-20
at: "center top"
}
}).on('mouseenter', function() {
var $a = $(this);
if($a.is('a')) {
$a.addClass('ui-state-hover');
} else {
$a.data('pw-tooltip-cursor', $a.css('cursor'));
$a.css('cursor', 'pointer');
}
$a.addClass('pw-tooltip-hover');
$a.css('cursor', 'pointer');
}).on('mouseleave', function() {
var $a = $(this);
$a.removeClass('pw-tooltip-hover ui-state-hover');
if(!$a.is('a')) {
$a.css('cursor', $a.data('pw-tooltip-cursor'));
}
});
},
/**
* Make buttons utilize the jQuery button state classes
*
*/
setupButtonStates: function() {
// jQuery UI button states
$(document).on('mouseover', '.ui-button', function() {
var $t = $(this);
$t.removeClass("ui-state-default").addClass("ui-state-hover");
if($t.hasClass('ui-priority-secondary')) $t.toggleClass('xui-priority-secondary ui-priority-secondary');
if($t.hasClass('pw-button-dropdown-main')) {
$t.siblings('#pw-dropdown-toggle-' + $t.attr('id')).trigger('mouseover');
}
}).on('mouseout', '.ui-button', function() {
var $t = $(this);
$t.removeClass("ui-state-hover").addClass("ui-state-default");
if($t.hasClass('xui-priority-secondary')) $t.toggleClass('xui-priority-secondary ui-priority-secondary');
if($t.hasClass('pw-button-dropdown-main')) {
$t.siblings('#pw-dropdown-toggle-' + $t.attr('id')).trigger('mouseout');
}
}).on('click', '.ui-button', function() {
$(this).removeClass("ui-state-default").addClass("ui-state-active"); // .effect('highlight', {}, 100);
});
/*
.on('click', 'a > button', function() {
var $a = $(this).parent();
var target = $a.attr('target');
if(typeof target != "undefined" && target == '_blank') {
// skip
} else {
// make buttons with <a> tags click to the href of the <a>
window.location = $a.attr('href');
}
});
*/
},
/**
* Setup dropdown menus
*
*/
setupDropdowns: function() {
// whether or not dropdown positions are currently being monitored
var dropdownPositionsMonitored = false;
var hoveredDropdownAjaxItem;
function setupDropdown() {
var $a = $(this);
var $ul;
if($a.attr('data-pw-dropdown')) {
// see if it is specifying a certain <ul>
// first check if the selector matches a sibling
$ul = $a.siblings($a.attr('data-pw-dropdown'));
// if no match for sibling, check entire document
if(!$ul.length) $ul = $($a.attr('data-pw-dropdown'));
} else {
// otherwise use the <ul> that is the sibling
$ul = $a.siblings('.pw-dropdown-menu');
}
$ul.hide();
$a.data('pw-dropdown-ul', $ul);
if($a.is('button')) {
if($a.find('.ui-button-text').length == 0) $a.button();
if($a.attr('type') == 'submit') {
$a.on('click', function() {
$a.addClass('pw-dropdown-disabled');
setTimeout(function() {
$a.removeClass('pw-dropdown-disabled');
}, 2000);
});
}
} else {
// $ul.css({ 'border-top-right-radius': 0 });
}
// hide nav when an item is selected to avoid the whole nav getting selected
$ul.find('a').on('click', function() {
$ul.hide();
return true;
});
// prepend icon to dropdown items that themselves have more items
$ul.find(".pw-has-items").each(function() {
var $icon = $("<i class='pw-has-items-icon fa fa-angle-right ui-priority-secondary'></i>");
$(this).prepend($icon);
});
// when the mouse leaves the dropdown menu, hide it
if($a.hasClass('pw-dropdown-toggle-click')) {
var timer = null;
function mouseleaver() {
if(timer) clearTimeout(timer);
timer = setTimeout(function() {
if(($ul.length && $ul[0].matches(':hover')) || ($a.length && $a[0].matches(':hover'))) {
return;
}
$ul.fadeOut('fast');
$a.removeClass('hover pw-dropdown-toggle-open');
}, 1000);
}
$ul.on('mouseleave', mouseleaver);
$a.on('mouseleave', mouseleaver);
} else {
$ul.on('mouseleave', function() {
//if($a.is(":hover")) return;
//if($a.filter(":hover").length) return;
$ul.hide();
$a.removeClass('hover');
});
}
}
function mouseenterDropdownToggle(e) {
var $a = $(this);
var $ul = $a.data('pw-dropdown-ul');
var delay = $a.hasClass('pw-dropdown-toggle-delay') ? 700 : 0;
var lastOffset = $ul.data('pw-dropdown-last-offset');
var timeout = $a.data('pw-dropdown-timeout');
if($a.hasClass('pw-dropdown-toggle-click')) {
if(e.type != 'mousedown') return false;
$a.removeClass('ui-state-focus');
if($a.hasClass('pw-dropdown-toggle-open')) {
$a.removeClass('pw-dropdown-toggle-open hover');
$ul.hide();
return;
} else {
$('.pw-dropdown-toggle-open').each(function() {
var $a = $(this);
var $ul = $a.data('pw-dropdown-ul');
$ul.trigger('mouseleave');
});
$a.addClass('pw-dropdown-toggle-open');
/*
$('body').one('click', function() {
$a.removeClass('pw-dropdown-toggle-open hover');
$ul.hide();
});
*/
}
}
if($a.hasClass('pw-dropdown-disabled')) return;
timeout = setTimeout(function() {
if($a.hasClass('pw-dropdown-disabled')) return;
var offset = $a.offset();
if(lastOffset != null) {
if(offset.top != lastOffset.top || offset.left != lastOffset.left) {
// dropdown-toggle has moved, destroy and re-create
$ul.menu('destroy').removeClass('pw-dropdown-ready');
}
}
if(!$ul.hasClass('pw-dropdown-ready')) {
$ul.css('position', 'absolute');
$ul.prependTo($('body')).addClass('pw-dropdown-ready').menu();
var position = {my: 'right top', at: 'right bottom', of: $a};
var my = $ul.attr('data-my');
var at = $ul.attr('data-at');
if(my) position.my = my;
if(at) position.at = at;
$ul.position(position).css('z-index', 200);
}
$a.addClass('hover');
$ul.show();
$ul.data('pw-dropdown-last-offset', offset);
}, delay);
$a.data('pw-dropdown-timeout', timeout);
}
function mouseleaveDropdownToggle() {
var $a = $(this);
var $ul = $a.data('pw-dropdown-ul');
var timeout = $a.data('pw-dropdown-timeout');
if(timeout) clearTimeout(timeout);
setTimeout(function() {
if($ul.filter(":hover").length) return;
$ul.find('ul').hide();
$ul.hide();
$a.removeClass('hover');
}, 50);
if($("body").hasClass('touch-device')) {
$(this).attr('data-touchCnt', 0);
}
}
function hoverDropdownAjaxItem($a) {
var fromAttr = $a.attr('data-from');
if(!fromAttr) return;
var $from = $('#' + $a.attr('data-from'));
if($from.length > 0) setTimeout(function() {
var fromLeft = $from.offset().left;
//if($a.attr('id') == 'topnav-page-22') fromLeft--;
var $ul = $a.closest('li').parent('ul');
var thisLeft = $ul.offset().left;
if(thisLeft != fromLeft) $ul.css('left', fromLeft);
}, 500);
}
function mouseenterDropdownAjaxItem() {
var $a = $(this);
hoveredDropdownAjaxItem = $a;
setTimeout(function() {
// check if user wasn't hovered long enough for this to be their intent
if(!hoveredDropdownAjaxItem) return;
if(hoveredDropdownAjaxItem != $a) return;
$a.addClass('pw-ajax-items-loaded');
// var url = $a.attr('href');
var url = $a.attr('data-json');
var $ul = $a.siblings('ul');
var setupDropdownHover = false;
var $itemsIcon = $a.children('.pw-has-items-icon');
$itemsIcon.removeClass('fa-angle-right').addClass('fa-spinner fa-spin');
$ul.css('opacity', 0);
$.getJSON(url, function(data) {
$itemsIcon.removeClass('fa-spinner fa-spin').addClass('fa-angle-right');
if(!data.list) {
console.log(data);
return;
}
// now add new event to monitor menu positions
if(!dropdownPositionsMonitored && data.list.length > 10) {
dropdownPositionsMonitored = true;
setupDropdownHover = true;
$(document).on('mouseenter', 'ul.pw-dropdown-menu a', function() {
hoverDropdownAjaxItem($(this));
});
}
if(data.add) {
var $li = $(
"<li class='ui-menu-item add'>" +
"<a href='" + data.url + data.add.url + "'>" +
"<i class='fa fa-fw fa-" + data.add.icon + "'></i>" +
data.add.label + "</a>" +
"</li>"
);
$ul.append($li);
}
var numSubnavJSON = 0;
// populate the retrieved items
$.each(data.list, function(n) {
var icon = '';
var url = '';
if(this.icon) {
icon = "<i class='ui-priority-secondary fa fa-fw fa-" + this.icon + "'></i>";
}
if(this.url == 'navJSON') {
// click triggers another navJSON load
} else if(this.url.indexOf('/') === 0) {
url = this.url;
} else if(this.url.length) {
url = data.url + this.url;
}
var $li = $("<li class='ui-menu-item'></li>");
var $a = $("<a>" + icon + this.label + "</a>");
var $ulSub = null;
if(url.length) $a.attr('href', url);
if(this.navJSON) {
$a.attr('data-json', this.navJSON).addClass('pw-has-items pw-has-ajax-items');
$ulSub = $("<ul></ul>").addClass('subnavJSON');
var $icon = $("<i class='pw-has-items-icon fa fa-angle-right ui-priority-secondary'></i>");
$a.prepend($icon);
$li.prepend($a).append($ulSub);
numSubnavJSON++;
} else {
$li.prepend($a);
}
if(typeof this.className != "undefined" && this.className && this.className.length) {
$li.addClass(this.className);
}
$ul.append($li);
});
$ul.addClass('navJSON').addClass('length' + parseInt(data.list.length)).hide();
if($ul.children().length) $ul.css('opacity', 1.0);
if(hoveredDropdownAjaxItem == $a) $ul.fadeIn('fast');
if(numSubnavJSON) {
var numParents = $ul.parents('ul').length;
$ul.find('ul.subnavJSON').css('z-index', 200 + numParents);
$ul.menu({});
}
// trigger the first call
hoverDropdownAjaxItem($a);
}); // getJSON
}, 250); // setTimeout
}
var $lastTouchClickItem = null;
function touchClick(e) {
var $item = $(this);
var touchCnt = $item.attr('data-touchCnt');
if($lastTouchClickItem && $item.attr('id') != $lastTouchClickItem.attr('id')) {
$lastTouchClickItem.attr('data-touchCnt', 0);
}
$lastTouchClickItem = $item;
if(!touchCnt) touchCnt = 0;
touchCnt++;
$item.attr('data-touchCnt', touchCnt);
if(touchCnt == 2 || ($item.hasClass('pw-has-ajax-items') && !$item.closest('ul').hasClass('topnav'))) {
var href = $item.attr('href');
$item.attr('data-touchCnt', 0);
if(typeof href != "undefined" && href.length > 1) {
return true;
} else {
$item.trigger('mouseleave');
}
} else {
var datafrom = $item.attr('data-from');
if(typeof datafrom == "undefined") var datafrom = '';
if(datafrom.indexOf('topnav') > -1) {
var from = datafrom.replace('topnav-', '') + '-';
$("a.pw-dropdown-toggle.hover:not('." + from + "')").attr('data-touchCnt', 0).trigger('mouseleave');
}
$item.mouseenter();
}
return false;
}
function init() {
if($("body").hasClass('touch-device')) {
$(document).on("touchstart", "a.pw-dropdown-toggle, a.pw-has-items", touchClick);
}
$(".pw-dropdown-menu").on("click", "a:not(.pw-modal)", function(e) {
e.stopPropagation();
});
$(".pw-dropdown-toggle").each(setupDropdown);
$(document)
.on('mousedown', '.pw-dropdown-toggle-click', mouseenterDropdownToggle)
.on('mouseenter', '.pw-dropdown-toggle:not(.pw-dropdown-toggle-click)', mouseenterDropdownToggle)
.on('mouseleave', '.pw-dropdown-toggle:not(.pw-dropdown-toggle-click)', mouseleaveDropdownToggle)
.on('mouseenter', '.pw-dropdown-menu a.pw-has-ajax-items:not(.pw-ajax-items-loaded)', mouseenterDropdownAjaxItem) // navJSON
.on('mouseleave', '.pw-dropdown-menu a.pw-has-ajax-items', function() { // navJSON
hoveredDropdownAjaxItem = null;
});
}
init();
} // setupDropdowns
};
if(typeof ProcessWire != "undefined") {
/**
* Confirmation dialog
*
* ~~~~~
* ProcessWire.confirm('Send this message now?', function() {
* // user clicked Ok
* }, function() {
* // user clicked Cancel
* });
* ~~~~~
*
* @param message Message to display (or question to ask)
* @param funcOk Callback called on "Ok"
* @param funcCancel Callback called on "Cancel" (optional)
*
*/
ProcessWire.confirm = function(message, funcOk, funcCancel) {
if(typeof vex != "undefined" && typeof funcOk != "undefined") {
vex.dialog.confirm({
message: message,
callback: function(v) {
if(v) {
funcOk();
} else if(typeof funcCancel != "undefined") {
funcCancel();
}
}
});
} else if(typeof funcOk != "undefined") {
if(confirm(message)) {
funcOk();
} else if(typeof funcCancel != "undefined") {
funcCancel();
}
} else {
// regular JS confirm behavior
return confirm(message);
}
};
ProcessWire.alert = function(message, allowMarkup) {
if(typeof allowMarkup == "undefined") var allowMarkup = false;
if(typeof vex != "undefined") {
if(allowMarkup) {
vex.dialog.alert({unsafeMessage: message});
} else {
if(message.indexOf('&') > -1 && message.indexOf(';') > 1) {
// remove entitity encoded sequences since Vex already encodes
var v = document.createElement('textarea');
v.innerHTML = message;
message = v.value;
}
vex.dialog.alert(message);
}
} else {
alert(message);
}
};
ProcessWire.prompt = function(message, placeholder, func) {
if(typeof vex == "undefined") {
alert("prompt function requires vex");
return;
}
return vex.dialog.prompt({
message: message,
placeholder: placeholder,
callback: func
})
};
ProcessWire.entities = function(str) {
return $('<textarea />').text(str).html();
};
/**
* Trim any type of given value and return a trimmed string
*
* @param str
* @returns {string}
* @since 3.0.216
*
*/
ProcessWire.trim = function(str) {
if(typeof str !== 'string') {
if(typeof str === 'undefined' || str === null || str === '') return '';
str = str.toString();
}
return str.trim();
};
}