' + '
' + '';
footer = '
';
$footer = $(footer);
$overlay = this.$overlay = $(html).overlay({
autoOpen: false,
destroyOnClose: false,
size: this.options.size,
closeSelector: '.lw_cancel a',
title: this.options.title,
footer: $footer,
customClass: 'lw_crop_overlay',
zIndex: 1305,
close: $.proxy(this._close, this)
}); // show/hide aspect ratio controls
if (this.options.hide_aspect_ratio_menu) {
this.$overlay.find('#lw_image_crop_ar').hide();
} else {
this.$overlay.find('#lw_image_crop_ar').show();
}
this.$preview = $overlay.find('#lw_image_crop_preview_image');
this.$ar_checkboxes = $overlay.find('#lw_image_crop_ar input[type=checkbox]'); // save!
$footer.on('click', '.btn-primary', function (e) {
e.preventDefault();
that.saveCrop();
return true;
}); // aspect ratio checkbox click handler
$overlay.on('click', '#lw_image_crop_ar input[type=checkbox]', function () {
var $this = $(this);
var $label = $this.closest('label');
if ($this.prop('checked')) {
// remove any other selected item
$label.siblings().removeClass('selected').find('input[type=checkbox]').prop('checked', false);
$label.addClass('selected'); // set jcrop aspect ratio option
that.setAspectRatio($this.val());
} else {
$label.removeClass('selected');
that.setAspectRatio('');
}
return true;
}); // a11y: map enter key to click
$overlay.on('keydown', '#lw_image_crop_ar label', function (e) {
switch (e.which) {
case 13:
// Enter
$(this).find('input').click();
break;
case 37:
// Left Arrow
$(this).prev().focus();
break;
case 39:
// Right Arrow
$(this).next().focus();
break;
}
}); // set custom aspect ratio when cropper ready
if (this.options.custom_aspect_ratio) {
this.bind('ready', function () {
if (_this2.jcrop_api) {
_this2.setAspectRatio(_this2.options.custom_aspect_ratio);
}
});
}
} // valid values are 'orig' or '\d:\d'
}, {
key: "setAspectRatio",
value: function setAspectRatio(string_ar) {
var ar = 0;
this.aspect_ratio = string_ar;
if (string_ar === 'orig') {
ar = this.width / this.height;
} else if (string_ar.match(/^\d+:\d+$/)) {
ar = parseInt(string_ar.split(':')[0], 10) / parseInt(string_ar.split(':')[1], 10);
}
this.jcrop_api.setOptions({
aspectRatio: ar
});
}
}, {
key: "setCropSelect",
value: function setCropSelect(coords) {
this.jcrop_api.setSelect(coords);
} // set the crop region (called during jcrop onSelect and onChange)
}, {
key: "setCropCoords",
value: function setCropCoords(c) {
this.coords = c;
this.trigger('set', [{
coords: c
}]);
}
}, {
key: "setPreviewImage",
value: function setPreviewImage(url) {
var preview_url, preview_width, preview_height;
if (this.height >= this.width) {
preview_height = this.options.size === 'large' ? 578 : 500;
preview_width = Math.round(preview_height * (this.width / this.height));
} else {
preview_width = this.options.size === 'large' ? 868 : 500;
preview_height = Math.round(preview_width * (this.height / this.width));
}
preview_url = url.replace(/\/(?=[^/]*$)/, "/width/" + preview_width + "/height/" + preview_height + "/");
this.$preview.attr('src', preview_url).width(preview_width).height(preview_height);
}
}, {
key: "initCropper",
value: function initCropper(coords) {
var that = this,
preview_width = this.$preview.width(),
preview_height = this.$preview.height(),
width_ratio = preview_width / this.width,
height_ratio = preview_height / this.height,
crop_coords;
if (!_.isArray(coords) || coords.length !== 4) {
if (preview_width > preview_height) {
crop_coords = [(preview_width - preview_height) / 2, 0, (preview_width - preview_height) / 2 + preview_height, preview_height];
} else {
crop_coords = [0, (preview_height - preview_width) / 2, preview_width, (preview_height - preview_width) / 2 + preview_width];
}
} else {
crop_coords = [Math.round(coords[0] * width_ratio), Math.round(coords[1] * height_ratio), Math.round(coords[2] * width_ratio), Math.round(coords[3] * height_ratio)];
} // initialize jcrop
this.$preview.Jcrop({
aspectRatio: 0,
keySupport: true,
trueSize: [this.width, this.height],
setSelect: crop_coords,
onSelect: $.proxy(this.setCropCoords, this),
onChange: $.proxy(this.setCropCoords, this),
onRelease: function onRelease(c) {}
}, function () {
var api = that.jcrop_api = this;
if (that.aspect_ratio) {
that.$ar_checkboxes.each(function () {
if ($(this).val() === that.aspect_ratio) {
$(this).trigger('click');
}
});
} // a11y: make handles keyboard focusable and add SR labels
var shifted = null; // save shift key status
var $handles = $('.jcrop-handle');
var $handle_container = $('.jcrop-handle').parent();
var handle_order = ['nw-resize', 'n-resize', 'ne-resize', 'w-resize', 'e-resize', 'sw-resize', 's-resize', 'se-resize'];
var handle_label = ['top left corner', 'top side', 'top right corner', 'left side', 'right side', 'bottom left corner', 'bottom side', 'bottom right corner'];
function moveCropHandle(which, direction) {
var current = api.tellSelect(); // get current coordinates
var amount_to_move = shifted ? 25 : 2; // in pixels (modified with shift key), min 2 for retina.
var move_x = null,
move_y = null; // set up which x/y variables we'll be moving
if (which.charAt(0) == 'n') {
move_y = 'y';
} else if (which.charAt(0) == 's') {
move_y = 'y2';
}
if (which.includes('w-')) {
move_x = 'x';
} else if (which.includes('e-')) {
move_x = 'x2';
} // Apply the changes
switch (direction) {
case 'left':
if (move_x) {
current[move_x] = current[move_x] - amount_to_move;
}
break;
case 'right':
if (move_x) {
current[move_x] = current[move_x] + amount_to_move;
}
break;
case 'up':
if (move_y) {
current[move_y] = current[move_y] - amount_to_move;
}
break;
case 'down':
if (move_y) {
current[move_y] = current[move_y] + amount_to_move;
}
break;
}
if (shifted) {
api.animateTo([current['x'], current['y'], current['x2'], current['y2']]); // animate to the new coords
} else {
api.setSelect([current['x'], current['y'], current['x2'], current['y2']]); // move to the new coords
}
}
$handles.attr('tabindex', '0').each(function () {
var which_handle = $(this).css('cursor'); // detect cursor type
$(this).attr('aria-label', 'Move ' + handle_label[handle_order.indexOf(which_handle)] + ' of crop area').attr('data-handle-type', which_handle).attr('data-handle-order', handle_order.indexOf(which_handle)).addClass(which_handle).on('keydown', function (e) {
switch (e.which) {
case 37:
// Left Arrow
e.preventDefault();
moveCropHandle(which_handle, 'left');
break;
case 39:
// Right Arrow
e.preventDefault();
moveCropHandle(which_handle, 'right');
break;
case 38:
// Up Arrow
e.preventDefault();
moveCropHandle(which_handle, 'up');
break;
case 40:
// Down Arrow
e.preventDefault();
moveCropHandle(which_handle, 'down');
break;
}
}).on('keyup keydown', function (e) {
shifted = e.shiftKey;
}); // track shift key
}); // Re-order handles into logical tab order
$handle_container.find('.jcrop-handle').sort(function (a, b) {
return +a.getAttribute('data-handle-order') - +b.getAttribute('data-handle-order');
}).appendTo($handle_container);
that.trigger('ready');
});
}
}, {
key: "open",
value: function open(url, width, height, coords) {
var that = this;
this.width = width;
this.height = height; // open the overlay and set the preview src
this.$overlay.overlay('open'); // initialize jcrop when image preview finishes loading
this.setPreviewImage(url);
this.$preview.parent().imagesLoaded(function () {
that.initCropper(coords);
});
}
}, {
key: "saveCrop",
value: function saveCrop() {
var c = this.coords,
coords;
if (_.isPlainObject(c) && _.keys(c).length === 6) {
coords = [c.x, c.y, c.x2, c.y2];
}
this.trigger('save', [{
coords: coords,
aspect_ratio: this.aspect_ratio
}]);
this.$overlay.overlay('close');
}
}, {
key: "_close",
value: function _close() {
this.coords = null;
this.$ar_checkboxes.prop('checked', false);
if (this.jcrop_api) {
this.jcrop_api.destroy();
this.jcrop_api = null;
}
this.$preview.removeAttr('src');
}
}]);
return CropDialog;
}(PubSub);
LW.lib.CropDialog = CropDialog;
/**
* Generic cropper
* @constructor
* @param {integer} preview_width - width of the preview (only required if preview_height not set)
* @param {integer} preview_height - height of the preview (only required if preview_width not set)
* @param {string} src [null] - image src
* @param {string} width [null] - image width
* @param {string} height [null] - image height
*/
function Cropper(preview_width) {
var preview_height = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
var src = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
var width = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
var height = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
this.preview_width = preview_width;
this.preview_height = preview_height;
this.src = src;
this.width = width;
this.height = height;
this.coords = null;
}
_.extend(Cropper.prototype, LW.lib.pubSub(), {
open: function open() {
var _this3 = this;
// initialize on first open
if (!this.crop_dialog) {
this.crop_dialog = new LW.lib.CropDialog({
hide_aspect_ratio_menu: false,
title: 'Crop image'
});
this.crop_dialog.bind('save', function (e, data) {
_this3.setCrop(data.coords);
});
}
this.crop_dialog.open(this.src, this.width, this.height, this.coords);
},
setImage: function setImage(src, width, height) {
this.src = src;
this.width = width;
this.height = height;
this.resetCoords();
},
resetCoords: function resetCoords() {
this.coords = null;
},
getPreviewHeight: function getPreviewHeight(coords) {
var crop_width = coords[2] - coords[0];
var crop_height = coords[3] - coords[1];
return this.preview_width * (crop_height / crop_width);
},
getPreviewWidth: function getPreviewWidth(coords) {
var crop_width = coords[2] - coords[0];
var crop_height = coords[3] - coords[1];
return this.preview_height * (crop_width / crop_height);
},
setCrop: function setCrop(coords) {
// do nothing if we have the wrong data
if (!_.isArray(coords) || coords.length !== 4) {
return;
}
this.coords = coords;
var preview_width, preview_height;
if (this.preview_width && !this.preview_height) {
preview_width = this.preview_width;
preview_height = this.getPreviewHeight(coords);
}
if (this.preview_height && !this.preview_width) {
preview_height = this.preview_height;
preview_width = this.getPreviewWidth(coords);
} // trigger crop event
this.trigger('crop', [{
src: this.src,
preview_width: preview_width,
preview_height: preview_height,
width: this.width,
height: this.height,
coords: coords
}]);
}
});
LW.lib.Cropper = Cropper;
var toolbar = {
init: function init() {
var $toolbar = this.$toolbar = $('#lw-toolbar'); // do nothing if toolbar doesn't exist on pages
if (!$toolbar.length) {
return;
}
this.initGroupSwitcher();
this.addDropdownHandlers();
this.adjustToolboxColumns();
this.initSearch();
this.initMobile(); // remove hidden front/back-end elements for screen readers
if ($toolbar.hasClass('lw-toolbar-backend')) {
$toolbar.find('.lw-frontend-only').remove();
} else {
$toolbar.find('.lw-backend-only').remove();
} // set focus on first form or search field when clicking Toolbox / Your Content / Search Content
LW.eventHub.bind('toolbarOpen', function (e, $nav_item) {
if ($nav_item.find('.lw-dropdown-menu .lw-group-switcher, .lw-dropdown-menu a, .lw-dropdown-menu input, .lw-dropdown-menu textarea').first().is('input,textarea')) {
// if first field is input or textarea
$nav_item.find('.lw-dropdown-menu input, .lw-dropdown-menu textarea').first().trigger('focus'); // focus it
}
return true;
});
$toolbar.show();
},
initGroupSwitcher: function initGroupSwitcher() {
if (LW.group_fullname && LW.group_title_native !== LW.group_fullname) {
// if page group is different from your group
$('.current-page-group').addClass('visible').html('Current Page Owner:
' + LW.group_fullname + ' ').show();
} else {
$('.current-page-group').hide();
}
var $filter = $('#lw-group-filter').attr('role', 'application');
$('.lw-group-switcher .no-results').hide();
$('.lw-group-switcher li').attr('data-show-filtered', 'true'); // start filters as all showing
// add aria-live region
$('
').appendTo($('.lw-group-switcher')); // if top groups are set, move to top
if (!_.isEmpty(LW.top_groups)) {
$('
').insertBefore('.lw-group-switcher div ul');
_.each(LW.top_groups, function (group_id) {
$('.lw-group-switcher div.all-groups').find('a[href$="group=' + group_id + '"]').parent().appendTo($('.lw-group-switcher div.all-groups ul.top-groups'));
$('.lw-group-switcher div.recent-groups').find('a[href$="group=' + group_id + '"]').parent().appendTo($('.lw-group-switcher div.recent-groups ul.top-groups'));
});
}
function setActiveGroup($li) {
var $dropdown = $('.lw-group-switcher div.lw-dropdown-menu-inner'),
dropdown_height = $dropdown.outerHeight(),
current_scroll = $dropdown.scrollTop(),
li_position = $li.position().top,
li_offset = $li.offset().top;
$li.addClass('active');
if (li_position + current_scroll < 160 && current_scroll > 0) {
// if focused item is near top, scroll to top
$dropdown.scrollTop(0);
} else if (li_offset < 40 || li_offset > dropdown_height + 30) {
// if focused item isn't in view, scroll to it
$li[0].scrollIntoView();
}
$('.lw-group-switcher div.system-groups a').prepend('' + XMLHttpRequest.responseText.replace(/...';
break;
// HTTP error; report the status error if not 0
case 'error':
if (XMLHttpRequest.status !== 0) {
details = 'The server returned the status error ' + '' + XMLHttpRequest.status + ' .';
}
break;
default:
// if the error is an unknown type
details = 'There’s been an unknown error loading the content requested.';
break;
} // remove any currently active spinners
$('.lw_spinner').remove(); // if there was error text
if (details) {
details = 'AJAX error: ' + details;
var url = '/livewhale/backend.php?' + $.param({
livewhale: 'log_error',
error: details,
url: this.url
});
$.ajax({
url: url,
error: false,
timeout: 60000
}); // log error
// notify the user of the error
var msg = 'Whoops, there was an error communicating with the server! Please check your internet ' + 'connection and try again.';
$('body').notify({
id: 'ajax',
message: msg,
details: '' + this.url + ' : ' + details,
type: 'failure'
});
}
return false;
};
/*
/* LiveWhale settings, uploads, constants
*/
LW.initAccessibility = function () {
$('.lw_accessibility_summary_full_report').on('click', '#lw_accessibility_more', function (e) {
e.preventDefault();
var $spinner = $('
');
var $overlay = $('
').append($spinner).appendTo('body');
var page_url = $(this).attr('href');
$overlay.overlay({
size: 'medium',
closeSelector: '.lw_cancel a',
title: 'Accessibility Report',
open: function open() {
$.ajax({
url: LW.lib.getAjaxUrl('getPagesAccessibilityReport', null, page_url),
dataType: 'json',
success: function success(data) {
$spinner.remove();
$overlay.append(data.html);
$overlay.on('click', '#lw_accessibility_refresh', function (e) {
$overlay.append($spinner);
$.ajax({
url: LW.lib.getAjaxUrl('refreshPagesAccessibilityReport', null, page_url),
dataType: 'html',
success: function success(data) {
$('#lw_accessibility_more').trigger('click');
$overlay.remove();
}
});
return false;
});
}
});
},
close: function close() {
$overlay.remove();
}
});
return true;
});
$('.lw_accessibility_start').on('click', '#lw_accessibility_first_report', function (e) {
var page_url = $(this).attr('href');
var msg = 'Your first report has been created. Refresh the page ' + 'and click the accessibility tab to view it.';
$.ajax({
url: LW.lib.getAjaxUrl('refreshPagesAccessibilityReport', null, page_url),
dataType: 'html',
success: function success(data) {
// show user
$('body').notify({
// notify the user
id: 'ajax',
message: msg,
details: '',
type: 'success'
});
}
});
return false;
});
};
$('#lw_pages_errors_container,body#pages_errors').on('click', '.lw_xhtml_why_errors', function (e) {
e.preventDefault();
var $spinner = $('
');
var $overlay = $('
').append($spinner).appendTo('body');
var page_url = $(this).attr('data-url');
$overlay.overlay({
size: 'medium',
closeSelector: '.lw_cancel a',
open: function open() {
$.ajax({
url: LW.lib.getAjaxUrl('getPagesXHTMLErrors', null, page_url),
dataType: 'json',
success: function success(data) {
$spinner.remove();
$overlay.append(data.html);
}
});
},
close: function close() {
$overlay.remove();
}
});
return true;
});
function initAsyncTask($overlay, async_exec, async_title, async_form_id) {
var html = (async_title.length ? '' + async_title + ' ' : '') + 'Please wait for the task to complete. This status will update automatically.
' + '
';
$overlay.html(html);
var confirm_msg = 'Are you sure you wish to close the status window? ' + 'The current task will continue running in the background.';
$overlay.overlay('addConfirmBeforeClosingMessage', confirm_msg);
window.onbeforeunload = function () {
return confirm_msg;
}; // set form data if form_id passed
var form_data = {};
if (async_form_id) {
var $form = $('#' + async_form_id);
if ($form.length) {
form_data = $form.serialize();
}
}
$.ajax({
url: livewhale.liveurl_dir + '/exec/start/' + async_exec,
// start the async exec script
dataType: 'json',
data: form_data,
method: 'POST',
success: function success(data) {
var async_status = '';
if (data.status.length) {
// add initial status
$.each(data.status, function (i, entry) {
async_status += '' + entry + '
';
});
$overlay.find('#async-exec-status').html(async_status);
}
;
var asyncInterval = setInterval(function () {
// on interval, update status
$.ajax({
url: livewhale.liveurl_dir + '/exec/status/' + data.id,
dataType: 'json',
success: function success(data2) {
// fetch current status
var async_status = '';
if (data2.status.length) {
$.each(data2.status, function (i, entry) {
// display all statuses
async_status += '' + entry + '
';
});
}
;
if (data2.error) {
// display any errors
async_status += '' + data2.error + '
';
}
if (data2.complete) {
// display completion
clearInterval(asyncInterval);
$overlay.overlay('clearConfirmBeforeClosingMessage');
window.onbeforeunload = $.noop;
}
;
$overlay.find('#async-exec-status').html(async_status);
},
error: function error() {
// clear if any requests have an error
clearInterval(asyncInterval);
$overlay.overlay('clearConfirmBeforeClosingMessage');
window.onbeforeunload = $.noop;
$overlay.overlay('close');
}
});
}, 1000 * 5); // time out after 15 minutes
setTimeout(function () {
clearInterval(asyncInterval);
}, 1000 * 60 * 15); // clear asyncInterval if clearAsyncInterval event fires
LW.eventHub.bind('clearAsyncInterval', function () {
clearInterval(asyncInterval);
});
}
});
}
function asyncExecClickHandler(e) {
var $this = $(e.currentTarget);
if (!$this.attr('data-exec').length) {
return false;
}
var async_exec = $this.attr('data-exec');
var async_title = $this.attr('data-title');
var async_form_id = $this.attr('data-form-id');
var $overlay = $this.closest('.lw_overlay_body').children();
if ($overlay.length) {
initAsyncTask($overlay, async_exec, async_title, async_form_id);
} else {
$overlay = $('
').appendTo('body'); // add this handler to .async-exec links clicked inside this overlay. We can't attach
// the handler to the body to handle both cases because LW dialogs don't allow click
// events to propagate outside the dialog. This is done so that we can enable closing
// the dialog when clicking outside it
$overlay.on('click', '.async-exec', asyncExecClickHandler);
$overlay.overlay({
size: 'large',
closeSelector: '.lw_cancel a',
open: function open() {
initAsyncTask($overlay, async_exec, async_title, async_form_id);
},
close: function close() {
// clear interval if canceled
LW.eventHub.trigger('clearAsyncInterval'); // stop async interval requests
$overlay.remove();
}
});
return false;
}
} // handle async exec tasks with status overlay
$('.async-exec').on('click', asyncExecClickHandler);
/*
/* LiveWhale-specific jQuery plugins
*/
// defind 'lw.library' plugin using the jQuery UI widget factory
$.widget('lw.library', {
// default options
options: {
type: 'images',
// default to images, but multiple types supported
select: null,
// selection callback
deselect: null,
// deselection callback
multiple: true,
// allow selection of multiple items
preselected: [],
// array of ids that should be pre-selected
requestMissing: true // when true, plugin will retrieve image data for selected images not in library
},
_page: 1,
_create: function _create() {
var that = this;
var $el = this.element;
var opts = this.options;
var str;
this.selected = {}; // item's selected elements
this.has_searched = false;
this.is_loaded = false; // insert basic structure
str = '';
$el.append(str);
this.$search = $el.find('.lw_search');
this.$results = $('').appendTo($el.find('.lw_results'));
this.$spinner = $el.find('.lw_spinner').hide();
if (opts.type === 'images') {
// if image type
this._initImageLibrary();
} else if (opts.type === 'widgets') {
this._initWidgetLibrary();
} else if (opts.type === 'files') {
this._initFileLibrary();
} else if (opts.type === 'blurbs') {
this._initBlurbLibrary();
} else if (opts.type === 'forms') {
this._initFormLibrary();
} else if (opts.type === 'galleries') {
this._initGalleryLibrary();
} // toggle item on click
this.$results.on('click', 'li.lw_item', function (e) {
// exclude links
if ($(e.target).is('a')) {
return true;
}
var item = $(this).data('item');
if (item && item.id) {
that.toggle(item.id, false, true);
}
return true;
});
this.$results.on('keydown', 'li.lw_item', function (e) {
var $li = $(e.target);
var li_index = $li.index();
var $lis;
if (13 === e.keyCode) {
e.preventDefault();
$li.trigger('click');
} else if (38 === e.keyCode) {
e.preventDefault();
$lis = $li.parent().children();
if (0 === li_index) {
$lis.eq($lis.length - 1).trigger('focus');
} else {
$lis.eq(li_index - 1).trigger('focus');
}
} else if (40 === e.keyCode) {
e.preventDefault();
$lis = $li.parent().children();
if (li_index === $lis.length - 1) {
$lis.eq(0).trigger('focus');
} else {
$lis.eq(li_index + 1).trigger('focus');
}
}
}); // when typing in the search box (which we'll now focus)
this.$search.on('keyup', function () {
that.$spinner.stop(true).show().fadeTo(150, 0.5); // show the spinner
}).on('keyup', _.debounce($.proxy(this.search, this), 200)).trigger('keyup'); // and do it now
// search more link
$el.on('click', '.lw_library_more', function (e) {
e.preventDefault();
that.search(null, true);
return true;
});
},
_initLibraryGroupSelector: function _initLibraryGroupSelector() {
var $el = this.element;
var that = this;
var group;
var library_group;
group = '' + 'Current group' + (livewhale.group_title_native ? ' (' + livewhale.group_title_native + ')' : livewhale.group_title ? ' (' + livewhale.group_title + ')' : '') + ' ' // default, no query parameters (all items in current group)
+ 'Shared by other groups ' // shared items in all groups except yours
+ 'All content in your groups ' // all items across all groups you have access to
+ ' ';
that.$group = $(group).appendTo($el.find('.lw_search_select'));
that.$group.wrap('
');
library_group = LW.lib.getCookie(LW.cookie_prefix + 'library_group');
if (library_group && that.$group.find('option[value="' + library_group + '"]').length) {
that.$group.val(library_group);
} // re-run the search when changing group
that.$group.on('change', function (e) {
if ($(this).val()) {
LW.lib.setCookie(LW.cookie_prefix + 'library_group', $(this).val());
that.$search.trigger('keyup');
}
return true;
});
},
_initImageLibrary: function _initImageLibrary() {
var $el = this.element;
var that = this;
var collections = '';
var viewToggle;
that._initLibraryGroupSelector(); // init the group dropdown
viewToggle = 'Select view:
';
$(viewToggle).insertAfter($el.find('.lw_search_wrapper')); // toggle views on library view icons
$('i.view_list').on('click', function (e) {
$(this).parents('.lw_library_images').removeClass('view_images');
});
$('i.view_images').on('click', function (e) {
$(this).parents('.lw_library_images').addClass('view_images');
}); // retrieve collections available for images (merged into group menu, so does not need to update when group changes)
$.ajax({
url: '/livewhale/backend.php?livewhale=images_get_collections' + (LW.group_id ? '&gid=' + LW.group_id : ''),
dataType: 'json',
async: false,
success: function success(data) {
if ($.isArray(data)) {
$.each(data, function (index, collection) {
// append collection options
collections += '' + collection[1] + ' ';
});
}
if (collections) {
that.$group.append('' + collections + ' ');
}
}
});
return;
},
_initFormLibrary: function _initFormLibrary() {
this._initLibraryGroupSelector(); // init the group dropdown
return;
},
_initGalleryLibrary: function _initGalleryLibrary() {
this._initLibraryGroupSelector(); // init the group dropdown
return;
},
_initWidgetLibraryTypeSelector: function _initWidgetLibraryTypeSelector() {
var $el = this.element;
var that = this;
var type;
var current_type = '';
if (that.$type) {
current_type = that.$type.val();
that.$type.parent().remove();
}
type = '' + 'All types ' + ' ';
that.$type = $(type).appendTo($el.find('.lw_search_select'));
that.$type.wrap('
'); // retrieve types
$.ajax({
url: '/livewhale/backend.php?livewhale=widgets_get_types' + (that.$group.val() === 'shared' ? '&only_shared=1' : that.$group.val() === 'your_groups' ? '&your_groups=1' : ''),
dataType: 'json',
async: false,
success: function success(data) {
var types = '';
$.each(data, function (index, type) {
types += '' + type + ' '; // append type options
});
if (types) {
that.$type.append(types);
that.$type.removeAttr('disabled');
if (current_type && that.$type.find('option[value="' + current_type + '"]').length) {
that.$type.val(current_type);
}
} else {
that.$type.attr('disabled', 'true');
}
}
}); // re-run the search when changing type
that.$type.on('change', function (e) {
that.$search.trigger('keyup');
return true;
});
return;
},
_initWidgetLibrary: function _initWidgetLibrary() {
var that = this;
this._initLibraryGroupSelector(); // init the group dropdown
this.$group.find('option[value="shared"]').remove(); // remove shared option for images only
this._initWidgetLibraryTypeSelector(); // init the type dropdown
// re-run the type selector any time the group changes
this.$group.on('change', function (e) {
that._initWidgetLibraryTypeSelector(); // init the type dropdown
return true;
});
return;
},
_initBlurbLibraryTypeSelector: function _initBlurbLibraryTypeSelector() {
var $el = this.element;
var that = this;
var type;
var current_type = '';
if (that.$type) {
current_type = that.$type.val();
that.$type.remove();
}
type = '' + 'All types ' + ' ';
that.$type = $(type).appendTo($el.find('.lw_search_select'));
that.$type.wrap('
'); // retrieve types
$.ajax({
url: '/livewhale/backend.php?livewhale=blurbs_get_types' + (that.$group.val() === 'shared' ? '&only_shared=1' : that.$group.val() === 'your_groups' ? '&your_groups=1' : ''),
dataType: 'json',
async: false,
success: function success(data) {
var types = '';
$.each(data, function (index, item) {
types += '' + item.title + ' '; // append type options
});
if (types) {
that.$type.append(types);
that.$type.removeAttr('disabled');
if (current_type && that.$type.find('option[value="' + current_type + '"]').length) {
that.$type.val(current_type);
}
} else {
that.$type.attr('disabled', 'true');
}
}
}); // re-run the search when changing type
that.$type.on('change', function (e) {
that.$search.trigger('keyup');
return true;
});
return;
},
_initBlurbLibrary: function _initBlurbLibrary() {
var that = this;
this._initLibraryGroupSelector(); // init the group dropdown
this._initBlurbLibraryTypeSelector(); // init the type dropdown
// re-run the type selector any time the group changes
this.$group.on('change', function (e) {
that._initBlurbLibraryTypeSelector(); // init the type dropdown
return true;
});
},
_initFileLibraryDateSelector: function _initFileLibraryDateSelector() {
var $el = this.element;
var that = this;
var date;
var current_date = '';
if (that.$date) {
current_date = that.$date.val();
that.$date.remove();
}
date = '' + 'All files ' + 'Last 30 days ' + ' ';
that.$date = $(date).appendTo($el.find('.lw_search_select'));
that.$date.wrap('
'); // retrieve years available for files
$.ajax({
url: '/livewhale/backend.php?livewhale=files_get_years' + (that.$group.val() === 'shared' ? '&only_shared=1' : that.$group.val() === 'your_groups' ? '&your_groups=1' : ''),
dataType: 'json',
success: function success(data) {
var years = '';
$.each(data, function (index, year) {
years += '' + year + ' ';
});
if (years) {
that.$date.append(years);
that.$date.removeAttr('disabled');
if (current_date && that.$date.find('option[value="' + current_date + '"]').length) {
that.$date.val(current_date);
}
} else {
that.$date.attr('disabled', 'true');
}
}
}); // re-run the search when changing type
that.$date.on('change', function (e) {
that.$search.trigger('keyup');
return true;
});
return;
},
_initFileLibrary: function _initFileLibrary() {
var that = this;
this._initLibraryGroupSelector(); // init the group dropdown
this._initFileLibraryDateSelector(); // init the type dropdown
// re-run the date selector any time the group changes
this.$group.on('change', function (e) {
that._initFileLibraryDateSelector(); // init the type dropdown
return true;
});
},
refresh: function refresh() {
this.$search.trigger('keyup');
},
isLoaded: function isLoaded() {
return this.is_loaded;
},
// toggle the item data
toggle: function toggle(item_id, silent, do_not_scroll) {
// if the item is not yet selected
if (!this.selected[item_id]) {
this.select(item_id, silent, false, do_not_scroll);
} else {
this.deselect(item_id, silent);
}
},
select: function select(item_id, silent, request_missing, do_not_scroll) {
var that = this;
var opts = this.options;
var $li = this.getItemById(item_id);
var item; // deselect selected items if multiple selections are not allowed
if (!opts.multiple) {
this.deselectAll();
} // Use $li data if image is loaded in library list. Otherwise, if the requestMissing option
// is true, make an ajax request to retrieve the image's data and trigger the select event
if ($li.length) {
// select the specified item
item = $li.data('item');
this.selected[item.id] = item; // highlight and check item
$li.addClass('lw_selected').attr('aria-checked', 'true').find('input').prop('checked', true); // scroll to item
if (!do_not_scroll) {
var $container = this.$results.closest('.lw_results');
$container.animate({
scrollTop: $li.offset().top - $container.offset().top + $container.scrollTop()
});
}
if (!silent) {
this._trigger('select', null, {
item: item
});
}
} else if (request_missing || opts.requestMissing && !silent) {
var url = opts.type === 'widgets' ? LW.lib.getAjaxUrl('getWidgets') + '&id=' + item_id : LW.liveurl_dir + '/json/v2/' + opts.type + '/id/' + item_id + '?is_library_search=1';
$.ajax({
url: url,
dataType: 'json',
success: function success(result) {
if (opts.type === 'widgets' && $.isArray(result) && result.length || _.isArray(result.data) && result.data.length) {
var _item = opts.type === 'widgets' ? result[0] : result.data[0];
that.selected[_item.id] = _item;
that._addItem(_item, true);
that._trigger('select', null, {
item: _item
});
}
}
});
}
return this;
},
deselect: function deselect(item_id, silent) {
var $li = this.getItemById(item_id); // deselect the specified item
delete this.selected[item_id]; // remove highlight and uncheck if item present in library
if ($li.length) {
$li.removeClass('lw_selected').attr('aria-checked', 'false').find('input').prop('checked', false);
}
if (!silent) {
this._trigger('deselect', null, item_id);
}
return this;
},
getItemById: function getItemById(id) {
return this.$results.children('#lw_item' + id);
},
deselectAll: function deselectAll() {
this.selected = {};
this.$results.children('.lw_selected').removeClass('lw_selected').attr('aria-checked', 'false').find('input[type=checkbox]').prop('checked', false);
},
search: function search(e, next_page) {
var opts = this.options;
var that = this;
var url; // show spinner
that.$spinner.show();
this.is_loaded = false; // reset to first page if we're not movign to next page
this._page = next_page ? this._page + 1 : 1; // form url depending on type
switch (opts.type) {
case "widgets":
url = this._getWidgetSearchUrl();
break;
case "images":
url = this._getImageSearchUrl();
break;
case "files":
url = this._getFileSearchUrl();
break;
case "galleries":
url = this._getGallerySearchUrl();
break;
case "blurbs":
url = this._getBlurbSearchUrl();
break;
case "forms":
url = this._getFormSearchUrl();
break;
} // load the search results
$.getJSON(url, function (data) {
// clear existing if we're not adding a page
if (!next_page) {
that.$results.empty();
}
var meta; // the widget type request is not an API request and does not return data and meta attributes
if (typeof data.data !== 'undefined') {
meta = data.meta;
data = data.data;
}
if (data.length) {
// remove previously added more link if we're fetching the next page
if (next_page) {
that.$results.find('.lw_library_more').remove();
}
$.each(data, function (index, item) {
that._addItem(item);
}); // append a more link if this isn't the last page
if (meta && meta.total_pages > that._page) {
that.$results.append('Show more ');
}
} else if (!next_page) {
that.$results.html('No matching results. ');
} // toggle pre-selected items on first load
if (!that.has_searched && opts.preselected && opts.preselected.length) {
$.each(opts.preselected, function (index, id) {
var $li = that.$results.find('#lw_item' + id); // select item if it exists, otherwise attempt to retrieve it
if ($li.length) {
that.toggle(id);
} else {
$.getJSON(LW.liveurl_dir + '/json/v2/' + opts.type + "/id/" + id, function (results) {
var data = results.data; // do nothing if no data
if (!data.length) return;
$.each(data, function (index, item) {
that._addItem(item);
}); // select item with id after adding
$li = that.$results.find('#lw_item' + id);
that.toggle(id);
});
}
});
} // mark that search has run once
that.has_searched = true; // hide the spinner
that.$spinner.stop(true).fadeOut(150);
that.is_loaded = true;
that._trigger('load', null);
});
},
_getSearchUrl: function _getSearchUrl() {
var query = this._getSearchString();
var url = LW.liveurl_dir + "/json/v2/" + this.options.type;
if (query) {
url += "/search/" + query + "*";
} // IX - make this a bigger number when paginate bug fixed
url += '/paginate/25';
return url;
},
_getUrlGroup: function _getUrlGroup() {
var group = this.$group && this.$group.length ? this.$group.val() : '';
var param = '';
if (group === 'shared') {
// add only_shared
param += '/only_shared/true';
} else if (group === 'your_groups') {
// add your_groups
param += '/your_groups/true';
}
return param;
},
_getImageSearchUrl: function _getImageSearchUrl() {
var url = this._getSearchUrl(); // add group
url += this._getUrlGroup(); // add collection
if (0 === this.$group.val().indexOf('collection:')) {
url += '/collection/' + this.$group.val().substring(11);
}
url += '?is_library_search=1&page=' + this._page;
return url;
},
_getFormSearchUrl: function _getFormSearchUrl() {
var url = this._getSearchUrl(); // add group
url += this._getUrlGroup();
url += '?is_library_search=1&page=' + this._page;
return url;
},
_getWidgetSearchUrl: function _getWidgetSearchUrl() {
var query = this._getSearchString();
var url = LW.lib.getAjaxUrl('getWidgets');
var group = this.$group && this.$group.length ? this.$group.val() : ''; // add search
if (query) {
url += "&search=*" + query + "*";
} // add type
if (this.$type.val()) {
url += "&type=" + this.$type.val();
} // add group
if (group === 'shared') {
// add only_shared
url += '&only_shared=1';
} else if (group === 'your_groups') {
// add your_groups
url += '&your_groups=1';
}
return url;
},
_getFileSearchUrl: function _getFileSearchUrl() {
var url = this._getSearchUrl(); // add group
url += this._getUrlGroup(); // add year
url += this._getUrlDateRange();
url += '?is_library_search=1&page=' + this._page;
return url;
},
_getGallerySearchUrl: function _getGallerySearchUrl() {
var url = this._getSearchUrl(); // add group
url += this._getUrlGroup();
url += '?is_library_search=1&page=' + this._page;
return url;
},
_getBlurbSearchUrl: function _getBlurbSearchUrl() {
var url = this._getSearchUrl(); // add group
url += this._getUrlGroup(); // add type
if (this.$type.val()) {
url += "/type/" + encodeURIComponent($.trim(this.$type.val()));
}
url += '?is_library_search=1&page=' + this._page;
return url;
},
_getSearchString: function _getSearchString() {
return encodeURIComponent($.trim(this.$search.val())) || '';
},
_getUrlDateRange: function _getUrlDateRange() {
var date = this.$date && this.$date.length ? this.$date.val() : '';
var daterange = '';
var today, start; // if there’s a date selector and it has a value
if (date) {
// if we’re checking sending "last 30 days"
if (date === 'last30') {
today = new Date(); // today
start = new Date(today.getTime() - 31 * 86400000); // 31 days ago
daterange = '/start_date/' + start.getFullYear() + '-' + (start.getMonth() + 1) + '-' + start.getDate() + '/end_date/' + today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate();
} else if (date.indexOf('year:') === 0) {
// fetch items from the start of the specified year to the end of the year
daterange = '/start_date/' + date.substring(6) + '-01-01' + '/end_date/' + date.substring(6) + '-12-31';
}
}
return daterange;
},
_addItem: function _addItem(item, prepend) {
var opts = this.options;
var itemThumbnail = '';
var itemShowPreview = '';
var itemGroupTitle = '';
var itemGroupTitleClean = '';
var itemTypeTitle = item.type_title ? '' + item.type_title + ' ' : ''; // if item group is different from current group
if (item.gid && livewhale.gid !== item.gid) {
// there is no concept of sharing for widgets
itemGroupTitle = opts.type === "widgets" ? ' in group ' + item.group_name + ' ' : ' shared by ' + item.group + ' ';
itemGroupTitleClean = opts.type === "widgets" ? ', in group ' + item.group_name : ', shared by ' + item.group;
}
var str;
var $li; // set thumb if valid
if (item.thumbnail) {
itemThumbnail = ' ';
} // set preview if gallery and url exists
if (item.url && opts.type === "galleries") {
itemShowPreview = ' Preview ';
}
str = '' + itemThumbnail + '' + itemTypeTitle + '' + item.title + ' ' + itemShowPreview + itemGroupTitle + '
' + ' '; // store the data and append the element
$li = $(str).data('item', item); // set tabindex="0" if this is the first item
if (0 === this.$results.children().length) {
$li.attr('tabindex', '0');
}
if (prepend) {
this.$results.prepend($li);
} else {
this.$results.append($li);
} // if the item is selected, highlight it now
if (this.selected[item.id]) {
$li.addClass('lw_selected').attr('aria-checked', 'true').find('input').prop('checked', true);
}
}
});
$.widget('lw.relatedsearch', {
// default options
options: {
module: 'pages',
is_backend: false,
search_root: null,
render_default_menu: true,
hide_empty_results: false,
hide_type_header: false,
max: 10
},
_create: function _create() {
var _this4 = this;
var opts = this.options;
var debounce;
if (this.options.render_default_menu) {
this._initResultsMenu();
}
this.element.on('keyup', function (e) {
// get keycode of current keypress event
var code = e.keyCode || e.which;
var query = $(e.currentTarget).val(); // do nothing if it's an arrow key or enter
if (code == 37 || code == 38 || code == 39 || code == 40 || code == 13) {
return;
}
clearTimeout(debounce); // return if query string not long enough
if (!query || query.length < 3) {
if (opts.render_default_menu) {
_this4.hideResults();
}
_this4._trigger('results', e);
return;
}
debounce = setTimeout(function (e) {
_this4.search(e, query);
}, 300);
});
},
hideResults: function hideResults() {
this.$results.hide();
this._trigger('hideResults');
},
showResults: function showResults() {
this.$results.show();
this._trigger('showResults');
},
search: function search(keyup_event, query) {
var opts = this.options;
var url_args = [];
var that = this;
var url;
var d;
query = $.trim(query);
var encoded_query = encodeURIComponent(query.replace(/\//g, '\\')); // construct url
url = LW.liveurl_dir + '/json/v2/' + opts.module + ',/max/' + opts.max + '/search/' + encoded_query + '*'; // add end_date for event searches
if (opts.module === 'events') {
d = new Date();
d.setDate(d.getDate() + 30 * 12);
url += '/end_date/' + d.toISOString().slice(0, 10);
} // add group
if (opts.group) {
url += '/group/' + encodeURIComponent(opts.group);
} // add search root
if (opts.search_root) {
url_args.push('search_root=' + opts.search_root);
} // make a library request
if (opts.is_library_search) {
url_args.push('is_library_search=1');
} // add backend search to adjust search logic for backend contexts
if (opts.is_backend) {
url_args.push('is_backend_search=1');
} // add /host/all if no search_root and pages included in search
if (!opts.search_root && -1 !== opts.module.indexOf('pages')) {
url += '/host/all';
} // combine and append optional url args
if (url_args.length) {
url += '?' + url_args.join('&');
} // return if this url the same as previous url
if (url === this.lasturl) {
this.showResults();
return;
} // make this url the lasturl so we don't execute it twice
this.lasturl = url; // show the spinner
if (opts.render_default_menu) {
this.$spinner.stop(true).show().fadeTo(150, 0.5);
} // go get it
$.getJSON(url, function (data) {
var filtered_data = {}; // filter by optional restrict_to
if (opts.module && opts.restrict_to && query) {
$.each(data, function (type, items) {
filtered_data[type] = [];
items = items.data;
var regex_query = new RegExp(query.toLowerCase().replace(' ', '.*?|') + '.*?', 'g');
$.each(items, function (index, item) {
var is_valid = false;
$.each(opts.restrict_to, function (restrict_key, restrict_field) {
var val = (item[restrict_field] || '').toLowerCase();
if (regex_query.test(val)) {
// if one of the query words is found
is_valid = true;
}
});
if (is_valid) {
filtered_data[type].push(item);
}
});
if (!filtered_data[type].length) {
delete filtered_data[type];
}
});
data = filtered_data;
} else {
$.each(data, function (type, items) {
data[type] = items.data;
});
} // render the default menu
if (opts.render_default_menu) {
that._renderResultsMenu(data);
}
that._trigger('results', keyup_event, data);
});
},
_initResultsMenu: function _initResultsMenu() {
var $el = this.element;
var that = this;
var $results = $('
').insertAfter($el).hide();
var $spinner = $('
').appendTo($results).hide();
var hideresults;
this.$results = $results;
this.$spinner = $spinner;
this.results_items = $(); // show results if there’s a value on focus
$el.on('focus', function () {
if ($el.val()) $el.trigger('keyup');
}).on('blur', function () {
// after 200ms
// We do the following inside the timer in case clicking on a suggestion has already selected a result
hideresults = setTimeout(function () {
// hide the suggestion popup (we can't hide it earlier, in case the user has clicked it)
that.hideResults();
}, 200);
}).on('keydown', function (e) {
var selected, index, result;
switch (e.which) {
// up arrow
case 38:
e.preventDefault();
selected = $results.find('.lw_selected').removeClass('lw_selected');
index = that.results_items.index(selected);
if (index > 0) {
selected = that.results_items.eq(index - 1).addClass('lw_selected');
} else {
selected = that.results_items.eq(-1).addClass('lw_selected');
}
var position = selected.position().top;
if (position < 0 || position + selected.outerHeight() > $results.height()) {
$results.scrollTop($results.scrollTop() + position);
}
$('.related_results_aria').text('Press Enter to select ' + selected.find('label').text());
break;
// down arrow
case 40:
e.preventDefault();
selected = $results.find('.lw_selected').removeClass('lw_selected');
index = that.results_items.index(selected);
selected = selected.next().addClass('lw_selected');
if (index < that.results_items.length - 1) {
selected = that.results_items.eq(index + 1).addClass('lw_selected');
} else {
selected = that.results_items.eq(0).addClass('lw_selected');
}
position = selected.position().top;
if (position < 0 || position + selected.outerHeight() > $results.height()) {
$results.scrollTop($results.scrollTop() + position + selected.outerHeight() - $results.height());
}
$('.related_results_aria').text('Press Enter to select ' + selected.find('label').text());
break;
// enter/return
case 13:
// prevent enter
e.preventDefault();
// fallthrough - absent break intentional
// tab
case 9:
// trigger select if item selected
result = that._triggerSelect(e); // prevent default if tab and an item selected
if (e.which === 9 && result) {
e.preventDefault();
}
break;
}
}); // disable the results-hiding timeout and keep the focus on the input on scroll
$results.on('scroll', function () {
clearTimeout(hideresults);
$el.trigger('focus');
}) // clicking a suggested item
.on('click', 'li', function (e) {
// adds the selected class
$(this).addClass('lw_selected').siblings().removeClass('lw_selected');
that._triggerSelect(e);
});
},
_renderResultsMenu: function _renderResultsMenu(data) {
var that = this;
var opts = this.options;
var host_regex = /^.+?:\/\/([^/]+)/;
var curr_host, is_empty; // we need to check the value of each property in the data object if querying for more than one module
is_empty = $.isEmptyObject(data) || _.every(data, function (val, prop) {
return _.isEmpty(val);
}); // just hide and return if no results and the hide_empty_results option is set
if (is_empty && opts.hide_empty_results) {
this.hideResults();
return true;
} // remove previous results
this.showResults();
this.$results.children().not('.lw_spinner').remove();
if (!is_empty) {
curr_host = window.location.href.match(host_regex);
if (curr_host) curr_host = curr_host[1];
var $aria = $('
').appendTo(that.$results); // data type loop
$.each(data, function (type, value) {
// do nothing if value isn't an array or if it's an empty array
if (!($.isArray(value) && value.length)) {
return true;
}
var $category = $('
').appendTo(that.$results);
var $list = $('').appendTo($category); // show type header
if (!opts.hide_type_header) {
$category.prepend('' + type + ': ');
} // and with each value
$.each(value, function (index, item) {
var group = item.group || '',
thumb = item.thumbnail ? ' ' : '',
date = item.date ? '' + item.date + ' ' : '',
descr = '',
url = '',
host,
local_path,
html;
if (item.url) {
url = item.url;
host = url.match(host_regex); // remove host from url if same as curr_host
if (host && host[1] === curr_host) {
local_path = /^.+?:\/\/.+?(\/.+?)(?:#|\?|$)/.exec(url);
if (local_path) {
url = local_path[1];
}
}
} // strip tags from description
if (item.description && typeof item.description === 'string') {
item.description = item.description.replace(/<\/?[^>]+>/gi, '');
descr = item.description + ' - ';
}
item.type = type;
html = thumb + '' + item.title + ' ' + date;
if (url) {
html += '' + url + ' ';
}
$(' ').html(html).data('item', item) // store the data and append the element
.appendTo($list);
});
$aria.append('' + value.length + ' ' + type + ' results found.
');
});
$aria.append('Use arrow keys and Enter to select.
');
} else {
// if there were no results, display message
this.$results.append('No matching results.
');
}
this.results_items = that.$results.find('li').not('.lw_noresults');
this.$spinner.stop(true).fadeOut(150); // hide the spinner
return true;
},
_triggerSelect: function _triggerSelect(evt) {
var selected = this.$results.find('.lw_selected'),
result = false;
this.hideResults();
this.results_items = $();
if (selected.length) {
this._trigger('select', evt, selected.data('item'));
result = true;
}
return result;
}
});
function MultiPaneDialog(size, custom_class) {
var that = this,
footer,
html;
this.mode = null;
this.modes = {};
html = '
';
footer = '';
var $footer = this.$footer = $(footer);
var $overlay = this.$overlay = $(html).overlay({
autoOpen: false,
destroyOnClose: false,
size: size || 'large',
closeSelector: '.lw_cancel a',
customClass: custom_class || 'lw_multi_pane_overlay',
title: 'Insert dynamic content',
footer: $footer,
close: function close() {
that.pane._close();
}
});
$footer.on('click', '.lw_save', function (e) {
e.preventDefault();
that.save();
$overlay.overlay('close');
return true;
});
}
_.extend(MultiPaneDialog.prototype, LW.lib.pubSub(), {
registerPane: function registerPane(mode, Pane) {
// do nothing if incorrect parameters
if (!mode || !Pane || typeof mode !== 'string' || typeof Pane !== 'function') return;
this.modes[mode] = {
class_name: Pane,
object: null
};
},
setTitle: function setTitle(title) {
this.$overlay.overlay('option', 'title', title);
},
setButtonText: function setButtonText(text) {
this.$footer.find('.lw_save').text(text);
},
open: function open(mode) {
// do nothin if this isn't a registered mode
if (!this.modes[mode]) return;
var pane = this.modes[mode]; // initialize pane if it hasn't been already
if (!pane.object) {
pane.object = new pane.class_name(this);
} // show/switch panes if mode differs from the one that's set
if (this.mode !== mode) {
this.mode = mode;
this.pane = pane.object;
}
this.$overlay.overlay('open');
this.$overlay.children().hide();
this.pane.show();
},
close: function close() {
this.$overlay.overlay('close');
},
save: function save() {
this.pane.save();
}
});
function FileLibraryPane(dialog) {
var that = this,
html;
this.dialog = dialog;
this.type = 'file';
this.title = 'Select a file';
this.button_text = 'Add this file';
this.item = null;
html = '';
var $el = this.$el = $(html).appendTo(dialog.$overlay);
this.$preview = $el.find('.lw_preview').one('load', $.proxy(this.previewLoadHandler, this));
this.$library = $el.find('.lw_library').library({
type: 'files',
multiple: false,
select: function select(e, data) {
if (data && data.item) {
that.item = data.item;
}
},
deselect: function deselect() {
that.item = null;
}
});
var upload = '' + ' Upload file' + ' ';
var $upload = this.$upload = $(upload).prependTo(this.dialog.$footer);
$upload.uploader('uploadModal', 'files', {
mode: 'quick_upload',
multiple: false,
onError: function onError(e, data) {},
onSuccess: function onSuccess(e, items) {
if (_.isArray(items) && items.length === 1) {
that.item = items[0];
that.save();
that.dialog.close();
}
}
});
}
_.extend(FileLibraryPane.prototype, {
setDialogTitle: function setDialogTitle() {
this.dialog.setTitle(this.title);
},
setDialogButtonText: function setDialogButtonText() {
this.dialog.setButtonText(this.button_text);
},
save: function save() {
this.dialog.trigger('filelibraryselect', [this.item]);
},
addUploadButton: function addUploadButton() {
this.dialog.$footer.prepend(this.$upload);
},
// $.fn.detach allows us to remove the button while preserving its handlers
removeUploadButton: function removeUploadButton() {
this.$upload.detach();
},
show: function show() {
this.setDialogTitle();
this.setDialogButtonText();
this.addUploadButton();
this.$el.show();
},
_close: function _close() {
this.removeUploadButton();
if (this.item) {
this.$library.library('deselect', this.item.id);
this.item = null;
}
this.dialog.trigger('filelibraryclose');
}
});
LW.lib.MultiPaneDialog = MultiPaneDialog;
LW.lib.libraryDialog = new MultiPaneDialog('large', 'lw_library_overlay_mini');
LW.lib.libraryDialog.registerPane('file', FileLibraryPane);
})(livewhale, livewhale.jQuery);
"use strict";
/*globals ace */
(function (LW, $) {
var $win = $(window);
var $body = $('body');
$.easing.def = 'easeInOutSine'; // set default easing for animations
if (!LW.editor) LW.editor = {}; // create editor object if not set
if (!LW.manager) LW.manager = {}; // create manager object if not set
/*
* Adds resizeEnd custom event to $(window) that fires when user finishes resizing
*/
function addOnResizeEndEvent() {
var prev_width, tid;
$win.on('resize', function () {
if (!tid) {
prev_width = $win.width();
} else {
clearTimeout(tid);
}
tid = setTimeout(function () {
LW.eventHub.trigger('windowResizeEnd', [prev_width]);
prev_width = null;
tid = null;
}, 200);
});
}
addOnResizeEndEvent();
// extend lib functions in common.js
LW.lib = LW.lib || {};
$.extend(LW.lib, {
_base64key: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
encode64: function encode64(input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = this._utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = (chr1 & 3) << 4 | chr2 >> 4;
enc3 = (chr2 & 15) << 2 | chr3 >> 6;
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output + this._base64key.charAt(enc1) + this._base64key.charAt(enc2) + this._base64key.charAt(enc3) + this._base64key.charAt(enc4);
}
return output;
},
decode64: function decode64(input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9+/=]/g, "");
while (i < input.length) {
enc1 = this._base64key.indexOf(input.charAt(i++));
enc2 = this._base64key.indexOf(input.charAt(i++));
enc3 = this._base64key.indexOf(input.charAt(i++));
enc4 = this._base64key.indexOf(input.charAt(i++));
chr1 = enc1 << 2 | enc2 >> 4;
chr2 = (enc2 & 15) << 4 | enc3 >> 2;
chr3 = (enc3 & 3) << 6 | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 !== 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 !== 64) {
output = output + String.fromCharCode(chr3);
}
}
return this._utf8_decode(output);
},
_utf8_encode: function _utf8_encode(string) {
string = string.replace(/\r\n/g, "\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if (c > 127 && c < 2048) {
utftext += String.fromCharCode(c >> 6 | 192);
utftext += String.fromCharCode(c & 63 | 128);
} else {
utftext += String.fromCharCode(c >> 12 | 224);
utftext += String.fromCharCode(c >> 6 & 63 | 128);
utftext += String.fromCharCode(c & 63 | 128);
}
}
return utftext;
},
_utf8_decode: function _utf8_decode(utftext) {
var string = "";
var i = 0;
var c, c2, c3;
c = c2 = 0;
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if (c > 191 && c < 224) {
c2 = utftext.charCodeAt(i + 1);
string += String.fromCharCode((c & 31) << 6 | c2 & 63);
i += 2;
} else {
c2 = utftext.charCodeAt(i + 1);
c3 = utftext.charCodeAt(i + 2);
string += String.fromCharCode((c & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
i += 3;
}
}
return string;
},
parseQueryString: function parseQueryString(str) {
var vars = str.split('&'),
obj = {},
pair;
for (var i = 0; i < vars.length; i++) {
pair = vars[i].split('=');
obj[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
}
return obj;
},
parseSlashSeparatedKeyValPairs: function parseSlashSeparatedKeyValPairs(str) {
var vars,
obj = {};
vars = str.split('/');
// return empty object if no vars
if (!vars.length) return {};
for (var i = 0; i < vars.length; i += 2) {
obj[vars[i]] = decodeURIComponent(vars[i + 1]);
}
return obj;
},
parseUrlQueryString: function parseUrlQueryString() {
var qstring = window.location.search.substring(1) || '';
return LW.lib.parseQueryString(qstring);
},
parseUrlHash: function parseUrlHash() {
var hash = window.location.href.split("#")[1] || ''; // unusual syntax necessary to account for FF bug
return LW.lib.parseSlashSeparatedKeyValPairs(hash);
},
stringifyUriArgs: function stringifyUriArgs(args) {
var args_arr = [];
// don't filter empty values - it can cause issues when backend expects key to be defined
_.each(args, function (val, key) {
args_arr.push(key + '=' + encodeURIComponent(val));
});
return args_arr.join('&');
},
getCropPreviewCss: function getCropPreviewCss(preview_width, preview_height, image_width, image_height, coords) {
var coords_width = coords[2] - coords[0],
coords_height = coords[3] - coords[1],
xfactor = preview_width / coords_width,
yfactor = preview_height / coords_height;
return {
position: 'absolute',
width: Math.round(xfactor * image_width) + 'px',
height: Math.round(yfactor * image_height) + 'px',
left: '-' + Math.round(xfactor * coords[0]) + 'px',
top: '-' + Math.round(yfactor * coords[1]) + 'px'
};
},
initAceCodeEditor: function initAceCodeEditor() {
var setCommandEnabled = function setCommandEnabled(editor, name, enabled) {
var command = editor.commands.byName[name];
if (!command.bindKeyOriginal) {
command.bindKeyOriginal = command.bindKey;
}
command.bindKey = enabled ? command.bindKeyOriginal : null;
editor.commands.addCommand(command);
// special case for backspace and delete which will be called from
// textarea if not handled by main commandb binding
if (!enabled) {
var key = command.bindKeyOriginal;
if (key && babelHelpers["typeof"](key) === "object") {
key = key[editor.commands.platform];
}
if (/backspace|delete/i.test(key)) {
editor.commands.bindKey(key, "null");
}
}
};
// swap code editor for a11y
$('body').on('click', '.swap-code-editor', function (e) {
e.preventDefault();
var $this = $(e.currentTarget);
if ($('textarea.code-input').is(':visible')) {
$('div.code-editor').show().attr('tabindex', 0);
$('textarea.code-input').hide().attr('tabindex', -1);
$this.text("Use Accessible Code Editor");
} else {
$('div.code-editor').hide().attr('tabindex', -1);
$('textarea.code-input').show().attr('tabindex', 0);
$this.text("Use Full-featured Code Editor");
}
});
$('.code-editor').each(function () {
var $this = $(this);
var target = $this.attr('data-target');
// get target input
var $input;
if (target) {
$input = $('#' + target);
}
// do nothing if no target input found
if (!$input || !$input.length) {
return;
}
ace.config.set("basePath", LW.liveurl_dir + '/resource/js/livewhale/thirdparty/ace');
var editor = ace.edit($this.attr('id'), {
wrap: true,
indentedSoftWrap: false,
//behavioursEnabled: false,
mode: 'ace/mode/xml',
useWorker: false // disable error checking; it expects a full document
});
editor.setTheme('ace/theme/eclipse');
editor.setShowPrintMargin(false);
editor.on('focus', function () {
setCommandEnabled(editor, "indent", true);
setCommandEnabled(editor, "outdent", true);
});
editor.commands.addCommand({
name: "escape",
bindKey: {
win: "Esc",
mac: "Esc"
},
exec: function exec() {
setCommandEnabled(editor, "indent", false);
setCommandEnabled(editor, "outdent", false);
}
});
// copy hidden value to custom editor on change
$input.on('change', function () {
// we lose the cursor position when we set the value here, save and restore after setting
var pos = editor.getCursorPosition();
editor.setValue($input.val());
editor.clearSelection();
editor.selection.moveCursorToPosition(pos);
});
// copy custom code field value to their corresponding hidden input element on change
editor.on('change', function () {
$input.val(editor.getValue());
});
// trigger change event on blur -- can't do this on editor('change', func) or it'll cause an infinite loop
editor.on('blur', function () {
$input.trigger('change');
});
if ($input.val()) {
editor.setValue($input.val());
}
setTimeout(function () {
$input.trigger('change');
}, 100);
});
}
});
var manager_state = LW.manager.manager_state = {
state: {},
// cache state (all input values and status text) of a manager item
// by passing a jQuery object containing the item's wrapping element
set: function set($wrapper) {
var $inputs = $wrapper.find('input:not(.with_this)');
var id = $wrapper.find('.with_this').val();
var status = $wrapper.find('.status_wrapper .selected').html();
var item = {};
// cache status text so we can restore scheduled time
if (status) item.status_html = status;
// cache all input values
$inputs.each(function () {
var $el = $(this);
item[$el.attr('name')] = $el.val();
});
this.state[id] = item;
},
get: function get() {
return this.state;
}
};
LW.lib.changedData = {
init: function init() {
var html;
var $manager = this.$manager = $('#manager');
var $main = $manager.closest('.main');
// do nothing if no data can be changed through the manager
if (!$manager.find('ul.manager').find('.status,.balloons,.star,.globe,textarea').length && !$manager.find('ul#manager_pages').length) {
return;
}
html = '' + 'Save these changes ' + 'Your changes to this page have not been saved. Use the "Save Changes" link to save. ' + '
';
var $alert = this.$alert = $(html);
$manager.before($alert);
function resizeSaveChangesAlert() {
if ($alert.hasClass('affix')) {
$alert.width($main.width() - 32);
}
}
$alert.affix({
offset: {
top: $alert.offset().top
}
}).hide().on('affixed.bs.affix', function () {
// add extra margin to top of manager form as a placeholder for affixed savechanges alert
var orig_margin_top = parseInt($manager.css('marginTop').replace('px', ''), 10);
$manager.css('marginTop', orig_margin_top + $alert.outerHeight(true));
// set width
resizeSaveChangesAlert();
})
// remove the extra margin when alert returns to static position
.on('affixed-top.bs.affix', function () {
$manager.css('marginTop', '');
$alert.css('width', '');
});
// call resize in case first changes done with the window scrolled below alert's top pos,
// in which case affix.bs.affix does not fire. Also register with win resize
resizeSaveChangesAlert();
$win.on('resize', resizeSaveChangesAlert);
// save changes handler
$body.on('click', '#savechanges button', function (e) {
e.preventDefault();
// if saving a navigation
if (LW.page === 'pages') {
var $form = $('form#manager');
var expanded = [];
$.each($form.find('li.open'), function (key, val) {
var id = $(val).attr('id');
if (id) {
expanded[expanded.length] = id.substring(4);
}
});
$form.append(' ');
}
// don't show an alert
window.onbeforeunload = $.noop;
$manager.submit();
return true;
});
// click and enter key handlers for SR save changes links, just clicks #savechanges button
$body.on('click', '.js_sr_manager_save_changes', function (e) {
e.stopPropagation();
e.preventDefault();
$('#savechanges button').trigger('click');
return false;
});
},
show: function show() {
var $alert = this.$alert,
$manager = this.$manager;
if (!$alert.length) return;
if (!$alert.is(':visible')) {
$alert.show();
// adjust scroll position to account for new dom item -- so there is no jump when we insert it
$win.scrollTop($win.scrollTop() + this.$alert.outerHeight(true));
}
// attach an unload event, so when you navigate away
window.onbeforeunload = function () {
var msg = 'Your changes to this page haven’t been saved. Please return to this page and ‘Save these changes’ ' + 'before navigating away if you wish to preserve your edits.';
return msg;
};
}
};
LW.lib.highlightStars = function () {
// turn star state on - we should move this to the backend
$('.star').each(function () {
var $this = $(this);
if ($this.find('input').val() === '1' && !$this.hasClass('active')) {
$this.addClass('active').attr('aria-checked', 'true');
}
});
};
// highlights and attaches action to stars
LW.lib.initStars = function () {
LW.lib.highlightStars();
// if on a manager page
$('form#manager,#star_wrap').on('click', 'div.star', function (e) {
e.stopPropagation();
var $this = $(this),
$input = $this.find('input');
if ($input.val() === '1') {
$input.val(0);
$this.removeClass('active').attr('aria-checked', 'false'); // click the checkbox and swap the class
} else {
$input.val(1);
$this.addClass('active').attr('aria-checked', 'true');
}
if (LW.is_manager) {
manager_state.set($this.closest('li'));
LW.lib.changedData.show(); // show "Save These Changes" button
$('.js_sr_manager_save_changes').remove(); // remove existing sr only save buttons
// add sr only save button
$this.after('Save changes ');
}
return true;
})
// keyboard toggle
.on('keypress', 'div.star', function (e) {
e.preventDefault();
// toggle star on enter or spacebar
if (e.keyCode === 13 || e.keyCode === 32) {
$(this).trigger('click');
}
return true;
});
// editor version differs in that the user can click on the star or star text
if (LW.is_editor) {
$('#star_wrap').on('click', function () {
$(this).find('.star').trigger('click');
});
}
};
function initGlobes() {
// highlights and attaches action to globes
var $globe = $('.globe');
// return if no globe elements
if (!$globe.length) return;
$globe.each(function () {
var $this = $(this);
var $input = $this.find('input');
// hide globes for borrowed items
if ($this.find('input').val() === 'x') {
$this.hide();
}
$this.toggleClass('active', $input.val() === '1').on('click', function (e) {
e.stopPropagation();
var $this = $(e.currentTarget);
// toggle checkbox and set class and aria-checked values
if ($input.val() === '1') {
$input.val(0);
$this.removeClass('active').attr('aria-checked', 'false');
} else {
$input.val(1);
$this.addClass('active').attr('aria-checked', 'true');
}
manager_state.set($this.closest('li'));
if (LW.is_manager) {
// if on a manager page
LW.lib.changedData.show(); // show "Save These Changes" button
}
});
return true;
})
// keyboard toggle
.on('keypress', function (e) {
e.preventDefault();
// toggle star on enter or spacebar
if (e.keyCode === 13 || e.keyCode === 32) {
$(e.currentTarget).trigger('click');
}
return true;
});
// make globe text clickable too
if (LW.is_editor) {
$('#globe_wrap').on('click', function () {
$(this).find('.globe').trigger('click');
});
}
}
function Dashboard() {
// message dismissal links
$('.message_dismiss').on('click', function () {
var $this = $(this);
$.get(LW.lib.getAjaxUrl('closeMessage', {
id: $this.closest('li').attr('id').replace('message', '')
}));
$this.parent().slideUp('slow', function () {
var $ul = $(this).parent();
$(this).remove();
if (!$ul.children().length) {
$('#attention').slideUp('slow');
}
});
return false;
});
// enable shortcut removal links
$('#dashboard').on('click', '.remove_shortcut', function () {
var $li = $(this).closest('li');
var $a = $li.find('.msg_content a');
// remove the shortcut
$.get(LW.lib.getAjaxUrl('saveShortcut', {
action: 'remove',
title: $a.text(),
url: $a.attr('href')
}));
$li.remove();
return false;
});
// treatment for empty columns
$('#dashboard_body > div > h2').each(function () {
var $this = $(this);
if (!$this.next().length || $this.next().is('h2')) {
$this.after('Nothing to display yet.
');
}
});
// if diagnostics needs to be run
if (livewhale.will_run_diagnostics) {
$.getJSON(livewhale.liveurl_dir + '/diagnostics/refresh', function (res) {
// run it
if (res.count_errors) {
// update dashboard tab and add message
$('#tab_dashboard a').html($('#tab_dashboard a').html() + ' ' + res.count_errors + ' ');
// reset empty messages back to object as expected
if ($.isArray(livewhale.messages) && livewhale.messages.length == 0) {
livewhale.messages = {};
}
if (!livewhale.messages.warning) {
livewhale.messages.warning = [];
}
livewhale.messages.warning.push('' + res.count_errors + ' installation issue' + (res.count_errors > 1 ? 's were' : ' was') + ' discovered' + (res.count_warnings ? ' (and ' + res.count_warnings + ' warning' + (res.count_warnings != 1 ? 's' : '') + ')' : '') + '. View details
');
livewhale.backend.initMessages();
}
});
}
}
function Search() {
// attach onclick to more results links
$('.more_results_link').on('click', function () {
$(this).next().show();
$(this).hide();
return false;
});
// handle copy-as-link
$('.item_copy_link').on('click', function () {
$(this).parent().prev().val('search_link');
$('#results_form').submit();
return false;
});
// handle copy-as-copy
$('.item_copy_copy').on('click', function () {
$(this).parent().prev().val('search_copy');
$('#results_form').submit();
return false;
});
}
function Settings() {
// The following is a fix for Chrome/Safari which autofills the settings username/password fields
// regardless of autocomplete="off"
var email = $('#email').val(); // fetch the original email that was prefilled by LiveWhale
// switch password field from text (as in the template) to password, which triggers the browser autofill
$('#password').attr('type', 'password');
// set an interval to wait for the autofill to happen, and then undo it
var autofill_fix = setInterval(function () {
if ($('#email').val() !== email) {
$('#email').val(email);
$('#password').val('');
}
}, 100);
setTimeout(function () {
// after 1000ms, terminate this fix
clearInterval(autofill_fix);
}, 1000);
}
// Pop up the status selector ('this' is the currently selected option)
function initSelectMenus($section, options, select_callback) {
var selectMenuItem = function selectMenuItem($item) {
var $menu = $item.parent();
var $wrapper = $item.closest('.status_wrapper').parent();
var is_archive_menu = $item.parent().hasClass('archive');
var val_default = 1;
var $input = $wrapper.find('input[name=status],input[name=status\\[\\]],input[name=is_archived]');
var label = $.trim($item.text());
var curr_val = parseInt($input.val(), 10);
// the default for the archive/expires menu needs to be an emtpy string
if (is_archive_menu) {
val_default = "";
}
var val = typeof options[label] !== 'undefined' && options[label].id ? parseInt(options[label].id, 10) : val_default;
// show "Save These Changes" button if a change is made and we’re on a manager
if (LW.is_manager && val !== curr_val) {
LW.lib.changedData.show();
}
$item.addClass('selected').attr('aria-label', 'Current status: ' + label + '. Press Enter and use arrow keys to change status.').siblings().remove();
// close menu
$menu.removeClass('open').css('z-index', '');
// set input element
$input.val(val);
// register changes
manager_state.set($item.closest('li'));
// add sr only save button on managers
if (LW.is_manager) {
$menu.append('Save changes ');
}
if (typeof select_callback === 'function') {
select_callback.call(this, label);
}
LW.eventHub.trigger('statusMenuClose');
};
var openMenu = function openMenu($menu) {
var $option = $menu.children(':first-child');
var label = $.trim($option.text());
// remove any sr save links
$menu.find('.js_sr_manager_save_changes').remove();
// open menu
$menu.addClass('open');
// remove instructions
$option.attr('aria-label', label).attr('role', 'option');
// select current status in menu
$.each(options, function (key, value) {
if (key !== label) {
$menu.append('' + key + '
');
}
});
// change z-index of element
$menu.css('z-index', '10100');
/*
/* next body click or focus out re-selects the current option and closes the menu, if it's open
*/
// we name this function so we can remove the handler when we close the menu
var focusInClose = function focusInClose(e) {
if (!$(e.target).parent().is('.status.open,.archive.open') && $menu.hasClass('open')) {
selectMenuItem($option);
}
};
$body.focusin(focusInClose);
// remove close on focus out handler
LW.eventHub.bind('statusMenuClose', function () {
$body.off('focusin', focusInClose);
// unbind this handler
LW.eventHub.unbind('statusMenuClose');
});
$body.one('click', function () {
if ($menu.hasClass('open')) {
selectMenuItem($option);
}
});
};
$section.on('keydown', '.status:not(.status_static),.archive', function (e) {
var $menu = $(this);
var $item = $(e.target);
var $items, item_index;
// do nothing if this is the save changes button
if ($item.hasClass('js_sr_manager_save_changes')) {
return true;
}
// enter
if (e.keyCode === 13) {
e.preventDefault();
if ($menu.hasClass('open')) {
selectMenuItem($item);
} else {
openMenu($menu, $item);
}
}
// up
else if (e.keyCode === 38) {
e.preventDefault();
if (!$menu.hasClass('open')) {
openMenu($menu, $item);
}
$items = $item.parent().children();
item_index = $item.index();
if (item_index > 0) {
$items.eq(item_index - 1).trigger('focus');
} else {
$items.eq($items.length - 1).trigger('focus');
}
}
// down
else if (e.keyCode === 40) {
e.preventDefault();
if (!$menu.hasClass('open')) {
openMenu($menu, $item);
}
$items = $item.parent().children();
item_index = $item.index();
if (item_index + 1 === $items.length) {
$items.eq(0).trigger('focus');
} else {
$items.eq(item_index + 1).trigger('focus');
}
}
// escape
else if (e.keyCode === 27) {
if ($menu.hasClass('open')) {
selectMenuItem($item);
}
}
return true;
});
// open handler
$section.on('click', '.status:not(.status_static),.archive', function (e) {
var $menu = $(this);
var $target = $(e.target);
// do nothing if clicking SR save link
if ($target.hasClass('js_sr_manager_save_changes')) {
return true;
}
if ($menu.hasClass('open')) {
// the user has clicked the arrow if the menu is open and the target is the menu.
// We want to close the menu without changing the selection in this case
if ($target.hasClass('status')) {
selectMenuItem($menu.children(':first-child'));
}
// if the menu is open and the target isn't the menu, then we're in select mode,
// in which case we want to let the select handler handle the click. In both cases
// we want to return here.
return true;
}
// stop propagation so this event doesn't immediately close menu
e.stopPropagation();
// and open
openMenu($menu);
});
// select handler
$section.on('click', '.status:not(.status_static) > div,.archive > div', function (e) {
var $this = $(this);
// do nothing if menu not open
if (!$this.parent().hasClass('open')) {
return true;
}
e.stopPropagation();
selectMenuItem($this);
});
}
function initStatusSelector($section) {
var onSelect = function onSelect(label) {
var $this = $(this);
var $wrapper = $this.closest('.status_wrapper').parent();
var $canceled = $wrapper.find('input[name=is_canceled],input[name=is_canceled\\[\\]]'); // only for events
// set canceled status if on events manager and canceled status option present
// val for Canceled option is 1, so setting option to Canceled also sets the
// hidden status input to 1, or Live
if ($canceled.length) {
if ($this.hasClass('status_canceled')) {
$canceled.val(1);
} else {
$canceled.val('');
}
}
if (label.toLowerCase() === 'scheduled for...' || label === 'Planned') {
$('#status .golive').show();
} else {
$('#status .golive').hide().find('input').val('');
}
if (label === 'Hidden') {
if (!$('#status_notice').length) {
$('.submit').before('Note: Your item will be hidden until you make it live.
');
}
} else {
$('#status_notice').remove();
}
};
// call select menu handler
initSelectMenus($section, LW.statuses, onSelect);
}
function initArchiveSelector($section) {
// handler for menu item selection
var onSelect = function onSelect(label) {
if (label === 'Expires on...') {
$('#archived .expiration').show();
} else {
$('#archived .expiration').hide().find('input').val('');
}
};
// call select menu handler
initSelectMenus($section, LW.archives, onSelect);
}
/* Status dropdowns */
function initStatus($section) {
$section.find('.status').each(function () {
var $this = $(this);
var $inner_div = $this.find('.status_loading');
var content = $inner_div.html().replace(/</g, '<').replace(/>/g, '>');
var status_class = 'status_ready';
// wrap with div.status_wrapper if it's not there already
if (!$this.parent().hasClass('status_wrapper')) {
$this.wrap('
');
}
$this.parent().attr('aria-label', 'Status Selector');
if (content === 'Scheduled for...' && LW.module === 'events') {
content = 'Planned';
}
if (LW.statuses[content]) {
status_class = LW.statuses[content].style;
} else if (content === 'Canceled') {
status_class = 'status_canceled';
$inner_div.replaceWith('Canceled
');
} else if (content.match(/fa-chain/)) {
status_class = 'status_original_hidden';
$this.addClass('original_hidden');
}
$inner_div.removeClass('status_loading').addClass(status_class).html(content).attr('tabindex', '0').attr('aria-label', 'Current status: ' + content.replace(/<.+?>/g, '') + '. Press Enter and use arrow keys to change status.');
if (LW.is_editor && (content === 'Scheduled for...' || content === 'Planned')) {
$('#status .golive').show();
}
if (content === 'Hidden') {
if (!$('#status_notice').length) {
$('.submit').before('Note: Your item will be hidden until you make it live.
');
}
} else {
$('#status_notice').remove();
}
});
// attach selector handlers
initStatusSelector($section);
}
/*
* Balloons
* Load the balloons ('this' is the $item) and bind the onclick
*/
function initBalloons() {
var $item = $(this); // the current $item
var input = $item.find('.input_balloons'); // the input where the balloon count is stored
var count = parseInt(input.val(), 10); // get the initial balloon count
var sortval = $item.find('.sortorder').val(); // find this $item's value for sorting
var balloons = $item.find('.balloons'); // and the balloon div
var randStringPos = function randStringPos() {
return Math.floor(Math.random() * 3) * 26;
};
// (re)draw red & gold balloons
var drawBalloons = function drawBalloons() {
var i;
// append the add a balloon balloon
balloons.empty().append('
');
// add a balloon for each 1-point balloon
for (i = 0; i < count % 10; i++) {
balloons.append('
');
}
// and for each 10-point gold balloon
for (i = 0; i < Math.floor(count / 10); i++) {
balloons.append('
');
}
};
drawBalloons(); // draw the balloons
// clicking the first (gray) balloon
$item.on('click', '.balloon', function (e) {
LW.lib.changedData.show(); // show "Save These Changes" button
// are we adding or removing a balloon? (clicking the first ballon adds a balloon)
var direction = $(this).index() === 0 ? 1 : -1;
count += direction * (e.shiftKey ? 10 : 1); // increment/decrement the count (multipled by ten if shift is held)
if (count < 0) {
// if the count is less than zero
count = 0; // set it to zero
}
// set the value
input.val(count);
manager_state.set($item);
// if the balloon count is now a multiple of ten, we’re removing, or shift is depressed
if (count % 10 === 0 || direction === -1 || e.shiftKey) {
drawBalloons(); // just redraw the whole set
} else {
// we just need to add a single balloon
balloons.append('
');
}
// find the in-between $items
var between = $item[direction === 1 ? 'prevAll' : 'nextAll']().filter(function () {
var comp_count = parseInt($(this).find('.input_balloons').val(), 10); // the comparison count
if (comp_count * direction < count * direction) {
// if the compared $item has more/less balloons
return true; // include it
} else if (comp_count * direction > count * direction) {
// but if it has less/more
return false; // exclude it off the bat
}
var comp_sortval = $(this).find('.sortorder').val(); // the comparison sort value
// if it’s an int (probably timestamp), sort desc; otherwise, sort asc (alphabetical)
return direction === 1 && parseInt(sortval, 10) ? comp_sortval < sortval : comp_sortval > sortval;
});
if (between.length) {
// if there are elements between the current placement and the target placement
LW.whiteout.show(); // Add whiteout overlay to prevent interaction during animation
var last = between.eq(-1),
// the edgemost $item
distance = last.position().top - $item.position().top,
// we move from the current location to the edgemost result
duration = Math.min(Math.abs(distance) / 150 * 1000, 750); // move at 150 pixels-per-second, or for 3/4 second, whichever is less
between.animate({
top: $item.outerHeight() * direction + 'px'
}, duration, 'easeInSine'); // move in-between $items down
$item.css({
zIndex: 100,
backgroundColor: '#f8f8f8'
}) // set a temporary z-index and background color for moving
.animate({
top: distance + 'px'
}, duration, 'easeInQuad', function () {
// move up the $item, then
// wipe the temporary styles
$item.css({
top: '',
zIndex: '',
backgroundColor: ''
})[direction === 1 ? 'insertBefore' : 'insertAfter'](last); // and re-insert the $item in the correct place
between.css('top', 0); // also wiping the temporary offset for the between $items
LW.whiteout.hide(); // then hide the whiteout div to restore interactivity
});
}
})
// when hovering
.on('mouseenter', '.balloon', function () {
var $this = $(this);
// offset the background appropriately
if (0 !== $this.index()) {
$this.css('background-position', '-36px -' + randStringPos() + 'px');
}
})
// and hovering out
.on('mouseleave', '.balloon', function () {
var $this = $(this);
// reset the state based on whether it was a golden balloon
if (0 !== $this.index()) {
var pos = ($(this).hasClass('golden') ? '0' : '-18px') + ' -' + randStringPos() + 'px';
$this.css('background-position', pos);
}
});
}
// inits the suggestion manager
function initSuggestionManager() {
var $ul = $('ul.share_alerts');
var $lis = $ul.children();
var $wrap = $('
');
var count = $lis.length;
$ul.wrap($wrap);
// if there are more than 3 share alerts, convert to a show-all approach after the first 3
if (count > 3) {
// hide all but first three items
$lis.slice(3).hide();
var show_all = '' + 'Showing top 3. Show all ' + ' ';
var show_three = '' + 'Showing all. Show top 3 ' + ' ';
// insert show all toggle
$ul.before('' + count + ' items have been suggested to your group. ' + show_all + '
');
// IX - why doesn't this work when I attach the handler to the $wrap element
// show all handler
$('body').on('click', '.show_all_suggested', function (e) {
e.preventDefault();
// show "Show top 3" message
$(this).closest('.suggested_toggle').replaceWith(show_three);
// show everything
$lis.show();
return true;
});
$('body').on('click', '.show_three_suggested', function (e) {
e.preventDefault();
// show "show all message"
$(this).closest('.suggested_toggle').replaceWith(show_all);
// hide all but first three items
$lis.slice(3).hide();
return true;
});
}
$body.on('click', '.share_alerts .item_copy_link', function (e) {
e.preventDefault();
var $alert = $(this).closest('.alert');
var id = $alert.find('input[name=id]').val();
var tid = LW.lib.getQueryStringParam('tid');
var bid = LW.lib.getQueryStringParam('bid');
var $spinner = $('
').appendTo($alert);
if (id) {
window.location.href = '?' + LW.page + '&item_copy_link=' + id + (tid ? '&tid=' + tid : '') + (bid ? '&bid=' + bid : '');
} else {
LW.prompt('Error', 'Unable to find item ID.
', 'warning');
$spinner.remove();
}
return true;
})
// handle
.on('click', '.share_alerts .item_copy_copy', function (e) {
e.preventDefault();
var $alert = $(this).closest('.alert'),
id = $alert.find('input[name=id]').val(),
tid = LW.lib.getQueryStringParam('tid'),
bid = LW.lib.getQueryStringParam('bid');
var $spinner = $('
').appendTo($alert);
if (id) {
window.location.href = '?' + LW.page + '&item_copy_copy=' + id + (tid ? '&tid=' + tid : '') + (bid ? '&bid=' + bid : '');
} else {
LW.prompt('Error', 'Unable to find item ID.
', 'warning');
$spinner.remove();
}
return true;
})
// reject share suggestion when closing a share alert
.on('close.bs.alert', '.share_alerts .alert', function (e) {
var $alert = $(this),
id = $alert.find('input[name=id]').val(),
tid = LW.lib.getQueryStringParam('tid'),
bid = LW.lib.getQueryStringParam('bid');
var $spinner = $('
').appendTo($alert);
if (id) {
$.get('/livewhale/?' + LW.page + '&reject=' + id + (tid ? '&tid=' + tid : '') + (bid ? '&bid=' + bid : ''));
} else {
LW.prompt('Error', 'Unable to find item ID.
', 'warning');
$spinner.remove();
}
});
}
function addSuggestSelectAllSelectNone() {
var $group_suggest = $('.group_suggest');
var html;
html = '' + 'Select all | ' + 'Select none ' + '
';
$(html).on('click', '.select-all', function (e) {
e.preventDefault();
// if we're using a multisuggest
if ($group_suggest.hasClass('lw-multisuggest')) {
// first remove everything so we don't get duplicates
$.each(LW.groups, function (i, group) {
$group_suggest.multisuggest('removeItem', group.id);
});
// then add everything back
$.each(LW.groups, function (i, group) {
$group_suggest.multisuggest('addById', group.id);
});
}
// if we're using a multisuggest
if ($group_suggest.hasClass('lw-multiselect')) {
$group_suggest.find('li').each(function () {
$group_suggest.multiselect('selectItem', $(this));
});
}
return true;
}).on('click', '.select-none', function (e) {
e.preventDefault();
// if we're using a multisuggest
if ($group_suggest.hasClass('lw-multisuggest')) {
// remove everything
$.each(LW.groups, function (i, group) {
$group_suggest.multisuggest('removeItem', group.id);
});
}
// if we're using a multiselect
if ($group_suggest.hasClass('lw-multiselect')) {
$group_suggest.find('li').each(function () {
$group_suggest.multiselect('deselectItem', $(this));
});
}
return true;
}).insertBefore($group_suggest);
}
// inits the suggestion element on an editor
function initSuggestionEditor() {
var $wrapper = $('#suggest');
$wrapper.find('.group_suggest')[LW.groups.length > 20 ? 'multisuggest' : 'multiselect']({
name: 'suggested',
type: 'groups',
data: LW.groups,
selected: LW.editor.values.suggested
});
if (LW.groups.length > 10) {
$wrapper.find('#multisuggest-suggested').attr('aria-label', 'Type a group name to suggest to a group, or use the show all groups link to select from a list.');
}
if (LW.editor.suggested) {
$.each(LW.editor.suggested, function () {
$('#group' + this).trigger('click').next().addClass('selected');
});
}
if (LW.editor.copied_from && !$('#suggest input:checked').length) {
var msg;
msg = 'This is your copy of an item by ' + LW.editor.copied_from + ' , ' + 'but if you’ve made significant changes, you can ' + 'share it anyway. ';
// hide controls
$wrapper.find('.group_suggest_controls').hide();
// show shared item message
$wrapper.append('' + msg + '
');
// share anyway handler
$wrapper.on('click', '#shareanyway', function () {
$(this).parent().hide();
$wrapper.find('.group_suggest_controls').show();
return false;
});
}
if ($body.hasClass('admin-user')) {
addSuggestSelectAllSelectNone();
}
}
// check the form's field lengths
function checkFieldLengths() {
var results = [];
var fields = LW.editor.fields_length;
// for each field to check
$.each(fields, function (field) {
var $field = $('[name="' + field + '"]');
var name = fields[field][0];
var limit = fields[field][1];
// skip if field not found
if (!$field.length) {
return true;
}
// get string to count, strip html including entities if this is wysiwyg field
var val = $field.hasClass('wysiwyg') ? $($field.wysiwyg('val')).text() : $field.val();
// if length exceeds max
if (val.length && val.length > limit) {
results.push('The ' + name + ' field must be no greater than ' + limit + ' characters in length.');
}
});
return results;
}
function RelatedContent(related_items) {
var $wrapper = $('fieldset.related'),
$find_form = $wrapper.find('.related_find'),
$link_form = $(this.getLinkFormMarkup()).appendTo($wrapper),
$link_title = $link_form.find('#related_link_title'),
$link_url = $link_form.find('#related_link_url'),
$related = $('').appendTo($wrapper),
$content_search = $find_form.find('#related_search_container'),
$related_search = $content_search.find('#related_search'),
that = this;
this.$related = $related;
// init related search plugin
$related_search.relatedsearch({
is_backend: true,
select: function select(e, data) {
var existing = $related.find('#related_' + data.type + '_' + data.id).parent();
if (!existing.length) {
// strip tags from description
if (data.description) {
data.description = data.description.replace(/<\/?[^>]+>/gi, '');
}
$related.append(that.getRelatedItem(data.id, data.type, data.title, data.url));
}
$related_search.val('');
$content_search.hide();
$find_form.find('.related_active').removeClass('related_active');
}
});
$content_search.hide(); // hide search box initially
LW.lib.libraryDialog.bind('filelibraryselect', function (e, file) {
$related.append(that.getRelatedItem(file.id, 'files', file.title, file.url));
});
LW.lib.libraryDialog.bind('filelibraryclose', function (e, file) {
$find_form.find('.related_active').removeClass('related_active');
});
// toggle related content types
$find_form.on('click', '.related_type', function () {
var $this = $(this),
module = $this.attr('data-type');
$find_form.find('.related_active').removeClass('related_active');
$this.addClass('related_active');
// change the module option in the related search plugin
$related_search.relatedsearch('option', 'module', module);
// set default element visibility
$link_form.hide();
$content_search.hide();
if (module === 'urls') {
$link_form.show().find('input').eq(0).trigger('focus');
} else if (module === 'files') {
LW.lib.libraryDialog.open('file');
} else {
$content_search.show();
}
$related_search.val('').trigger('focus'); // reset search
return false;
});
// clicking the remove link
$related.on('click', '.related_remove', function () {
$(this).parent().remove();
})
// clicking to edit a link
.on('click', '.related_editlink', function (e) {
e.preventDefault();
// makes sure the find form is hidden and the link form is visible
$find_form.hide();
$link_form.show();
// set the title to this link’s title
$link_title.val($(this).parent().find('input[name="urls_title[]"]').val().replace(/"/g, '"'));
// and the URL to this link’s URL
$link_url.val($(this).parent().find('input[name="related_content[]"]').val());
// and removes the current version of the link
$(this).parent().remove();
return true;
})
// and activate the sortable
.sortable({
cancel: 'a,.related_remove',
containment: 'fieldset.related',
cursor: 'move',
placeholder: 'lw_placeholder',
handle: '.fa-arrows'
});
if (_.isArray(related_items)) {
this.loadRelatedItems(related_items);
}
// when typing in the link fields
$link_title.add($link_url).on('keydown', function (e) {
if (e.which === 13) {
// if enter is pressed
e.preventDefault(); // don’t submit the page form
$link_form.find('.related_link_add').trigger('click'); // submit the link
}
});
$('.related_cancel').on('click', function () {
$link_form.hide();
$content_search.hide();
$find_form.find('.related_active').removeClass('related_active');
$find_form.show(); // makes sure the find form is visible
return false;
});
$link_form.find('.related_link_add').on('click', function () {
var title = $.trim($link_title.val()).replace(/"/g, '"'),
// trim and encode quotes in the title
url = $.trim($link_url.val()).replace(/"/g, '"'); // trim and encode quotes in the URL
if (!url.match(/:\/\//) && url.substring(0, 1) !== '/') url = 'http://' + url; // enforce protocol
if (title && url) {
$related.append(that.getRelatedUrlItem(title, url)).sortable('refresh');
$link_title.add($link_url).val(''); // and blank the inputs
$link_form.hide(); // and hide the linkform
$find_form.find('.related_active').removeClass('related_active');
$find_form.show(); // makes sure the find form is visible
}
return false;
});
}
_.extend(RelatedContent.prototype, {
loadRelatedItems: function loadRelatedItems(related_items) {
var that = this;
if (!_.isArray(related_items)) return;
this.$related.empty();
// add items
_.each(related_items, function (item, index) {
if (item.module === "urls") {
that.$related.append(that.getRelatedUrlItem(item.title, item.url));
} else {
that.$related.append(that.getRelatedItem(item.id, item.module, item.title, item.url));
}
});
this.$related.sortable('refresh');
},
getLinkFormMarkup: function getLinkFormMarkup() {
var html;
html = '';
return html;
},
getRelatedItem: function getRelatedItem(id, type, title, url) {
var html;
html = '' + '' + title + ' ' + 'View ' + title + ' ' + '× ' + ' ' + ' ' + ' ' + ' ' + ' ';
return html;
},
getRelatedUrlItem: function getRelatedUrlItem(title, url) {
var $html = $(this.getRelatedItem('', 'urls', title, url));
$html.append(' ').find('.item_preview').after('Edit link ');
return $('
').append($html).html();
}
});
function GlobalBackend() {
this.$content = $('#content');
this.$footer = $('#footer');
this.init();
}
$.extend(GlobalBackend.prototype, {
init: function init() {
this.initAdminToolbar();
this.highlightActiveSubnavItem();
this.initShortcuts();
// make Bootstrap-style dropdowns behave like selects
$('.dropdown-menu li a').on('click', function () {
$(this).parents('.dropdown').find('.btn').html($(this).text() + ' ');
$(this).parents('.dropdown').find('.lw_dropdown_input').val($(this).data('value'));
});
// init accordions if plugin present
if ($.fn.lw_accordion && $('.lw_accordion').length) {
$('.lw_accordion').lw_accordion();
}
if (!_.isEmpty(LW.messages)) {
this.initMessages();
}
initGlobes();
LW.lib.initStars();
this.parseBackendWidgets();
this.initAlwaysPostCheckboxes();
this.initEditorShade();
},
initMessages: function initMessages() {
var $wrapper = $('#content > .container > .row > .main,#content > .container > .main');
var $messages;
$messages = !$('#lw_messages').length ? $('
').prependTo($wrapper) : $('#lw_messages');
$messages.html('');
$.each(LW.messages, function (type, data) {
var html;
// skip if there are no messages for this type
if (_.isEmpty(data) || data.length === 1 && !data[0]) {
return true;
}
// failure translates to danger
if (type === 'failure') {
type = 'danger';
}
html = '' + '
' + ' × ' + ' ';
if (data.length === 1) {
html += data[0];
} else {
html += '
';
$.each(data, function () {
html += '' + this + ' ';
});
html += ' ';
}
html += '
';
$messages.append(html);
});
},
// adds a hidden element kept in sync with the checkbox, so that all the checkbox elements POST every time
initAlwaysPostCheckboxes: function initAlwaysPostCheckboxes() {
var cb_count = 1;
$.each($('input[type="checkbox"].always-post'), function () {
var cb = $(this),
name = cb.attr('name');
if (name) {
cb.attr('name', 'always-post-checkbox' + cb_count);
cb.after(' ');
cb_count++;
}
});
$('body').on('change', 'input[type="checkbox"].always-post', function () {
if ($(this).next().is(':input')) {
$(this).next().val($(this).is(':checked') ? '1' : '');
}
});
$('input[type="checkbox"].always-post').trigger('change');
},
parseBackendWidgets: function parseBackendWidgets() {
// parse backend widgets
$.each($('.lw_widget'), function () {
var $widget = $(this);
var regex = new RegExp('^' + LW.liveurl_dir + '/widget/preview/');
if ($widget.attr('data-url') && regex.exec($widget.attr('data-url'))) {
$.get($widget.attr('data-url'), function (content) {
if (content.length) {
content = content.match(/]*>((.|[\n\r])*)<\/body>/im)[1];
content = content.replace(/';
$('body').append(str);
return true;
});
}
};
var eventSubscriptionEditor = {
init: function init() {
var $form = $('.editor-form'),
$reg = $('fieldset.registration'),
$reg_more = $('#registration_more', $reg),
$has_reg = $('#events_has_registration', $reg);
this.$form = $form;
this.$status = $('#status_wrapper', $form);
this.mode = $form.find('#item_id').val() ? 'edit' : 'add';
this.initSectionToggle();
this.initRsvp();
this.$registration = $reg; // define has registration checkbox click handler as named function so
// we can call it independently when the checkbox is already selected
var has_reg_click_handler = function has_reg_click_handler() {
$reg_more.slideToggle(); // expand/collapse content
};
$has_reg.on('click', has_reg_click_handler); // expand rsvp content if has reg checked
if ($has_reg.is(':checked')) has_reg_click_handler();
this.initLocationSelector();
this.initCost();
this.initOnline();
this.initEmailConfirmation(); // handle test feed button
$('.editor').on('click', '#test_feed input[type=button]', function () {
var $this = $(this),
$wrapper = $this.closest('#title_wrapper'),
$status = $wrapper.find('#test_feed_status'),
button = $this,
button_value = $this.val(),
url = $wrapper.find('#events_subscriptions_url').val(); // create status element
if (!$status.length) {
$status = $('
').appendTo($wrapper);
}
button.val('Please wait...');
$('#test_feed_status').html('');
if (url.match(/^[a-zA-Z]+?:\/\/[^/]+/)) {
// validate url
// fetch the feed analysis
$.getJSON(LW.lib.getAjaxUrl('testEventsFeed', {
url: url
}), function (data) {
button.val(button_value);
if (data.msg) {
$status.html(data.msg); // display status
if ($('#events_subscriptions_title').val() === '') {
// set feed title if we can
if (data.title) {
$('#events_subscriptions_title').val(data.title);
} else {
var m = url.match(/^[a-zA-Z]+?:\/\/([^/]+)/);
if (m && m[1]) {
$('#events_subscriptions_title').val('Events from ' + m[1].replace('www.', ''));
}
}
}
}
});
} else {
alert('You must enter a valid feed url.');
}
}); // click test button on blur
$('.editor').on('blur', '#events_subscriptions_url', function () {
$('#test_feed input[type=button]').trigger('click');
});
if ($('body.admin-user').length && 'edit' === this.mode) {
// if admin user editing existing feed
$('.submit-bar').find('.container').append(' Save calendar and reset all events in feed '); // add the save and reset button
$('.submit-bar .save-and-reset-button').on('click', function (e) {
// and handle the click with approval
e.preventDefault();
var approve = confirm('Are you sure you want to reset all events? Any per-event customizations or RSVPs will be lost.');
if (approve) {
$('.submit-bar').append(' ');
$('.submit-bar button[type=submit]').trigger('click');
}
;
});
}
;
}
};
_.extend(eventSubscriptionEditor, editorBase);
var eventEditor = {
init: function init() {
var that = this,
$form = $('.editor-form'),
$reg = $('fieldset.registration'),
$reg_more = $('#registration_more', $reg),
$has_reg = $('#events_has_registration', $reg);
this.$form = $form;
this.$status = $('#status_wrapper', $form);
this.$images = $('#images', $form);
this.$title = $('#item_title', $form);
this.mode = $form.find('#item_id').val() ? 'edit' : 'add';
this.is_linked_event = !!(LW.editor.parent && LW.editor.url);
this.repeat_date_changed = false;
this.initSectionToggle();
this.initStatus();
this.initRsvp(); // hide TZ if so configured
if (LW.disable_timezones) {
$('div.timezone').addClass('lw_hidden');
}
this.initEndDate();
if (!LW.events) LW.events = {}; // init LW.events
this.initRepeating();
this.$events_date = $('#events_date');
this.$registration = $reg; // set default date on date2 and repeats_until to that of start date
var defaultToStartDateHandler = function defaultToStartDateHandler() {
var startDate = that.$events_date.val();
if (startDate && !$(this).val()) {
$(this).val(startDate);
}
};
this.$events_date2 = $('#events_date2').datepicker('option', 'beforeShow', defaultToStartDateHandler);
this.$repeats_until = $('#events_repeats_until').datepicker('option', 'beforeShow', defaultToStartDateHandler);
this.$repeats_from = $('#events_repeats_from').datepicker();
this.$registration_open = $('#events_registration_open_date');
this.$registration_close = $('#events_registration_close_date'); // disable date and time fields if this is a linked event
if (this.is_linked_event) {
this.$events_date.prop('disabled', true);
this.$events_date2.prop('disabled', true);
$('#events_date_time').prop('disabled', true);
$('#events_date2_time').prop('disabled', true);
$('#timezones').prop('disabled', true);
$('#events_allday').prop('disabled', true);
$('#add_end_date').prop('disabled', true); // change details
$('#details').find('header > h2').hide().filter('.linked_event_detail_header').show();
} // set the date and time picker formats (euro or us) based on EVENT's current timezone
this.setDateTimeFormat($('input[name=timezone_format]').val());
this.toggleAllDay();
$('#events_allday').on('click', this.toggleAllDay);
$reg_more.removeClass('lw_hidden').slideUp(0); // toggle RSVP options
// define has registration checkbox click handler as named function so
// we can call it independently when the checkbox is already selected
var has_reg_click_handler = function has_reg_click_handler() {
$reg_more.slideToggle(); // expand/collapse content
};
$has_reg.on('click', has_reg_click_handler); // expand rsvp content if has reg checked
if ($has_reg.is(':checked')) has_reg_click_handler();
$('#revisions .cancel a').on('click', function () {
$(this).parent().parent().hide().prev().toggleClass('selected');
return false;
});
var change_modes = {
submit_button: 1,
submit_button_subsequent: 2,
submit_button_this: 3
};
var $submit = $('.submit-button,.submit-button-subsequent,.submit-button-this'); // set change mode
$submit.off('click').on('click', function (e) {
// enable repeats before submit
if (that.is_linked_event) {
$('.repeats_wrap').find('input,select').prop('disabled', false);
}
$('input[name=change_mode]').val(change_modes[$(this).attr('data-mode')]);
return true;
}); // add change-only-this submit handler that prompts user when repeat data has changed
$('.submit-button-this,.submit-button-subsequent').on('click', function () {
if (that.repeat_date_changed) {
var msg = 'Adjustments to the event series date and time cannot be customized on a per-event basis. ' + 'Click \'Ok\' to save all other changes.';
return confirm(msg);
}
});
LW.images_batch = [];
$('#eid_count').html(LW.events.eid_count);
$('#link_delete_series').on('click', function () {
if (confirm('Are you sure you want to delete all ' + LW.events.eid_count + ' events in this series?')) {
var id = $('#item_id').val();
window.location.href = '?' + LW.page + '&id=' + id + '&ds=' + LW.events.eid;
}
return false;
});
this.initLocationSelector();
if (!this.is_linked_event) {
this.initTimezoneSelector();
} // disable sharing if visibility != everyone
$('.editor').on('change', 'input[name="visibility"]', function () {
if ($(this).val() !== '1') {
$('#globe_wrap').attr('disabled', 'disabled');
if (parseInt($('input[name=is_shared]').val(), 10) === 1) {
$('#globe_wrap .globe').trigger('click');
}
} else {
$('#globe_wrap').removeAttr('disabled');
}
});
this.initCost(); // if not an existing series, OR if on the first event of a series,
// make events_repeats_from match events_date
if (!LW.events.eid || LW.events.eid && $('#events_date').val() == $('#events_repeats_from').val()) {
$('.editor').on('change', '#events_date', function () {
$('#events_repeats_from').val($('#events_date').val());
});
} // handle RSVP period selections
$('.date_time_rsvp_wrap').hide(); // hide the RSVP period section
$('.editor').on('change', '#date_time_rsvp_toggle', function () {
if ($(this).is(':checked')) {
$('.date_time_rsvp_wrap').slideDown(150);
} else {
$('.date_time_rsvp_wrap').slideUp(150);
}
});
$('.editor').on('change', '#events_date', function () {
// keep placeholder of close date in sync with event date
$('#events_registration_close_date').attr('placeholder', $('#events_date').val() ? $('#events_date').val() : 'Event date');
});
$('#events_date').trigger('change');
if ($('#events_registration_open_date').val() || $('#events_registration_open_time').val() || $('#events_registration_close_date').val() || $('#events_registration_close_time').val()) {
// if any part of the RSVP period section is filled out
$('#date_time_rsvp_toggle').trigger('click'); // click the box to expand this section
} // handle event planning
if ($('body.has_event_planning').length && LW.page !== 'events_sub_edit') {
// if event planning is enabled and not on a linked calendar event
this.initEventPlanning();
}
this.initOnline();
this.initEmailConfirmation();
if ($('#events_has_registration_reminder').is(':checked')) {
// if the registration reminder checkbox is set
$('#events_registration_reminder_text_wrapper').show(); // reveal the text field
}
$('.editor').on('change', '#events_has_registration_reminder', function () {
// upon clicking the checkbox
if ($(this).is(':checked')) {
// if it's checked
$('#events_registration_reminder_text_wrapper').show(); // reveal the text field
} else {
// else if it's not checked
$('#events_registration_reminder_text_wrapper').hide(); // hide the text field
}
});
if ($('#events_has_registration_followup').is(':checked')) {
// if the registration followup checkbox is set
$('#events_registration_followup_text_wrapper').show(); // reveal the text field
}
$('.editor').on('change', '#events_has_registration_followup', function () {
// upon clicking the checkbox
if ($(this).is(':checked')) {
// if it's checked
$('#events_registration_followup_text_wrapper').show(); // reveal the text field
} else {
// else if it's not checked
$('#events_registration_followup_text_wrapper').hide(); // hide the text field
}
}); // if this is a linked calendar event
if (LW.page === 'events_sub_edit') {
var was_customized_on_load = false;
if ($('.events_has_customized_description input').is(':checked')) {
// if the customized description checkbox is set
$('#events_description_fieldset').find('.events_description').hide(); // hide the non-editable description
$('#events_description_fieldset').find('.events_description_editable').show(); // and reveal the editable one
was_customized_on_load = true;
}
$('.editor').on('change', '.events_has_customized_description input', function () {
// upon clicking the checkbox
if ($(this).is(':checked')) {
// if it's checked
$('#events_description_fieldset').find('.events_description').hide(); // hide the non-editable description
$('#events_description_fieldset').find('.events_description_editable').show(); // and reveal the editable one
} else {
// else if it's not checked
if (was_customized_on_load) {
// only if description was already customized on page load
$('#events_description_fieldset').find('.events_description').html('Original description from feed will load when you save this event.
'); // set the read-only display of the original feed value to an instructional msg (because we don't have the original feed value anymore in this case)
}
$('#events_description_fieldset').find('.events_description').show(); // reveal the non-editable description (with msg about feed updating)
$('#events_description_fieldset').find('.events_description_editable').hide(); // and hide the editable one
}
});
if ($('.events_has_customized_location input').is(':checked')) {
// if the customized location checkbox is set
$('#events_location_fieldset').find('.events_location').hide(); // hide the non-editable location
$('#events_location_fieldset').find('.events_location_editable').show(); // and reveal the editable one
}
$('.editor').on('change', '.events_has_customized_location input', function () {
// upon clicking the checkbox
if ($(this).is(':checked')) {
// if it's checked
$('#events_location_fieldset').find('.events_location').hide(); // hide the non-editable location
$('#events_location_fieldset').find('.events_location_editable').show(); // and reveal the editable one
} else {
// else if it's not checked
$('#events_location_fieldset').find('.events_location').show(); // reveal the non-editable location
$('#events_location_fieldset').find('.events_location_editable').hide(); // and hide the editable one
}
});
if ($('.events_has_customized_contact_info input').is(':checked')) {
// if the customized contact_info checkbox is set
$('#events_contact_info_fieldset').find('.events_contact_info').hide(); // hide the non-editable contact_info
$('#events_contact_info_fieldset').find('.events_contact_info_editable').show(); // and reveal the editable one
}
$('.editor').on('change', '.events_has_customized_contact_info input', function () {
// upon clicking the checkbox
if ($(this).is(':checked')) {
// if it's checked
$('#events_contact_info_fieldset').find('.events_contact_info').hide(); // hide the non-editable contact_info
$('#events_contact_info_fieldset').find('.events_contact_info_editable').show(); // and reveal the editable one
} else {
// else if it's not checked
$('#events_contact_info_fieldset').find('.events_contact_info').show(); // reveal the non-editable contact_info
$('#events_contact_info_fieldset').find('.events_contact_info_editable').hide(); // and hide the editable one
}
});
if ($('.events_has_customized_cost input').is(':checked')) {
// if the customized cost checkbox is set
$('#events_cost_fieldset').find('.events_cost').hide(); // hide the non-editable cost
$('#events_cost_fieldset').find('.events_cost_editable').show(); // and reveal the editable one
}
$('.editor').on('change', '.events_has_customized_cost input', function () {
// upon clicking the checkbox
if ($(this).is(':checked')) {
// if it's checked
$('#events_cost_fieldset').find('.events_cost').hide(); // hide the non-editable cost
$('#events_cost_fieldset').find('.events_cost_editable').show(); // and reveal the editable one
} else {
// else if it's not checked
$('#events_cost_fieldset').find('.events_cost').show(); // reveal the non-editable cost
$('#events_cost_fieldset').find('.events_cost_editable').hide(); // and hide the editable one
}
});
}
},
initEndDate: function initEndDate() {
var $enddate = $('#events_enddate', this.$form),
$toggle = $('#add_end_date', this.$form); // show/hide end date toggle
$toggle.on('click', function (e) {
// clear input vals if we're hiding the enddate
if ($enddate.is(':visible')) {
$enddate.find('#events_date2').val('');
$enddate.find('#events_date2_time').val('');
}
$enddate.slideToggle();
return true;
});
if ($enddate.find('#events_date2').val() && !$enddate.is(':visible')) {
this.$form.find('#add_end_date').trigger('click');
}
},
initStatus: function initStatus() {
var $cancel_button = $('#cancel_button'),
$cancel_checkbox = $('#is_canceled'); // activate status button if is_canceled
if ($cancel_checkbox.prop('checked')) {
$cancel_button.addClass('active').text('Uncancel Event');
}
$cancel_button.on('click', function (e) {
$cancel_checkbox.trigger('click');
return true;
});
$cancel_checkbox.on('click', function (e) {
if ($cancel_checkbox.prop('checked')) {
$cancel_button.addClass('active').text('Uncancel Event');
} else {
$cancel_button.removeClass('active').text('Cancel Event');
}
return true;
});
},
initTimezoneSelector: function initTimezoneSelector() {
var that = this,
default_tz = null,
$startdate = $('#events_startdate'); // replaces the timezone select menu with a hidden form field that
// contains the selected value
var setTimezone = function setTimezone() {
var $tz = $startdate.find('.timezone'),
$sel = $startdate.find('option:selected'),
val = $sel.val(),
format_zone; // remove handler to remove select menu when clicking outside select menu
$('body').off('click', setTimezone); // replace content with abbreviation and hidden input field
$tz.html($sel.attr('data-tz-abbrv') + ' '); // set current val as default
default_tz = val; // set datepicker format on change
format_zone = parseInt($sel.attr('data-is-euro'), 10) ? 'euro' : 'us';
that.setDateTimeFormat(format_zone);
}; // toggle timezone
$startdate.on('click', '.timezone', function () {
var $this = $(this); // do nothing if select menu already there
if ($this.find('#timezones').length) {
return false;
} // set default timezone if it's not already set
if (!default_tz && $this.find('input[name=timezone]').length) {
default_tz = encodeURIComponent($this.find('input[name=timezone]').val());
}
$this.load(LW.lib.getAjaxUrl('getTimezoneSelector', {
preselect: default_tz
}), function () {
var val = $this.find('option:selected').val(); // include hidden input with default value in case user doesn't change value
$this.append(' '); // cancel timezone select when user clicks outside select menu
// this handler gets removed as soon as it's called
$('body').on('click', setTimezone);
});
}).on('change', '#timezones', setTimezone); // update the timezone label when an earlier version of the event is restored
LW.eventHub.bind('fieldUpdate.editor', function (e, data) {
if (data.name === 'timezone') {
var $tz = data.element.closest('.timezone');
var poll_cnt = 0;
if (!$tz.length) return; // we need to click the timezone wrapper, poll for the presence of the
// timezone select menu, then click the body to select the current value.
// Timeout after 5 seconds
$tz.trigger('click');
var interval_id = setInterval(function () {
if ($tz.find('#timezones').length || poll_cnt >= 25) {
$('body').trigger('click');
clearInterval(interval_id);
}
poll_cnt++;
}, 200);
}
});
},
// change the format used by jQuery UI datepicker widgets
setDateTimeFormat: function setDateTimeFormat(format_zone) {
var date_format = format_zone === 'euro' ? 'dd-mm-yy' : 'mm/dd/yy';
if ('euro' === format_zone) {
// setting these when 'us' zone and custom date format breaks the inputs for some reason
this.$registration_open.datepicker('option', 'dateFormat', date_format);
this.$registration_close.datepicker('option', 'dateFormat', date_format);
} // set date format
$('.hasDatepicker').datepicker('option', 'dateFormat', date_format);
},
toggleAllDay: function toggleAllDay() {
if ($('#events_allday').is(':checked')) $('.date_time .time').hide();else $('.date_time .time').show();
},
initRepeating: function initRepeating() {
var $wrap = $('.repeats_wrap'),
$repeats = $wrap.find('#events_repeats'),
$every_wrap = $wrap.find('#repeats_every'),
$every_unit = $every_wrap.find('#repeats_every_unit'),
$by_wrap = $wrap.find('#repeats_by'),
$by = $by_wrap.find('[name=repeats_by]'),
$on_wrap = $wrap.find('#repeats_on'),
$on_days = $wrap.find('#events_repeats_on_days'),
$days_wrap = $wrap.find('#repeats_on_days'),
$days = $days_wrap.children(),
$is_repeater = $('#events_is_repeater'),
that = this; // disable individual event deletion if this is an existing repeat series member
if (LW.events.eid) {
$('#delete').hide();
} // if euro TZ, move Sunday checkbox to end
if (LW.timezone_format === 'euro') {
$days.eq(0).insertAfter($days.eq(6));
}
$wrap.removeClass('lw_hidden').slideUp(0); // toggle repeat option section
$is_repeater.on('change', function () {
$wrap.slideToggle('fast');
if (!$(this).is(':checked')) {
// if it was previously checked
if (LW.enable_repeat_warning && $('#item_id').val()) {
// and this is a previously-saved event
var msg = 'Saving this event with repeats disabled will delete all other events in this series.';
if (!confirm(msg)) {
$wrap.slideToggle('fast');
return false;
}
}
$repeats.val('').trigger('change');
}
return true;
}); // expand repeat section if repeating event
if ($repeats.val()) {
$is_repeater.trigger('click');
LW.enable_repeat_warning = 1; // enable notifications when removing repeat mode (required so that it doesn't warn immediately on page load)
// set start/end date changed flag to true after second change event.
// it fires the first time on load
var date_change_cnt = 0;
$('#events_startdate,#events_enddate').on('change', 'input,select', function () {
if (date_change_cnt) {
that.repeat_date_changed = true;
}
date_change_cnt++;
});
} // toggle repeat on days section according to checkbox
$wrap.on('change', '#events_repeats_on_days', function () {
$days_wrap.toggleClass('lw_hidden'); // uncheck repeat on days if unchecking the whole section
if (!$on_days.is(':checked')) {
$days_wrap.find('input[name^="repeats_on"]:checked').prop('checked', false);
}
return true;
}); // if any repeats_on days checked, expand repeat on days section
if ($('input[name^="repeats_on"]:checked').length) {
$('#events_repeats_on_days').trigger('click');
} // toggle options associated with repeat mode
$repeats.on('change', function () {
// hide options if not repeating
if ($(this).val() === '') {
$wrap.find('#repeats_every').addClass('lw_hidden');
$wrap.find('#repeats_by').addClass('lw_hidden');
$wrap.find('#repeats_on').addClass('lw_hidden');
$wrap.find('#repeats_until').addClass('lw_hidden');
$wrap.find('#repeats_from').addClass('lw_hidden'); // if this is an existing repeating event, re-enable event date
if (LW.events.eid) {
$('#events_date').removeAttr('disabled');
$('#events_date_time').removeAttr('disabled');
$('#events_date2').removeAttr('disabled');
$('#events_date2_time').removeAttr('disabled');
if ($('#events_date').next().attr('name') === 'date') {
$('#events_date').next().remove();
}
}
} else {
// else if repeating
// if this is an existing repeating event, disallow editing date/time
// (unless it's the first event in the series)
if (LW.events.eid && $('#events_date').val() !== $('#events_repeats_from').val()) {
$('#events_date').attr('disabled', 'disabled');
$('#events_date_time').attr('disabled', 'disabled');
$('#events_date2').attr('disabled', 'disabled');
$('#events_date2_time').attr('disabled', 'disabled');
if ($('#events_date').next().attr('name') !== 'date') {
$('#events_date').after(' ');
}
} // always show repeats_from and repeats_until if repeating
$wrap.find('#repeats_from').removeClass('lw_hidden');
$wrap.find('#repeats_until').removeClass('lw_hidden'); // show repeats_every for daily, weekly, monthly, yearly
var mode = parseInt($(this).val(), 10);
if (mode === 1 || mode === 2 || mode === 3 || mode === 7) {
$every_unit.text(mode === 1 ? 'days' : mode === 2 ? 'weeks' : mode === 3 ? 'months' : 'years');
$every_wrap.removeClass('lw_hidden');
} else {
$every_wrap.addClass('lw_hidden');
} // show repeats_by for monthly
if (mode === 3) {
if (!$by.filter(':checked').val()) {
$by.eq(0).trigger('click');
}
$by_wrap.removeClass('lw_hidden');
} else {
$by_wrap.addClass('lw_hidden');
} // show repeats_on for weekly
if (mode === 2) {
$on_wrap.removeClass('lw_hidden');
} else {
$on_wrap.addClass('lw_hidden');
}
}
return true;
}); // if any of the repeat elements are changed
$('.editor').on('change', '.repeats_wrap input, .repeats_wrap select', function () {
$('#repeats_summary').html(''); // clear the current summary
var repeats = parseInt($('#events_repeats').val(), 10),
// fetch all repeats info
opts = $('.repeats_wrap'),
repeats_every = parseInt(opts.find('#events_repeats_every').val(), 10),
repeats_until = opts.find('#events_repeats_until').val(),
repeats_from = opts.find('#events_repeats_from').val(),
repeats_by = parseInt(opts.find('input[name="repeats_by"]:checked').val(), 10),
repeats_on = opts.find('input[name^="repeats_on"]:checked').length,
repeats_occurrences = parseInt(opts.find('#events_repeats_occurrences').val(), 10) || 0,
days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
summary = '',
months,
repeats_from_date,
repeats_until_date;
if (repeats_from) {
if (LW.timezone_format === 'euro') {
var from = repeats_from.split('-');
repeats_from_date = new Date(from[2], from[1] - 1, from[0]);
} else {
var _from = repeats_from.split('/');
repeats_from_date = new Date(_from[2], _from[0] - 1, _from[1]);
}
if (repeats_from_date) {
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
if (LW.timezone_format === 'euro') {
repeats_from = repeats_from_date.getDate() + ' ' + months[repeats_from_date.getMonth()];
} else {
repeats_from = months[repeats_from_date.getMonth()] + ' ' + repeats_from_date.getDate();
}
}
}
if (repeats_until) {
// format until date
if (LW.timezone_format === 'euro') {
var until = repeats_until.split('-');
repeats_until_date = new Date(until[2], until[1] - 1, until[0]);
} else {
var _until = repeats_until.split('/');
repeats_until_date = new Date(_until[2], _until[0] - 1, _until[1]);
}
if (repeats_until_date) {
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
if (LW.timezone_format === 'euro') {
repeats_until = repeats_until_date.getDate() + ' ' + months[repeats_until_date.getMonth()] + ' ' + repeats_until_date.getFullYear();
} else {
repeats_until = months[repeats_until_date.getMonth()] + ' ' + repeats_until_date.getDate() + ', ' + repeats_until_date.getFullYear();
}
}
}
if (repeats === 1) {
// daily
if (repeats_from && repeats_every && (repeats_until || repeats_occurrences > 1)) {
// if selections valid
summary = (repeats_every === 1 ? 'Repeats daily' : 'Repeats every ' + repeats_every + ' days') + ', from ' + repeats_from + ", " + (repeats_until ? ' until ' + repeats_until : repeats_occurrences + ' times');
}
} else if (repeats === 2) {
// weekly
if (repeats_from && repeats_every && (repeats_until || repeats_occurrences > 1)) {
// if selections valid
if (repeats_on) {
// format repeats_on days
var daysStr = [];
$('input[name^="repeats_on"]:checked').each(function () {
daysStr[daysStr.length] = days[$(this).val() - 1];
});
repeats_on = ' on ' + daysStr.join(', ');
}
summary = (repeats_every === 1 ? 'Repeats weekly' : 'Repeats every ' + repeats_every + ' weeks') + (repeats_on ? repeats_on : '') + ', from ' + repeats_from + ', ' + (repeats_until ? 'until ' + repeats_until : repeats_occurrences + ' times');
}
} else if (repeats === 3) {
// monthly
if (repeats_from && repeats_every && repeats_by && (repeats_until || repeats_occurrences > 1)) {
// if selections valid
var d = new Date(repeats_from_date),
// get count of weekday (i.e. fourth Friday, etc.)
month = d.getMonth(),
srcDate = repeats_from_date.getDate(),
targetDay = repeats_from_date.getDay(),
month_days = [],
weekday_count = 1;
if (repeats_by === 2) {
// format repeats_by if repeating by day of week
d.setDate(1);
while (d.getDay() !== targetDay) {
d.setDate(d.getDate() + 1);
}
month_days.push(d.getDate());
while (d.getMonth() === month) {
month_days.push(d.getDate());
d.setDate(d.getDate() + 7);
}
while (weekday_count < month_days.length && month_days[weekday_count] !== srcDate) {
weekday_count++;
}
}
summary = (repeats_every === 1 ? 'Repeats monthly' : 'Repeats every ' + repeats_every + ' months') + ' on ' + (repeats_by === 1 ? 'day ' + repeats_from_date.getDate() : 'the ' + (weekday_count === 1 ? 'first' : weekday_count === 2 ? 'second' : weekday_count === 3 ? 'third' : weekday_count === 4 ? 'fourth' : 'fifth') + ' ' + days[targetDay]) + ', from ' + repeats_from + ', ' + (repeats_until ? 'until ' + repeats_until : repeats_occurrences + ' times');
}
} else if (repeats === 4) {
// M-F
if (repeats_from && repeats_every && (repeats_until || repeats_occurrences > 1)) {
// if selections valid
summary = 'Repeats on weekdays, ' + (repeats_until ? 'starting ' + repeats_from + ' and ending ' + repeats_until : 'from ' + repeats_from + ', ' + repeats_occurrences + ' times');
}
} else if (repeats === 5) {
// M/W/F
if (repeats_from && repeats_every && (repeats_until || repeats_occurrences > 1)) {
// if selections valid
summary = 'Repeats on Monday/Wednesday/Friday, ' + (repeats_until ? 'starting ' + repeats_from + ' and ending ' + repeats_until : 'from ' + repeats_from + ', ' + repeats_occurrences + ' times');
}
} else if (repeats === 6) {
// T/R
if (repeats_from && repeats_every && (repeats_until || repeats_occurrences > 1)) {
// if selections valid
summary = 'Repeats on Tuesday/Thursday, ' + (repeats_until ? 'starting ' + repeats_from + ' and ending ' + repeats_until : 'from ' + repeats_from + ', ' + repeats_occurrences + ' times');
}
} else if (repeats === 7) {
// yearly
if (repeats_from && repeats_every && (repeats_until || repeats_occurrences > 1)) {
// if selections valid
summary = (repeats_every === 1 ? 'Repeats yearly' : 'Every ' + repeats_every + ' years') + ', from ' + repeats_from + ', ' + (repeats_until ? 'until ' + repeats_until : repeats_occurrences + ' times');
}
}
$('#repeats_summary').html(summary); // set new summary
return true;
});
$('#events_repeats').trigger('change'); // fire change on page load
// disable repeat controls if this is a repeating linked event
if (this.is_linked_event) {
$is_repeater.prop('disabled', true);
$wrap.find('input,select').prop('disabled', true); // readonly attribute doesn't work for checkboxes and selects and it doesn't give us the look
// that disabled does. Instead, create a hidden element for every repeat input with a value
// and disable all the original fields
/*
$wrap.find('input,select').each(function() {
let $el = $(this);
if ((!$el.is(':checkbox,:radio') && $el.val()) || ($el.is(':checkbox,:radio') && $el.prop('checked'))) {
$wrap.append(' ');
}
})
.prop('disabled', true);
*/
}
},
createPlanningPanel: function createPlanningPanel() {
var $planningPanel = $(document.createElement('div')).addClass('fields').attr('id', 'planning-panel');
var $planningPanelHeader = $('').appendTo($planningPanel);
var $planningPanelContent = $('
').appendTo($planningPanel); //enable show/hide toggle on header click
$planningPanelHeader.click(function (e) {
e.preventDefault();
$planningPanelContent.slideToggle();
});
$planningPanel.slideUp(0);
return $planningPanel;
},
updatePlanningPanel: function updatePlanningPanel() {
// Load planning panel and update panel content
var $planningPanel = $('#planning-panel');
var $planningPanelContent = $planningPanel.find('.fields-content').html(' Loading Events');
var $planningPanelHeader = $planningPanel.find('.header');
var $planningEventList = $planningPanelContent.find('.event-list');
var $planningLocationsList = $planningPanelContent.find('.locations-list');
var $date = $('#events_date').val();
var $date2 = $('#events_date2').val();
var $tz = $('input[name="timezone"]').val();
var $item_id = $('input[name="item_id"]').val();
if ($date.length) {
var newDate = new Date($date),
year = newDate.getFullYear(),
month = newDate.getMonth() + 1,
day = newDate.getDate(),
$date = year + '-' + (month < 10 ? '0' + month : month) + '-' + (day < 10 ? '0' + day : day);
}
;
if ($date2.length) {
var newDate = new Date($date2),
year = newDate.getFullYear(),
month = newDate.getMonth() + 1,
day = newDate.getDate(),
$date2 = year + '-' + (month < 10 ? '0' + month : month) + '-' + (day < 10 ? '0' + day : day);
}
;
var url = livewhale.liveurl_dir + '/events/planning/' + encodeURIComponent($date) + '/' + encodeURIComponent($date2) + '/' + encodeURIComponent($tz.replace('/', '|')) + '/' + encodeURIComponent($item_id);
$.ajax({
url: url,
dataType: "json",
success: function success(data) {
// update matching events count
$planningPanelHeader.find('.count').html('(' + data.length + ')'); // remove any existing locations and events list from panel content
$planningPanelContent.html(''); // process locations from results
var locations = _.map(data, function (event) {
return event.location;
});
locations = _.compact(locations);
locations = _.uniq(locations);
locations = locations.sort(function (a, b) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}); // add list of locations to panel
if (locations.length > 0) {
// create locations list and header if it doesn't already exist
if ($planningLocationsList.length < 1) {
$planningPanelContent.append('');
$planningLocationsList = $(document.createElement('ul')).attr('class', 'location-list').appendTo($planningPanelContent);
}
$planningLocationsList.html(''); // add locations to locations list
$(locations).each(function (i) {
var location = this.split(' - ');
var $locationItem = $(document.createElement('li')).attr('class', 'location').html(location[location.length - 1].replace('Location: ', ''));
$planningLocationsList.append($locationItem);
});
} // add list of events to panel
if (data.length > 0) {
if ($planningEventList.length < 1) {
$planningPanelContent.append('The following ' + $(data).length + ' ' + ($(data).length != 1 ? 'events happen' : 'event happens') + ' concurrently with this one: ');
$planningEventList = $(document.createElement('ol')).attr('class', 'event-list').appendTo($planningPanelContent);
}
$planningEventList.html('');
$(data).each(function () {
var $eventItem = $(document.createElement('li')).attr('class', 'event').html(this.title + ' ' + (this.location ? 'Location: ' + this.location : '') + ' Group: ' + this.group + ' Date: ' + this.date + ' ');
$planningEventList.append($eventItem);
});
} else {
$planningPanelContent.html(' No other events are happening at this time.
');
}
$planningPanel.slideDown();
}
});
},
initEventPlanning: function initEventPlanning() {
var $this = this,
$date_section = $('body').find('.fields_date_time');
$date_section.after($this.createPlanningPanel()); // add planning panel to the page
$date_section.on('change', '#events_date, #events_date_time, #timezones, #events_date2, #events_date2_time, #events_allday, #add_end_date', function () {
// update the planning panel
$this.updatePlanningPanel();
});
if ($('#item_id').val()) {
$this.updatePlanningPanel();
}
;
}
};
_.extend(eventEditor, editorBase);
function EventTypeManager() {
var $wrapper = $('#manager_content');
var $category_list = $('ul#manager_events_categories');
var category_type = $('input[name="type"]').val();
if (category_type === 'audience') {
$('#subnav_page_events_categories').removeClass('active');
$('#subnav_page_events_categories_aud').addClass('active');
} else if (category_type === 'campus') {
$('#subnav_page_events_categories').removeClass('active');
$('#subnav_page_events_categories_cam').addClass('active');
}
if (!$category_list.length && $('.lw_nonefound').length) {
$('.lw_nonefound').parent().append('');
$category_list = $('ul#manager_events_categories');
} // add new category
$('a.addnew').on('click', function (e) {
e.preventDefault();
var html;
if (!$('.new_category').length) {
if ($('.lw_nonefound').length) {
$('.lw_nonefound').remove();
}
html = '' + ' ' + '' + ' ';
$category_list.prepend(html).children().eq(0).find('a').trigger('click');
}
return true;
}); // when clicking a category to edit it
$wrapper.on('click', '.item_name a', function (e) {
e.preventDefault();
var $this = $(this),
category = $this.text(),
$item = $this.parent().hide(),
// select and hide item
html,
$form;
html = '' + ' ' + ' ' + 'or cancel ' + ' ';
$form = $(html).insertAfter($item);
$form.find('input[type=text]').val(category).trigger('focus').on('keypress', function (e) {
if (e.keyCode === 13) {
// capture enter
$(this).next().trigger('click');
return false;
}
});
return true;
}) // save category button - adds a new category
.on('click', '.category_save', function (e) {
var $this = $(e.currentTarget);
var $li = $this.closest('li');
var title = $this.prev().val();
var id = $li.find('input.with_this').val() || ''; // prompt user and return if saving/renaming to an existing event type
var titles = [];
$li.siblings().find('.item_name a').each(function () {
titles.push($(this).text());
});
if (_.includes(titles, title)) {
LW.prompt('Duplicate Event Type', 'An event type named "' + title + '" already exists.', 'failure');
return;
} // for UH Event Type featuree - LW.eventH
$('body').trigger('eventTypeManagerBeforeLoad');
var url_components = {
livewhale: 'ajax',
"function": 'saveEventsCategoriesTitle',
id: id,
title: encodeURIComponent(title),
type: category_type
};
$.getJSON('/livewhale/backend.php?' + $.param(url_components), function (data) {
var stars = {};
$category_list.children().each(function () {
var $input = $(this).find('.star input');
if ($input.length) {
stars[this.id] = $input.val(); // store the star state
}
});
var list_url = '/livewhale/backend.php';
var list_url_comps = {
livewhale: 'ajax',
"function": 'getEventsCategoriesList',
type: category_type
}; // reset stars
$wrapper.load(list_url + '?' + $.param(list_url_comps), function () {
// IX - I don't love this setting this global-live var again here. Refactor soon
$category_list = $('#manager_events_categories');
$.each(stars, function (id, value) {
$category_list.find('li#' + id + ' .star input').val(value);
});
LW.lib.initStars(); // re-initialize stars
// for UH Event Type featuree - LW.eventH
$('body').trigger('eventTypeManagerLoad');
});
$li.find('.item_name a').text(title).parent().show();
$li.find('.category_edit_form').remove(); // prompt user if backend returns an error, which can be for duplicate event types
if (data.error) {
LW.prompt('Duplicate Event Type', data.error, 'failure');
}
});
return true;
}).on('click', '.lw_cancel a', function (e) {
e.preventDefault();
var $this = $(this),
$li = $this.closest('li'),
$item = $li.find('.item_name');
if (!$item.text()) {
// if this is a new category
$li.remove(); // kill the whole li
if (!$category_list.children().length) {
// if this was the last li
$category_list.append('None found. ');
}
} else {
$item.show(); // show the category
$li.find('.category_edit_form').remove(); // and remove the editor
}
return true;
}); // attach click to dropdown
$('#dropdown_checked').on('change', function () {
var $this = $(this);
var html = '';
$('#dropdown_merge').html(''); // do nothing if not merging events categories
if ($this.val() !== 'events_categories_merge') {
return true;
} // add option for each checked category
$category_list.children().each(function () {
var $li = $(this);
var $with_this = $li.find('input.with_this');
if ($with_this.prop('checked')) {
html += '' + $li.find('.item_name > a').text() + ' ';
}
}); // add merge_as dropdown if items were checked
if (html) {
html = 'Merge event types as: ' + '' + ' ' + html + ' ';
} else {
// else if no items checked
alert('You must first select the event type you wish to merge.'); // give error
$('#dropdown_checked').val(''); // clear dropdown selection
} // set merge_as menu
$('#dropdown_merge').html(html);
return true;
});
}
function EventManager() {
// toggle dropdown for the "Apply category..." item
$('#dropdown_checked').on('change', function () {
var $event_type = $('#apply_category_container').hide();
var $campus = $('#apply_category_campus_container').hide();
var $audience = $('#apply_category_audience_container').hide();
if ($(this).val().indexOf('_apply_category_campus') !== -1) {
$campus.show();
} else if ($(this).val().indexOf('_apply_category_audience') !== -1) {
$audience.show();
} else if ($(this).val().indexOf('_apply_category') !== -1) {
$event_type.show();
}
}); // and activate the "new" choice in that dropdown
$('.apply_category_container').on('change', 'select', function () {
if (!$(this).next().is('input[type=text]')) {
$(this).after(' ');
}
if ($(this).val() !== '' && parseInt($(this).val(), 10) === 0) {
$(this).next().show();
} else {
$(this).next().hide();
}
});
$('.item_archive').on('click', function () {
if (confirm('Are you sure you wish to archive this item?')) {
var id = $(this).parents('li').find('input[name="events[]"]').val();
$.get(LW.lib.getAjaxUrl('setEventsArchived', {
id: id
}));
$(this).parents('li').remove();
}
return false;
});
}
var events_import_csv = {
init: function init() {
var $upload_wrap = $('.js-upload-wrap');
var $upload_button = $upload_wrap.find('.js-upload-button');
var $upload = $upload_wrap.find('.js-upload'); // remove uploaded file handler
$upload_wrap.on('click', '.js-upload-remove', function () {
$upload.hide();
$upload_button.show();
});
$('#csv_file').uploader('upload', 'csv', {
onSuccess: function onSuccess(e, data) {
$upload.find('.js-upload-name').text(data.files[0].name).end().show();
$upload_button.hide();
}
});
}
};
var events_export_csv = {
init: function init() {
$('body').on('click', '#export_now', function () {
// handle export link
document.location.href = LW.liveurl_dir + '/events/csv/group/' + LW.gid;
return false;
});
}
}; // on DOM ready
$(function ($) {
// Actions to perform only on specific pages
switch (LW.page) {
case 'events_list':
LW.page_obj = new EventManager();
break;
case 'events_registrations':
$('#show').on('change', function () {
if ($('#show').val()) window.location.href = '?events_registrations&show=' + $('#show').val();
});
break;
case 'events_edit':
case 'events_sub_edit':
eventEditor.init();
break;
case 'events_registrations_list':
$('.events_registrations_comments_by_editor').on('keypress', function (e) {
LW.lib.changedData.show(); // show "Save These Changes" button
LW.manager.manager_state.set($(e.currentTarget).closest('tr'));
});
$('#events_registrants_printable').on('click', function () {
window.open(this.href);
return false;
}); // add extra confirmation for canceling registrations
$('.with_checked').on('click', 'input[type=submit]', function () {
if ($('#dropdown_checked').val() === 'events_registrations_cancel') {
var approve = window.confirm('Are you sure you want to cancel these reservations? If a waitlist is in effect, the freed positions will be given to waitlisted individuals.');
if (!approve) {
return false;
}
}
});
$('.manager').on('click', '.email_registrants', function () {
var $submit = $('Send message ');
var overlay = $('
').overlay({
title: 'Enter a message to send to all registrants',
footer: $submit,
closeSelector: '.lw_cancel a'
});
$submit.on('click', function (e) {
var spinner = $('
').appendTo(overlay);
var form_data = $('#lw_email_registrants').serialize();
$.post(LW.lib.getAjaxUrl('emailEventRegistrants', {
id: LW.event_id
}), form_data, function (response) {
spinner.remove(); // remove the spinner
if (response.error) {
LW.prompt('Error', response.error, 'failure');
} else {
overlay.overlay('destroy'); // close the overlay
LW.prompt('Success', 'Your email has been sent.', 'success');
}
}, 'json');
return false; // don’t submit the form
});
return false; // cancel the click
});
break;
case 'events_categories':
LW.manager.page = new EventTypeManager();
break;
case 'events_subscriptions_edit':
eventSubscriptionEditor.init();
break;
case 'events_import_csv':
events_import_csv.init();
break;
case 'events_export_csv':
events_export_csv.init();
break;
} // manually refresh a subscription
$('#events_subscriptions .refresh_subscription').on('click', function () {
var status = $(this);
status.html('Refreshing, please wait...');
$.ajax({
url: LW.lib.getAjaxUrl('refreshEventsSubscription', {
id: status.attr('data-subscription-id'),
is_async: '',
force_refresh: 1
}),
dataType: 'json',
success: function success(data) {
if (data.html) {
status.html(data.html);
}
},
timeout: 120000 // 120 second timeout
});
return false;
});
function promptForDeleteAction(id) {
var footer = '' + '
' + ' Delete all events' + ' ' + '
' + ' Keep all events' + ' ' + '
or cancel ' + '
';
var $footer = $(footer).on('click', '.lw_delete', function (e) {
e.preventDefault();
document.location.href = '/livewhale/?events_subscriptions&d=' + id + '&m=1';
return true;
}).on('click', '.lw_keep', function (e) {
e.preventDefault();
document.location.href = '/livewhale/?events_subscriptions&d=' + id + '&m=2';
return true;
});
$('When deleting this linked calendar, do you want to delete all its events or keep them? If you choose "keep all events" they will become native, fully-editable LiveWhale events and will no longer stay in sync with the source feed.
').overlay({
destroyOnClose: true,
closeOnBodyClick: true,
closeButton: true,
closeSelector: '.lw_cancel',
title: 'Delete linked calendar',
footer: $footer
});
} // confirm before deleting subscription (manager)
$('#events_subscriptions .events_unsubscribe').on('click', function (e) {
e.preventDefault();
var id = $(e.currentTarget).attr('data-subscription-id');
promptForDeleteAction(id);
return true;
}); // confirm before deleting subscription (editor)
$('#events_subscriptions_edit #delete').off('click').on('click', function (e) {
e.preventDefault();
var id = $('#item_id').val();
promptForDeleteAction(id);
return true;
}); // open details in planning view
$('#events_planning').on('click', '.pl_event', function () {
$(this).toggleClass('open');
$(this).find('i.fa').toggleClass('fa-caret-right');
$(this).find('i.fa').toggleClass('fa-caret-down');
});
});
})(livewhale);
"use strict";
/*
* feeds module
*/
(function (LW, global) {
// only run on news an event import pages
if (LW.page !== 'news_import' && LW.page !== 'events_import') {
return;
} // select all handler
$('.feeds_select_all').on('click', function () {
var $this = $(this);
if (!$this.text().match(/deselect/i)) {
$('#feeds_results input[type=checkbox]').prop('checked', true);
$this.html('(Deselect all)');
} else {
$('#feeds_results input[type=checkbox]').prop('checked', false);
$this.html('(Select all)');
}
return false;
});
})(livewhale, window);
"use strict";
(function (LW, global) {
// do nothing if not the files module
if (LW.module !== 'files') {
return;
}
var files = {
init: function init() {
// bulk uploader
$('#files_bulk_add').uploader('uploadBatch', 'files', {
mode: 'files_upload_batch',
multiple: true,
onSuccess: function onSuccess(e, data) {
window.location.href = '?files';
}
});
this.initDragToUpload(); // archive link handler
$('#manager').on('click', '.item_archive', function (e) {
var $this = $(e.currentTarget);
var id = $this.closest('li').find('input[name="files[]"]').val();
if (id && confirm('Are you sure you wish to archive this item?')) {
$.get(LW.lib.getAjaxUrl('setFilesArchived', {
id: id
}), function () {
$this.closest('li').remove();
});
}
return false;
});
},
initDragToUpload: function initDragToUpload() {
var $target = $('#drag-target');
var $instructions = $target.find('.instructions');
var original_text = $instructions.html();
$target.uploader('uploadDropzone', 'files', {
mode: 'files_upload_batch',
multiple: true,
dropZone: $target,
onSuccess: function onSuccess(e, data) {
window.location.href = '?files';
}
}); // drag event handlers
$target.on({
dragenter: function dragenter(e) {
$(this).addClass('on');
$instructions.html('Now let go!');
},
dragover: function dragover(e) {
$(this).addClass('on');
$instructions.html('Now let go!');
},
dragleave: function dragleave(e) {
$(this).removeClass('on');
$instructions.html(original_text);
},
drop: function drop(e) {
$(this).removeClass('on');
$instructions.html(original_text);
}
});
}
};
var files_edit = {
init: function init() {
var $wrapper = $('fieldset.upload');
$('.upload_select').uploader('upload', 'files', {
onSuccess: function onSuccess(e, data) {
$wrapper.find('.upload_title').text(data.result.name);
LW.eventHub.trigger('upload.editor', [data]);
}
});
}
};
var files_import_csv = {
init: function init() {
var $upload_wrap = $('.js-upload-wrap');
var $upload_button = $upload_wrap.find('.js-upload-button');
var $upload = $upload_wrap.find('.js-upload'); // remove uploaded file handler
$upload_wrap.on('click', '.js-upload-remove', function () {
$upload.hide();
$upload_button.show();
});
$('#csv_file').uploader('upload', 'csv', {
onSuccess: function onSuccess(e, data) {
$upload.find('.js-upload-name').text(data.files[0].name).end().show();
$upload_button.hide();
}
});
}
};
var files_export_csv = {
init: function init() {
$('body').on('click', '#export_now', function () {
// handle export link
document.location.href = LW.liveurl_dir + '/files/csv/group/' + LW.gid;
return false;
});
}
};
var page; // execute per page JS on DOM ready
switch (LW.page) {
case 'files':
files.init();
break;
case 'files_edit':
files_edit.init();
break;
case 'files_import_csv':
files_import_csv.init();
break;
case 'files_export_csv':
files_export_csv.init();
break;
}
return page;
})(livewhale, window);
"use strict";
(function (LW, global) {
// do nothing if this is not a galleries module
if (LW.module !== 'galleries') {
return;
}
function galleriesPage() {
$('#manager').on('click', '.code_link', function (e) {
e.preventDefault();
var $target = $(e.target),
html = $target.next().find('.code_textarea').html(); // return if the plugin is attached to this element i
// this allows plugin to close currently open hoverbox
if ($target.hasClass('lwui-widget')) return true;
e.stopPropagation();
$(e.target).hoverbox({
autoOpen: true,
position: 'right',
html: html,
maxWidth: 500,
beforeOpen: function beforeOpen() {
// close any open hoverbox
$('body').trigger('click');
},
close: function close() {
$(this).hoverbox('destroy');
}
});
return true;
}); // archive gallery handler
$('.item_archive').on('click', function (e) {
if (confirm('Are you sure you wish to archive this item?')) {
var $li = $(e.currentTarget).closest('li');
var url = LW.lib.getAjaxUrl('setGalleriesArchived', {
id: $li.find('input[name="galleries[]"]').val()
});
$.get(url);
$li.remove();
}
return false;
});
}
function galleriesEditor() {
var $photos = $('#gallery_photos'),
$selected = $(''),
$thumb_id = $('#lw_cropper_image_id'),
$thumb_coords = $('#lw_cropper_coordinates'),
$thumb_map = $('#lw_cropper_map'),
$preview = $('.galleries_thumbnail img');
var gallery_items = {
items: [],
addItem: function addItem(item) {
this.items.push(item);
},
removeItem: function removeItem(item_id) {
this.items = _.filter(this.items, function (item) {
return parseInt(item.id, 10) !== parseInt(item_id, 10);
});
},
getItems: function getItems() {
return this.items;
}
};
if (!$preview.length) {
$preview = $(' ').hide().appendTo('.galleries_thumbnail');
}
function setPreviewImage(id, coords, image_src) {
$thumb_id.val(id || '');
$thumb_coords.val(coords || '');
$thumb_map.val(1);
$preview.attr('src', image_src || '');
if (image_src) {
$preview.show();
} else {
$preview.hide();
}
}
$selected.appendTo($photos).on('click', '.lw_images_remove', function (e) {
e.preventDefault();
var id = $(this).parents('li').data('item').id;
removeItem(id);
$library.library('deselect', id, true);
return true;
}).on('click', 'img', function () {
LW.previewImage($(this).closest('li').data('item').preview_sm);
}).on('click', '.image-alt-link', function (e) {
e.preventDefault();
var data = $(this).closest('li').data('item');
LW.lib.openAltTextOverlay(data.id, data.alt);
}).sortable({
cancel: 'a,img,textarea,.lw_nonefound',
containment: $photos.parent(),
cursor: 'move',
placeholder: 'lw_placeholder',
stop: function stop(e, ui) {
// the iframe gets reset when we dom is updated, and so we need to re-initize the wysiwyg
ui.item.find('[name="captions[]"]').wysiwyg('destroy').wysiwyg({
limited: true,
init: function init(e, data) {
var id = data.editor.id; // show the thumbnail controls when wysiwyg finished initializing
$('#' + id + '_ifr').closest('li').find('.lw_thumbnail_controls').css('visibility', 'visible');
},
tiny_options: {
height: 115
}
});
}
});
var addItem = function addItem(item, is_saved_item) {
var thumb_src_region = '';
var caption = item.caption || '';
var is_preview_image = false;
var gallery_image_data, str, $item; // set this as the preview/cover image if it was previously saved as the
// cover image, or if this is the first image being added to the gallery
if (LW.editor.thumb_id && parseInt(LW.editor.thumb_id, 10) === parseInt(item.id, 10) || !is_saved_item && $selected.children().length === 1) {
is_preview_image = true;
}
gallery_items.addItem(item); // add/override with any data specfic to gallery
if (_.has(LW.editor, 'images')) {
gallery_image_data = _.find(LW.editor.images, function (obj) {
return parseInt(obj.id, 10) === parseInt(item.id, 10);
});
if (gallery_image_data) {
if (gallery_image_data.thumb_src_region) {
thumb_src_region = gallery_image_data.thumb_src_region;
item.thumb_src_region = thumb_src_region;
} // use previously saved value, even when empty. The user needs to be able to wipe the caption
if (_.has(gallery_image_data, 'caption')) {
caption = gallery_image_data.caption || '';
item.caption = caption;
} // thumbnail specific to gallery
if (gallery_image_data.thumbnail) {
item.thumbnail = gallery_image_data.thumbnail;
}
}
}
str = '' + ' ' + 'ALT ' + '' + '' + caption + ' ' + '
' + ' ' + ' ' + ' ' + ' ';
$item = $(str).data('item', item);
$selected.append($item).sortable('refresh').find('li.lw_nonefound').hide();
if (!item.alt) {
$item.find('.image-alt-link').hide();
}
$item.find('[name="captions[]"]').wysiwyg({
limited: true,
init: function init(e, data) {
var id = data.editor.id; // show the thumbnail controls when wysiwyg finished initializing
$('#' + id + '_ifr').closest('li').find('.lw_thumbnail_controls').addClass('visible');
},
tiny_options: {
height: 115
}
});
if (is_preview_image) {
setPreviewImage(item.id, thumb_src_region, item.thumbnail);
}
};
var removeItem = function removeItem(item_id) {
var curr_thumb_id = parseInt($thumb_id.val(), 10),
curr_thumb_match,
is_last_image,
$li;
gallery_items.removeItem(item_id); // remove item
$selected.find('#lw_item_' + item_id).remove();
is_last_image = $selected.children().length === 1; // if current thumb id is not available via $thumb_id, then we need to get it from the preview src
if (!curr_thumb_id && $preview.attr('src')) {
curr_thumb_match = $preview.attr('src').match(/\/(\d+)[^/]*$/);
if (curr_thumb_match.length === 2) {
curr_thumb_id = parseInt(curr_thumb_match[1], 10);
}
} // select first image as cover thumbnail if this was the cover image
if (parseInt(item_id, 10) === curr_thumb_id && !is_last_image) {
$li = $selected.children(':not(.lw_nonefound)').first();
$li.find('.lw_main_thumbnail').trigger('click');
} // show no images and remove cover thumbnail if this was the last image
if (is_last_image) {
$selected.find('li.lw_nonefound').show();
setPreviewImage();
}
}; // livewhale.editor.images is propagated when user selects images from image manager and chooses to
// create gallery with images. thus its presence alone does indicate that this is a saved item
_.each(LW.editor.images, function (item) {
var is_saved_item = LW.editor.id ? true : false;
addItem(item, is_saved_item);
});
var $library = $('#library').library({
type: 'images',
select: function select(event, data) {
addItem(data.item);
},
deselect: function deselect(event, item_id) {
removeItem(item_id);
},
load: function load() {
// highlight gallery items in library pane, third param tells select method not to trigger
// a select event, which would cause addItem to be called a second time
_.each(gallery_items.getItems(), function (item) {
$library.library('select', item.id, true, false, true);
});
}
}).on('click', 'img', function () {
LW.previewImage($(this).parent().data('item').preview_sm);
});
$('#upload_button').uploader('uploadBatch', 'images', {
mode: 'images_upload_batch',
multiple: true,
onSuccess: function onSuccess(e, data) {
// once complete
$.each(data, function (index, item) {
addItem(item);
$library.library('refresh');
});
}
}); // choosing a different cover image
$photos.on('click', 'a.lw_main_thumbnail', function () {
var $li = $(this).closest('li'),
id = $li.find('input[name="images[]"]').val(),
coords = $li.find('input[name="thumb_src_regions[]"]').val(),
src = $li.data('item').thumbnail; // reset all cover image links
$li.siblings().find('.lw_main_thumbnail').replaceWith('Use as cover image '); // set the new cover image label
$li.find('.lw_main_thumbnail').replaceWith('Cover image '); // set cover thumbnail inputs
setPreviewImage(id, coords, src);
return false;
});
var $crop_item;
$photos.on('click', '.lw_make_thumbnail', function (e) {
e.preventDefault();
var $this = $(this),
$li = $this.closest('li'),
$coords = $li.find('[name="thumb_src_regions[]"]'),
coord_str = $coords.val(),
data = $li.data('item'),
coords = [];
$crop_item = $li;
if (coord_str) {
coords = _.map(coord_str.split(','), function (val) {
return parseInt(val, 10);
});
}
this.cropper = new livewhale.lib.CropDialog({
aspect_ratio: '1:1',
hide_aspect_ratio_menu: true,
title: 'Set thumbnail image'
});
this.cropper.bind('save', function (e, crop_data) {
var coord_str = crop_data.coords.join(','); // do nothing if not current crop item set
if (!$crop_item || !$crop_item.length) return;
$crop_item.find('[name="thumb_src_regions[]"]').val(coord_str);
$crop_item.find('[name="thumb_src_regions_map[]"]').val(1);
var item_data = $crop_item.data('item');
var src = '/livewhale/?livewhale=images_preview&is_thumb=true&id=' + item_data.id + '&cropper_src_region=' + coord_str;
$crop_item.find('img').attr('src', src);
item_data.thumbnail = src;
if (parseInt($thumb_id.val(), 10) === parseInt(item_data.id, 10)) {
setPreviewImage(item_data.id, coord_str, src);
}
});
this.cropper.open(data.url, data.width, data.height, coords);
return true;
}); // add caption validation
window.extra_validation = function () {
var is_valid = true; // iterate through selected images and make sure each has a caption
$('.lw_images_selected li').each(function () {
var $textarea = $(this).find('textarea');
if ($textarea.length && !$textarea.val()) {
is_valid = false;
var msg = 'Please ensure that all gallery images have captions before you attempt to save.';
LW.prompt('Captions Required', msg, 'failure');
return false; // immediately break from loop
}
});
return is_valid;
};
} // call JS for appropriate page on DOM ready
switch (LW.page) {
case 'galleries':
galleriesPage();
break;
case 'galleries_edit':
galleriesEditor();
break;
}
})(livewhale, window);
"use strict";
(function (LW, global) {
var editor = {
init: function init() {
$('body').on('click', '.fields_group_authorization input[type="checkbox"]', function () {
if ($('#item_id').length && $('#item_id').val() && $(this).is(':checked')) {
var approve = window.confirm('Are you sure you wish to authorize all groups? Any groups that have previously disabled this item will gain access to it again.');
return approve;
}
});
}
};
if (LW.page === 'groups_edit' || LW.page === 'blurbs_type_edit' || LW.page === 'profiles_type_edit' || LW.page === 'widgets_edit') {
editor.init();
}
})(livewhale, window);
"use strict";
(function (LW, global) {
// only execute if groups module
if (LW.module !== 'groups') {
return;
}
var groups = {
expanded: [],
init: function init() {
var _this = this;
var has_local = LW.lib.localStore.has();
var $groups = $('#manager_groups');
var $items = $groups.find('.panel'); // expand groups that were expanded on last visit
if (has_local && localStorage.expandedGroups) {
var _groups = localStorage.expandedGroups.split(',');
for (var i = 0; i < _groups.length; i++) {
$items.filter('#item' + _groups[i]).find('.collapse-toggle').trigger('click');
}
}
$groups.on('show.bs.collapse', function (e) {
var gid = $(e.target).closest('.panel').attr('id').replace('item', '');
_this.addToExpanded(gid);
}).on('hide.bs.collapse', function (e) {
var gid = $(e.target).closest('.panel').attr('id').replace('item', '');
_this.removeFromExpanded(gid);
});
$('#user_table_controls').on('click', 'a', function (e) {
e.preventDefault();
var $this = $(e.currentTarget);
if ($this.hasClass('close_all')) {
$items.find('.panel-collapse.in').collapse('hide');
}
if ($this.hasClass('open_all')) {
$items.find('.panel-collapse:not(".in")').collapse('show');
}
return true;
});
},
addToExpanded: function addToExpanded(gid) {
if (!_.includes(this.expanded, gid)) {
this.expanded.push(gid);
}
localStorage.expandedGroups = this.expanded.join(',');
},
removeFromExpanded: function removeFromExpanded(gid) {
if (_.includes(this.expanded, gid)) {
this.expanded = _.without(this.expanded, gid);
}
localStorage.expandedGroups = this.expanded.join(',');
}
};
var users = {
addChangePrimaryGroupMenuToggle: function addChangePrimaryGroupMenuToggle() {
$('#dropdown_checked').on('change', function (e) {
if ($(e.currentTarget).val() === 'change_primary_group') {
$('#change_primary_group').show();
} else {
$('#change_primary_group').hide();
}
return true;
});
}
};
var groups_users = {
init: function init() {
this.addChangePrimaryGroupMenuToggle();
var logged_in = $('.logged_in').length; // display total logged in
$('.manager_select_all').after('' + logged_in + ' user' + (logged_in !== 1 ? 's' : '') + ' logged in');
}
};
_.extend(groups_users, users);
var groups_edit = {
init: function init() {
this.addChangePrimaryGroupMenuToggle();
this.setPagesSettingsVisibility();
this.addDeleteGroupHandler();
this.addPaymentGatewaySelectHandler();
this.addHomePageWarningHandler(); // hide TZ if so configured
if (LW.disable_timezones) {
$('#timezone').closest('div').addClass('lw_hidden');
} // hide users in this group section if this is the Public group
if ($('#groups_fullname').val() === 'Public') {
$('.addnew').parent().hide();
} // move contact info fields to their section
$('.custom_settings').find(':input[name$="_contact_info"]').each(function (i, el) {
$('.default_contact_info').find('fieldset').append($(el).parent('div'));
}); // hide redundant contact info label for LWC
if (LW.is_lwc) {
$('.default_contact_info').find('label').addClass('lw_sr_only');
}
; // update authorization hosts to match group host (onChange doesn't work here, so using interval)
setInterval(function () {
var directory_host = $('#directory_host').val();
if (directory_host) {
$('.authorization_host').html(directory_host);
}
}, 3000);
},
addHomePageWarningHandler: function addHomePageWarningHandler() {
var $title = $('#item_title'); // on group title keyup
$title.on('keyup', function (e) {
var group_directory = $('#groups_directory_label').parent('fieldset');
if ($title.val().match(/^home\s*page$/i)) {
if (!$('#homepage_warning').length) {
group_directory.hide();
var msg = 'The ' + $title.val() + ' group\'s group directory ' + 'will be set to the root directory of the web site.
';
$(msg).insertAfter($(e.currentTarget));
}
} else {
$('#homepage_warning').remove();
group_directory.show();
}
}); // trigger group title keyup on page load
$title.trigger('keyup');
},
addPaymentGatewaySelectHandler: function addPaymentGatewaySelectHandler() {
// enable gateway selection
$('#gateway').on('change', function (e) {
var val = $(e.currentTarget).val();
$('.gateway').addClass('lw_hidden');
if ($('#gateway_' + val).length) {
$('#gateway_' + val).toggleClass('lw_hidden');
}
}).trigger('change');
},
addDeleteGroupHandler: function addDeleteGroupHandler() {
// confirm group delete
$('#delete').off('click').on('click', function (e) {
e.preventDefault();
if (confirm('Are you sure you want to delete this group, along with all of its users and content? Warning: Deleting an entire group may take a few minutes.')) {
var id = $('#group_id').val();
window.location.href = '/livewhale/?groups_edit&id=' + id + '&d=' + id;
}
return true;
});
},
setPagesSettingsVisibility: function setPagesSettingsVisibility() {
// show pages settings if logged in user has pages module
if (LW.groups && LW.groups.has_pages_settings) {
if ($('#pages_settings')) {
$('#pages_settings').show();
}
} else if ($('#pages_settings')) {
$('#pages_settings').hide();
}
}
};
_.extend(groups_edit, users); // on DOM ready
$(function () {
switch (LW.page) {
case 'groups':
groups.init();
break;
case 'groups_users':
groups_users.init();
break;
case 'groups_edit':
groups_edit.init();
groups_users.init();
break;
default:
break;
}
});
})(livewhale, window);
"use strict";
(function (LW, global) {
// don't do anything if this isn't an events module
if (LW.module !== 'images') {
return;
}
function ImagesManager() {
$('#images_bulk_add').uploader('uploadBatch', 'images', {
mode: 'images_upload_batch',
multiple: true,
collection_id: LW.collection_id || null,
dragDropSupport: null,
onSuccess: function onSuccess(e, data) {
window.location.href = '?images';
}
}).on("drop", function () {
return false;
});
var $drag_target = $('#drag-target');
$drag_target.uploader('uploadDropzone', 'images', {
mode: 'quick_upload',
multiple: true,
collection_id: LW.collection_id || null,
dropZone: $drag_target,
onSuccess: function onSuccess(e, data) {
window.location.href = '?images';
}
});
$('#dropdown_checked').on('change', function () {
var val = $(this).val();
if (val === 'images_add_to_gallery') {
$('#galleries_container').show();
} else {
$('#galleries_container').hide();
}
if (val === 'images_add_to_collection' || val === 'images_copy') {
$('#collections_container').show();
} else {
$('#collections_container').hide();
}
return true;
}); // and activate the "new" choice in that dropdown
$('#collections_container').find('select').on('change', function () {
if (!$(this).next().is('input[type=text]')) {
$(this).after(' ');
}
if ($(this).val() === '0') {
$(this).next().show();
} else {
$(this).next().hide();
}
});
$('#images_search_submit').on('click', function () {
location.href = '?images&search=' + $('#images_query').val();
});
$('#images_query').on('keyup', function (e) {
if (e.keyCode === 13) {
e.preventDefault();
$('#images_search_submit').trigger('click');
return false;
}
});
$('#manager_content').on('mouseenter focusin', 'li', function (e) {
if ($(this).find('.preview').length === 0) {
$('#manager_content li .preview').remove(); // Remove all other preview links
$(this).append('Preview '); // Add this one
}
}) // .on('mouseleave focusout', 'li', function(e) {
// $(this).find('.preview').remove();
// })
.on('click', 'li .preview', function (e) {
e.stopPropagation();
LW.previewImage($(this).closest('li').data('preview-href'));
return false;
}).on('click', 'li label a', function (e) {
e.preventDefault();
return true;
}); // temporary band-aid for bulk image uploads
// there's an issue with bulk image uploading in early ff
// and ie less than 10
if ($.browser.mozilla && $.browser.version.slice(0, 3) === "1.9" || $.browser.msie && parseInt($.browser.version, 10) < 10) {
$('#bulk-add, #drag-target').hide();
$('.sidebar, .sidebar > h5').css('margin-top', 0);
} // drag
$('#drag-target').data('originalText', $(this).find('.instructions').html()).on({
dragenter: function dragenter(e) {
$(this).addClass('on').find('.instructions').html('Now let go!');
},
dragover: function dragover(e) {
$(this).addClass('on').find('.instructions').html('Now let go!');
},
dragleave: function dragleave(e) {
var self = $(this);
self.removeClass('on').find('.instructions').html(self.data('originalText'));
},
drop: function drop(e) {
var self = $(this);
self.removeClass('on').find('.instructions').html(self.data('originalText'));
}
}); // override the add new link to incorporate default collection
$('a.addnew[id!="images_bulk_add"]').on('click', function () {
var collection_id;
if ($('#collection').length) {
collection_id = $('#collection').val();
}
document.location.href = '/livewhale/?images_edit' + (collection_id ? '&collection_id=' + collection_id : '');
return false;
});
}
function ImagesCollectionManager() {
// add manager ul if nonefound exists instead of ul
if (!$('ul#manager_images_collections').length && $('.lw_nonefound').length) {
$('.lw_nonefound').parent().append('');
}
var manager = $('ul#manager_images_collections'); // add new handler
$('a.addnew').on('click', function () {
var html;
if (!$('.new_collection').length) {
if ($('.lw_nonefound').length) {
$('.lw_nonefound').remove();
}
html = '' + ' ' + 'Rename ' + ' ' + ' ';
$(html).prependTo(manager).find('.rename').trigger('click');
}
return false; // cancel the click
}); // when clicking a collection to edit it
manager.on('click', 'li .rename', function (e) {
e.preventDefault();
var $li = $(this).closest('li');
var $item_name = $li.find('.item_name').hide();
var text = $.trim($item_name.find('a').text());
var html, $form;
html = '' + ' ' + 'Save collection ' + ' or cancel ' + ' ';
$form = $(html).insertAfter($item_name);
$form.find('input[type=text]').val(text).trigger('focus').on('keypress', function (e) {
if (e.keyCode === 13) {
// capture enter
$(this).next().trigger('click');
return false;
}
});
return false; // cancel the link click
}).on('click', '.collection_save', function (e) {
// when clicking to save the collection
e.preventDefault();
var $this = $(this),
$li = $this.closest('li'),
title = encodeURIComponent($this.prev().val()),
id = $li.find('.with_this').val() || '',
url = LW.lib.getAjaxUrl('saveImagesCollectionsTitle', {
id: id,
title: title
});
$.getJSON(url, function (data) {
manager.load(LW.lib.getAjaxUrl('getImagesCollectionsList'));
if (data.error) alert(data.error); // alert if collection already exists
});
}).on('click', '.lw_cancel a', function () {
var $li = $(this).closest('li'),
collection = $li.find('span.item_name a').text();
if (!collection) {
// if this is a new collection
$li.remove(); // kill the whole li
if (!manager.children().length) {
// if this was the last LI
manager.append('None found. ');
}
} else {
$li.find('span.item_name').show(); // show the collection
$(this).closest('.collection_input_wrapper').remove(); // and remove the editor
}
return false; // cancel the original click
});
}
function ImagesEditor() {
this.$upload_wrapper = $('fieldset.upload');
this.init();
}
$.extend(ImagesEditor.prototype, {
init: function init() {
// activate the "new" choice in the collection dropdown
$('fieldset.collection').find('select').on('change', function () {
if (!$(this).next().is('input[type=text]')) {
$(this).after(' ');
}
if ($(this).val() === '0') {
$(this).next().show();
} else {
$(this).next().hide();
}
}); // trigger click event on decoration-only checkbox if decoration only
$('#images_caption').on('wysiwyginit', function () {
var $decoration = $('.fields_caption .decoration-only input:checkbox');
if ($decoration.prop('checked')) {
setTimeout(function () {
$decoration.prop('checked', false);
$decoration.trigger('click');
}, 200);
}
});
if (LW.editor.id) {
this.showPreviewImage();
}
this.initCropper();
this.initUploader();
},
initCropper: function initCropper() {
var _this = this;
// init cropper
var src, width, height;
var preview_width = $('.preview_wrapper').width();
if (LW.editor.id) {
src = LW.editor.values.image_src;
width = LW.editor.values.image_width;
height = LW.editor.values.image_height;
}
this.cropper = new LW.lib.Cropper(preview_width, null, src, width, height); // set crop coords in input element and show crop preview on crop
this.cropper.bind('crop', function (e, data) {
// set master_cropper_coordinates input
$('input[name="master_cropper_coordinates"]').val(data.coords.join(','));
_this.setCropPreview(data);
}); // crop button handler
$('.fields_upload').on('click', '.crop', function (e) {
e.preventDefault(); // for existing images warn user of destructive nature of crop
if (LW.editor.id) {
var msg = 'Cropping a saved image may impact any ' + (LW.is_lwc ? 'events' : 'pages or content') + ' where this image is in use. Please proceed with caution.';
LW.prompt('Notice', msg, 'warning', {
Ok: $.proxy(_this.cropper.open, _this.cropper),
Cancel: null
});
} else {
_this.cropper.open();
}
});
},
setCropPreview: function setCropPreview(data) {
var $wrapper = this.$upload_wrapper;
$wrapper.find('.preview_wrapper').height(data.preview_height);
$wrapper.find('img').css(LW.lib.getCropPreviewCss(data.preview_width, data.preview_height, data.width, data.height, data.coords)).css('maxWidth', 'none');
},
initUploader: function initUploader() {
var $wrapper = this.$upload_wrapper;
var that = this; // image or file upload from the images/files editors
$wrapper.find('.upload_select').uploader('upload', 'images', {
onSuccess: function onSuccess(e, data) {
var result = data.result;
var $descr = $('#images_description');
var $caption = $('#images_caption');
var $credit = $('#images_credit');
var $keywords = $('#images_keywords'); // populate fields from metadata if available
if ($.isPlainObject(result)) {
if (result.meta_title && $descr.val() === '') {
$descr.val(result.meta_title);
}
if (result.meta_caption && $caption.wysiwyg('val') === '') {
$caption.wysiwyg('val', result.meta_caption);
}
if (result.meta_credit && $credit.wysiwyg('val') === '') {
$credit.wysiwyg('val', result.meta_credit);
}
if (result.meta_keywords && $keywords.val() === '') {
$keywords.val(result.meta_keywords);
}
}
that.showReplaceButton();
that.showPreviewImage();
var src = '?' + $.param({
livewhale: 'uploader_image_preview',
size: 'preview_sm',
filename: data.result.preview,
type: data.result.type
});
if (data.result) {
// set image info in cropper
that.cropper.setImage(src, data.result.width, data.result.height); // reset master cropper coordinates
$('input[name="master_cropper_coordinates"]').val('');
} // load and position image
var $preview = $wrapper.find('.preview_image');
if ($preview.is('picture')) {
$preview.find('source').remove().end().find('img').attr('src', src);
} else if ($preview.is('img')) {
$preview.attr('src', src);
}
LW.eventHub.trigger('upload.editor', [data]);
}
});
},
showReplaceButton: function showReplaceButton() {
this.$upload_wrapper.find('.upload_select').removeClass('upload-new').find('span').text('Replace this with a new file from your computer').end().end().find('.note').hide();
},
showPreviewImage: function showPreviewImage() {
var $wrapper = this.$upload_wrapper;
$wrapper.find('button.crop').show();
$wrapper.find('.preview_wrapper').show();
$wrapper.find('.note').hide();
}
});
var page;
switch (LW.page) {
case 'images':
case 'images_archive':
page = new ImagesManager();
break;
case 'images_edit':
page = new ImagesEditor();
break;
case 'images_collections':
page = new ImagesCollectionManager();
break;
}
return page;
})(livewhale, window);
"use strict";
/*global ace: true */
/* ingredients.js */
(function (LW, global) {
// don't execute if not ingredients module
if (LW.module !== 'ingredients') {
return;
} // methods used by Ingredients and IngredientsVersion
var mixins = {
updateIngredientsStatus: function updateIngredientsStatus(callback) {
var that = this;
$.ajax({
url: '/livewhale/backend.php',
data: {
livewhale: 'ajax',
"function": 'getIngredientsStatus',
vid: LW.ingredients.id
},
method: 'GET',
dataType: 'json',
success: function success(response) {
response = response || {};
if ($.isEmptyObject(response) || response.error) {
LW.prompt('Error', response.error || 'Unable to load status.', 'failure');
} else {
// set status property
that.status = response;
LW.ingredients.status = response;
if ($.isFunction(callback)) {
callback.apply(that);
}
}
}
});
},
initPreviewToggle: function initPreviewToggle() {
// set preview button to correct state
var $preview_checkbox = $('.js-preview-toggle-checkbox');
var ingredients_preview = LW.lib.getCookie(LW.cookie_prefix + 'ingredients_preview');
if (ingredients_preview) {
$preview_checkbox.prop('checked', true);
} // We hide the preview toggle until after the state is set so we don't get a flash with the wrong state
$('.js-preview-toggle').show(); // preview toggle handler
$preview_checkbox.on('click', function (e) {
var $checkbox = $(this);
var ajax_function = $checkbox.prop('checked') ? 'enableIngredientsPreview' : 'disableIngredientsPreview';
$.ajax({
url: '/livewhale/backend.php',
data: {
livewhale: 'ajax',
"function": ajax_function,
vid: LW.ingredients.id
},
method: 'GET',
dataType: 'json',
success: function success(response) {
response = response || {};
if ($.isEmptyObject(response) || response.error) {
LW.prompt('Error', response.error || 'Unable to set preview mode.', 'failure');
}
}
});
return true;
});
},
discardUnsavedVersion: function discardUnsavedVersion(success_callback) {
var that = this;
$.ajax({
url: LW.lib.getAjaxUrl('discardUnsavedIngredientsVersion'),
method: 'POST',
dataType: 'json',
success: function success(response) {
response = response || {};
if ($.isEmptyObject(response) || response.error) {
LW.prompt('Error', response.error || 'Unable to discard unsaved version.', 'failure');
} else {
if ($.isFunction(success_callback)) {
success_callback.apply(that);
}
}
}
});
}
};
function Ingredients() {
var that = this;
var $browser = this.$browser = $('.js-browser');
this.$browser_wrapper = $('.js-browser-wrapper');
this.$file_list = $browser.find('> ul');
var $editor = this.$editor = $('#editor').hide();
this.$editor_wrapper = $('.js-editor-wrapper');
this.$change_notice = $('.js-change-notice');
this.$intro_msg = $('.js-intro-msg');
this.$success_msg = $('.js-success-msg');
this.$spinner = $('.js-spinner');
this.$save_notify = $('.js-save-notify');
this.$fail_notify = $('.js-fail-notify');
this.$notify_bg = $('.js-notify-background');
this.$controls = $('.js-controls');
this.current_file = null;
this.root_dir = '/_ingredients/themes/global';
this.change_count = 0;
this.has_changes = false;
this.loadFileBrowser();
var id = LW.lib.getQueryStringParam('id'); // ask user if they're sure they want to discard unsaved version
var unsaved = LW.ingredients.unsaved_status;
if (id && unsaved && unsaved.total_changed > 0) {
var msg = 'You\'ve already committed changes to one or more files that haven\'t been saved or published. ' + 'Before loading a new version, please either save or discard those changes. Discarding an unsaved version cannot be undone.';
LW.prompt('Recent changes', msg, 'warning', {
'Discard changes': function DiscardChanges() {
that.discardUnsavedVersion();
},
'Save changes': function SaveChanges() {
document.location.href = '/livewhale?ingredients_version&return_id=' + id;
}
});
} // set status and show status bar
this.status = LW.ingredients.status;
this.onUpdateIngredients();
this.initPreviewToggle(); // folder click handler
$browser.on('click', 'a.pages_file_folder', function (e) {
e.preventDefault();
var $ul = $(this).parent().siblings('ul');
if ($ul.is(':visible')) {
$ul.hide();
} else {
$ul.show();
}
return true;
}); // file click handlers (any context)
$('body').on('click', 'a.pages_file_file, a.path', function (e) {
e.preventDefault();
var $this = $(this);
that.loadFile($this.attr('href'));
return true;
}); // commit changes button
$('.js-commit-file').on('click', function (e) {
e.preventDefault(); // show message
if (!that.has_changes) {
that.showFailNotify('No changes since last save.');
return true;
}
var content = that.editor.getValue();
var url = LW.lib.getAjaxUrl('saveContentForIngredientsEditor', {
path: that.current_file,
vid: LW.ingredients.id
}); // show background right away, so user has immediate feedback when clicking commit
that.showNotifyBackground();
$.ajax({
url: url,
method: 'POST',
data: {
'content': content
},
error: function error() {
that.hideNotifyBackground();
},
success: function success(response) {
response = response || {};
if ($.isEmptyObject(response) || response.error) {
that.showFailNotify(response.error || 'Unable to commit file.');
} else {
that.updateIngredientsStatus(that.onUpdateIngredients);
$('body').removeClass('code_editor_editing');
that.has_changes = false;
$(window).off('beforeunload'); //that.$editor.hide();
//that.$success_msg.text('The file "' + that.current_file + '" has been saved.').show();
//that.current_file = null;
}
}
});
return true;
});
$('.js-close-file').on('click', function (e) {
e.preventDefault();
that.closeFile();
return true;
}); // cancel editing
$editor.on('click', '.js-cancel-edit', function (e) {
e.preventDefault();
that.closeFile();
return true;
}); // file browser action buttons
$browser.on('click', '.actions a', function (e) {
e.preventDefault();
var $a = $(this);
var $ul = $a.closest('ul');
var parent_path = that.getFileParentPath($ul);
if ($a.hasClass('add-file')) {
that.addFile(parent_path);
} else if ($a.hasClass('add-dir')) {
that.addDir(parent_path);
} else if ($a.hasClass('upload')) {
that.upload(parent_path);
}
return true;
});
$(function () {
$('[data-toggle="popover"]').popover();
}); // handlers for dropdown menu items
$('.buttons').on('click', function (e) {
e.preventDefault();
return true;
}).on('click', '.js-indent', function (e) {
// not working
//that.beautify();
return true;
}).on('click', '.js-fullscreen', function (e) {
var $a = $(this).find('i');
var $editor_wrapper = that.$editor_wrapper; // var $editorHeight = (window.innerHeight - 200);
// $('#code_editor').css("height",$editorHeight+"px");
if ($editor_wrapper.hasClass('fullscreen')) {
$editor_wrapper.removeClass('fullscreen');
$a.removeClass('fa-compress');
$a.addClass('fa-expand');
} else {
$editor_wrapper.addClass('fullscreen');
$a.removeClass('fa-expand');
$a.addClass('fa-compress');
}
$a.closest('.dropdown').find('.dropdown-toggle').text('...');
return true;
});
$('.js-close-file').on('click', function (e) {
$('.js-editor-wrapper').removeClass('fullscreen');
}); // handler for listing conflicts
this.$change_notice.on('click', '.js-list-conflicts', function (e) {
e.preventDefault();
var html = '' + LW.ingredients.status.conflicts.join(' ') + '
';
$(html).overlay({
autoOpen: true,
destroyOnClose: true,
size: 'medium',
closeSelector: '.js-cancel',
footer: false,
title: 'Conflicts'
});
return true;
}); // handler for listing conflicts
this.$change_notice.on('click', '.js-list-syntax-errors', function (e) {
e.preventDefault();
var html = '';
$.each(LW.ingredients.status.syntax_errors, function (i, data) {
var errors = '';
$.each(data.errors, function (i2, data2) {
errors += '' + (data2.type ? data2.type : 'Error') + ': ' + data2.error + (data2.code ? '' + data2.code + ' ' : '');
});
html += '';
});
$('' + html + '
').overlay({
autoOpen: true,
destroyOnClose: true,
size: 'medium',
closeSelector: '.js-cancel',
footer: false,
title: 'Syntax Errors'
});
return true;
}); // handler for directory selector
$('#directory-selector').on('change', function (e) {
var subdir = $(this).val();
if (subdir) {
that.root_dir = '/_ingredients/' + subdir;
that.loadFileBrowser();
}
}); // handlers for code search
$('.code_search_btn').on('click', function (e) {
e.preventDefault();
var version_id = LW.lib.getQueryStringParam('id'),
q = $('.code_search_text').val();
if (q) {
document.location.href = '/livewhale/?ingredients' + (version_id ? '&id=' + version_id : '') + '&q=' + encodeURIComponent(q);
} else {
LW.prompt('Search', 'Please enter a search query.', 'warning');
}
return true;
}); // don’t submit the page form if enter is pressed
$('.code_search_text').on('keydown', function (e) {
if (e.which === 13) {
e.preventDefault();
$('.code_search_btn').trigger('click'); // click the submit button
}
}); // handlers for discarding changed files
$('.discard-changed-file').on('click', function (e) {
e.preventDefault();
var msg = 'Are you sure you want to discard your changes to this file? This change cannot be undone.';
var confirm = window.confirm(msg);
if (confirm) {
$(this).closest('tr').remove();
$.ajax({
url: LW.lib.getAjaxUrl('discardIngredientsFile&vid=' + livewhale.ingredients.status.vid + '&path=' + $(this).attr('data-path')),
method: 'GET',
dataType: 'json',
success: function success(response) {
response = response || {};
if ($.isEmptyObject(response) || response.error) {
LW.prompt('Error', response.error || 'Unable to discard file.', 'failure');
} else {
if ($.isFunction(success_callback)) {
success_callback.apply(that);
}
}
}
});
}
;
return true;
});
}
Ingredients.prototype = _.extend({
closeFile: function closeFile() {
var close = function close() {
this.$editor.hide();
this.$intro_msg.show();
this.current_file = null;
$('body').removeClass('code_editor_editing');
this.has_changes = false;
$(window).off('beforeunload');
};
if (this.has_changes) {
var msg = 'The editor contains unsaved changes. Are you sure you want to close the file and lose ' + 'those changes?';
LW.prompt('Confirm lost changes', msg, 'warning', {
'Close without saving': $.proxy(close, this),
'Cancel': function Cancel() {}
});
} else {
close.apply(this);
}
},
getFolderOptions: function getFolderOptions() {
return '' + '' + ' ' + ' ' + '' + ' ' + ' ' + '' + ' ' + ' ' + ' ';
},
buildFileTree: function buildFileTree(data, is_subdir) {
var that = this;
var html = is_subdir ? '' : ''; // output li for each item, make recursive buildFileTree call if dir has contents
$.each(data, function (key, file) {
var classes = [];
var has_content = babelHelpers["typeof"](file.listing) === 'object' && !$.isEmptyObject(file.listing);
classes.push(file.is_directory ? 'pages_file_folder' : 'pages_file_file');
if (file.is_prototype) {
classes.push('pages_is_prototype');
}
if (file.is_directory && !has_content) {
classes.push('is_empty');
}
html += '' + '';
if (file.is_directory) {
html += that.buildFileTree(file.listing || [], true);
}
html += ' ';
});
html += that.getFolderOptions();
html += is_subdir ? ' ' : '';
return html;
},
loadFile: function loadFile(url) {
var that = this;
var filename = url.substring(url.lastIndexOf('/') + 1); // don't reload the currently selected page if clicked - we don't want to overwrite changes
if (this.current_file === url) {
return false;
} // warn user that changes will be lost if they open another file
if (this.current_file && this.has_changes) {
var msg = 'Changes to the current file will be lost if you open a new file. Would you like to proceed?';
var conf = window.confirm(msg);
if (!conf) {
return false;
}
}
$('html,body').scrollTop(0); // scroll to top of page in case the file was at the bottom of a long list
this.current_file = url;
this.has_changes = false; //this.$controls.addClass('saved');
this.$intro_msg.hide();
this.$success_msg.hide();
this.$editor.hide();
this.$spinner.show(); // change current file title and show editor
this.$editor.find('.js-file-name').text(filename);
if (!this.editor) {
ace.config.set("basePath", "/livewhale/thirdparty/ace");
this.editor = ace.edit("code_editor");
this.editor.setTheme('ace/theme/eclipse'); // flag change to file
this.editor.on('change', function (e) {
if (that.has_changes === false && (e.start.row > 0 || e.start.column > 0)) {
that.has_changes = true;
$('body').addClass('code_editor_editing'); //that.$controls.removeClass('saved');
$(window).on('beforeunload', function () {
return "There are unsaved changes in the file editor. Are you sure you want leave?";
});
}
});
} // set the syntax highlighting mode based on file extension
var ext = filename.substring(filename.lastIndexOf('.') + 1);
var mode = '';
switch (ext) {
case 'js':
mode = 'javascript';
break;
case 'less':
case 'css':
case 'sass':
case 'scss':
case 'html':
mode = ext;
break;
}
if (mode) {
that.editor.session.setMode('ace/mode/' + mode);
}
$.ajax({
url: '/livewhale/backend.php',
data: {
livewhale: 'ajax',
"function": 'getContentForIngredientsEditor',
path: url,
vid: LW.ingredients.id
},
method: 'GET',
dataType: 'json',
success: function success(response) {
that.$spinner.hide();
if (typeof response.content === 'undefined' || response.error) {
LW.prompt('Error', response.error || 'Unable to load file.', 'failure');
that.$intro_msg.show();
} else {
that.$editor.show();
that.editor.session.setValue(response.content || "");
}
}
});
},
hideEditor: function hideEditor() {
// warn user about losing changes
if (this.has_changes) {
var conf = window.confirm('You have uncommitted changes. Are you sure you want to close the file?');
if (!conf) {
return false;
}
}
this.$editor.hide();
this.$intro_msg.show();
this.current_file = null;
this.has_changes = false;
},
openCreateFileOrDirectoryDialog: function openCreateFileOrDirectoryDialog(type, callback) {
var that = this;
var type_title = type.charAt(0).toUpperCase() + type.slice(1);
var html, footer;
html = '' + ' ' + type_title + ' name: ' + ' ' + '
';
footer = '';
var $footer = $(footer);
var $overlay = $(html).overlay({
autoOpen: true,
destroyOnClose: true,
size: 'medium',
closeSelector: '.js-cancel',
footer: $footer,
title: 'Add new ' + type
});
$footer.on('click', '.js-create', function (e) {
e.preventDefault();
var name = $overlay.find('.js-name').val();
if ($.isFunction(callback)) {
callback.call(that, $overlay, name);
}
return true;
});
},
addFile: function addFile(parent_path) {
var that = this;
this.openCreateFileOrDirectoryDialog('file', function ($overlay, name) {
var err_msg = that.validateFileName(name);
var path = parent_path + '/' + name;
if (err_msg) {
LW.prompt('Invalid file name', err_msg, 'failure');
} else {
$.ajax({
url: '/livewhale/backend.php',
data: {
livewhale: 'ajax',
"function": 'addIngredientsFile',
path: path,
vid: LW.ingredients.id
},
method: 'GET',
dataType: 'json',
success: function success(response) {
response = response || {};
if ($.isEmptyObject(response) || response.error) {
LW.prompt('Error', response.error || 'Unable to add File.', 'failure');
} else {
// refresh file browser to pick up change
that.loadFileBrowser(parent_path); // refresh status bar
that.updateIngredientsStatus(that.onUpdateIngredients); // we may want to load newly created files. If we do, we need to not
// close out files with uncommitted changes
//that.loadFile(path);
$overlay.overlay('close');
}
}
});
}
});
},
addDir: function addDir(parent_path) {
var that = this;
this.openCreateFileOrDirectoryDialog('folder', function ($overlay, name) {
var err_msg = that.validateDirName(name);
var path = parent_path + '/' + name;
if (err_msg) {
LW.prompt('Invalid folder name', err_msg, 'failure');
} else {
$.ajax({
url: '/livewhale/backend.php',
data: {
livewhale: 'ajax',
"function": 'addIngredientsDirectory',
path: path,
vid: LW.ingredients.id
},
method: 'GET',
dataType: 'json',
success: function success(response) {
response = response || {};
if ($.isEmptyObject(response) || response.error) {
LW.prompt('Error', response.error || 'Unable to add Folder.', 'failure');
} else {
// refresh file browser to pick up change
that.loadFileBrowser(parent_path); // refresh status bar
that.updateIngredientsStatus(that.onUpdateIngredients);
$overlay.overlay('close');
}
}
});
}
});
},
upload: function upload(parent_path) {
var that = this;
if (!this.$uploader) {
this.$uploader = $('.js-uploader').uploader('uploadModal', 'files', {
mode: 'quick_upload',
multiple: true,
onError: function onError(e, data) {},
onSuccess: function onSuccess(e, items) {
var files = e; // post file details to endpoint so they can be moved to path
$.ajax({
url: LW.lib.getAjaxUrl('moveUploadedIngredientsFiles'),
data: {
path: parent_path,
vid: LW.ingredients.id,
files: files
},
method: 'POST',
dataType: 'json',
success: function success(response) {
response = response || {};
if ($.isEmptyObject(response) || response.error) {
LW.prompt('Error', response.error || 'Unable to save uploaded files.', 'failure');
} else {
// refresh file browser to pick up change
that.loadFileBrowser(parent_path); // refresh status bar
that.updateIngredientsStatus(that.onUpdateIngredients);
}
return true;
}
});
}
});
}
this.$uploader.trigger('click');
},
getFileParentPath: function getFileParentPath($ul) {
var $parent = $ul.closest('li');
return !$parent.length ? this.root_dir : $parent.find('.page_file > a').attr('href');
},
validateFileName: function validateFileName(file_name) {
var errors = []; // don't do anything if there's no name
if (!file_name) {
return false;
}
if (file_name.match(/[^\w._-]/)) {
errors.push('File names can only contain alpha-numeric characters, dashes, underscores and dots.');
}
if (!file_name.match(/^[a-zA-Z]/)) {
errors.push('Filenames must begin with a letter.');
}
if (!file_name.match(/\.(htm|html|js|css|less|scss|txt|xml|es6')$/)) {
// keep this in sync with the PHP module!
errors.push('Filenames must have a valid file extension (htm, html, js, css, less, scss, txt, xml, es6)');
}
return errors.length ? '' + errors.join('
') + '
' : '';
},
validateDirName: function validateDirName(file_name) {
var errors = []; // don't do anything if there's no name
if (!file_name) {
return false;
}
if (file_name.match(/[^\w_-]/)) {
errors.push('Folders can only contain alpha-numeric characters, hyphens, and underscores.');
}
if (!file_name.match(/^[a-zA-Z]/)) {
errors.push('Folders must begin with a letter.');
}
return errors.length ? '' + errors.join('
') + '
' : '';
},
loadFileBrowser: function loadFileBrowser(expand_to_path) {
var that = this;
var $spinner = $('
').appendTo(this.$browser_wrapper);
this.$browser.hide(); // load file browser
$.ajax({
url: LW.liveurl_dir + '/directory_listing/path/' + this.root_dir.replace(/\//g, '%5C') + '/recursive/true/allowed_types/' + livewhale.ingredients.allowed_types.join(',') + '/ingredients_version/' + LW.uid + '_' + LW.ingredients.id,
method: 'GET',
dataType: 'json',
success: function success(response) {
if (response.error) {
LW.prompt('Error', response.error, 'failure');
} else {
var html = that.buildFileTree(response.listing);
that.$file_list.html(html);
$spinner.remove();
that.$browser.show(); // expand folder in which file or dir was created
that.expandBrowserToPath(expand_to_path);
}
}
});
},
expandBrowserToPath: function expandBrowserToPath(path) {
if (!path) return false;
this.$file_list.find('a[href="' + path + '"]').parents('ul').show().end().closest('li').find('> ul').show();
},
commitChanges: function commitChanges() {},
onUpdateIngredients: function onUpdateIngredients() {
if (this.status.total_changed) {
this.$change_notice.find('.js-change-count').text(this.status.total_changed);
if (this.status.changes && this.status.changes.length) {
this.$change_notice.find('.js-list-changes').show();
} else {
this.$change_notice.find('.js-list-changes').hide();
}
if (this.status.conflicts && this.status.conflicts.length) {
this.$change_notice.find('.js-list-conflicts').show().find('.badge').text(this.status.conflicts.length);
} else {
this.$change_notice.find('.js-list-conflicts').hide();
}
if (this.status.syntax_errors && this.status.syntax_errors.length) {
this.$change_notice.find('.js-list-syntax-errors').show().find('.badge').text(this.status.syntax_errors.length);
} else {
this.$change_notice.find('.js-list-syntax-errors').hide();
}
} else {
this.$change_notice.find('.js-change-count').text('0');
}
},
// this is not working
beautify: function beautify() {
var beautify = ace.require('ace/ext/beautify');
beautify.beautify(this.editor);
},
showNotifyBackground: function showNotifyBackground() {
this.$notify_bg.show().addClass('on');
},
hideNotifyBackground: function hideNotifyBackground() {
this.$notify_bg.hide().removeClass('on');
},
showFailNotify: function showFailNotify(msg) {
this.$fail_notify.html(msg).show().addClass('on');
},
showSaveNotify: function showSaveNotify() {
this.$save_notify.show().addClass('on');
}
}, mixins);
function IngredientsList() {
var that = this;
var $file_list = $('.js-file-list');
var file_list_row_tmpl = _.template($('#file_list_row').html());
this.$file_count = $('.js-change-count');
var file_rows = "";
var changes = this.changes = !_.isEmpty(LW.ingredients.status.changes) ? LW.ingredients.status.changes : null;
var is_saved = this.is_saved = LW.ingredients.is_saved;
if (changes) {
// add files
$.each(changes, function (index, item) {
file_rows += file_list_row_tmpl({
path: item,
href: '#'
});
});
$file_list.html(file_rows);
that.updateFileCount();
$('.js-committed-changes').show();
} else {
$('.js-changes-msg').hide();
$('.js-no-changes-msg').show();
}
this.initPreviewToggle(); // file close/remove handler
$file_list.on('click', '.close', function (e) {
var $li = $(this).closest('li');
var path = $li.find('.js-path').text();
$li.addClass('to-discard'); // remove item from this.changes
_.remove(that.changes, function (n) {
return n === path;
});
that.updateFileCount(); // IX - need endpoint for un-staging files
}).on('click', 'li.to-discard', function (e) {
e.preventDefault();
var $li = $(this);
var path = $li.find('.js-path').text();
$(this).removeClass('to-discard');
that.changes.push(path);
that.updateFileCount();
return true;
}); // publish version handler
$('.js-publish').on('click', function (e) {
e.preventDefault();
var description = $('.js-description').val();
if (!description) {
LW.prompt('Missing field', 'A description is required when publishing a version.', 'warning');
return;
}
LW.prompt('Apply changes', 'Are you sure you wish to publish these changes? Please be sure to preview them first. This action cannot be undone.', 'warning', {
'Publish changes': function PublishChanges() {
$.ajax({
url: LW.lib.getAjaxUrl('publishIngredientsVersion', {
vid: LW.ingredients.id
}),
method: 'POST',
dataType: 'json',
data: {
description: encodeURIComponent(description)
},
success: function success(response) {
if (response.error) {
LW.prompt('Error', response.error, 'failure');
} else {
document.location.href = '/livewhale/?ingredients_published';
}
}
});
},
'Cancel': $.noop
});
return true;
});
if (is_saved) {
$('.js-save').hide();
} else {
// save version handler
$('.js-save').on('click', function (e) {
e.preventDefault();
var description = $('.js-description').val();
if (!description) {
LW.prompt('Missing field', 'A description is required when saving a version.', 'warning');
return;
}
$.ajax({
url: LW.lib.getAjaxUrl('saveIngredientsVersion'),
method: 'POST',
data: {
description: encodeURIComponent(description)
},
dataType: 'json',
success: function success(response) {
response = response || {};
if ($.isEmptyObject(response) || response.error) {
LW.prompt('Error', response.error || 'Unable to save version.', 'failure');
} else {
document.location.href = '/livewhale/?ingredients_version';
}
}
});
return true;
});
} // discard version handler
$('.js-discard').on('click', function (e) {
e.preventDefault();
if (is_saved) {
alert('Not yet implemented for saved versions. We need to decide what "discard changes" means here.');
return;
}
LW.prompt('Confirm delete', 'Are you sure you want to discard all your changes?', 'warning', {
'Discard changes': function DiscardChanges() {
that.discardUnsavedVersion(function () {
document.location.href = '/livewhale/?ingredients';
});
},
'Cancel': function Cancel() {}
});
return true;
});
}
IngredientsList.prototype = _.extend({
updateFileCount: function updateFileCount() {
this.$file_count.text(this.changes.length);
}
}, mixins);
function IngredientsVersion() {
$('.version').on('click', '.js-preview', function (e) {
e.preventDefault();
alert('http://' + LW.host + '/?lw_ingredients_preview=' + LW.uid + '_' + $(this).closest('div').attr('data-id'));
return true;
}).on('click', '.js-descr', function (e) {
e.preventDefault();
return true;
}).on('click', '.js-archive', function (e) {
e.preventDefault();
return true;
}).on('click', '.js-delete', function (e) {
e.preventDefault();
return true;
});
}
var page;
switch (LW.page) {
case 'ingredients':
page = new Ingredients();
break;
case 'ingredients_list':
page = new IngredientsList();
break;
case 'ingredients_version':
page = new IngredientsVersion();
break;
}
return page;
})(livewhale, window);
"use strict";
(function (LW, global) {
// do nothing if not an editor with language support
if (!LW.editor || !LW.languages) {
return;
}
var $wrapper = $('#languages'),
$lang_list = $wrapper.find('.enable > ul'),
$lang_buttons = $wrapper.find('.language-buttons'),
$body = $('body'),
$h1 = $('#content .main h1'),
initialized = {},
active_lang = 'english',
wysiwyg = LW.editor.wysiwyg,
wysiwyg_limited = LW.editor.wysiwyg_limited,
selected_langs;
function addLanguageButton(language, label, is_active) {
var btn = '' + label + ' ';
$lang_buttons.append(btn);
}
LW.languages.getActiveLanguage = function () {
return active_lang;
};
function removeLanguageButton(lang) {
// select english if removing active language
if (lang === active_lang) {
$lang_buttons.find('button:first').trigger('click');
}
$lang_buttons.find('.lang_' + lang).remove();
} // return an array of selected languages - excluding english
var getCheckedLanguages = LW.languages.getCheckedLanguages = function () {
var langs = {};
$lang_list.find('input[type=checkbox]').each(function () {
var $this = $(this),
$label = $this.closest('label');
if ($this.prop('checked') && 'english' !== $this.val()) {
langs[$.trim($this.val())] = $.trim($label.text());
}
});
return langs;
};
function toggleLanguageListVisiblity() {
var sel_langs;
$lang_list.toggleClass('lw_hidden');
sel_langs = getCheckedLanguages();
if ($.isEmptyObject(sel_langs)) {
// toggle english button if no other items selected
if (!$lang_list.hasClass('lw_hidden')) {
addLanguageButton('english', 'English', true);
} else {
removeLanguageButton('english');
}
}
}
function initLanguage(language) {
var config = LW.languages.config[language];
initialized[language] = {
fields: {}
}; // turn on all customizations for subscription events editor
if ('events_sub_edit' === LW.page) {
$('input:checkbox[name^="has_customized"]').on('click', function () {
return confirm('Customizing this field will enable a customized value for all language versions.');
});
}
_.each(initialized.english.fields, function ($field, field) {
var $new_field = $field.clone(),
is_wysiwyg = _.includes(wysiwyg, field),
is_wysiwyg_limited = _.includes(wysiwyg_limited, field),
field_data = '',
placeholder;
$new_field = $field.clone(); // set saved field data
if (config.values && _.has(config.values, field)) {
field_data = config.values[field];
} // change name and id attributes
$new_field.attr('name', field + '_lang_' + language).attr('id', $new_field.attr('id') + '_' + language).addClass('multi-lang-input').removeAttr('disabled') // language inputs should be enabled even when english is disabled
.val(field_data); // add new title placeholder
if ('title' === field || 'summary' === field) {
if (config.dir && 'rtl' === config.dir) {
placeholder = '(' + $field.attr('placeholder') + ' (' + getLanguageTitle(language);
} else {
placeholder = $field.attr('placeholder') + ' (' + getLanguageTitle(language) + ')';
}
$new_field.attr('placeholder', placeholder);
}
if (config.lang) {
$new_field.attr('lang', config.lang);
}
if (config.dir) {
$new_field.attr('dir', config.dir);
} else {
$new_field.attr('dir', 'auto');
} // insert new field
// wrap wysiwyg fields so we can show/hide both input element and wysiwyg iframe
if (is_wysiwyg || is_wysiwyg_limited) {
$field.parent().after($new_field);
$new_field.show().wrap('
');
} else {
$field.after($new_field);
} // also add a class to nearest div.fields so we can style header
$field.closest('div.fields').addClass('multi-lang-has-input');
initialized[language].fields[field] = $new_field;
});
}
function initLanguageWysiwyg(language) {
var config = LW.languages.config[language];
_.each(initialized[language].fields, function ($field, field) {
var is_wysiwyg = _.includes(wysiwyg, field),
is_wysiwyg_limited = _.includes(wysiwyg_limited, field),
wysiwyg_opts = {},
value; // skip if not a wysiwyg field
if (!is_wysiwyg && !is_wysiwyg_limited) return true;
if (config.dir) {
wysiwyg_opts.tiny_options = {
directionality: config.dir
};
}
if (is_wysiwyg_limited) {
wysiwyg_opts.limited = 1;
} // extract value from form field, then re-insert below using wysiwyg val method
// this is necessary to prevent TinyMCE from displaying scrollbars in form field
value = $field.val();
$field.val(''); // init wysiwyg field
$field.wysiwyg(wysiwyg_opts); // set data
if (value) {
$field.wysiwyg('val', value);
}
});
initialized[language].wysiwyg = true;
}
function getLanguageTitle(language) {
return 'english' === language ? 'English' : LW.languages.config[language].title;
}
function showLanguageTitle(language) {
var $lang_msg = $h1.find('.multi-lang-current'),
disp_lang = getLanguageTitle(language);
if (!$lang_msg.length) {
$lang_msg = $(' ').appendTo($h1);
}
$lang_msg.html(' (Language: ' + disp_lang + ' )');
$('div.fields.multi-lang-has-input > .header').each(function () {
$(this).find('.multi-lang-label').remove();
if ('english' !== language) {
$(this).append(' (Language: ' + disp_lang + ') ');
}
});
}
function hideLanguage(language) {
_.each(initialized[language].fields, function ($field, field) {
if (_.includes(wysiwyg, field) || _.includes(wysiwyg_limited, field)) {
$field.parent().hide();
} else {
$field.hide();
}
});
}
function showLanguage(language) {
// add body class indicating whether a non-english language is active
if ('english' === language) {
$body.removeClass('multi-lang-non-english-active');
} else {
$body.addClass('multi-lang-non-english-active');
}
showLanguageTitle(language); // hide previously active language
if (active_lang) {
hideLanguage(active_lang);
} // show selected language fields
_.each(initialized[language].fields, function ($field, field) {
if (_.includes(wysiwyg, field) || _.includes(wysiwyg_limited, field)) {
$field.parent().show();
} else {
$field.show();
}
}); // set selected lang active
active_lang = language;
}
var switchToLanguage = LW.languages.switchToLanguage = function (language) {
if (initialized[language] && !initialized[language].wysiwyg) {
initLanguageWysiwyg(language);
}
showLanguage(language);
};
function addLanguage(language, label) {
addLanguageButton(language, label);
initLanguage(language);
hideLanguage(language);
} // add currently displayed english to initilized object
initialized.english = {
fields: {},
wysiwyg: true
};
_.each(LW.languages.fields, function (field) {
$('[name=' + field + ']').each(function () {
var $field = $(this); // wrap wysiwyg fields so we can show/hide both input element and wysiwyg iframe
if (_.includes(wysiwyg, field) || _.includes(wysiwyg_limited, field)) {
$field.add($field.siblings('.mceEditor')).wrap('
');
}
if ($field.length && 'hidden' !== $field.attr('type')) {
initialized.english.fields[field] = $field;
}
});
}); // add pre-selected language buttons
selected_langs = getCheckedLanguages();
if (!$.isEmptyObject(selected_langs)) {
addLanguageButton('english', 'English', true);
showLanguageTitle('english');
_.each(selected_langs, function (label, language) {
addLanguage(language, label);
});
} // Current language button switch
$lang_buttons.on('click', 'button', function (e) {
e.preventDefault();
var $this = $(this),
language;
$.each($this.attr('class').split(' '), function (i, val) {
if (val.match(/^lang_/)) {
language = val.replace(/^lang_/, '');
return false;
}
});
if ($this.hasClass('active')) {
return true;
}
$this.siblings('.active').removeClass('active').end().addClass('active');
switchToLanguage(language);
return true;
}); // handlers for Languages button and list checkboxes
$wrapper.on('click', '.enable', function (e) {
e.preventDefault();
e.stopPropagation();
toggleLanguageListVisiblity(); // if visible attach close handler to body
if (!$lang_list.hasClass('hidden')) {
$('body').one('click.closeLanguageButton', function () {
toggleLanguageListVisiblity();
});
} else {
$('body').off('click.closeLanguageButton');
}
}).on('click', '.enable > ul', function (e) {
// prevent item clicks from propagating to .enable
e.stopPropagation();
}).on('click', '.enable input[type=checkbox]', function (e) {
var $this = $(this),
$label = $this.closest('label'),
language = $this.val(),
approve,
msg;
if ($this.prop('checked')) {
addLanguage(language, $.trim($label.text()));
} else {
msg = 'Are you sure you wish to disable this language? Any previousy entered values for the language ' + 'will be cleared upon saving.';
approve = confirm(msg);
if (!approve) {
return false;
} else {
removeLanguageButton(language);
}
}
return true;
});
})(livewhale, window);
"use strict";
(function (LW, global) {
// only execute if missions module
if (LW.module !== 'missions') {
return;
}
var missions_edit = {
init: function init() {
$('#link_restore').on('click', function () {
$(this).toggleClass('selected');
$('#revisions').show();
return false;
});
$('#revisions .cancel a').on('click', function () {
$(this).parent().parent().hide().prev().toggleClass('selected');
return false;
});
LW.archives = {
'Never expires': {
style: 'not_archived',
id: ''
},
'Expires on...': {
style: 'expires',
id: ''
}
};
$('.not_archived').html('Never expires');
}
}; // per-page actions
switch (LW.page) {
case 'missions_edit':
missions_edit.init();
break;
}
})(livewhale, window);
"use strict";
/*globals google:true */
(function (LW, $, global) {
var map, marker;
var placesBase = {
showAddressSelectDialog: function showAddressSelectDialog(results, title) {
var html, $html, footer;
html = '' + '
' + '';
for (var i = 0; i < results.length; i++) {
html += '' + results[i].formatted_address + ' ';
}
html += ' ' + '
' + '
';
$html = $(html);
$html.find('#lw_places_result_list').data('geocodeResults', results).data('title', title);
footer = 'Use this address ' + 'or cancel and close ';
$html.overlay({
id: 'lw_places_multiple_results',
title: 'Which of these did you mean?',
footer: footer,
closeButton: false,
closeSelector: '.lw_cancel a'
});
return true;
}
};
var places_editor = {
init: function init() {
var that = this;
this.$map_wrapper = $('#places_map_holder');
this.initAddressSelectHandler();
this.initMap();
$('#places_add').on('click', function () {
var val = $('#places_address').val(); // if an address has been set
if (val) that.findAddress(val);
}); // confirms a location we thought already exists
$('#places_confirm').on('click', function () {
$(':input[name="confirmed"]').val(1); // flag this as confirmed
$('form[name="places_edit"]').submit(); // resubmit
});
},
initAddressSelectHandler: function initAddressSelectHandler() {
var that = this;
$('body').on('click', '#lw_places_choose_multiple', function (e) {
var $this = $(this),
$overlay = $this.closest('.lw_overlay'),
$list = $overlay.find('#lw_places_result_list'),
id = $list.val(),
results = $list.data('geocodeResults'),
loc = results[id].geometry.location;
that.setPlaceCoordinates(loc);
that.makePlaceMap(loc);
$overlay.find('.lw_editor').overlay('close');
});
},
initMap: function initMap() {
if ($('#places_latitude').val() && $('#places_longitude').val()) {
var latlng = new google.maps.LatLng($('#places_latitude').val(), $('#places_longitude').val());
this.makePlaceMap(latlng);
this.setPlaceCoordinates(latlng);
}
},
findAddress: function findAddress(val) {
var that = this,
address = {
address: val
},
geocoder = new google.maps.Geocoder(); // do nothing if no address
if (!address.address.length) {
return;
} // if the user enter coordinates it means they want exactly that location,
// not an address nearby. Use exact coordinates when entered
if (val.match(/^(-?\d+(\.\d+)?),\s*(-?\d+(\.\d+)?)$/)) {
var coords = val.replace(/\s+/g, '').split(','); // set place and map if two coordinates that match format
if (coords.length === 2) {
var loc = new google.maps.LatLng(parseFloat(coords[0]), parseFloat(coords[1]));
that.setPlaceCoordinates(loc);
that.makePlaceMap(loc);
return true;
}
}
geocoder.geocode(address, function (results, status) {
if (status === 'OK') {
if (results.length === 1) {
var loc = results[0].geometry.location;
that.setPlaceCoordinates(loc);
that.makePlaceMap(loc);
} else if (results.length > 1) {
that.showAddressSelectDialog(results, val);
}
} else if (status === 'ZERO_RESULTS') {
$('body').notify({
message: 'Could not find that address on the map.',
duration: 3000,
type: 'failure'
});
}
});
},
displayHelperMessage: function displayHelperMessage() {
// add helper dialog box
if ($('#places_map').siblings('.coaching').length === 0) {
$('#places_map').after('
');
}
$('#places_map').siblings('.coaching').html('Drag the pin to adjust the exact location of your place.').show(500);
},
setPlaceCoordinates: function setPlaceCoordinates(googleLatLng) {
$('#places_latitude').val(googleLatLng.lat());
$('#places_longitude').val(googleLatLng.lng());
$('#places_thumb').val(this.makeStaticImageLink(googleLatLng));
},
makeStaticImageLink: function makeStaticImageLink(googleLatLng) {
return LW.liveurl_dir + '/places/thumb?url=' + encodeURIComponent('http://maps.googleapis.com/maps/api/staticmap?sensor=false&size=320x320&zoom=17&markers=size:small|' + googleLatLng.lat() + ',' + googleLatLng.lng());
},
makePlaceMap: function makePlaceMap(googleLatLng) {
var that = this;
var interactive = typeof arguments[1] === 'boolean' ? arguments[1] : true;
this.$map_wrapper.slideDown(500, function () {
map = new google.maps.Map($('#places_map').get(0), {
zoom: 17,
center: googleLatLng,
mapTypeId: google.maps.MapTypeId.ROADMAP,
streetViewControl: false,
scrollwheel: false
});
marker = new google.maps.Marker({
map: map,
draggable: interactive,
animation: google.maps.Animation.DROP
});
marker.setPosition(googleLatLng);
marker.setClickable(interactive);
marker.setTitle($('#places_new_title').val());
if (interactive) {
that.displayHelperMessage();
} // create listener
google.maps.event.addListener(marker, 'dragend', function () {
that.setPlaceCoordinates(marker.position);
});
});
}
};
$.extend(places_editor, placesBase);
var Places = function Places(opts) {
var that = this;
var $wrapper = this.$wrapper = $('.places-module');
var $add_form = this.$add_form = $('.places-add', $wrapper);
var $add_new = this.$add_new = $('.places-add-new', $wrapper);
var $add_link = $add_new.find('#places-add-link');
this.$search_wrapper = $wrapper.find('.places-search');
this.$options = $wrapper.find('.places-options');
this.$map_wrapper = $('.places-map-wrapper', $wrapper); // set selected place if it exists in livewhale object
this.selected_place = null;
if ($.isArray(LW.editor.values.places_id) && LW.editor.values.places_id.length) {
this.selected_place = LW.editor.values.places_id;
}
this.initSearch(); // add remove link
this.$remove_link = $wrapper.find('.places-remove').hide().on('click', function (e) {
e.preventDefault();
that.removePlace();
return true;
}); // add place form toggle
$wrapper.on('change', '.places-add-new-checkbox', function (e) {
if ($(this).prop('checked')) {
that.showAddForm();
} else {
that.hideAddForm();
}
}); // return right away if there is no location form element or this is not the places editor
//if (!$location.length && LW.page !== 'places_edit') return false;
//
var $places_select = $('.places-select-existing'),
$multiselect = $('
'),
$places_overlay = $('
');
$multiselect.multiselect({
data: LW.places,
//selected: that.selected_place || [],
onlyone: true,
change: function change(e, data) {
setTimeout(function () {
$places_overlay.overlay('close'); // addPlace if a single place returned
if (data.selected && data.selected.length === 1) {
that.setPlace(data.selected[0]);
}
}, 200);
}
}).appendTo($places_overlay);
var places_footer = '' + '
' + ' Select ' + '
or cancel ' + '
';
var $places_footer = $(places_footer);
$places_overlay.overlay({
autoOpen: false,
destroyOnClose: false,
id: 'lw_places_overlay',
title: 'Select a Place',
size: 'medium',
open: function open() {
$multiselect.multiselect('deselectAll');
}
});
$places_footer.on('click', '.lw_save', function (e) {
e.preventDefault();
$places_overlay.overlay('close');
return true;
});
$places_select.on('click', function (e) {
e.preventDefault();
$places_overlay.overlay('open');
return true;
}); // if add link is clicked
$add_form.on('click', '.places-add-button', function () {
var val = $('.places-address').val(); // if an address has been set
if (val) {
that.findAddress(val);
}
$add_link.html('add a new one'); // set the add link text
}); // make enter keypress click the add button
$add_form.find('.places-address').on('keypress', function (e) {
if (e.which === 13) {
e.preventDefault();
$add_form.find('.places-add-button').trigger('click');
}
});
$('#places_confirm').on('click', function () {
// confirms a location we thought already exists
$(':input[name="confirmed"]').val(1); // flag this as confirmed
$('form[name="places_edit"]').submit(); // resubmit
}); // handler for selecting from amongst multiple locations results
$('body').on('click', '#lw_places_choose_multiple', function (e) {
var $this = $(this),
$overlay = $this.closest('.lw_overlay'),
$list = $overlay.find('#lw_places_result_list'),
id = $list.val(),
results = $list.data('geocodeResults'),
title = $list.data('title'),
loc = results[id].geometry.location;
that.setLocation(loc, title);
$overlay.find('.lw_editor').overlay('close');
});
this.setSavedPlace();
this.initMap(); // initialize the map
this.initCompatibilityCode();
};
$.extend(Places.prototype, {
initSearch: function initSearch() {
var that = this;
var $search = this.$search_wrapper.find('input:text');
$search.attr('autocomplete', 'off').relatedsearch({
module: 'places',
is_backend: true,
is_library_search: true,
render_default_menu: true,
hide_type_header: true,
hide_empty_results: true,
group: LW.group_title || '',
select: function select(e, data) {
var place = {
id: data.id,
title: data.title,
latitude: String(data.location_latitude),
longitude: String(data.location_longitude)
};
$search.val(data.title).blur();
that.setPlace(place);
return false;
}
});
},
showSearch: function showSearch() {
this.$add_form.hide();
this.$search_wrapper.show().find('input:text').val('');
this.$options.show();
},
showAddForm: function showAddForm() {
this.$add_form.slideDown(500);
},
hideAddForm: function hideAddForm() {
this.$add_form.slideUp(500);
},
showMap: function showMap(title) {
title = title || ''; // hide and clear add form
this.$add_form.hide().find('.places-address').val('');
this.$options.hide();
this.$search_wrapper.hide();
this.$map_wrapper.find('.places-title').text(title).end().show();
},
setSavedPlace: function setSavedPlace() {
// set saved place
if (_.isArray(LW.editor.values.places_id) && LW.editor.values.places_id.length === 1) {
this.setPlaceWithId(LW.editor.values.places_id[0].id);
}
},
setPlaceWithId: function setPlaceWithId(id) {
// do nothing if no id or no LW.places
if (!id || !LW.places) return;
var place = _.find(LW.places, function (o) {
return parseInt(id, 10) === parseInt(o.id, 10);
});
if (place) {
this.setPlace(place);
}
},
// this is code that I hope to be able to remove when we stop using the current
// places widget code, and when we can modify the backend to remove its cruft
initCompatibilityCode: function initCompatibilityCode() {
$('#places_add_new').hide();
},
setPlace: function setPlace(place) {
var $wrapper = this.$map_wrapper;
var $places_save_wrapper = $wrapper.find('.places-save-wrapper');
this.selected_place = [place]; // set hidden input
this.$wrapper.find('.places-id').val(place.id); // hide save as place box
$places_save_wrapper.find('.places-save-preset').prop('checked', false).end().find('.places-new-title').val('').end().hide(); // create map
this.makePlaceMap(new google.maps.LatLng(place.latitude, place.longitude), false); // show remove link
this.$remove_link.show();
this.showMap(place.title); // show reservation instructions if this is an event
if (LW.page === 'events_edit' || LW.page === 'events_sub_edit') {
this.showReservationInstructions(place.id);
}
LW.eventHub.trigger('placeSet.places', [{
place: place
}]);
},
// used when setting a new location via the new location form
setLocation: function setLocation(loc, title) {
this.$wrapper.find('.places-save-wrapper').show(); // unset any previously set place
this.$wrapper.find('.places-id').val(''); // set title
this.$wrapper.find('.places-new-title').val(title); // set coords and show map
this.setPlaceCoordinates(loc);
this.makePlaceMap(loc);
this.$remove_link.show();
this.$add_form.hide();
},
resetForm: function resetForm() {
var $places_id = this.$wrapper.find('.places-id'); // add a new location removes this element, so we need to add it if it doesn't exist
if ($places_id.length) {
$places_id.val('');
} else {
this.$wrapper.prepend(' ');
} // reset latitude and longitude
this.$wrapper.find('.places-latitude').val('').end().find('.places-longitude').val('').end(); // reset address
this.$add_form.find('.places-address').val(''); // reset save input
this.$map_wrapper.find('.places-save-wrapper').hide().find('.places-save-preset').prop('checked', false).end().find('.places-new-title').val(''); // remove reservation note
this.$map_wrapper.find('.places_reservation_note').remove();
},
showReservationInstructions: function showReservationInstructions(place_id) {
var that = this; // remove any existing
this.$map_wrapper.find('.places_reservation_note').remove();
var url = LW.lib.getAjaxUrl('getPlacesReservationInstructions', {
id: place_id,
event_id: $('#item_id').val(),
date: $('#events_date').val(),
time: $('#events_date_time').val(),
date2: $('#events_date2').val(),
time2: $('#events_date2_time').val()
});
$.getJSON(url, function (data) {
// add reservation instructions and conflicts
if (data.requires_reservation) {
$('' + (data.conflict ? '
Note: Possible double booking There is currently a conflict between your event and "' + data.conflict + ' " . Make sure any conflicts are resolved before confirming your event.
' : '') + (data.requires_reservation ? '
Note: Reservation required Please make sure this location is correctly reserved before confirming your event.
' : '') + (data.instructions ? '
Reservation instructions: ' + data.instructions : '') + '
').appendTo(that.$map_wrapper);
}
});
},
removePlace: function removePlace() {
var that = this;
this.selected_place = null;
this.resetForm();
this.showSearch(); // slide-up map holder and empty contents if visible
if (this.$map_wrapper.is(':visible')) {
this.$map_wrapper.slideUp(300, function () {
$(this).find('.places-map').empty();
that.showSearch();
});
}
},
initMap: function initMap() {
if ($('.places-latitude').val() && $('.places-longitude').val()) {
var latlng = new google.maps.LatLng($('.places-latitude').val(), $('.places-longitude').val());
this.makePlaceMap(latlng);
this.setPlaceCoordinates(latlng);
}
},
findAddress: function findAddress(val) {
var that = this,
result = false,
geocoder;
if (!val.length) return false;
geocoder = new google.maps.Geocoder();
geocoder.geocode({
address: val
}, function (results, status) {
if (status === 'OK') {
if (results.length === 1) {
that.setLocation(results[0].geometry.location, val);
} else if (results.length > 1) {
that.showAddressSelectDialog(results, val);
}
} else if (status === 'ZERO_RESULTS') {
that.showUnableToFindAddress();
}
return result;
});
},
showUnableToFindAddress: function showUnableToFindAddress() {
var html;
html = '' + '
Unable to find address. Please provide more detail and try again.
' + '
Close ' + '
';
$(html).overlay({
closeSelector: '.close-overlay'
});
},
displayHelperMessage: function displayHelperMessage() {
// add helper dialog box
if ($('.places-map').siblings('#places_instructions').length === 0) {
$('.places-map').after('
');
}
$('.places-map').siblings('#places_instructions').html('Drag the pin to adjust the exact location of your place.').show(500);
},
setPlaceCoordinates: function setPlaceCoordinates(googleLatLng) {
$('.places-latitude', this.$wrapper).val(googleLatLng.lat());
$('.places-longitude', this.$wrapper).val(googleLatLng.lng());
$('.places-thumb', this.$wrapper).val(this.makeStaticImageLink(googleLatLng));
},
makeStaticImageLink: function makeStaticImageLink(googleLatLng) {
return LW.liveurl_dir + '/places/thumb?url=' + encodeURIComponent('http://maps.googleapis.com/maps/api/staticmap?sensor=false&size=320x320&zoom=17&markers=size:small|' + googleLatLng.lat() + ',' + googleLatLng.lng());
},
makePlaceMap: function makePlaceMap(googleLatLng) {
var that = this,
interactive = typeof arguments[1] === 'boolean' ? arguments[1] : true;
this.showMap();
map = new google.maps.Map($('.places-map').get(0), {
zoom: 17,
center: googleLatLng,
mapTypeId: google.maps.MapTypeId.ROADMAP,
streetViewControl: false,
scrollwheel: false
});
marker = new google.maps.Marker({
map: map,
draggable: interactive,
animation: google.maps.Animation.DROP
});
marker.setPosition(googleLatLng);
marker.setClickable(interactive);
marker.setTitle($('.places-new-title').val());
if (interactive) {
that.displayHelperMessage();
} // create listener
google.maps.event.addListener(marker, 'dragend', function () {
that.setPlaceCoordinates(marker.position);
});
},
disableSearch: function disableSearch() {
this.search_disabled = true;
}
}, placesBase); // on DOM ready
$(function ($) {
// if places editor
if (LW.page === 'places_edit') {
places_editor.init();
} // if page has places_id, then init places component JS
if (LW.editor && LW.editor.values && LW.editor.values.places_id) {
LW.editor.places_widget = new Places();
}
});
})(livewhale, livewhale.jQuery, window);
"use strict";
(function (LW, global) {
// only execute on search and search_data pages
if (LW.page !== 'search' && LW.page !== 'search_data') {
return;
}
var search = {
init: function init() {
var $checkbox_wrapper = $('#content_type_checkboxes');
var all_checked = true;
var that = this; // add type class to body, so we can position subnav
if (LW.module !== 'search') {
$('body').addClass(LW.module + '_search');
}
this.$content = $('#content');
var $search_wrapper = this.$search_wrapper = $('#search_options'); // change visibility of group options according to whether content shared by others is searched
var $other_groups = $('#search_other_groups');
$other_groups.on('change', function () {
if ($other_groups.is(':checked')) {
$('#search_groups').show();
} else {
$('#search_groups').hide();
}
$search_wrapper.resize();
});
$other_groups.trigger('change'); // TODO: remove and integrate .shared_content_search CSS. All searches are now shared content searches
$('body').addClass('shared_content_search'); // show/hide checkboxes when Everything checkbox changes
var $select_switch = $('#select_switch').on('change', function (e) {
var $this = $(e.currentTarget);
var checked = $this.prop('checked');
$checkbox_wrapper.find('input[type="checkbox"]').prop('checked', checked);
if (checked) {
$checkbox_wrapper.slideUp(300);
} else {
$checkbox_wrapper.slideDown(300, function () {
$search_wrapper.resize();
});
}
return true;
}); // check determine whether all checkboxes checked
$checkbox_wrapper.find('input[type="checkbox"]').each(function (i, el) {
if (!$(el).prop('checked')) {
all_checked = false;
}
}); // check the Everything checkbox if all checkboxes checked
if (all_checked) $select_switch.trigger('click');
this.formatResults();
this.adjustPageHeight();
$search_wrapper.on('resize', function () {
that.adjustPageHeight();
}); // enable searching for more results
$('.results_links').on('click', '.results_more', function (e) {
var data_type = $(e.currentTarget).attr('data-type');
if (data_type) {
// uncheck all content types
$('#select_switch:checked').trigger('click'); // uncheck all content types
$('#content_type_checkboxes input:checked').trigger('click'); // check the one content type
$('#content_type_checkboxes input#type_' + data_type).trigger('click'); // perform search
$('#search_options button').trigger('click');
}
return false;
}); // enable searching for number in content if searching by id
if ($('#search_options #search').val().match(/^[0-9]+$/)) {
$('#search_search_for_number').on('click', 'a', function () {
var str = $('input#search').val();
document.location.href = document.location.href.replace('=' + str, '=%22' + str + '%22');
return false;
});
}
},
formatResults: function formatResults() {
var $results = $('#manager_search'); // return right away if no results; nothing to format
if ($results.children('.nonefound').length) {
$results.show();
return;
}
$results.show();
$results.on('click', '.content_results', function (e) {
var $this = $(e.currentTarget);
if (!$this.hasClass('search_select')) {
$this.siblings().removeClass('search_select');
$this.addClass('search_select');
}
return true;
}); // make "make your own copy" button visible by default for images
var $types = $('#content_type_checkboxes').find('input[name="types\\[\\]"]:checked');
if ($types.length === 1 && $types.val() === 'images') {
$results.find('.content_results').addClass('search_select');
}
},
// adjust height of container if search opts height greater than container's
adjustPageHeight: function adjustPageHeight() {
// tack on an additional 30px for good measure if wrapper height greater than content height
if (this.$search_wrapper.height() > this.$content.height()) {
this.$content.height(this.$search_wrapper.height() + 30);
}
}
};
var search_data = {
init: function init() {
$('.data_details').hide();
$('.show_details').on('click', 'a', function (e) {
var $this = $(e.currentTarget);
if ($this.text() === '(show details)') {
var url_params = {
livewhale: 'ajax',
'function': 'getSearchDataDetails',
n: LW.lib.getQueryStringParam('n'),
u: LW.lib.getQueryStringParam('u'),
phrase: encodeURIComponent($this.attr('href').substring(1))
};
$this.html('(hide details)'); // load the search results and show
$this.closest('li').find('.data_details').load('/livewhale/backend.php?' + $.param(url_params)).show();
} else {
$this.html('(show details)');
$this.closest('li').find('.data_details').hide();
}
return false;
});
}
};
switch (LW.page) {
case 'search':
search.init();
break;
case 'search_data':
search_data.init();
break;
}
})(livewhale, window);
"use strict";
(function (LW, global) {
function initManagerApplyTag() {
var $tag_container = $('#apply_tag_container');
var $dropdown_checked = $('#dropdown_checked'); // toggle dropdown for the "Apply tag..." item on any manager
// with an #apply_tag_container and checked items dropdown
if ($tag_container.length && $dropdown_checked.length) {
$dropdown_checked.on('change', function (e) {
if ($(e.currentTarget).val().indexOf('_apply_tag') !== -1) {
$tag_container.show();
} else {
$tag_container.hide();
}
return true;
}); // and activate the "new" choice in that dropdown
$tag_container.find('select').on('change', function (e) {
var $this = $(e.currentTarget);
if (!$this.next().is('input[type=text]')) {
$this.after(' ');
}
if ($this.val() !== '' && $this.val() === '0') {
$this.next().show();
} else {
$this.next().hide();
}
});
}
}
function initManagerRemoveTag() {
var $tag_container = $('#remove_tag_container');
var $dropdown_checked = $('#dropdown_checked'); // toggle dropdown for the "Remove tag..." item on any manager
// with an #remove_tag_container and checked items dropdown
if ($tag_container.length && $dropdown_checked.length) {
$dropdown_checked.on('change', function (e) {
if ($(e.currentTarget).val().indexOf('_remove_tag') !== -1) {
$tag_container.show();
} else {
$tag_container.hide();
}
return true;
});
}
}
if (LW.is_manager) {
initManagerApplyTag();
initManagerRemoveTag();
} // do nothing if this isn't the tags module
if (LW.module !== 'tags') {
return;
}
var tags = {
init: function init() {
var $ul = $('ul#manager_tags');
if (!$ul.length && $('.lw_nonefound').length) {
$ul = $('').appendTo($('.lw_nonefound').parent());
} // edit existing
$ul.on('click', '.item_name a', function (e) {
e.preventDefault();
var $this = $(e.currentTarget);
var $h5 = $this.parent().hide(); // cache and hide h5
var tag = $this.text();
var html;
html = '';
var $form = $(html).insertAfter($h5);
$form.find('input[type=text]').val(tag).trigger('focus').on('keypress', function (e) {
if (e.keyCode === 13) {
// capture enter
$(e.currentTarget).next().trigger('click');
return false;
}
});
return true; // cancel the link click
}) // when clicking to save the tag
.on('click', '.tag_save', function (e) {
var $this = $(e.currentTarget);
var title = encodeURIComponent($this.prev().val());
var id = $this.closest('li').find('.with_this').val() || '';
var url_opts = {
id: id,
title: title
};
if (LW.page === 'tags_global') {
url_opts.is_global = '1';
}
var url = LW.lib.getAjaxUrl('saveTagsTitle', url_opts);
$.getJSON(url, function (data) {
var stars = {};
var tags_url_opts = LW.page === 'tags_global' ? {
is_global: '1'
} : null;
var tags_url = LW.lib.getAjaxUrl('getTagsList', tags_url_opts); // store star state
$ul.children().each(function (i, el) {
var val = parseInt($(el).find('.star input').val(), 10);
if (el.id) {
stars[el.id] = val;
}
}); // reload the tags list
$ul.load(tags_url + ' ul#manager_tags > li', function () {
// reset the stars
$.each(stars, function (id, value) {
$ul.find('li#' + id + ' .star input').val(value);
});
LW.lib.highlightStars(); // re-initialize stars
});
if (data.error) alert(data.error); // alert if tag already exists
});
}).on('click', '.lw_cancel a', function (e) {
var $this = $(e.currentTarget);
var $li = $this.closest('li');
var tag = $.trim($li.find('.item_name a').text());
if (!tag) {
// if this is a new tag
$li.remove(); // kill the whole li
if (!$ul.children().length) {
// if this was the last LI
$ul.append('None found. ');
}
} else {
$this.closest('.tag_fields').siblings('.item_name').show().end().remove();
}
return false; // cancel the original click
}); // add new
$('.addnew').on('click', function (e) {
var html; // do nothing if a new item alread exists
if ($ul.children('.new_tag').length) return;
if ($('.lw_nonefound').length) {
$('.lw_nonefound').remove();
}
html = '' + ' ' + ' ' + ' ';
$ul.prepend(html).children().eq(0).find('a').trigger('click');
return false; // cancel the click
}); // show merge tags menu when "Merge Tags" item selected in with checked select menu
$('#dropdown_checked').on('change', function (e) {
var $this = $(e.currentTarget);
var $dropdown_merge = $this.siblings('#dropdown_merge');
var html = '';
var options = '';
if ($this.val() === 'tags_merge') {
// loop through checked tags
$ul.find('input.with_this:checked').each(function (i, el) {
var $this = $(el);
var tag = $this.closest('li').find('.item_name > a').text();
options += '' + tag + ' ';
}); // add merge_as dropdown if items were checked
if (options) {
html = 'Merge tags as: ' + '' + ' ' + options + ' ';
} else {
// else if no items checked
alert('You must first select the tags you wish to merge.'); // give error
$this.val(''); // clear dropdown selection
}
$dropdown_merge.html(html); // set merge_as menu
} else {
$dropdown_merge.html(''); // else if tags_merge not selected, clear merge_as menu
}
});
}
};
if (LW.page === 'tags' || LW.page === 'tags_global') {
tags.init();
}
})(livewhale, window);
"use strict";
(function (LW, global) {
// only execute if updates module
if (LW.module !== 'updates') {
return;
}
var updates_clients_edit = {
init: function init() {
$('.modules_select').multiselect({
name: 'allowed_modules',
type: 'modules',
data: LW.modules,
selected: LW.editor.values.allowed_modules
});
// enable reveal master password click
$('body').on('click', '#reveal_master_password', function (e) {
var $this = $(e.currentTarget);
$this.replaceWith('' + $this.attr('data-master-password') + '
');
return false;
});
// customize user limits
$('body').on('click', '#updates_customize_user_limits', function (e) {
var $this = $(e.currentTarget);
$this.parent().next().toggle();
return false;
});
}
};
var updates_clients = {
init: function init() {
var _this = this;
// enable filter search box
$('.sidebar').on('click', '.filter_submit_code', function (e) {
_this.search();
return false;
});
$('.sidebar').on('keypress', '.filter_search_code', function (e) {
if (e.keyCode === 13) {
_this.search();
}
return true;
});
var search_terms = window.location.href.match(/&code_search=([^&]+)/);
// add link to clear active search
if (search_terms) {
// add cancel search link
var html = '' + '
' + decodeURIComponent(search_terms[1]) + ' ' + '
[cancel] ' + '
';
$('.filter_submit_code').after(html);
// handle cancel search link
$('.filter_code_cancel').on('click', 'a', function () {
window.location.href = LW.request.replace(/&code_search=[^&]+/, '');
return false;
});
}
},
search: function search() {
var search_str = $('.filter_search_code').val();
if (search_str) {
var href = LW.request.replace(/&code_search=[^&]+/, '');
window.location.href = href + '&code_search=' + encodeURIComponent(search_str);
}
}
};
var updates_pull = {
init: function init() {
// init accordion
if ($.fn.accordion) {
$('.lw_accordion').accordion();
}
$('ul.release_notes').closest('.lw_accordion_block').find('.lw_accordion_block_title button').click(); // expand release notes on page load
// handle development server config help
$('#configure_pull_source a').on('click', function () {
$($('#configure_pull_source_details').prop('outerHTML')).overlay({
closeSelector: '.lw_cancel a',
title: 'Pull Configuration'
});
return false;
});
// add JS confirm to update button
$('body').on('click', '#run-update', function () {
return confirm('Are you sure you wish to run this software update?');
});
}
};
var updates_sync = {
init: function init() {
// handle content sync click
$('body').on('click', '.content-sync-btn,.content-sync-confirmed-btn', function (e) {
var $this = $(e.currentTarget);
// do nothing if link not valid
if (!$this.attr('data-host').length || !$this.hasClass('content-sync-btn') && !$this.hasClass('content-sync-confirmed-btn')) {
return true;
}
var sync_host = $this.attr('data-host');
var is_validation = $this.hasClass('content-sync-btn');
var is_pull = $this.hasClass('content-sync-confirmed-btn');
var url;
url = 'http' + (window.location.protocol == "https:" ? 's' : '') + '://' + livewhale.host + livewhale.liveurl_dir + '/updates/sync/' + (is_pull ? 'pull' : 'validate-target') + '/' + sync_host;
// validate or pull
$.getJSON(url, function (data) {
if (data.error.length) {
// show errors
// clear any previous notice
if ($('.lw_notice_close_button').length) {
$('.lw_notice_close_button').click();
}
$('body').notify({
id: 'ajax',
message: 'Cannot proceed with content sync due to the following errors: ' + data.error.join(' ') + ' ',
type: 'failure'
});
} else {
// if no error
if (is_validation) {
// if this is a validation
$('body').notify({
// show notices and get confirmation
id: 'ajax',
message: 'Ready to proceed with content sync ' + data.notice.join(' ') + ' ' : '') + 'Sync Content
',
type: 'success'
});
} else if (is_pull) {
// else if pull
if (data.success) {
// if sync successfully started
window.location.href = '/livewhale/?login'; // redirect to login
}
}
}
});
return false;
});
}
};
// initialize page
switch (LW.page) {
case 'updates_clients':
updates_clients.init();
break;
case 'updates_clients_edit':
updates_clients_edit.init();
break;
case 'updates_pull':
updates_pull.init();
break;
case 'updates_sync':
updates_sync.init();
break;
}
})(livewhale, window);
"use strict";
(function (LW, global) {
// don't do anything if this isn't an events module
if (LW.module !== 'users') {
return;
}
var group_switch_enabled = false;
function users() {
$('body').removeClass('manager').addClass('editor'); // enable gateway selection
$('#gateway').on('change', function (e) {
var $gateway_options = $('#gateway_' + $(this).val());
$('.gateway').addClass('lw_hidden');
if ($gateway_options.length) {
$gateway_options.removeClass('lw_hidden');
}
return false;
}).trigger('change');
}
function usersEdit() {
var user_id = $('#user_id').val(); // init multiselect for module select menu
var $module_select = $('.modules_select').multiselect({
name: 'authorized_modules',
type: 'modules',
data: LW.modules,
selected: LW.editor.values.authorized_modules
});
$('.link_delete').off('click').on('click', function () {
if (confirm('Are you sure you want to delete this user?')) {
var id = $('#user_id').val(),
gid = $('#group_id').val();
window.location.href = '?users_edit&id=' + id + '&gid=' + gid + '&d=' + id;
}
return false;
});
var groups = LW.groups;
var switch_groups = LW.editor.values.switch_groups || {}; // only applies to limited group editors
if (!_.isEmpty(LW.limited_groups)) {
// set groups; limit to those in LW.limited_groups
var limited = _.map(LW.limited_groups, function (g) {
return parseInt(g);
}); // convert array items to ints
groups = _.filter(groups, function (o) {
return _.includes(limited, parseInt(o.id));
}); // lock already assigned switch groups
if (!_.isEmpty(switch_groups)) {
switch_groups = _.map(switch_groups, function (o) {
if (!_.includes(limited, parseInt(o.id))) {
o.is_locked = true;
}
return o;
});
}
}
$('.group_suggest').multisuggest({
name: 'switch_groups',
type: 'groups',
data: groups,
submitLockedItems: true,
selected: switch_groups
});
var $group_switch = $('#group_switch'),
$groups = $group_switch.find('.group_suggest'),
$group_toggle = $('#group_switch_toggle');
$group_toggle.on('click', function (e) {
// deselect all groups when unchecking toggle
if (!$(this).is(':checked')) {
$group_switch.slideUp('fast');
group_switch_enabled = true;
} else {
$group_switch.slideDown('fast');
group_switch_enabled = false;
}
}); // remove switch to group values if an administrator
$('.submit-button').closest('form').on('submit', function (e) {
var role = $('#users_edit').find('input[name="role"]:checked').val();
if (role === 'administrator') {
$groups.find('.lw-item .lw-remove').trigger('click');
}
}); // show additional groups if any groups are selected. set this regardless of role so it appears
// properly in case the user switches from admin or editor to curator or publisher
if ($groups.find('.lw-item').length || $('#custom_core_groups_all').is(':checked')) {
$group_switch.slideDown('fast');
}
var $modules = $('.modules_select'),
$core_publish = $('#custom_core_publish'),
$core_globals = $('#custom_core_globals'); // upon toggling core_edit
$('body').on('change', '#custom_core_edit', function () {
if ($(this).is(':checked')) {
$modules.show(); // show the authorized modules selector
$core_publish.prop('disabled', false).trigger('change'); // unlock core_publish
$core_globals.prop('disabled', false).trigger('change'); // unlock core_globals
// select all content types if loading the editor for a brand new user
if (!user_id && LW.editor.values.authorized_modules.length === 0) {
$module_select.multiselect('selectAll');
}
} else {
$modules.hide(); // hide the authorized modules selector
$core_publish.prop('checked', false).prop('disabled', true).trigger('change'); // uncheck core_publish and lock it
$core_globals.prop('checked', false).prop('disabled', true).trigger('change'); // uncheck core_globals and lock it
}
}); // The following is a fix for Chrome/Safari which autofills the user edit username/password fields regardless of autocomplete="off"
var username = $('#users_username').val(); // fetch the original username that was prefilled by LiveWhale
$('#users_password.password-mode').attr('type', 'password'); // switch password field from text (as in the template) to password, which triggers the browser autofill
var autofill_fix = setInterval(function () {
// set an interval to wait for the autofill to happen, and then undo it
if ($('#users_username').val() !== username) {
$('#users_username').val(username);
$('#users_password').val('');
}
}, 100);
setTimeout(function () {
// after 1000ms, terminate this fix
clearInterval(autofill_fix);
}, 1000);
$('#users_edit').on('change', '#custom_pages_edit', function () {
// upon toggling pages_edit
// disable pages_browse if neither pages_edit nor pages_manage are checked
if (!$(this).is(':checked') && !$('#custom_pages_manage').is(':checked')) {
$('#custom_pages_browse').prop('checked', false).prop('disabled', true).trigger('change');
} else {
$('#custom_pages_browse').prop('disabled', false).trigger('change');
}
}); // for Add, edit, and delete pages and navigations option, toggle the show-file-browser option
$('#users_edit').on('change', '#custom_pages_manage', function () {
// disable pages_browse if neither pages_edit nor pages_manage are checked
if (!$(this).is(':checked') && !$('#custom_pages_edit').is(':checked')) {
$('#custom_pages_browse').prop('checked', false).prop('disabled', true).trigger('change');
} else {
$('#custom_pages_browse').prop('disabled', false).trigger('change');
} // enable pages_publish if pages_manage is enabled
if ($(this).is(':checked') && !$('#custom_pages_publish').is(':checked')) {
$('#custom_pages_publish').prop('checked', true).trigger('change');
}
}); // upon toggling core_admin
$('#users_edit').on('change', '#custom_core_admin', function () {
var $this = $(this);
var enabled_for_admins = ['core_edit', 'core_upload', 'core_submissions', 'core_activity', 'core_publish', 'pages_edit', 'pages_manage', 'pages_publish', 'core_globals', 'widgets_manage'];
if ($this.is(':checked')) {
// if checked
// check and lock all enabled_for_admins options
$.each(enabled_for_admins, function (key, setting) {
$('#custom_' + setting).prop('checked', true).prop('disabled', true).trigger('change');
}); // select all, lock all, and hide authorized modules
$module_select.multiselect('lockAll').multiselect('selectAll').hide();
$module_select.multiselect('selectAll');
if ($('#group_switch_toggle').is(':checked')) {
// disable group switching option for admins
$('#group_switch_toggle').trigger('click');
}
$('#group_switch').slideUp('fast');
$('#group_switch_toggle').prop('disabled', true);
if ($('#group_limited_editing_toggle').is(':checked')) {
// disable limited group editing option for admins
$('#group_limited_editing_toggle').trigger('click');
}
$('#group_limited_editing_toggle').prop('disabled', true);
if ($('#custom_core_groups_all').is(':checked')) {
// disable custom_core_groups_all for admins, since that's already implied
$('#custom_core_groups_all').trigger('click');
}
} else {
// else if not checked
// unlock all enabled_for_admins options
$.each(enabled_for_admins, function (key, setting) {
$('#custom_' + setting).prop('disabled', false);
}); // change all affected options so they can re-disable where needed
$.each(enabled_for_admins, function (key, setting) {
$('#custom_' + setting).trigger('change');
});
$module_select.multiselect('resetSelection').multiselect('unlockAll').show(); // unlock all, and show authorized modules
$('#group_switch_toggle').prop('disabled', false);
$('#group_limited_editing_toggle').prop('disabled', false);
}
}); // upon toggling core_groups
$('#users_edit').on('change', '#custom_core_groups', function () {
// disable limited group editing if enabling full group/user editing
if (!$(this).is(':checked')) {
$('#group_limited_editing_toggle').prop('disabled', false);
} else {
if ($('#group_limited_editing_toggle').is(':checked')) {
// disable limited group editing option for admins
$('#group_limited_editing_toggle').trigger('click');
}
$('#group_limited_editing_toggle').prop('disabled', true);
}
}); // upon toggling custom_core_groups_all
$('body').on('change', '#custom_core_groups_all', function () {
if ($(this).is(':checked')) {
$group_switch.find('.group_suggest').hide();
$group_switch.find('.lw-showall').hide();
$group_switch.find('.lw-item').remove();
if ($('#group_switch_toggle').is(':checked')) {
$('#group_switch').slideDown('fast');
}
} else {
$group_switch.find('.group_suggest').show();
$group_switch.find('.lw-showall').show();
}
});
$('#custom_core_groups_all').trigger('change'); // toggle all child permissions when category toggled
$('#users_edit').on('change', '.category_checkbox', function () {
var $this = $(this),
is_checked = $this.prop('checked'),
$td_next = $this.closest('td').next(),
$to_check = $td_next.find('input[type="checkbox"]').not('.modules_select input'),
has_module_select = $td_next.find('.modules_select').length; // if enabling category
if (is_checked) {
// if enabling category, check all child permissions that aren't already checked
$.each($to_check, function () {
if (!$(this).prop('checked')) {
$(this).trigger('click');
}
}); // select all modules
if (has_module_select && !user_id) {
$module_select.multiselect('selectAll');
}
$.each($this.parents('tr').prevAll().find('input[type="checkbox"].category_checkbox'), function () {
if ($(this).is(':checked') !== is_checked) {
// if enabling category, check all earlier categories
$(this).trigger('click');
}
});
}
}); // toggle category checkbox when child permissions toggled
$('#user_settings').on('change', '.user_setting_cb', function () {
var $this = $(this),
$td = $this.closest('td'),
$tr = $td.parent(),
$checkboxes = $td.find('input[type="checkbox"]').not(':checked').not('[name^="authorized_modules"]'),
category_checked = !$checkboxes.length; // toggle the checkbox if there are no earlier unchecked options (modules aside)
if ($td.prev().find('input[type="checkbox"]').is(':checked') !== category_checked && !$tr.prevAll().find('.user_setting_cb').not(':checked').not('[name^="authorized_modules"]').length) {
$td.prev().find('input[type="checkbox"]').trigger('click');
} // if unchecking, also uncheck all subsequent checkboxes
if (!category_checked) {
$tr.nextAll().find('.category_checkbox:checked').trigger('click');
}
});
$('.user_setting_cb').trigger('change'); // init all permission checkboxes at page load time
// if this is LiveWhale Calendar
if (LW.is_lwc) {
usersEditLWC();
}
$('form[name="users_edit"]').on('submit', function () {
// remove disabled flag on all inputs before posting, so that their state is preserved
$('input').prop('disabled', false);
}); // Lastly, override all element access for limited group editors with special rules
if ($('body.has_core_groups_limited').length) {
// if the current user is a limited group editor
$('.role_curator input').prop('disabled', true); // disable everything under the curator section
$('.role_administrator input').prop('disabled', true); // disable everything under the administrator section
$('.limited_groups input').prop('disabled', true); // disable everything under the limited group editor section
}
}
function showUserSwitch(role) {
var $group_switch = $('#group_switch'),
$toggle_switch = $('#group_switch_toggle'),
$toggle_editing = $('#group_limited_editing_toggle'),
$admin_msg = $('#admin_group_message');
if ('administrator' === role) {
// if user is an admin
if ($toggle_switch.is(':checked')) {
// uncheck group switching (because it's implied)
$toggle_switch.trigger('click');
}
$toggle_switch.prop('disabled', true); // and disable group switching
$group_switch.slideUp('fast');
if ($toggle_editing.is(':checked')) {
// uncheck limited group editing (superceded)
$toggle_editing.trigger('click');
}
$toggle_editing.prop('disabled', true); // and disable limited group editing
$admin_msg.show(); // and show the admin msg
} else {
// else if not an admin
if (!$('body.has_core_groups_limited').length) {
// if editor is not a limited group editor
$toggle_switch.prop('disabled', false); // enable group switching
$toggle_editing.prop('disabled', false); // enable limited group editing
// make sure the check toggle switch if it should be enabled
// this is necessary when selecting non-admin roles when admin is selected
if (!$toggle_switch.is(':checked') && group_switch_enabled) {
$toggle_switch.trigger('click');
}
}
$admin_msg.hide(); // hide the admin msg
}
}
function usersEditLWC() {
var role = $('#users_edit').find('input[name="role"]:checked').val(); // toggle certain elements according to role
showUserSwitch(role); // show/hide additional elements when changing role setting
$('#user_settings').on('change', 'input[name="role"]', function () {
var role = $(this).val();
showUserSwitch(role);
});
}
function usersExportCsv() {
$('#export_now').on('click', function () {
// handle export link
document.location.href = LW.liveurl_dir + '/users/csv' + ($('#include_headers').is(':checked') ? '?include_headers=1' : '');
return false;
});
} // on DOM ready
switch (LW.page) {
case 'users':
users();
break;
case 'users_edit':
usersEdit();
break;
case 'users_import_csv':
$('#csv_file').uploader('upload', 'csv', {});
break;
case 'users_export_csv':
usersExportCsv();
break;
}
})(livewhale, window);
/* Resource ID: f88005d8f5c463cd13df8ad6f09 ('+i+') */
/* Resource not found (). */