new static files.
Signed-off-by: rscnt <rascnt@gmail.com>
This commit is contained in:
		
					parent
					
						
							
								83e792bcaa
							
						
					
				
			
			
				commit
				
					
						fe4f6c97d5
					
				
			
		
					 778 changed files with 71557 additions and 0 deletions
				
			
		
							
								
								
									
										79
									
								
								static/cms/js/modules/cms.app_hook_select.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								static/cms/js/modules/cms.app_hook_select.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,79 @@
 | 
			
		|||
/*##################################################|*/
 | 
			
		||||
/* #CMS.API# */
 | 
			
		||||
/* global apphooks_configuration */
 | 
			
		||||
(function($) {
 | 
			
		||||
// CMS.$ will be passed for $
 | 
			
		||||
$(document).ready(function () {
 | 
			
		||||
 | 
			
		||||
	var appHooks = $('#application_urls'),
 | 
			
		||||
		selected = appHooks.find('option:selected'),
 | 
			
		||||
		appNsRow = $('.form-row.application_namespace'),
 | 
			
		||||
		appNs = appNsRow.find('#id_application_namespace'),
 | 
			
		||||
		appCfgsRow = $('.form-row.application_configs'),
 | 
			
		||||
		appCfgs = appCfgsRow.find('#application_configs'),
 | 
			
		||||
		appCfgsAdd = appCfgsRow.find('#add_application_configs'),
 | 
			
		||||
		original_ns = appNs.val();
 | 
			
		||||
 | 
			
		||||
	// Shows / hides namespace / config selection widgets depending on the user input
 | 
			
		||||
	appHooks.setupNamespaces = function() {
 | 
			
		||||
		var opt = $(this).find('option:selected');
 | 
			
		||||
 | 
			
		||||
		if($(appCfgs).length > 0 && apphooks_configuration[opt.val()]){
 | 
			
		||||
			appCfgs.html('');
 | 
			
		||||
			for(var i=0; i < apphooks_configuration[opt.val()].length; i++) {
 | 
			
		||||
				selectedCfgs = '';
 | 
			
		||||
				if(apphooks_configuration[opt.val()][i][0] == apphooks_configuration_value) {
 | 
			
		||||
					selectedCfgs = 'selected="selected"';
 | 
			
		||||
				}
 | 
			
		||||
				appCfgs.append('<option ' + selectedCfgs + ' value="' + apphooks_configuration[opt.val()][i][0] + '">' + apphooks_configuration[opt.val()][i][1] + '</option>')
 | 
			
		||||
			}
 | 
			
		||||
			appCfgsAdd.attr('href', apphooks_configuration_url[opt.val()]);
 | 
			
		||||
			appCfgsRow.removeClass('hidden');
 | 
			
		||||
			appNsRow.addClass('hidden');
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			appCfgsRow.addClass('hidden');
 | 
			
		||||
			if(opt.data('namespace')) {
 | 
			
		||||
				appNsRow.removeClass('hidden');
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				appNsRow.addClass('hidden');
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// Hide the namespace widgets if its not required.
 | 
			
		||||
	appHooks.setupNamespaces();
 | 
			
		||||
 | 
			
		||||
	// Show it if we change to an app_hook that requires a namespace
 | 
			
		||||
	appHooks.on('change', function(){
 | 
			
		||||
		var self = $(this),
 | 
			
		||||
			opt = self.find('option:selected');
 | 
			
		||||
 | 
			
		||||
		appHooks.setupNamespaces();
 | 
			
		||||
 | 
			
		||||
		// If we clear the app_hook, clear out the app_namespace too
 | 
			
		||||
		if (!self.val()) {
 | 
			
		||||
			appNs.val('');
 | 
			
		||||
			appNs.removeAttr('value');
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// When selecting back the original apphook we try
 | 
			
		||||
		// to restore the original configuration
 | 
			
		||||
		if(selected.val() == opt.val()) {
 | 
			
		||||
			if(original_ns) {
 | 
			
		||||
				appNs.val(original_ns);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		// If new apphook has a namespace, suggest the default
 | 
			
		||||
		else if (opt.data('namespace')) {
 | 
			
		||||
			appNs.val(opt.data('namespace'));
 | 
			
		||||
		}
 | 
			
		||||
		// Cleanup the whole thing
 | 
			
		||||
		else {
 | 
			
		||||
			appNs.val('');
 | 
			
		||||
			appNs.removeAttr('value');
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
})(CMS.$);
 | 
			
		||||
							
								
								
									
										242
									
								
								static/cms/js/modules/cms.base.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										242
									
								
								static/cms/js/modules/cms.base.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,242 @@
 | 
			
		|||
/*##################################################|*/
 | 
			
		||||
/* #CMS# */
 | 
			
		||||
 | 
			
		||||
// ensuring django namespace is set correctly
 | 
			
		||||
window.django = window.django || undefined;
 | 
			
		||||
 | 
			
		||||
// ensuring jQuery namespace is set correctly
 | 
			
		||||
window.jQuery = (django && django.jQuery) ? django.jQuery : window.jQuery || undefined;
 | 
			
		||||
 | 
			
		||||
// ensuring Class namespace is set correctly
 | 
			
		||||
window.Class = window.Class || undefined;
 | 
			
		||||
 | 
			
		||||
// ensuring CMS namespace is set correctly
 | 
			
		||||
var CMS = {
 | 
			
		||||
	'$': (typeof jQuery === 'function') ? jQuery : undefined,
 | 
			
		||||
	'Class': (typeof Class === 'function') ? Class : undefined,
 | 
			
		||||
	'API': {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*##################################################|*/
 | 
			
		||||
/* #CMS.API# */
 | 
			
		||||
(function($) {
 | 
			
		||||
// CMS.$ will be passed for $
 | 
			
		||||
$(document).ready(function () {
 | 
			
		||||
	/*!
 | 
			
		||||
	 * CNS.API.Helpers
 | 
			
		||||
	 * Multiple helpers used accross all CMS features
 | 
			
		||||
	 */
 | 
			
		||||
	CMS.API.Helpers = {
 | 
			
		||||
 | 
			
		||||
		// redirects to a specific url or reloads browser
 | 
			
		||||
		reloadBrowser: function (url, timeout, ajax) {
 | 
			
		||||
			var that = this;
 | 
			
		||||
			// is there a parent window?
 | 
			
		||||
			var parent = (window.parent) ? window.parent : window;
 | 
			
		||||
 | 
			
		||||
			// if there is an ajax reload, prioritize
 | 
			
		||||
			if(ajax) {
 | 
			
		||||
				parent.CMS.API.locked = true;
 | 
			
		||||
				// check if the url has changed, if true redirect to the new path
 | 
			
		||||
				// this requires an ajax request
 | 
			
		||||
				$.ajax({
 | 
			
		||||
					'async': false,
 | 
			
		||||
					'type': 'GET',
 | 
			
		||||
					'url': parent.CMS.config.request.url,
 | 
			
		||||
					'data': {
 | 
			
		||||
						'model': parent.CMS.config.request.model,
 | 
			
		||||
						'pk': parent.CMS.config.request.pk
 | 
			
		||||
					},
 | 
			
		||||
					'success': function (response) {
 | 
			
		||||
						parent.CMS.API.locked = false;
 | 
			
		||||
 | 
			
		||||
						if(response === '' && !url) {
 | 
			
		||||
							// cancel if response is empty
 | 
			
		||||
							return false;
 | 
			
		||||
						} else if(parent.location.pathname !== response) {
 | 
			
		||||
							// api call to the backend to check if the current path is still the same
 | 
			
		||||
							that.reloadBrowser(response);
 | 
			
		||||
						} else if(url === 'REFRESH_PAGE') {
 | 
			
		||||
							// if on_close provides REFRESH_PAGE, only do a reload
 | 
			
		||||
							that.reloadBrowser();
 | 
			
		||||
						} else if(url) {
 | 
			
		||||
							// on_close can also provide a url, reload to the new destination
 | 
			
		||||
							that.reloadBrowser(url);
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
				// cancel further operations
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// add timeout if provided
 | 
			
		||||
			parent.setTimeout(function () {
 | 
			
		||||
				if (url && url != parent.location.href) {
 | 
			
		||||
					// location.reload() takes precedence over this, so we
 | 
			
		||||
					// don't want to reload the page if we need a redirect
 | 
			
		||||
					parent.location.href = url;
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					// ensure page is always reloaded #3413
 | 
			
		||||
					parent.location.reload()
 | 
			
		||||
				}
 | 
			
		||||
			}, timeout || 0);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// disable multiple form submissions
 | 
			
		||||
		preventSubmit: function () {
 | 
			
		||||
			var forms = $('#cms_toolbar').find('form');
 | 
			
		||||
				forms.submit(function () {
 | 
			
		||||
					// show loader
 | 
			
		||||
					CMS.API.Toolbar._loader(true);
 | 
			
		||||
					// we cannot use disabled as the name action will be ignored
 | 
			
		||||
					$('input[type="submit"]').bind('click', function (e) {
 | 
			
		||||
						e.preventDefault();
 | 
			
		||||
					}).css('opacity', 0.5);
 | 
			
		||||
				});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// fixes csrf behaviour
 | 
			
		||||
		csrf: function (csrf_token) {
 | 
			
		||||
			$.ajaxSetup({
 | 
			
		||||
				beforeSend: function (xhr) {
 | 
			
		||||
					// set csrf_token
 | 
			
		||||
					xhr.setRequestHeader("X-CSRFToken", csrf_token);
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// handles the tooltip for the plugins
 | 
			
		||||
		showTooltip: function (name, id) {
 | 
			
		||||
			var tooltip = $('.cms_tooltip');
 | 
			
		||||
 | 
			
		||||
			// change css and attributes
 | 
			
		||||
			tooltip.css('visibility', 'visible')
 | 
			
		||||
				.data('plugin_id', id || null)
 | 
			
		||||
				.show()
 | 
			
		||||
				.find('span').html(name);
 | 
			
		||||
 | 
			
		||||
			// attaches move event
 | 
			
		||||
			// this sets the correct position for the edit tooltip
 | 
			
		||||
			$('body').bind('mousemove.cms', function (e) {
 | 
			
		||||
				// so lets figure out where we are
 | 
			
		||||
				var offset = 20;
 | 
			
		||||
				var relX = e.pageX - $(tooltip).offsetParent().offset().left;
 | 
			
		||||
				var relY = e.pageY - $(tooltip).offsetParent().offset().top;
 | 
			
		||||
				var bound = $(tooltip).offsetParent().width();
 | 
			
		||||
				var pos = relX + tooltip.outerWidth(true) + offset;
 | 
			
		||||
 | 
			
		||||
				tooltip.css({
 | 
			
		||||
					'left': (pos >= bound) ? relX - tooltip.outerWidth(true) - offset : relX + offset,
 | 
			
		||||
					'top': relY - 12
 | 
			
		||||
				});
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// attach tooltip event for touch devices
 | 
			
		||||
			tooltip.bind('touchstart.cms', function () {
 | 
			
		||||
				$('.cms_plugin-' + $(this).data('plugin_id')).trigger('dblclick');
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		hideTooltip: function () {
 | 
			
		||||
			var tooltip = $('.cms_tooltip');
 | 
			
		||||
 | 
			
		||||
			// change css
 | 
			
		||||
			tooltip.css('visibility', 'hidden').hide();
 | 
			
		||||
 | 
			
		||||
			// unbind events
 | 
			
		||||
			$('body').unbind('mousemove.cms');
 | 
			
		||||
			tooltip.unbind('touchstart.cms');
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// sends or retrieves a JSON from localStorage or the session if local storage is not available
 | 
			
		||||
		setSettings: function (settings) {
 | 
			
		||||
			var that = this;
 | 
			
		||||
			// merge settings
 | 
			
		||||
			settings = JSON.stringify($.extend({}, CMS.config.settings, settings));
 | 
			
		||||
			// set loader
 | 
			
		||||
			if(CMS.API.Toolbar) CMS.API.Toolbar._loader(true);
 | 
			
		||||
 | 
			
		||||
			// use local storage or session
 | 
			
		||||
			if(window.localStorage) {
 | 
			
		||||
				// save within local storage
 | 
			
		||||
				localStorage.setItem('cms_cookie', settings);
 | 
			
		||||
				if(CMS.API.Toolbar) CMS.API.Toolbar._loader(false);
 | 
			
		||||
			} else {
 | 
			
		||||
				// save within session
 | 
			
		||||
				CMS.API.locked = true;
 | 
			
		||||
 | 
			
		||||
				$.ajax({
 | 
			
		||||
					'async': false,
 | 
			
		||||
					'type': 'POST',
 | 
			
		||||
					'url': CMS.config.urls.settings,
 | 
			
		||||
					'data': {
 | 
			
		||||
						'csrfmiddlewaretoken': this.config.csrf,
 | 
			
		||||
						'settings': settings
 | 
			
		||||
					},
 | 
			
		||||
					'success': function (data) {
 | 
			
		||||
						CMS.API.locked = false;
 | 
			
		||||
						// determine if logged in or not
 | 
			
		||||
						settings = (data) ? JSON.parse(data) : CMS.config.settings;
 | 
			
		||||
						if(CMS.API.Toolbar) CMS.API.Toolbar._loader(false);
 | 
			
		||||
					},
 | 
			
		||||
					'error': function (jqXHR) {
 | 
			
		||||
						that.showError(jqXHR.response + ' | ' + jqXHR.status + ' ' + jqXHR.statusText);
 | 
			
		||||
					}
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// save settings
 | 
			
		||||
			CMS.settings = JSON.parse(settings);
 | 
			
		||||
 | 
			
		||||
			// ensure new settings are returned
 | 
			
		||||
			return CMS.settings;
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		getSettings: function () {
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var settings;
 | 
			
		||||
			// set loader
 | 
			
		||||
			if(CMS.API.Toolbar) CMS.API.Toolbar._loader(true);
 | 
			
		||||
 | 
			
		||||
			// use local storage or session
 | 
			
		||||
			if(window.localStorage) {
 | 
			
		||||
				// get from local storage
 | 
			
		||||
				settings = JSON.parse(localStorage.getItem('cms_cookie'));
 | 
			
		||||
				if(CMS.API.Toolbar) CMS.API.Toolbar._loader(false);
 | 
			
		||||
			} else {
 | 
			
		||||
				CMS.API.locked = true;
 | 
			
		||||
				// get from session
 | 
			
		||||
				$.ajax({
 | 
			
		||||
					'async': false,
 | 
			
		||||
					'type': 'GET',
 | 
			
		||||
					'url': CMS.config.urls.settings,
 | 
			
		||||
					'success': function (data) {
 | 
			
		||||
						CMS.API.locked = false;
 | 
			
		||||
						// determine if logged in or not
 | 
			
		||||
						settings = (data) ? JSON.parse(data) : CMS.config.settings;
 | 
			
		||||
						if(CMS.API.Toolbar) CMS.API.Toolbar._loader(false);
 | 
			
		||||
					},
 | 
			
		||||
					'error': function (jqXHR) {
 | 
			
		||||
						that.showError(jqXHR.response + ' | ' + jqXHR.status + ' ' + jqXHR.statusText);
 | 
			
		||||
					}
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if(settings === null) settings = this.setSettings(CMS.config.settings);
 | 
			
		||||
 | 
			
		||||
			// save settings
 | 
			
		||||
			CMS.settings = settings;
 | 
			
		||||
 | 
			
		||||
			// ensure new settings are returned
 | 
			
		||||
			return CMS.settings;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// autoinits
 | 
			
		||||
	CMS.API.Helpers.preventSubmit();
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
})(CMS.$);
 | 
			
		||||
							
								
								
									
										67
									
								
								static/cms/js/modules/cms.changeform.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								static/cms/js/modules/cms.changeform.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,67 @@
 | 
			
		|||
/*##################################################|*/
 | 
			
		||||
/* #CMS# */
 | 
			
		||||
(function($) {
 | 
			
		||||
// CMS.$ will be passed for $
 | 
			
		||||
$(document).ready(function () {
 | 
			
		||||
 | 
			
		||||
	// set local variables
 | 
			
		||||
	var title= $('#id_title');
 | 
			
		||||
	var slug = $('#id_slug');
 | 
			
		||||
	var changed = false;
 | 
			
		||||
	var prefill = false;
 | 
			
		||||
 | 
			
		||||
	// hide rows when hidden input fields are added
 | 
			
		||||
	$('input[type="hidden"]').each(function () {
 | 
			
		||||
		$(this).parent('.form-row').hide()
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	// determine if slug is empty
 | 
			
		||||
	if(slug.val() === '') prefill = true;
 | 
			
		||||
 | 
			
		||||
	// always bind the title > slug generation and do the validation inside for better ux
 | 
			
		||||
	title.bind('keyup', function() {
 | 
			
		||||
		var value = title.val();
 | 
			
		||||
		// international language handling
 | 
			
		||||
		if(window.UNIHANDECODER) value = UNIHANDECODER.decode(value);
 | 
			
		||||
		// if slug is empty, prefill again
 | 
			
		||||
		if(prefill === false && slug.val() === '') prefill = true;
 | 
			
		||||
		// urlify
 | 
			
		||||
		var urlified = URLify(value, 64);
 | 
			
		||||
		if(prefill) slug.val(urlified);
 | 
			
		||||
	});
 | 
			
		||||
	// autocall
 | 
			
		||||
	title.trigger('keyup');
 | 
			
		||||
 | 
			
		||||
	// set focus to title
 | 
			
		||||
	title.focus();
 | 
			
		||||
 | 
			
		||||
	// all permissions and page states loader
 | 
			
		||||
	$('div.loading').each(function () {
 | 
			
		||||
		$(this).load($(this).attr('rel'));
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	// add changed data bindings to elements
 | 
			
		||||
	slug.add(title).bind('change', function () {
 | 
			
		||||
		$(this).data('changed', true);
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	// public api for changing the language tabs
 | 
			
		||||
	// used in admin/cms/page/change_form.html
 | 
			
		||||
	CMS.API.changeLanguage = function (url) {
 | 
			
		||||
		// also make sure that we will display the confirm dialog
 | 
			
		||||
		// in case users switch tabs while editing plugins
 | 
			
		||||
		var answer = true;
 | 
			
		||||
		if(slug.length) {
 | 
			
		||||
			// check if the slug has the changed attribute
 | 
			
		||||
			if(slug.data('changed') || title.data('changed')) changed = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if(changed) {
 | 
			
		||||
			var question = gettext("Are you sure you want to change tabs without saving the page first?");
 | 
			
		||||
			answer = confirm(question);
 | 
			
		||||
		}
 | 
			
		||||
		if(answer) window.location.href = url;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
})(CMS.$);
 | 
			
		||||
							
								
								
									
										779
									
								
								static/cms/js/modules/cms.changelist.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										779
									
								
								static/cms/js/modules/cms.changelist.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,779 @@
 | 
			
		|||
/*##################################################|*/
 | 
			
		||||
/* #CMS# */
 | 
			
		||||
(function($) {
 | 
			
		||||
// CMS.$ will be passed for $
 | 
			
		||||
$(document).ready(function () {
 | 
			
		||||
	/*!
 | 
			
		||||
	 * TreeManager
 | 
			
		||||
	 * Handles treeview
 | 
			
		||||
	 * TODO this will be refactored in 3.1
 | 
			
		||||
	 */
 | 
			
		||||
	CMS.TreeManager = new CMS.Class({
 | 
			
		||||
 | 
			
		||||
		options: {
 | 
			
		||||
			'lang': {}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		initialize: function (options) {
 | 
			
		||||
			this.options = $.extend(true, {}, this.options, options);
 | 
			
		||||
 | 
			
		||||
			// load internal functions
 | 
			
		||||
			if(!this.options.settings.filtered) {
 | 
			
		||||
				this.setupFunctions();
 | 
			
		||||
				this.setupTreePublishing();
 | 
			
		||||
				this.setupUIHacks();
 | 
			
		||||
				this.setupGlobals();
 | 
			
		||||
				this.setupTree();
 | 
			
		||||
 | 
			
		||||
				// init tree component
 | 
			
		||||
				initTree();
 | 
			
		||||
			} else {
 | 
			
		||||
				// when filtered is active, prevent tree actions
 | 
			
		||||
				this.setupUIHacks();
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		setupFunctions: function () {
 | 
			
		||||
			var that = this;
 | 
			
		||||
 | 
			
		||||
			$.syncCols = function(){
 | 
			
		||||
				$('#sitemap .col-softroot').syncWidth(0);
 | 
			
		||||
				$('#sitemap .col-apphook').syncWidth(0);
 | 
			
		||||
				$('#sitemap .col-language').syncWidth(0);
 | 
			
		||||
				$('#sitemap .col-navigation').syncWidth(0);
 | 
			
		||||
				$('#sitemap .col-actions').syncWidth(0);
 | 
			
		||||
				$('#sitemap .col-info').syncWidth(0);
 | 
			
		||||
 | 
			
		||||
				that.refreshColumns.call($('ul.tree-default li'));
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			/* Colums width sync */
 | 
			
		||||
			$.fn.syncWidth = function(max) {
 | 
			
		||||
				var visible = false;
 | 
			
		||||
 | 
			
		||||
				$(this).each(function() {
 | 
			
		||||
					if($(this).is(':visible')) {
 | 
			
		||||
						visible = true;
 | 
			
		||||
						var val= $(this).width();
 | 
			
		||||
						if(val > max){
 | 
			
		||||
							max = val;
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				});
 | 
			
		||||
				if (visible && max > 0) {
 | 
			
		||||
					$(this).each(function() {
 | 
			
		||||
						$(this).css('width', max);
 | 
			
		||||
					});
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			// jquery.functional
 | 
			
		||||
			$.curry = function(fn) {
 | 
			
		||||
				if (arguments.length < 2) return fn;
 | 
			
		||||
				args = $.makeArray(arguments).slice(1, arguments.length);
 | 
			
		||||
				return function() {
 | 
			
		||||
					return fn.apply(this, args.concat($.makeArray(arguments)));
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			$.__callbackPool = {};
 | 
			
		||||
 | 
			
		||||
			$.callbackRegister = function(name, fn /*, arg0, arg1, ..*/){
 | 
			
		||||
				if (arguments.length > 2) {
 | 
			
		||||
					// create curried function
 | 
			
		||||
					fn = $.curry.apply(this, $.makeArray(arguments).slice(1, arguments.length));
 | 
			
		||||
				}
 | 
			
		||||
				$.__callbackPool[name] = fn;
 | 
			
		||||
				return name;
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			$.callbackCall = function(name/*, extra arg0, extra arg1, ..*/){
 | 
			
		||||
				if (!name || !name in $.__callbackPool) {
 | 
			
		||||
					throw "No callback registered with name: " + name;
 | 
			
		||||
				}
 | 
			
		||||
				$.__callbackPool[name].apply(this, $.makeArray(arguments).slice(1, arguments.length));
 | 
			
		||||
				$.callbackRemove(name);
 | 
			
		||||
				return name;
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			$.callbackRemove = function(name) {
 | 
			
		||||
				delete $.__callbackPool[name];
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			// very simple yellow fade plugin..
 | 
			
		||||
			$.fn.yft = function(){
 | 
			
		||||
				this.effect("highlight", {}, 1000);
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			// jquery replace plugin :)
 | 
			
		||||
			$.fn.replace = function(o) {
 | 
			
		||||
				return this.after(o).remove().end();
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		setupTreePublishing: function () {
 | 
			
		||||
			// ADD DIRECT PUBLISHING
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var tree = $('.tree');
 | 
			
		||||
			var langTrigger = '.col-language .trigger-tooltip span';
 | 
			
		||||
			var langTooltips = '.language-tooltip';
 | 
			
		||||
			var langTimer = function () {};
 | 
			
		||||
			var langDelay = 100;
 | 
			
		||||
			var langFadeDuration = 200;
 | 
			
		||||
 | 
			
		||||
			// show the tooltip
 | 
			
		||||
			tree.delegate(langTrigger, 'mouseenter', function () {
 | 
			
		||||
				var el = $(this).closest('.col-language').find('.language-tooltip');
 | 
			
		||||
				var anchors = el.find('a');
 | 
			
		||||
				var span = $(this);
 | 
			
		||||
 | 
			
		||||
				// clear timer
 | 
			
		||||
				clearTimeout(langTimer);
 | 
			
		||||
 | 
			
		||||
				// cancel if tooltip already visible
 | 
			
		||||
				if(el.is(':visible')) return false;
 | 
			
		||||
 | 
			
		||||
				// set correct position
 | 
			
		||||
				el.css('right', 20 + $(this).position().left);
 | 
			
		||||
 | 
			
		||||
				// figure out what should be shown
 | 
			
		||||
				anchors.hide();
 | 
			
		||||
				if(span.hasClass('unpublished') || span.hasClass('unpublishedparent')) anchors.eq(1).show();
 | 
			
		||||
				if(span.hasClass('published')) anchors.eq(0).show();
 | 
			
		||||
				if(span.hasClass('dirty')) anchors.show().parent().addClass('language-tooltip-multiple');
 | 
			
		||||
 | 
			
		||||
				// hide all elements
 | 
			
		||||
				$(langTooltips).fadeOut(langDelay);
 | 
			
		||||
 | 
			
		||||
				// use a timeout to display the tooltip
 | 
			
		||||
				langTimer = setTimeout(function () {
 | 
			
		||||
					el.stop(true, true).fadeIn(langFadeDuration);
 | 
			
		||||
				}, langDelay);
 | 
			
		||||
			});
 | 
			
		||||
			// hide the tooltip when leaving the area
 | 
			
		||||
			tree.delegate(langTrigger, 'mouseleave', function () {
 | 
			
		||||
				// clear timer
 | 
			
		||||
				clearTimeout(langTimer);
 | 
			
		||||
				// hide all elements
 | 
			
		||||
				langTimer = setTimeout(function () {
 | 
			
		||||
					$(langTooltips).fadeOut(langFadeDuration);
 | 
			
		||||
				}, langDelay * 2);
 | 
			
		||||
			});
 | 
			
		||||
			// reset hiding when entering the tooltip itself
 | 
			
		||||
			tree.delegate(langTooltips, 'mouseover', function () {
 | 
			
		||||
				// clear timer
 | 
			
		||||
				clearTimeout(langTimer);
 | 
			
		||||
			});
 | 
			
		||||
			tree.delegate(langTooltips, 'mouseleave', function () {
 | 
			
		||||
				// hide all elements
 | 
			
		||||
				langTimer = setTimeout(function () {
 | 
			
		||||
					$(langTooltips).fadeOut(langFadeDuration);
 | 
			
		||||
				}, langDelay * 2);
 | 
			
		||||
			});
 | 
			
		||||
			// attach double check event if publish or unpublish should be triggered
 | 
			
		||||
			tree.delegate('.language-tooltip a', 'click', function (e) {
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
 | 
			
		||||
				// cancel if not confirmed
 | 
			
		||||
				if(!confirm(that.options.lang.publish.replace('§', $(this).text().toLowerCase()))) return false;
 | 
			
		||||
 | 
			
		||||
				// publish page and update
 | 
			
		||||
				window.location.href = $(this).attr('href');
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		setupUIHacks: function () {
 | 
			
		||||
			// enables tab click on title entry to open in new window
 | 
			
		||||
			$('.tree').delegate('.col1 .title', 'click', function (e) {
 | 
			
		||||
				if(!e.metaKey) {
 | 
			
		||||
					window.top.location.href = $(this).attr('href');
 | 
			
		||||
				} else {
 | 
			
		||||
					window.open($(this).attr('href'), '_blank');
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// adds functionality to the filter
 | 
			
		||||
			$('#changelist-filter-button').bind('click', function () {
 | 
			
		||||
				$("#changelist-filter").toggle();
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// set correct active entry
 | 
			
		||||
			if(window.parent && window.parent.CMS && window.parent.CMS.config) {
 | 
			
		||||
				var page_id = window.parent.CMS.config.request.page_id;
 | 
			
		||||
 | 
			
		||||
				$('div[data-page_id="'+page_id+'"]').addClass('cont-active');
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		setupGlobals: function () {
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var msg = '';
 | 
			
		||||
			var parent = null;
 | 
			
		||||
 | 
			
		||||
			window.moveSuccess = function(node){
 | 
			
		||||
				$.syncCols();
 | 
			
		||||
 | 
			
		||||
				msg = $('<span class="success">'+that.options.lang.success+'</span>');
 | 
			
		||||
				parent = window.parent;
 | 
			
		||||
 | 
			
		||||
				node.after(msg);
 | 
			
		||||
				node.parent().find('.col2').hide();
 | 
			
		||||
				msg.fadeOut(1000, function () {
 | 
			
		||||
					node.parent().find('.col2').show()
 | 
			
		||||
				});
 | 
			
		||||
				// check for reload changes
 | 
			
		||||
				if(window.self !== window.top) {
 | 
			
		||||
					window.parent.CMS.API.Helpers.reloadBrowser(false, false, true);
 | 
			
		||||
					window.parent.CMS.API.Toolbar.openMessage(that.options.lang.changes, false, 0);
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			window.moveError = function(node,message){
 | 
			
		||||
				if(message && message !== 'error') {
 | 
			
		||||
					msg = $('<span class="success">'+message+'</span>');
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					msg = $('<span class="success">'+that.options.lang.error+'</span>');
 | 
			
		||||
				}
 | 
			
		||||
				node.parent().find('.col2').hide();
 | 
			
		||||
				node.after(msg);
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		setupTree: function () {
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var tree;
 | 
			
		||||
			// global initTree function
 | 
			
		||||
			initTree = function(){
 | 
			
		||||
				tree = new tree_component();
 | 
			
		||||
				var options = {
 | 
			
		||||
					rules: {
 | 
			
		||||
						clickable: "all",
 | 
			
		||||
						renameable: "none",
 | 
			
		||||
						deletable: "all",
 | 
			
		||||
						creatable: "all",
 | 
			
		||||
						draggable: "all",
 | 
			
		||||
						dragrules: "all",
 | 
			
		||||
						droppable: "all",
 | 
			
		||||
						metadata : "mdata",
 | 
			
		||||
						use_inline: true
 | 
			
		||||
						//droppable : ["tree_drop"]
 | 
			
		||||
					},
 | 
			
		||||
					path: false,
 | 
			
		||||
					ui: {
 | 
			
		||||
						dots: true,
 | 
			
		||||
						rtl: false,
 | 
			
		||||
						animation: 0,
 | 
			
		||||
						hover_mode: true,
 | 
			
		||||
						//theme_path: script_url_path() + "/../jstree/themes/",
 | 
			
		||||
						a_class: "title"
 | 
			
		||||
					},
 | 
			
		||||
					cookies : {
 | 
			
		||||
						prefix: "djangocms_nodes"
 | 
			
		||||
					},
 | 
			
		||||
					callback: {
 | 
			
		||||
						beforemove  : function(what, where, position) {
 | 
			
		||||
							item_id = what.id.split("page_")[1];
 | 
			
		||||
							target_id = where.id.split("page_")[1];
 | 
			
		||||
							old_node = what;
 | 
			
		||||
 | 
			
		||||
							if($(what).parent().children("li").length > 1){
 | 
			
		||||
								if($(what).next("li").length){
 | 
			
		||||
									old_target = $(what).next("li")[0];
 | 
			
		||||
									old_position = "right";
 | 
			
		||||
								}
 | 
			
		||||
								if($(what).prev("li").length){
 | 
			
		||||
									old_target = $(what).prev("li")[0];
 | 
			
		||||
									old_position = "left";
 | 
			
		||||
								}
 | 
			
		||||
							}else{
 | 
			
		||||
								if($(what).attr("rel") != "topnode"){
 | 
			
		||||
									old_target = $(what).parent().parent()[0];
 | 
			
		||||
									old_position = "inside";
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
 | 
			
		||||
							addUndo(what, where, position);
 | 
			
		||||
							return true;
 | 
			
		||||
						},
 | 
			
		||||
						onmove: function(what, where, position){
 | 
			
		||||
							item_id = what.id.split("page_")[1];
 | 
			
		||||
							target_id = where.id.split("page_")[1];
 | 
			
		||||
 | 
			
		||||
							if (position == "before") {
 | 
			
		||||
								position = "left";
 | 
			
		||||
							}else if (position == "after") {
 | 
			
		||||
								position = "right";
 | 
			
		||||
							}else if(position == "inside"){
 | 
			
		||||
								position = "last-child";
 | 
			
		||||
							}
 | 
			
		||||
							moveTreeItem(what, item_id, target_id, position, false);
 | 
			
		||||
						},
 | 
			
		||||
 | 
			
		||||
						onload: function () {
 | 
			
		||||
							setTimeout(function () {
 | 
			
		||||
								reCalc();
 | 
			
		||||
							}, 250);
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
					}
 | 
			
		||||
				};
 | 
			
		||||
 | 
			
		||||
				if (!$($("div.tree").get(0)).hasClass('root_allow_children')){
 | 
			
		||||
					// disalow possibility for adding subnodes to main tree, user doesn't
 | 
			
		||||
					// have permissions for this
 | 
			
		||||
					options.rules.dragrules = ["node inside topnode", "topnode inside topnode", "node * node"];
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				tree.init($("div.tree"), options);
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			selected_page = false;
 | 
			
		||||
			action = false;
 | 
			
		||||
 | 
			
		||||
			var _oldAjax = $.ajax;
 | 
			
		||||
 | 
			
		||||
			$.ajax = function(s){
 | 
			
		||||
				// just override ajax function, so the loader message gets displayed
 | 
			
		||||
				// always
 | 
			
		||||
				$('#loader-message').show();
 | 
			
		||||
 | 
			
		||||
				callback = s.success || false;
 | 
			
		||||
				s.success = function(data, status){
 | 
			
		||||
					if (callback) {
 | 
			
		||||
						callback(data, status);
 | 
			
		||||
					}
 | 
			
		||||
					$('#loader-message').hide();
 | 
			
		||||
				};
 | 
			
		||||
 | 
			
		||||
				// just for debuging!!
 | 
			
		||||
				/*s.complete = function(xhr, status) {
 | 
			
		||||
					if (status == "error" && that.options.settings.debug) {
 | 
			
		||||
						$('body').before(xhr.responseText);
 | 
			
		||||
					}
 | 
			
		||||
				}*/
 | 
			
		||||
				// end just for debuging
 | 
			
		||||
 | 
			
		||||
				// TODO: add error state!
 | 
			
		||||
				return _oldAjax(s);
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			function refresh(){
 | 
			
		||||
				window.location = window.location.href;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			function refreshIfChildren(pageId){
 | 
			
		||||
				return $('#page_' + pageId).find('li[id^=page_]').length ? refresh : function(){ return true; };
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/**
 | 
			
		||||
			 * Loads remote dialog to dialogs div.
 | 
			
		||||
			 *
 | 
			
		||||
			 * @param {String} url
 | 
			
		||||
			 * @param {Object} data Data to be send over post
 | 
			
		||||
			 * @param {Function} noDialogCallback Gets called when response is empty.
 | 
			
		||||
			 * @param {Function} callback Standard callback function.
 | 
			
		||||
			 */
 | 
			
		||||
			function loadDialog(url, data, noDialogCallback, callback){
 | 
			
		||||
				if (data === undefined) data = {};
 | 
			
		||||
				$.post(url, data, function(response) {
 | 
			
		||||
					if (response == '' && noDialogCallback) noDialogCallback();
 | 
			
		||||
					$('#dialogs').empty().append(response);
 | 
			
		||||
					if (callback) callback(response);
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// let's start event delegation
 | 
			
		||||
			$('#changelist li').click(function(e) {
 | 
			
		||||
				// I want a link to check the class
 | 
			
		||||
				if(e.target.tagName == 'IMG' || e.target.tagName == 'SPAN') {
 | 
			
		||||
					target = e.target.parentNode;
 | 
			
		||||
				} else {
 | 
			
		||||
					target = e.target;
 | 
			
		||||
				}
 | 
			
		||||
				var jtarget = $(target);
 | 
			
		||||
				if(jtarget.hasClass("move")) {
 | 
			
		||||
					// prepare tree for move / cut paste
 | 
			
		||||
					var id = e.target.id.split("move-link-")[1];
 | 
			
		||||
					if(id==null){
 | 
			
		||||
						id = e.target.parentNode.id.split("move-link-")[1];
 | 
			
		||||
					}
 | 
			
		||||
					var page_id = id;
 | 
			
		||||
					selected_page = page_id;
 | 
			
		||||
					action = "move";
 | 
			
		||||
					$('span.move-target-container, span.line, a.move-target').show();
 | 
			
		||||
					$('#page_'+page_id).addClass("selected");
 | 
			
		||||
					$('#page_'+page_id+' span.move-target-container').hide();
 | 
			
		||||
					e.stopPropagation();
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if(jtarget.hasClass("copy")) {
 | 
			
		||||
					// prepare tree for copy
 | 
			
		||||
					id = e.target.id.split("copy-link-")[1];
 | 
			
		||||
					if(id==null){
 | 
			
		||||
						id = e.target.parentNode.id.split("copy-link-")[1];
 | 
			
		||||
					}
 | 
			
		||||
					selected_page = id;
 | 
			
		||||
					action = mark_copy_node(id);
 | 
			
		||||
					e.stopPropagation();
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if(jtarget.hasClass("viewpage")) {
 | 
			
		||||
					var view_page_url = $('#' + target.id + '-select').val();
 | 
			
		||||
					if(view_page_url){
 | 
			
		||||
						window.open(view_page_url);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if(jtarget.hasClass("addlink")) {
 | 
			
		||||
					if (!/#$/g.test(jtarget.attr('href'))) {
 | 
			
		||||
						// if there is url instead of # inside href, follow this url
 | 
			
		||||
						// used if user haves add_page
 | 
			
		||||
						return true;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					$("tr").removeClass("target");
 | 
			
		||||
					$("#changelist table").removeClass("table-selected");
 | 
			
		||||
					page_id = target.id.split("add-link-")[1];
 | 
			
		||||
					selected_page = page_id;
 | 
			
		||||
					action = "add";
 | 
			
		||||
					$('tr').removeClass("selected");
 | 
			
		||||
					$('#page-row-'+page_id).addClass("selected");
 | 
			
		||||
					$('.move-target-container').hide();
 | 
			
		||||
					$('a.move-target, span.line, #move-target-'+page_id).show();
 | 
			
		||||
					e.stopPropagation();
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// don't assume admin site is root-level
 | 
			
		||||
				// grab base url to construct full absolute URLs
 | 
			
		||||
				admin_base_url = document.URL.split("/cms/page/")[0] + "/";
 | 
			
		||||
 | 
			
		||||
				// in navigation
 | 
			
		||||
				if(jtarget.hasClass('navigation-checkbox')) {
 | 
			
		||||
					e.stopPropagation();
 | 
			
		||||
 | 
			
		||||
					var pageId = jtarget.attr('name').split('navigation-')[1];
 | 
			
		||||
					var language = jtarget.closest('.cont').find('a[lang]').attr('lang') || '';
 | 
			
		||||
 | 
			
		||||
					// if I don't put data in the post, django doesn't get it
 | 
			
		||||
					reloadItem(jtarget, admin_base_url + 'cms/page/' + pageId + '/change-navigation/?language=' + language, { 1:1 });
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				 // lazy load descendants on tree open
 | 
			
		||||
				if(jtarget.hasClass("closed")) {
 | 
			
		||||
					// only load them once
 | 
			
		||||
					if(jtarget.find('ul > li').length == 0 && !jtarget.hasClass("loading")) {
 | 
			
		||||
						// keeps this event from firing multiple times before
 | 
			
		||||
						// the dom as changed. it still needs to propagate for
 | 
			
		||||
						// the other click event on this element to fire
 | 
			
		||||
						jtarget.addClass("loading");
 | 
			
		||||
						var pageId = $(jtarget).attr("id").split("page_")[1];
 | 
			
		||||
						var language = $(jtarget).children('div.cont').children('div.col1').children('.title').attr('lang')
 | 
			
		||||
						$.get(admin_base_url + "cms/page/" + pageId + "/" + language + "/descendants/", {}, function(r, status) {
 | 
			
		||||
							jtarget.children('ul').append(r);
 | 
			
		||||
							// show move targets if needed
 | 
			
		||||
							if($('span.move-target-container:visible').length > 0) {
 | 
			
		||||
								jtarget.children('ul').find('a.move-target, span.move-target-container, span.line').show();
 | 
			
		||||
							}
 | 
			
		||||
							reCalc();
 | 
			
		||||
						});
 | 
			
		||||
					} else{
 | 
			
		||||
						reCalc();
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if(jtarget.hasClass("move-target")) {
 | 
			
		||||
					if(jtarget.hasClass("left")){
 | 
			
		||||
						position = "left";
 | 
			
		||||
					}
 | 
			
		||||
					if(jtarget.hasClass("right")){
 | 
			
		||||
						position = "right";
 | 
			
		||||
					}
 | 
			
		||||
					if(jtarget.hasClass("last-child")){
 | 
			
		||||
						position = "last-child";
 | 
			
		||||
					}
 | 
			
		||||
					target_id = target.parentNode.id.split("move-target-")[1];
 | 
			
		||||
 | 
			
		||||
					if(action=="move") {
 | 
			
		||||
						moveTreeItem(null, selected_page, target_id, position, tree);
 | 
			
		||||
						$('.move-target-container').hide();
 | 
			
		||||
					}else if(action=="copy") {
 | 
			
		||||
						site = $('#site-select')[0].value;
 | 
			
		||||
						copyTreeItem(selected_page, target_id, position, site);
 | 
			
		||||
						$('.move-target-container').hide();
 | 
			
		||||
					}else if(action=="add") {
 | 
			
		||||
						site = $('#site-select')[0].value;
 | 
			
		||||
						window.location.href = window.location.href.split("?")[0].split("#")[0] + 'add/?target='+target_id+"&position="+position+"&site="+site;
 | 
			
		||||
					}
 | 
			
		||||
					e.stopPropagation();
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				return true;
 | 
			
		||||
			});
 | 
			
		||||
			$("div#sitemap").show();
 | 
			
		||||
 | 
			
		||||
			function reCalc(){
 | 
			
		||||
				$.syncCols();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			$(window).bind('resize', reCalc);
 | 
			
		||||
			/* Site Selector */
 | 
			
		||||
			$('#site-select').change(function(){
 | 
			
		||||
				var form = $(this).closest('form');
 | 
			
		||||
				// add correct value for copy
 | 
			
		||||
				if(action === 'copy') $('#site-copy').val(selected_page);
 | 
			
		||||
				// submit form
 | 
			
		||||
				form.submit();
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			//
 | 
			
		||||
			// If an A element has a data-attribute 'alt-class'. At this time,
 | 
			
		||||
			// this is only the edit button in the page-tree, but could be
 | 
			
		||||
			// more in future. It is important that the CSS be written in such
 | 
			
		||||
			// a manner that the alt-class is defined after the normal class,
 | 
			
		||||
			// so that it can be overridden when the alt-key is depressed.
 | 
			
		||||
			//
 | 
			
		||||
			// NOTE: This 'preview' part of the 'alt-click to [alternative
 | 
			
		||||
			// function]' feature may not work in some environments (Windows
 | 
			
		||||
			// in a some virtual machine environments, notably), but is only a
 | 
			
		||||
			// nice-'extra', not a requirement for the feature.
 | 
			
		||||
			//
 | 
			
		||||
			$(document).on('keydown keyup', function(evt){
 | 
			
		||||
				if (evt.which === 18) {
 | 
			
		||||
					$('a[data-alt-class]').each(function(){
 | 
			
		||||
						var self = $(this);
 | 
			
		||||
						self.toggleClass(self.data('alt-class'), evt.type === 'keydown');
 | 
			
		||||
					})
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			//
 | 
			
		||||
			// If the A-element has a data-attribute 'alt-href', then this
 | 
			
		||||
			// click-handler uses that instead of the normal href attribute as
 | 
			
		||||
			// the click-destination. Again, currently this is only on the
 | 
			
		||||
			// edit button, but could be more in future.
 | 
			
		||||
			//
 | 
			
		||||
			$('a[data-alt-href]').on('click', function(evt){
 | 
			
		||||
				var href;
 | 
			
		||||
				evt.preventDefault();
 | 
			
		||||
				if (evt.shiftKey) {
 | 
			
		||||
					href = $(this).data('alt-href');
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					href = $(this).attr('href');
 | 
			
		||||
				}
 | 
			
		||||
				window.location = href;					
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			var copy_splits = window.location.href.split("copy=");
 | 
			
		||||
			if(copy_splits.length > 1){
 | 
			
		||||
				var id = copy_splits[1].split("&")[0];
 | 
			
		||||
				var action = mark_copy_node(id);
 | 
			
		||||
				selected_page = id;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			function copyTreeItem(item_id, target_id, position, site){
 | 
			
		||||
				if (that.options.settings.permission) {
 | 
			
		||||
					return loadDialog('./' + item_id + '/dialog/copy/', {
 | 
			
		||||
						position:position,
 | 
			
		||||
						target:target_id,
 | 
			
		||||
						site:site,
 | 
			
		||||
						callback: $.callbackRegister("_copyTreeItem", _copyTreeItem, item_id, target_id, position, site)
 | 
			
		||||
					});
 | 
			
		||||
				}
 | 
			
		||||
				return _copyTreeItem(item_id, target_id, position, site);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			function _copyTreeItem(item_id, target_id, position, site, options) {
 | 
			
		||||
				var data = {
 | 
			
		||||
					position:position,
 | 
			
		||||
					target:target_id,
 | 
			
		||||
					site:site
 | 
			
		||||
				};
 | 
			
		||||
				data = $.extend(data, options);
 | 
			
		||||
 | 
			
		||||
				$.post("./" + item_id + "/copy-page/", data, function(decoded) {
 | 
			
		||||
					response = decoded.content;
 | 
			
		||||
					status = decoded.status;
 | 
			
		||||
					if(status==200) {
 | 
			
		||||
						// reload tree
 | 
			
		||||
						window.location = window.location.href;
 | 
			
		||||
					}else{
 | 
			
		||||
						alert(response);
 | 
			
		||||
						moveError($('#page_'+item_id + " div.col1:eq(0)"),response);
 | 
			
		||||
					}
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			function mark_copy_node(id){
 | 
			
		||||
				$('a.move-target, span.move-target-container, span.line').show();
 | 
			
		||||
				$('#page_'+id).addClass("selected");
 | 
			
		||||
				$('#page_'+id).parent().parent().children('div.cont').find('a.move-target.first-child, span.second').hide();
 | 
			
		||||
				$('#page_'+id).parent().parent().children('ul').children('li').children('div.cont').find('a.move-target.left, a.move-target.right, span.first, span.second').hide();
 | 
			
		||||
				return "copy";
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/**
 | 
			
		||||
			 * Reloads tree item (one line). If some filtering is found, adds
 | 
			
		||||
			 * filtered variable into posted data.
 | 
			
		||||
			 *
 | 
			
		||||
			 * @param {HTMLElement} el Any child element of tree item
 | 
			
		||||
			 * @param {String} url Requested url
 | 
			
		||||
			 * @param {Object} data Optional posted data
 | 
			
		||||
			 * @param {Function} callback Optional calback function
 | 
			
		||||
			 */
 | 
			
		||||
			function reloadItem(el, url, data, callback, errorCallback) {
 | 
			
		||||
				if (data === undefined) data = {};
 | 
			
		||||
 | 
			
		||||
				if (/\/\?/ig.test(window.location.href)) {
 | 
			
		||||
					// probably some filter here, tell backend, we need a filtered
 | 
			
		||||
					// version of item
 | 
			
		||||
					data['fitlered'] = 1;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				function onSuccess(response, textStatus) {
 | 
			
		||||
					var status = true;
 | 
			
		||||
					var target = null;
 | 
			
		||||
 | 
			
		||||
					if(callback) status = callback(response, textStatus);
 | 
			
		||||
					if(status) {
 | 
			
		||||
						if (/page_\d+/.test($(el).attr('id'))) {
 | 
			
		||||
							// one level higher
 | 
			
		||||
							target = $(el).find('div.cont:first');
 | 
			
		||||
						} else {
 | 
			
		||||
							target = $(el).parents('div.cont:first');
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
						var parent = target.parent();
 | 
			
		||||
 | 
			
		||||
						// remove the element if something went wrong
 | 
			
		||||
						if(response == 'NotFound') return parent.remove();
 | 
			
		||||
 | 
			
		||||
						var origin = $('.messagelist');
 | 
			
		||||
						target.replace(response);
 | 
			
		||||
 | 
			
		||||
						var messages = $(parent).find('.messagelist');
 | 
			
		||||
						if(messages.length) {
 | 
			
		||||
							origin.remove();
 | 
			
		||||
							messages.insertAfter('.breadcrumbs');
 | 
			
		||||
						}
 | 
			
		||||
						parent.find('div.cont:first').yft();
 | 
			
		||||
 | 
			
		||||
						// ensure after removal everything is aligned again
 | 
			
		||||
						$(window).trigger('resize');
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				$.ajax({
 | 
			
		||||
					'type': 'POST',
 | 
			
		||||
					'data': data,
 | 
			
		||||
					'url': url,
 | 
			
		||||
					'success': onSuccess,
 | 
			
		||||
					'error': function (XMLHttpRequest, textStatus, errorThrown) {
 | 
			
		||||
						// errorCallback is passed through the reloadItem function
 | 
			
		||||
						if(errorCallback) errorCallback(XMLHttpRequest, textStatus, errorThrown);
 | 
			
		||||
					},
 | 
			
		||||
					'xhr': (window.ActiveXObject) ? function(){try {return new window.ActiveXObject("Microsoft.XMLHTTP");} catch(e) {}} : function() {return new window.XMLHttpRequest();}
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			function moveTreeItem(jtarget, item_id, target_id, position, tree){
 | 
			
		||||
				reloadItem(
 | 
			
		||||
					jtarget, "./" + item_id + "/move-page/",
 | 
			
		||||
 | 
			
		||||
					{ position: position, target: target_id },
 | 
			
		||||
 | 
			
		||||
					// on success
 | 
			
		||||
					function(decoded,textStatus){
 | 
			
		||||
						response = decoded.content;
 | 
			
		||||
						status = decoded.status;
 | 
			
		||||
						if(status==200) {
 | 
			
		||||
							if (tree) {
 | 
			
		||||
								var tree_pos = {'left': 'before', 'right': 'after'}[position] || 'inside';
 | 
			
		||||
								tree.moved("#page_" + item_id, $("#page_" + target_id + " a.title")[0], tree_pos, false, false);
 | 
			
		||||
							} else {
 | 
			
		||||
								moveSuccess($('#page_'+item_id + " div.col1:eq(0)"));
 | 
			
		||||
							}
 | 
			
		||||
							return false;
 | 
			
		||||
						}
 | 
			
		||||
						else {
 | 
			
		||||
							moveError($('#page_'+item_id + " div.col1:eq(0)"),response);
 | 
			
		||||
							return false;
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			var undos = [];
 | 
			
		||||
 | 
			
		||||
			function addUndo(node, target, position){
 | 
			
		||||
				undos.push({node:node, target:target, position:position});
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		refreshColumns: function () {
 | 
			
		||||
			$('div.col2').children('div').each(function(index, item){
 | 
			
		||||
				$(item).css('display', 'block');
 | 
			
		||||
			});
 | 
			
		||||
			var min_width = 100000;
 | 
			
		||||
			var max_col2_width = 0;
 | 
			
		||||
			var max_col2 = null;
 | 
			
		||||
			$(this).each(function() {
 | 
			
		||||
				var cont = $(this).children('div.cont');
 | 
			
		||||
				if (!cont.is(':visible')) {
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
				var col1 = cont.children('div.col1');
 | 
			
		||||
				var col2 = cont.children('div.col2');
 | 
			
		||||
				var col1_width = col1.outerWidth(true);
 | 
			
		||||
				var col2_width = col2.outerWidth(true);
 | 
			
		||||
				var total_width = cont.outerWidth(true);
 | 
			
		||||
 | 
			
		||||
				var dif = total_width - col1_width;
 | 
			
		||||
				if(dif < min_width){
 | 
			
		||||
				   min_width = dif;
 | 
			
		||||
				}
 | 
			
		||||
				if(col2_width > max_col2_width){
 | 
			
		||||
					max_col2_width = col2_width;
 | 
			
		||||
					max_col2 = col2
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			var offset = 50;
 | 
			
		||||
			var w = 0;
 | 
			
		||||
			var hidden_count = 0;
 | 
			
		||||
			var max_reached = false;
 | 
			
		||||
			if(max_col2){
 | 
			
		||||
				max_col2.children('div').each(function(){
 | 
			
		||||
					if(!max_reached){
 | 
			
		||||
						w += $(this).outerWidth(true);
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					if(max_reached || w > (min_width - offset)){
 | 
			
		||||
						hidden_count = hidden_count + 1;
 | 
			
		||||
						max_reached = true
 | 
			
		||||
					}
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
				if(hidden_count){
 | 
			
		||||
					$(this).each(function() {
 | 
			
		||||
						$(this).children('div.cont').children('div.col2').children('div').slice(-hidden_count).each(function(){
 | 
			
		||||
							$(this).css('display', 'none');
 | 
			
		||||
						})
 | 
			
		||||
					});
 | 
			
		||||
					$('div#sitemap ul.header div.col2').children().slice(-hidden_count).each(function(){
 | 
			
		||||
						$(this).css('display','none');
 | 
			
		||||
					})
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
})(CMS.$);
 | 
			
		||||
							
								
								
									
										107
									
								
								static/cms/js/modules/cms.clipboard.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								static/cms/js/modules/cms.clipboard.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,107 @@
 | 
			
		|||
/*##################################################|*/
 | 
			
		||||
/* #CMS# */
 | 
			
		||||
(function($) {
 | 
			
		||||
// CMS.$ will be passed for $
 | 
			
		||||
$(document).ready(function () {
 | 
			
		||||
	/*!
 | 
			
		||||
	 * Clipboard
 | 
			
		||||
	 * Handles copy & paste
 | 
			
		||||
	 */
 | 
			
		||||
	CMS.Clipboard = new CMS.Class({
 | 
			
		||||
 | 
			
		||||
		implement: [CMS.API.Helpers],
 | 
			
		||||
 | 
			
		||||
		options: {
 | 
			
		||||
			'position': 220, // offset to top
 | 
			
		||||
			'speed': 100,
 | 
			
		||||
			'id': null,
 | 
			
		||||
			'url': ''
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		initialize: function (options) {
 | 
			
		||||
			this.clipboard = $('.cms_clipboard');
 | 
			
		||||
			this.options = $.extend(true, {}, this.options, options);
 | 
			
		||||
			this.config = CMS.config;
 | 
			
		||||
			this.settings = CMS.settings;
 | 
			
		||||
 | 
			
		||||
			// elements
 | 
			
		||||
			this.containers = this.clipboard.find('.cms_clipboard-containers > .cms_draggable');
 | 
			
		||||
			this.triggers = this.clipboard.find('.cms_clipboard-triggers a');
 | 
			
		||||
			this.triggerRemove = this.clipboard.find('.cms_clipboard-empty a');
 | 
			
		||||
 | 
			
		||||
			// states
 | 
			
		||||
			this.click = (document.ontouchstart !== null) ? 'click.cms' : 'touchend.cms click.cms';
 | 
			
		||||
			this.timer = function () {};
 | 
			
		||||
 | 
			
		||||
			// setup initial stuff
 | 
			
		||||
			this._setup();
 | 
			
		||||
 | 
			
		||||
			// setup events
 | 
			
		||||
			this._events();
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// initial methods
 | 
			
		||||
		_setup: function () {
 | 
			
		||||
			var that = this;
 | 
			
		||||
 | 
			
		||||
			// attach visual events
 | 
			
		||||
			this.triggers.bind('mouseenter mouseleave', function (e) {
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
				// clear timeout
 | 
			
		||||
				clearTimeout(that.timer);
 | 
			
		||||
 | 
			
		||||
				if(e.type === 'mouseleave' && !that.containers.has(e.toElement).length) hide();
 | 
			
		||||
 | 
			
		||||
				var index = that.clipboard.find('.cms_clipboard-triggers a').index(this);
 | 
			
		||||
				var el = that.containers.eq(index);
 | 
			
		||||
				// cancel if element is already open
 | 
			
		||||
				if(el.data('open') === true) return false;
 | 
			
		||||
 | 
			
		||||
				// show element
 | 
			
		||||
				that.containers.stop().css({ 'margin-left': -that.options.position }).data('open', false);
 | 
			
		||||
				el.stop().animate({ 'margin-left': 0 }, that.options.speed);
 | 
			
		||||
				el.data('open', true);
 | 
			
		||||
			});
 | 
			
		||||
			that.containers.bind('mouseover mouseleave', function (e) {
 | 
			
		||||
				// clear timeout
 | 
			
		||||
				clearTimeout(that.timer);
 | 
			
		||||
 | 
			
		||||
				// cancel if we trigger mouseover
 | 
			
		||||
				if(e.type === 'mouseover') return false;
 | 
			
		||||
 | 
			
		||||
				// we need a little timer to detect if we should hide the menu
 | 
			
		||||
				hide();
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			function hide() {
 | 
			
		||||
				that.timer = setTimeout(function () {
 | 
			
		||||
					that.containers.stop().css({ 'margin-left': -that.options.position }).data('open', false);
 | 
			
		||||
				}, that.options.speed);
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_events: function () {
 | 
			
		||||
			var that = this;
 | 
			
		||||
 | 
			
		||||
			// add remove event
 | 
			
		||||
			this.triggerRemove.bind(this.click, function (e) {
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
				that.clear(function () {
 | 
			
		||||
				    // remove element on success
 | 
			
		||||
				    that.clipboard.hide();
 | 
			
		||||
				});
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// public methods
 | 
			
		||||
		clear: function (callback) {
 | 
			
		||||
			// post needs to be a string, it will be converted using JSON.parse
 | 
			
		||||
			var post = '{ "csrfmiddlewaretoken": "' + this.config.csrf + '" }';
 | 
			
		||||
			// redirect to ajax
 | 
			
		||||
			CMS.API.Toolbar.openAjax(this.config.clipboard.url, post, '', callback);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
})(CMS.$);
 | 
			
		||||
							
								
								
									
										638
									
								
								static/cms/js/modules/cms.modal.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										638
									
								
								static/cms/js/modules/cms.modal.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,638 @@
 | 
			
		|||
/*##################################################|*/
 | 
			
		||||
/* #CMS# */
 | 
			
		||||
(function($) {
 | 
			
		||||
// CMS.$ will be passed for $
 | 
			
		||||
$(document).ready(function () {
 | 
			
		||||
	/*!
 | 
			
		||||
	 * Modal
 | 
			
		||||
	 * Controls a cms specific modal
 | 
			
		||||
	 */
 | 
			
		||||
	CMS.Modal = new CMS.Class({
 | 
			
		||||
 | 
			
		||||
		implement: [CMS.API.Helpers],
 | 
			
		||||
 | 
			
		||||
		options: {
 | 
			
		||||
			'onClose': false,
 | 
			
		||||
			'minHeight': 400,
 | 
			
		||||
			'minWidth': 800,
 | 
			
		||||
			'modalDuration': 300,
 | 
			
		||||
			'newPlugin': false,
 | 
			
		||||
			'urls': {
 | 
			
		||||
				'css_modal': 'cms/css/cms.toolbar.modal.css'
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		initialize: function (options) {
 | 
			
		||||
			this.options = $.extend(true, {}, this.options, options);
 | 
			
		||||
			this.config = CMS.config;
 | 
			
		||||
 | 
			
		||||
			// elements
 | 
			
		||||
			this.body = $('html');
 | 
			
		||||
			this.modal = $('.cms_modal');
 | 
			
		||||
			this.toolbar = $('.cms_toolbar');
 | 
			
		||||
 | 
			
		||||
			// states
 | 
			
		||||
			this.click = (document.ontouchstart !== null) ? 'click.cms' : 'touchend.cms click.cms';
 | 
			
		||||
			this.maximized = false;
 | 
			
		||||
			this.minimized = false;
 | 
			
		||||
			this.triggerMaximized = false;
 | 
			
		||||
			this.saved = false;
 | 
			
		||||
 | 
			
		||||
			// if the modal is initialized the first time, set the events
 | 
			
		||||
			if(!this.modal.data('ready')) this._events();
 | 
			
		||||
 | 
			
		||||
			// ready modal
 | 
			
		||||
			this.modal.data('ready', true);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// initial methods
 | 
			
		||||
		_events: function () {
 | 
			
		||||
			var that = this;
 | 
			
		||||
 | 
			
		||||
			// attach events to window
 | 
			
		||||
			this.modal.find('.cms_modal-collapse').bind(this.click, function (e) {
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
				that._minimize();
 | 
			
		||||
			});
 | 
			
		||||
			this.modal.find('.cms_modal-title').bind('mousedown.cms', function (e) {
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
				that._startMove(e);
 | 
			
		||||
			});
 | 
			
		||||
			this.modal.find('.cms_modal-title').bind('dblclick.cms', function () {
 | 
			
		||||
				that._maximize();
 | 
			
		||||
			});
 | 
			
		||||
			this.modal.find('.cms_modal-resize').bind('mousedown.cms', function (e) {
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
				that._startResize(e);
 | 
			
		||||
			});
 | 
			
		||||
			this.modal.find('.cms_modal-maximize').bind(this.click, function (e) {
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
				that._maximize();
 | 
			
		||||
			});
 | 
			
		||||
			this.modal.find('.cms_modal-breadcrumb-items').on(this.click, 'a', function (e) {
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
				that._changeContent($(this));
 | 
			
		||||
			});
 | 
			
		||||
			this.modal.find('.cms_modal-close, .cms_modal-cancel').bind(this.click, function (e) {
 | 
			
		||||
				that.options.onClose = null;
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
				that.close();
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// stopper events
 | 
			
		||||
			$(document).bind('mouseup.cms', function (e) {
 | 
			
		||||
				that._endMove(e);
 | 
			
		||||
				that._endResize(e);
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// public methods
 | 
			
		||||
		open: function (url, name, breadcrumb) {
 | 
			
		||||
			// cancel if another lightbox is already being opened
 | 
			
		||||
			if(CMS.API.locked) {
 | 
			
		||||
				CMS.API.locked = false;
 | 
			
		||||
				return false
 | 
			
		||||
			} else {
 | 
			
		||||
				CMS.API.locked = true;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// because a new instance is called, we have to ensure minimized state is removed #3620
 | 
			
		||||
			if(this.modal.is(':visible') && this.modal.find('.cms_modal-collapsed').length) {
 | 
			
		||||
				this.minimized = true;
 | 
			
		||||
				this._minimize();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// show loader
 | 
			
		||||
			CMS.API.Toolbar._loader(true);
 | 
			
		||||
 | 
			
		||||
			// hide tooltip
 | 
			
		||||
			this.hideTooltip();
 | 
			
		||||
 | 
			
		||||
			// reset breadcrumb
 | 
			
		||||
			this.modal.find('.cms_modal-breadcrumb').hide();
 | 
			
		||||
			this.modal.find('.cms_modal-breadcrumb-items').html('');
 | 
			
		||||
 | 
			
		||||
			// empty buttons
 | 
			
		||||
			this.modal.find('.cms_modal-buttons').html('');
 | 
			
		||||
 | 
			
		||||
			var contents = this.modal.find('.cms_modal-body, .cms_modal-foot');
 | 
			
		||||
				contents.show();
 | 
			
		||||
 | 
			
		||||
			this._loadContent(url, name);
 | 
			
		||||
 | 
			
		||||
			// insure modal is not maximized
 | 
			
		||||
			if(this.modal.find('.cms_modal-collapsed').length) this._minimize();
 | 
			
		||||
 | 
			
		||||
			// reset styles
 | 
			
		||||
			this.modal.css({
 | 
			
		||||
				'left': '50%',
 | 
			
		||||
				'top': '50%',
 | 
			
		||||
				'mergin-left': 0,
 | 
			
		||||
				'margin-right': 0
 | 
			
		||||
			});
 | 
			
		||||
			// lets set the modal width and height to the size of the browser
 | 
			
		||||
			var widthOffset = 300; // adds margin left and right
 | 
			
		||||
			var heightOffset = 350; // adds margin top and bottom;
 | 
			
		||||
			var screenWidth = $(window).width(); // it has to be the height of the window not computer screen
 | 
			
		||||
			var screenHeight = $(window).height(); // it has to be the height of the window and not computer screen
 | 
			
		||||
 | 
			
		||||
			var width = (screenWidth >= this.options.minWidth + widthOffset) ? screenWidth - widthOffset : this.options.minWidth;
 | 
			
		||||
			var height = (screenHeight >= this.options.minHeight + heightOffset) ? screenHeight - heightOffset : this.options.minHeight;
 | 
			
		||||
			this.modal.find('.cms_modal-body').css({
 | 
			
		||||
				'width': width,
 | 
			
		||||
				'height': height
 | 
			
		||||
			});
 | 
			
		||||
			this.modal.find('.cms_modal-body').removeClass('cms_loader');
 | 
			
		||||
			this.modal.find('.cms_modal-maximize').removeClass('cms_modal-maximize-active');
 | 
			
		||||
			this.maximized = false;
 | 
			
		||||
			// in case, the window is larger than the windows height, we trigger fullscreen mode
 | 
			
		||||
			if(height >= screenHeight) this.triggerMaximized = true;
 | 
			
		||||
 | 
			
		||||
			// we need to render the breadcrumb
 | 
			
		||||
			this._setBreadcrumb(breadcrumb);
 | 
			
		||||
 | 
			
		||||
			// display modal
 | 
			
		||||
			this._show(this.options.modalDuration);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		close: function () {
 | 
			
		||||
			var that = this;
 | 
			
		||||
			// handle remove option when plugin is new
 | 
			
		||||
			if(this.options.newPlugin) {
 | 
			
		||||
				var data = this.options.newPlugin;
 | 
			
		||||
				var post = '{ "csrfmiddlewaretoken": "' + this.config.csrf + '" }';
 | 
			
		||||
				var text = this.config.lang.confirm;
 | 
			
		||||
 | 
			
		||||
				// trigger an ajax request
 | 
			
		||||
				CMS.API.Toolbar.openAjax(data['delete'], post, text, function () {
 | 
			
		||||
					that._hide(100);
 | 
			
		||||
				});
 | 
			
		||||
			} else {
 | 
			
		||||
				this._hide(100);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// handle refresh option
 | 
			
		||||
			if(this.options.onClose) this.reloadBrowser(this.options.onClose, false, true);
 | 
			
		||||
 | 
			
		||||
			// reset maximize or minimize states for #3111
 | 
			
		||||
			setTimeout(function () {
 | 
			
		||||
				if(that.minimized) { that._minimize(); }
 | 
			
		||||
				if(that.maximized) { that._maximize(); }
 | 
			
		||||
			}, 300);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// private methods
 | 
			
		||||
		_show: function (speed) {
 | 
			
		||||
			// we need to position the modal in the center
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var width = this.modal.width();
 | 
			
		||||
			var height = this.modal.height();
 | 
			
		||||
 | 
			
		||||
			// animates and sets the modal
 | 
			
		||||
			this.modal.show().css({
 | 
			
		||||
				'width': 0,
 | 
			
		||||
				'height': 0,
 | 
			
		||||
				'margin-left': 0,
 | 
			
		||||
				'margin-top': 0
 | 
			
		||||
			}).stop(true, true).animate({
 | 
			
		||||
				'width': width,
 | 
			
		||||
				'height': height,
 | 
			
		||||
				'margin-left': -(width / 2),
 | 
			
		||||
				'margin-top': -(height / 2)
 | 
			
		||||
			}, speed, function () {
 | 
			
		||||
				$(this).removeAttr('style');
 | 
			
		||||
 | 
			
		||||
				that.modal.css({
 | 
			
		||||
					'margin-left': -(width / 2),
 | 
			
		||||
					'margin-top': -(height / 2)
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
				// fade in modal window
 | 
			
		||||
				that.modal.show();
 | 
			
		||||
 | 
			
		||||
				// hide loader
 | 
			
		||||
				CMS.API.Toolbar._loader(false);
 | 
			
		||||
 | 
			
		||||
				// check if we should maximize
 | 
			
		||||
				if(that.triggerMaximized) that._maximize();
 | 
			
		||||
 | 
			
		||||
				// changed locked status to allow other modals again
 | 
			
		||||
				CMS.API.locked = false;
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// add esc close event
 | 
			
		||||
			$(document).bind('keydown.cms', function (e) {
 | 
			
		||||
				if(e.keyCode === 27) that.close();
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// set focus to modal
 | 
			
		||||
			this.modal.focus();
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_hide: function (speed) {
 | 
			
		||||
			this.modal.fadeOut(speed);
 | 
			
		||||
			this.modal.find('.cms_modal-frame iframe').remove();
 | 
			
		||||
			this.modal.find('.cms_modal-body').removeClass('cms_loader');
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_minimize: function () {
 | 
			
		||||
			var trigger = this.modal.find('.cms_modal-collapse');
 | 
			
		||||
			var maximize = this.modal.find('.cms_modal-maximize');
 | 
			
		||||
			var contents = this.modal.find('.cms_modal-body, .cms_modal-foot');
 | 
			
		||||
			var title = this.modal.find('.cms_modal-title');
 | 
			
		||||
 | 
			
		||||
			// cancel action if maximized
 | 
			
		||||
			if(this.maximized) return false;
 | 
			
		||||
 | 
			
		||||
			if(this.minimized === false) {
 | 
			
		||||
				// ensure toolbar is shown
 | 
			
		||||
				CMS.API.Toolbar.toggleToolbar(true);
 | 
			
		||||
 | 
			
		||||
				// minimize
 | 
			
		||||
				trigger.addClass('cms_modal-collapsed');
 | 
			
		||||
				contents.hide();
 | 
			
		||||
 | 
			
		||||
				// save initial state
 | 
			
		||||
				this.modal.data('css', {
 | 
			
		||||
					'left': this.modal.css('left'),
 | 
			
		||||
					'top': this.modal.css('top'),
 | 
			
		||||
					'margin': this.modal.css('margin')
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
				this.modal.css({
 | 
			
		||||
					'left': this.toolbar.find('.cms_toolbar-left').outerWidth(true) + 50,
 | 
			
		||||
					'top': (this.config.debug) ? 6 : 1,
 | 
			
		||||
					'margin': 0
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
				// enable scrolling
 | 
			
		||||
				this.body.css('overflow', '');
 | 
			
		||||
 | 
			
		||||
				// ensure maximize element is hidden #3111
 | 
			
		||||
				maximize.hide();
 | 
			
		||||
				// set correct cursor when maximized #3111
 | 
			
		||||
				title.css('cursor', 'default');
 | 
			
		||||
 | 
			
		||||
				this.minimized = true;
 | 
			
		||||
			} else {
 | 
			
		||||
				// minimize
 | 
			
		||||
				trigger.removeClass('cms_modal-collapsed');
 | 
			
		||||
				contents.show();
 | 
			
		||||
 | 
			
		||||
				// reattach css
 | 
			
		||||
				this.modal.css(this.modal.data('css'));
 | 
			
		||||
 | 
			
		||||
				// disable scrolling
 | 
			
		||||
				this.body.css('overflow', 'hidden');
 | 
			
		||||
 | 
			
		||||
				// ensure maximize element is shown #3111
 | 
			
		||||
				maximize.show();
 | 
			
		||||
				// set correct cursor when maximized #3111
 | 
			
		||||
				title.css('cursor', 'move');
 | 
			
		||||
 | 
			
		||||
				this.minimized = false;
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_maximize: function () {
 | 
			
		||||
			var debug = (this.config.debug) ? 5 : 0;
 | 
			
		||||
			var container = this.modal.find('.cms_modal-body');
 | 
			
		||||
			var minimize = this.modal.find('.cms_modal-collapse');
 | 
			
		||||
			var trigger = this.modal.find('.cms_modal-maximize');
 | 
			
		||||
			var title = this.modal.find('.cms_modal-title');
 | 
			
		||||
 | 
			
		||||
			// cancel action when minimized
 | 
			
		||||
			if(this.minimized) return false;
 | 
			
		||||
 | 
			
		||||
			if(this.maximized === false) {
 | 
			
		||||
				// maximize
 | 
			
		||||
				this.maximized = true;
 | 
			
		||||
				trigger.addClass('cms_modal-maximize-active');
 | 
			
		||||
 | 
			
		||||
				this.modal.data('css', {
 | 
			
		||||
					'left': this.modal.css('left'),
 | 
			
		||||
					'top': this.modal.css('top'),
 | 
			
		||||
					'margin-left': this.modal.css('margin-left'),
 | 
			
		||||
					'margin-top': this.modal.css('margin-top')
 | 
			
		||||
				});
 | 
			
		||||
				container.data('css', {
 | 
			
		||||
					'width': container.width(),
 | 
			
		||||
					'height': container.height()
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
				// reset
 | 
			
		||||
				this.modal.css({
 | 
			
		||||
					'left': 0,
 | 
			
		||||
					'top': debug,
 | 
			
		||||
					'margin': 0
 | 
			
		||||
				});
 | 
			
		||||
				// bind resize event
 | 
			
		||||
				$(window).bind('resize.cms.modal', function () {
 | 
			
		||||
					container.css({
 | 
			
		||||
						'width': $(window).width(),
 | 
			
		||||
						'height': $(window).height() - 60 - debug
 | 
			
		||||
					});
 | 
			
		||||
				});
 | 
			
		||||
				$(window).trigger('resize.cms.modal');
 | 
			
		||||
 | 
			
		||||
				// ensure maximize element is hidden #3111
 | 
			
		||||
				minimize.hide();
 | 
			
		||||
				// set correct cursor when maximized #3111
 | 
			
		||||
				title.css('cursor', 'default');
 | 
			
		||||
			} else {
 | 
			
		||||
				// minimize
 | 
			
		||||
				this.maximized = false;
 | 
			
		||||
				trigger.removeClass('cms_modal-maximize-active');
 | 
			
		||||
 | 
			
		||||
				$(window).unbind('resize.cms.modal');
 | 
			
		||||
 | 
			
		||||
				// reattach css
 | 
			
		||||
				this.modal.css(this.modal.data('css'));
 | 
			
		||||
				container.css(container.data('css'));
 | 
			
		||||
 | 
			
		||||
				// ensure maximize element is shown #3111
 | 
			
		||||
				minimize.show();
 | 
			
		||||
				// set correct cursor when maximized #3111
 | 
			
		||||
				title.css('cursor', 'move');
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_startMove: function (initial) {
 | 
			
		||||
			// cancel if maximized
 | 
			
		||||
			if(this.maximized) return false;
 | 
			
		||||
			// cancel action when minimized
 | 
			
		||||
			if(this.minimized) return false;
 | 
			
		||||
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var position = that.modal.position();
 | 
			
		||||
 | 
			
		||||
			this.modal.find('.cms_modal-shim').show();
 | 
			
		||||
 | 
			
		||||
			$(document).bind('mousemove.cms', function (e) {
 | 
			
		||||
				var left = position.left - (initial.pageX - e.pageX);
 | 
			
		||||
				var top = position.top - (initial.pageY - e.pageY);
 | 
			
		||||
 | 
			
		||||
				that.modal.css({
 | 
			
		||||
					'left': left,
 | 
			
		||||
					'top': top
 | 
			
		||||
				});
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_endMove: function () {
 | 
			
		||||
			this.modal.find('.cms_modal-shim').hide();
 | 
			
		||||
 | 
			
		||||
			$(document).unbind('mousemove.cms');
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_startResize: function (initial) {
 | 
			
		||||
			// cancel if in fullscreen
 | 
			
		||||
			if(this.maximized) return false;
 | 
			
		||||
			// continue
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var container = this.modal.find('.cms_modal-body');
 | 
			
		||||
			var width = container.width();
 | 
			
		||||
			var height = container.height();
 | 
			
		||||
			var modalLeft = this.modal.position().left;
 | 
			
		||||
			var modalTop = this.modal.position().top;
 | 
			
		||||
 | 
			
		||||
			this.modal.find('.cms_modal-shim').show();
 | 
			
		||||
 | 
			
		||||
			$(document).bind('mousemove.cms', function (e) {
 | 
			
		||||
				var mvX = initial.pageX - e.pageX;
 | 
			
		||||
				var mvY = initial.pageY - e.pageY;
 | 
			
		||||
 | 
			
		||||
				var w = width - (mvX * 2);
 | 
			
		||||
				var h = height - (mvY * 2);
 | 
			
		||||
				var max = 680;
 | 
			
		||||
 | 
			
		||||
				// add some limits
 | 
			
		||||
				if(w <= max || h <= 100) return false;
 | 
			
		||||
 | 
			
		||||
				// set centered animation
 | 
			
		||||
				container.css({
 | 
			
		||||
					'width': width - (mvX * 2),
 | 
			
		||||
					'height': height - (mvY * 2)
 | 
			
		||||
				});
 | 
			
		||||
				that.modal.css({
 | 
			
		||||
					'left': modalLeft + mvX,
 | 
			
		||||
					'top': modalTop + mvY
 | 
			
		||||
				});
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_endResize: function () {
 | 
			
		||||
			this.modal.find('.cms_modal-shim').hide();
 | 
			
		||||
 | 
			
		||||
			$(document).unbind('mousemove.cms');
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_setBreadcrumb: function (breadcrumb) {
 | 
			
		||||
			var bread = this.modal.find('.cms_modal-breadcrumb');
 | 
			
		||||
			var crumb = '';
 | 
			
		||||
 | 
			
		||||
			// cancel if there is no breadcrumb)
 | 
			
		||||
			if(!breadcrumb || breadcrumb.length <= 0) return false;
 | 
			
		||||
			if(!breadcrumb[0].title) return false;
 | 
			
		||||
 | 
			
		||||
			// load breadcrumb
 | 
			
		||||
			$.each(breadcrumb, function (index, item) {
 | 
			
		||||
				// check if the item is the last one
 | 
			
		||||
				var last = (index >= breadcrumb.length - 1) ? 'cms_modal-breadcrumb-last' : '';
 | 
			
		||||
				// render breadcrumb
 | 
			
		||||
				crumb += '<a href="' + item.url + '" class="' + last + '"><span>' + item.title + '</span></a>';
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// attach elements
 | 
			
		||||
			bread.find('.cms_modal-breadcrumb-items').html(crumb);
 | 
			
		||||
 | 
			
		||||
			// show breadcrumb
 | 
			
		||||
			bread.show();
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_setButtons: function (iframe) {
 | 
			
		||||
			var djangoSuit = iframe.contents().find('.suit-columns').length > 0;
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var row;
 | 
			
		||||
			if (!djangoSuit) {
 | 
			
		||||
				row = iframe.contents().find('.submit-row:eq(0)');
 | 
			
		||||
			} else {
 | 
			
		||||
				row = iframe.contents().find('.save-box:eq(0)');
 | 
			
		||||
			}
 | 
			
		||||
			// hide all submit-rows
 | 
			
		||||
			iframe.contents().find('.submit-row').hide();
 | 
			
		||||
			var buttons = row.find('input, a, button');
 | 
			
		||||
			var render = $('<span />'); // seriously jquery...
 | 
			
		||||
 | 
			
		||||
			// if there are no given buttons within the submit-row area
 | 
			
		||||
			// scan deeper within the form itself
 | 
			
		||||
			if(!buttons.length) {
 | 
			
		||||
				row = iframe.contents().find('body:not(.change-list) #content form:eq(0)');
 | 
			
		||||
				buttons = row.find('input[type="submit"], button[type="submit"]');
 | 
			
		||||
				buttons.addClass('deletelink')
 | 
			
		||||
					.hide();
 | 
			
		||||
			}
 | 
			
		||||
			// attach relation id
 | 
			
		||||
			buttons.each(function (index, item) {
 | 
			
		||||
				$(item).attr('data-rel', '_' + index);
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// loop over input buttons
 | 
			
		||||
			buttons.each(function (index, item) {
 | 
			
		||||
				item = $(item);
 | 
			
		||||
 | 
			
		||||
				// cancel if item is a hidden input
 | 
			
		||||
				if(item.attr('type') === 'hidden') return false;
 | 
			
		||||
 | 
			
		||||
				// create helper variables
 | 
			
		||||
				var title = item.attr('value') || item.text();
 | 
			
		||||
				var cls = 'cms_btn';
 | 
			
		||||
 | 
			
		||||
				// set additional special css classes
 | 
			
		||||
				if(item.hasClass('default')) cls = 'cms_btn cms_btn-action';
 | 
			
		||||
				if(item.hasClass('deletelink')) cls = 'cms_btn cms_btn-caution';
 | 
			
		||||
 | 
			
		||||
				// create the element and attach events
 | 
			
		||||
				var el = $('<div class="'+cls+' '+item.attr('class')+'">'+title+'</div>');
 | 
			
		||||
					el.bind(that.click, function () {
 | 
			
		||||
						if(item.is('input') || item.is('button')) item[0].click();
 | 
			
		||||
						if(item.is('a')) that._loadContent(item.prop('href'), title);
 | 
			
		||||
 | 
			
		||||
						// trigger only when blue action buttons are triggered
 | 
			
		||||
						if(item.hasClass('default') || item.hasClass('deletelink')) {
 | 
			
		||||
 							that.options.newPlugin = null;
 | 
			
		||||
 							// reset onClose when delete is triggered
 | 
			
		||||
							if(item.hasClass('deletelink')) that.options.onClose = null;
 | 
			
		||||
							// hide iframe
 | 
			
		||||
							that.modal.find('.cms_modal-frame iframe').hide();
 | 
			
		||||
							// page has been saved or deleted, run checkup
 | 
			
		||||
							that.saved = true;
 | 
			
		||||
						}
 | 
			
		||||
					});
 | 
			
		||||
 | 
			
		||||
				// append element
 | 
			
		||||
				render.append(el);
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// manually add cancel button at the end
 | 
			
		||||
			var cancel = $('<div class="cms_btn">'+that.config.lang.cancel+'</div>');
 | 
			
		||||
				cancel.bind(that.click, function () {
 | 
			
		||||
					that.options.onClose = false;
 | 
			
		||||
					that.close();
 | 
			
		||||
				});
 | 
			
		||||
			render.append(cancel);
 | 
			
		||||
 | 
			
		||||
			// render buttons
 | 
			
		||||
			this.modal.find('.cms_modal-buttons').html(render);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_loadContent: function (url, name) {
 | 
			
		||||
			var that = this;
 | 
			
		||||
 | 
			
		||||
			// FIXME: A better fix is needed for '&' being interpreted as the
 | 
			
		||||
			// start of en entity by jQuery. See #3404
 | 
			
		||||
			url = url.replace('&', '&');
 | 
			
		||||
			// now refresh the content
 | 
			
		||||
			var iframe = $('<iframe src="'+url+'" class="" frameborder="0" />');
 | 
			
		||||
				iframe.css('visibility', 'hidden');
 | 
			
		||||
			var holder = this.modal.find('.cms_modal-frame');
 | 
			
		||||
 | 
			
		||||
			// set correct title
 | 
			
		||||
			var title = this.modal.find('.cms_modal-title');
 | 
			
		||||
				title.html(name || ' ');
 | 
			
		||||
 | 
			
		||||
			// ensure previous iframe is hidden
 | 
			
		||||
			holder.find('iframe').css('visibility', 'hidden');
 | 
			
		||||
 | 
			
		||||
			// attach load event for iframe to prevent flicker effects
 | 
			
		||||
			iframe.bind('load', function () {
 | 
			
		||||
				// check if iframe can be accessed
 | 
			
		||||
				try {
 | 
			
		||||
					iframe.contents();
 | 
			
		||||
				} catch (error) {
 | 
			
		||||
					CMS.API.Toolbar.showError('<strong>' + error + '</strong>');
 | 
			
		||||
					that.close();
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// show messages in toolbar if provided
 | 
			
		||||
				var messages = iframe.contents().find('.messagelist li');
 | 
			
		||||
					if(messages.length) CMS.API.Toolbar.openMessage(messages.eq(0).text());
 | 
			
		||||
					messages.remove();
 | 
			
		||||
				var contents = iframe.contents();
 | 
			
		||||
 | 
			
		||||
				// determine if we should close the modal or reload
 | 
			
		||||
				if(messages.length && that.enforceReload) that.reloadBrowser();
 | 
			
		||||
				if(messages.length && that.enforceClose) {
 | 
			
		||||
					that.close();
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// after iframe is loaded append css
 | 
			
		||||
				contents.find('head').append($('<link rel="stylesheet" type="text/css" href="' + that.config.urls.static + that.options.urls.css_modal + '" />'));
 | 
			
		||||
 | 
			
		||||
				// adding django hacks
 | 
			
		||||
				contents.find('.viewsitelink').attr('target', '_top');
 | 
			
		||||
 | 
			
		||||
				// set modal buttons
 | 
			
		||||
				that._setButtons($(this));
 | 
			
		||||
 | 
			
		||||
				// when an error occurs, reset the saved status so the form can be checked and validated again
 | 
			
		||||
				if(iframe.contents().find('.errornote').length || iframe.contents().find('.errorlist').length) {
 | 
			
		||||
					that.saved = false;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// when the window has been changed pressing the blue or red button, we need to run a reload check
 | 
			
		||||
				// also check that no delete-confirmation is required
 | 
			
		||||
				if(that.saved && !contents.find('.delete-confirmation').length) {
 | 
			
		||||
					that.reloadBrowser(window.location.href, false, true);
 | 
			
		||||
				} else {
 | 
			
		||||
					iframe.show();
 | 
			
		||||
					// set title of not provided
 | 
			
		||||
					var innerTitle = iframe.contents().find('#content h1:eq(0)');
 | 
			
		||||
					if(name === undefined) title.html(innerTitle.text());
 | 
			
		||||
					innerTitle.remove();
 | 
			
		||||
 | 
			
		||||
					// than show
 | 
			
		||||
					iframe.css('visibility', 'visible');
 | 
			
		||||
 | 
			
		||||
					// append ready state
 | 
			
		||||
					iframe.data('ready', true);
 | 
			
		||||
 | 
			
		||||
					// attach close event
 | 
			
		||||
					contents.find('body').bind('keydown.cms', function (e) {
 | 
			
		||||
						if(e.keyCode === 27) that.close();
 | 
			
		||||
					});
 | 
			
		||||
					contents.find('body').addClass('cms_modal-window');
 | 
			
		||||
 | 
			
		||||
					// figure out if .object-tools is available
 | 
			
		||||
					if(contents.find('.object-tools').length) {
 | 
			
		||||
						contents.find('#content').css('padding-top', 38);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// inject
 | 
			
		||||
			setTimeout(function () {
 | 
			
		||||
				that.modal.find('.cms_modal-body').addClass('cms_loader');
 | 
			
		||||
				holder.html(iframe);
 | 
			
		||||
			}, this.options.modalDuration);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_changeContent: function (el) {
 | 
			
		||||
			if(el.hasClass('cms_modal-breadcrumb-last')) return false;
 | 
			
		||||
 | 
			
		||||
			var parents = el.parent().find('a');
 | 
			
		||||
				parents.removeClass('cms_modal-breadcrumb-last');
 | 
			
		||||
 | 
			
		||||
			el.addClass('cms_modal-breadcrumb-last');
 | 
			
		||||
 | 
			
		||||
			this._loadContent(el.attr('href'));
 | 
			
		||||
 | 
			
		||||
			// update title
 | 
			
		||||
			this.modal.find('.cms_modal-title').text(el.text());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
})(CMS.$);
 | 
			
		||||
							
								
								
									
										775
									
								
								static/cms/js/modules/cms.plugins.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										775
									
								
								static/cms/js/modules/cms.plugins.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,775 @@
 | 
			
		|||
/*##################################################|*/
 | 
			
		||||
/* #CMS# */
 | 
			
		||||
(function($) {
 | 
			
		||||
// CMS.$ will be passed for $
 | 
			
		||||
$(document).ready(function () {
 | 
			
		||||
	/*!
 | 
			
		||||
	 * Plugins
 | 
			
		||||
	 * for created plugins or generics (static content)
 | 
			
		||||
	 */
 | 
			
		||||
	CMS.Plugin = new CMS.Class({
 | 
			
		||||
 | 
			
		||||
		implement: [CMS.API.Helpers],
 | 
			
		||||
 | 
			
		||||
		options: {
 | 
			
		||||
			'type': '', // bar, plugin or generic
 | 
			
		||||
			'placeholder_id': null,
 | 
			
		||||
			'plugin_type': '',
 | 
			
		||||
			'plugin_id': null,
 | 
			
		||||
			'plugin_language': '',
 | 
			
		||||
			'plugin_parent': null,
 | 
			
		||||
			'plugin_order': null,
 | 
			
		||||
			'plugin_breadcrumb': [],
 | 
			
		||||
			'plugin_restriction': [],
 | 
			
		||||
			'urls': {
 | 
			
		||||
				'add_plugin': '',
 | 
			
		||||
				'edit_plugin': '',
 | 
			
		||||
				'move_plugin': '',
 | 
			
		||||
				'copy_plugin': '',
 | 
			
		||||
				'delete_plugin': ''
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		initialize: function (container, options) {
 | 
			
		||||
			this.container = $('.' + container);
 | 
			
		||||
			this.options = $.extend(true, {}, this.options, options);
 | 
			
		||||
 | 
			
		||||
			// elements
 | 
			
		||||
			this.body = $(document);
 | 
			
		||||
 | 
			
		||||
			// states
 | 
			
		||||
			this.csrf = CMS.config.csrf;
 | 
			
		||||
			this.timer = function () {};
 | 
			
		||||
			this.timeout = 250;
 | 
			
		||||
			this.focused = false;
 | 
			
		||||
			this.click = (document.ontouchstart !== null) ? 'click.cms' : 'tap.cms click.cms';
 | 
			
		||||
 | 
			
		||||
			// bind data element to the container
 | 
			
		||||
			this.container.data('settings', this.options);
 | 
			
		||||
 | 
			
		||||
			// determine type of plugin
 | 
			
		||||
			switch(this.options.type) {
 | 
			
		||||
				case 'placeholder': // handler for placeholder bars
 | 
			
		||||
					this._setPlaceholder();
 | 
			
		||||
					this._collapsables();
 | 
			
		||||
					break;
 | 
			
		||||
				case 'plugin': // handler for all plugins
 | 
			
		||||
					this._setPlugin();
 | 
			
		||||
					this._collapsables();
 | 
			
		||||
					break;
 | 
			
		||||
				default: // handler for static content
 | 
			
		||||
					this._setGeneric();
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// initial methods
 | 
			
		||||
		_setPlaceholder: function () {
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var title = '.cms_dragbar-title';
 | 
			
		||||
			var expanded = 'cms_dragbar-title-expanded';
 | 
			
		||||
			var dragbar = $('.cms_dragbar-' + this.options.placeholder_id);
 | 
			
		||||
 | 
			
		||||
			// register the subnav on the placeholder
 | 
			
		||||
			this._setSubnav(dragbar.find('.cms_submenu'));
 | 
			
		||||
 | 
			
		||||
			// enable expanding/collapsing globally within the placeholder
 | 
			
		||||
			dragbar.find(title).bind(this.click, function () {
 | 
			
		||||
				($(this).hasClass(expanded)) ? that._collapseAll($(this)) : that._expandAll($(this));
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_setPlugin: function () {
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var timer = function () {};
 | 
			
		||||
 | 
			
		||||
			// adds double click to edit
 | 
			
		||||
			this.container.bind('dblclick', function (e) {
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
				e.stopPropagation();
 | 
			
		||||
				that.editPlugin(that.options.urls.edit_plugin, that.options.plugin_name, that.options.plugin_breadcrumb);
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// adds edit tooltip
 | 
			
		||||
			this.container.bind('mouseover.cms mouseout.cms', function (e) {
 | 
			
		||||
				e.stopPropagation();
 | 
			
		||||
				var name = that.options.plugin_name;
 | 
			
		||||
				var id = that.options.plugin_id;
 | 
			
		||||
				(e.type === 'mouseover') ? that.showTooltip(name, id) : that.hideTooltip();
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// adds listener for all plugin updates
 | 
			
		||||
			this.container.bind('cms.plugins.update', function (e) {
 | 
			
		||||
				e.stopPropagation();
 | 
			
		||||
				that.movePlugin();
 | 
			
		||||
			});
 | 
			
		||||
			// adds listener for copy/paste updates
 | 
			
		||||
			this.container.bind('cms.plugin.update', function (e) {
 | 
			
		||||
				e.stopPropagation();
 | 
			
		||||
 | 
			
		||||
				var el = $(e.delegateTarget);
 | 
			
		||||
				var dragitem = $('.cms_draggable-' + el.data('settings').plugin_id);
 | 
			
		||||
				var placeholder_id = that._getId(dragitem.parents('.cms_draggables').last().prevAll('.cms_dragbar').first());
 | 
			
		||||
 | 
			
		||||
				// if placeholder_id is empty, cancel
 | 
			
		||||
				if(!placeholder_id) return false;
 | 
			
		||||
 | 
			
		||||
				var data = el.data('settings');
 | 
			
		||||
					data.target = placeholder_id;
 | 
			
		||||
					data.parent= that._getId(dragitem.parent().closest('.cms_draggable'));
 | 
			
		||||
 | 
			
		||||
				that.copyPlugin(data);
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// variables for dragitems
 | 
			
		||||
			var draggable = $('.cms_draggable-' + this.options.plugin_id);
 | 
			
		||||
			var dragitem = draggable.find('> .cms_dragitem');
 | 
			
		||||
			var submenu = draggable.find('.cms_submenu:eq(0)');
 | 
			
		||||
			var submenus = $('.cms_draggables').find('.cms_submenu');
 | 
			
		||||
 | 
			
		||||
			// attach event to the plugin menu
 | 
			
		||||
			this._setSubnav(draggable.find('> .cms_dragitem .cms_submenu'));
 | 
			
		||||
 | 
			
		||||
			// adds event for hiding the subnav
 | 
			
		||||
			draggable.bind('mouseenter mouseleave mouseover', function (e) {
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
				e.stopPropagation();
 | 
			
		||||
 | 
			
		||||
				if(that.focused) return false;
 | 
			
		||||
 | 
			
		||||
				if(e.type === 'mouseenter' || e.type === 'mouseover') $(this).data('active', true);
 | 
			
		||||
				if(e.type === 'mouseleave') {
 | 
			
		||||
					$(this).data('active', false);
 | 
			
		||||
					submenus.hide();
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// add timeout to determine if we should hide the element
 | 
			
		||||
				setTimeout(function () {
 | 
			
		||||
					if(!$(e.currentTarget).data('active')) {
 | 
			
		||||
						$(e.currentTarget).find('.cms_submenu:eq(0)').hide();
 | 
			
		||||
					}
 | 
			
		||||
				}, 100);
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// adds event for showing the subnav
 | 
			
		||||
			dragitem.bind('mouseenter', function (e) {
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
				e.stopPropagation();
 | 
			
		||||
 | 
			
		||||
				submenus.hide();
 | 
			
		||||
				submenu.show();
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// adds double click to edit
 | 
			
		||||
			dragitem.bind('dblclick', function (e) {
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
				e.stopPropagation();
 | 
			
		||||
				that.editPlugin(that.options.urls.edit_plugin, that.options.plugin_name, that.options.plugin_breadcrumb);
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_setGeneric: function () {
 | 
			
		||||
			var that = this;
 | 
			
		||||
 | 
			
		||||
			// adds double click to edit
 | 
			
		||||
			this.container.bind('dblclick', function (e) {
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
				e.stopPropagation();
 | 
			
		||||
				that.editPlugin(that.options.urls.edit_plugin, that.options.plugin_name, []);
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// adds edit tooltip
 | 
			
		||||
			this.container.bind('mouseover.cms mouseout.cms', function (e) {
 | 
			
		||||
				e.stopPropagation();
 | 
			
		||||
				var name = that.options.plugin_name;
 | 
			
		||||
				var id = that.options.plugin_id;
 | 
			
		||||
				(e.type === 'mouseover') ? that.showTooltip(name, id) : that.hideTooltip();
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// public methods
 | 
			
		||||
		addPlugin: function (type, name, parent) {
 | 
			
		||||
			// cancel request if already in progress
 | 
			
		||||
			if(CMS.API.locked) return false;
 | 
			
		||||
			CMS.API.locked = true;
 | 
			
		||||
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var data = {
 | 
			
		||||
				'placeholder_id': this.options.placeholder_id,
 | 
			
		||||
				'plugin_type': type,
 | 
			
		||||
				'plugin_parent': parent || '',
 | 
			
		||||
				'plugin_language': this.options.plugin_language,
 | 
			
		||||
				'csrfmiddlewaretoken': this.csrf
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			$.ajax({
 | 
			
		||||
				'type': 'POST',
 | 
			
		||||
				'url': this.options.urls.add_plugin,
 | 
			
		||||
				'data': data,
 | 
			
		||||
				'success': function (data) {
 | 
			
		||||
					CMS.API.locked = false;
 | 
			
		||||
					that.newPlugin = data;
 | 
			
		||||
					that.editPlugin(data.url, name, data.breadcrumb);
 | 
			
		||||
				},
 | 
			
		||||
				'error': function (jqXHR) {
 | 
			
		||||
					CMS.API.locked = false;
 | 
			
		||||
					var msg = CMS.config.lang.error;
 | 
			
		||||
					// trigger error
 | 
			
		||||
					that._showError(msg + jqXHR.responseText || jqXHR.status + ' ' + jqXHR.statusText);
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		editPlugin: function (url, name, breadcrumb) {
 | 
			
		||||
			// trigger modal window
 | 
			
		||||
			var modal = new CMS.Modal({
 | 
			
		||||
				'newPlugin': this.newPlugin || false,
 | 
			
		||||
				'onClose': this.options.onClose || false,
 | 
			
		||||
				'redirectOnClose': this.options.redirectOnClose || false
 | 
			
		||||
			});
 | 
			
		||||
			modal.open(url, name, breadcrumb);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		copyPlugin: function (options, source_language) {
 | 
			
		||||
			// cancel request if already in progress
 | 
			
		||||
			if(CMS.API.locked) return false;
 | 
			
		||||
			CMS.API.locked = true;
 | 
			
		||||
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var move = (options || source_language) ? true : false;
 | 
			
		||||
			// set correct options
 | 
			
		||||
			options = options || this.options;
 | 
			
		||||
			if(source_language) {
 | 
			
		||||
				options.target = options.placeholder_id;
 | 
			
		||||
				options.plugin_id = '';
 | 
			
		||||
				options.parent = '';
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				source_language = options.plugin_language
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			var data = {
 | 
			
		||||
				'source_placeholder_id': options.placeholder_id,
 | 
			
		||||
				'source_plugin_id': options.plugin_id || '',
 | 
			
		||||
				'source_language': source_language,
 | 
			
		||||
				'target_plugin_id': options.parent || '',
 | 
			
		||||
				'target_placeholder_id': options.target || CMS.config.clipboard.id,
 | 
			
		||||
				'target_language': options.page_language || source_language,
 | 
			
		||||
				'csrfmiddlewaretoken': this.csrf
 | 
			
		||||
			};
 | 
			
		||||
			var request = {
 | 
			
		||||
				'type': 'POST',
 | 
			
		||||
				'url': options.urls.copy_plugin,
 | 
			
		||||
				'data': data,
 | 
			
		||||
				'success': function () {
 | 
			
		||||
					CMS.API.Toolbar.openMessage(CMS.config.lang.success);
 | 
			
		||||
					// reload
 | 
			
		||||
					CMS.API.Helpers.reloadBrowser();
 | 
			
		||||
				},
 | 
			
		||||
				'error': function (jqXHR) {
 | 
			
		||||
					CMS.API.locked = false;
 | 
			
		||||
					var msg = CMS.config.lang.error;
 | 
			
		||||
					// trigger error
 | 
			
		||||
					that._showError(msg + jqXHR.responseText || jqXHR.status + ' ' + jqXHR.statusText);
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			if(move) {
 | 
			
		||||
				$.ajax(request);
 | 
			
		||||
			} else {
 | 
			
		||||
				// ensure clipboard is cleaned
 | 
			
		||||
				CMS.API.Clipboard.clear(function () {
 | 
			
		||||
					$.ajax(request);
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		cutPlugin: function () {
 | 
			
		||||
			// if cut is once triggered, prevend additional actions
 | 
			
		||||
			if(CMS.API.locked) return false;
 | 
			
		||||
			CMS.API.locked = true;
 | 
			
		||||
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var data = {
 | 
			
		||||
				'placeholder_id': CMS.config.clipboard.id,
 | 
			
		||||
				'plugin_id': this.options.plugin_id,
 | 
			
		||||
				'plugin_parent': '',
 | 
			
		||||
				'plugin_language': this.options.page_language,
 | 
			
		||||
				'plugin_order': [this.options.plugin_id],
 | 
			
		||||
				'csrfmiddlewaretoken': this.csrf
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			// ensure clipboard is cleaned
 | 
			
		||||
			CMS.API.Clipboard.clear(function () {
 | 
			
		||||
				// cancel request if already in progress
 | 
			
		||||
				if(CMS.API.locked) return false;
 | 
			
		||||
				CMS.API.locked = true;
 | 
			
		||||
 | 
			
		||||
				// move plugin
 | 
			
		||||
				$.ajax({
 | 
			
		||||
					'type': 'POST',
 | 
			
		||||
					'url': that.options.urls.move_plugin,
 | 
			
		||||
					'data': data,
 | 
			
		||||
					'success': function (response) {
 | 
			
		||||
						CMS.API.Toolbar.openMessage(CMS.config.lang.success);
 | 
			
		||||
						// if response is reload
 | 
			
		||||
						CMS.API.Helpers.reloadBrowser();
 | 
			
		||||
					},
 | 
			
		||||
					'error': function (jqXHR) {
 | 
			
		||||
						CMS.API.locked = false;
 | 
			
		||||
						var msg = CMS.config.lang.error;
 | 
			
		||||
						// trigger error
 | 
			
		||||
						that._showError(msg + jqXHR.responseText || jqXHR.status + ' ' + jqXHR.statusText);
 | 
			
		||||
					}
 | 
			
		||||
				});
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		movePlugin: function (options) {
 | 
			
		||||
			// cancel request if already in progress
 | 
			
		||||
			if(CMS.API.locked) return false;
 | 
			
		||||
			CMS.API.locked = true;
 | 
			
		||||
 | 
			
		||||
			var that = this;
 | 
			
		||||
			// set correct options
 | 
			
		||||
			options = options || this.options;
 | 
			
		||||
 | 
			
		||||
			var plugin = $('.cms_plugin-' + options.plugin_id);
 | 
			
		||||
			var dragitem = $('.cms_draggable-' + options.plugin_id);
 | 
			
		||||
 | 
			
		||||
			// SETTING POSITION
 | 
			
		||||
			this._setPosition(options.plugin_id, plugin, dragitem);
 | 
			
		||||
 | 
			
		||||
			// SAVING POSITION
 | 
			
		||||
			var placeholder_id = this._getId(dragitem.parents('.cms_draggables').last().prevAll('.cms_dragbar').first());
 | 
			
		||||
			var plugin_parent = this._getId(dragitem.parent().closest('.cms_draggable'));
 | 
			
		||||
			var plugin_order = this._getIds(dragitem.siblings('.cms_draggable').andSelf());
 | 
			
		||||
 | 
			
		||||
			// cancel here if we have no placeholder id
 | 
			
		||||
			if(placeholder_id === false) return false;
 | 
			
		||||
 | 
			
		||||
			// gather the data for ajax request
 | 
			
		||||
			var data = {
 | 
			
		||||
				'placeholder_id': placeholder_id,
 | 
			
		||||
				'plugin_id': options.plugin_id,
 | 
			
		||||
				'plugin_parent': plugin_parent || '',
 | 
			
		||||
				 // this is a hack: when moving to different languages use the global language
 | 
			
		||||
				'plugin_language': options.page_language,
 | 
			
		||||
				'plugin_order': plugin_order,
 | 
			
		||||
				'csrfmiddlewaretoken': this.csrf
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			$.ajax({
 | 
			
		||||
				'type': 'POST',
 | 
			
		||||
				'url': options.urls.move_plugin,
 | 
			
		||||
				'data': data,
 | 
			
		||||
				'success': function (response) {
 | 
			
		||||
					// if response is reload
 | 
			
		||||
					if(response.reload) CMS.API.Helpers.reloadBrowser();
 | 
			
		||||
 | 
			
		||||
					// enable actions again
 | 
			
		||||
					CMS.API.locked = false;
 | 
			
		||||
 | 
			
		||||
					// TODO: show only if(response.status)
 | 
			
		||||
					that._showSuccess(dragitem);
 | 
			
		||||
				},
 | 
			
		||||
				'error': function (jqXHR) {
 | 
			
		||||
					CMS.API.locked = false;
 | 
			
		||||
					var msg = CMS.config.lang.error;
 | 
			
		||||
					// trigger error
 | 
			
		||||
					that._showError(msg + jqXHR.responseText || jqXHR.status + ' ' + jqXHR.statusText);
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// show publish button
 | 
			
		||||
			$('.cms_btn-publish').addClass('cms_btn-publish-active').parent().show();
 | 
			
		||||
 | 
			
		||||
			// enable revert to live
 | 
			
		||||
			$('.cms_toolbar-revert').removeClass('cms_toolbar-item-navigation-disabled');
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		deletePlugin: function (url, name, breadcrumb) {
 | 
			
		||||
			// trigger modal window
 | 
			
		||||
			var modal = new CMS.Modal({
 | 
			
		||||
				'newPlugin': this.newPlugin || false,
 | 
			
		||||
				'onClose': this.options.onClose || false,
 | 
			
		||||
				'redirectOnClose': this.options.redirectOnClose || false
 | 
			
		||||
			});
 | 
			
		||||
			modal.open(url, name, breadcrumb);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// private methods
 | 
			
		||||
		_setPosition: function (id, plugin, dragitem) {
 | 
			
		||||
			// after we insert the plugin onto its new place, we need to figure out where to position it
 | 
			
		||||
			var prevItem = dragitem.prev('.cms_draggable');
 | 
			
		||||
			var nextItem = dragitem.next('.cms_draggable');
 | 
			
		||||
			var parent = dragitem.parent().closest('.cms_draggable');
 | 
			
		||||
			var child = $('.cms_plugin-' + this._getId(parent));
 | 
			
		||||
			var placeholder = dragitem.closest('.cms_dragarea');
 | 
			
		||||
 | 
			
		||||
			// determine if there are other plugins within the same level, this makes the move easier
 | 
			
		||||
			if(prevItem.length) {
 | 
			
		||||
				plugin.insertAfter($('.cms_plugin-' + this._getId(prevItem)));
 | 
			
		||||
			} else if(nextItem.length) {
 | 
			
		||||
				plugin.insertBefore($('.cms_plugin-' + this._getId(nextItem)));
 | 
			
		||||
			} else if(parent.length) {
 | 
			
		||||
				// if we can't find a plugin on the same level, we need to travel higher
 | 
			
		||||
				// for this we need to find the deepest child
 | 
			
		||||
				while(child.children().length) {
 | 
			
		||||
					child = child.children();
 | 
			
		||||
				}
 | 
			
		||||
				child.append(plugin);
 | 
			
		||||
			} else if(placeholder.length) {
 | 
			
		||||
				// we also need to cover the case if we move the plugin to an empty placeholder
 | 
			
		||||
				plugin.append($('.cms_plugin-' + this._getId(placeholder)));
 | 
			
		||||
			} else {
 | 
			
		||||
				// if we did not found a match, reload
 | 
			
		||||
				CMS.API.Helpers.reloadBrowser();
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		editPluginPostAjax: function(caller, toolbar, response){
 | 
			
		||||
			if (typeof toolbar == 'undefined' || typeof response == 'undefined') {
 | 
			
		||||
				return function(toolbar, response) {
 | 
			
		||||
					var that = caller;
 | 
			
		||||
					that.editPlugin(response['url'], that.options.plugin_name, response['breadcrumb']);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			that.editPlugin(response['url'], that.options.plugin_name, response['breadcrumb']);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_setSubnav: function (nav) {
 | 
			
		||||
			var that = this;
 | 
			
		||||
 | 
			
		||||
			nav.bind('mouseenter mouseleave tap.cms', function (e) {
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
				e.stopPropagation();
 | 
			
		||||
				(e.type === 'mouseenter') ? that._showSubnav($(this)) : that._hideSubnav($(this));
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			nav.find('a').bind('click.cms tap.cms', function (e) {
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
				e.stopPropagation();
 | 
			
		||||
 | 
			
		||||
				// show loader and make sure scroll doesn't jump
 | 
			
		||||
				CMS.API.Toolbar._loader(true);
 | 
			
		||||
 | 
			
		||||
				var el = $(this);
 | 
			
		||||
 | 
			
		||||
				// set switch for subnav entries
 | 
			
		||||
				switch(el.attr('data-rel')) {
 | 
			
		||||
					case 'add':
 | 
			
		||||
						that.addPlugin(el.attr('href').replace('#', ''), el.text(), that._getId(el.closest('.cms_draggable')));
 | 
			
		||||
						break;
 | 
			
		||||
					case 'ajax_add':
 | 
			
		||||
						CMS.API.Toolbar.openAjax(el.attr('href'), JSON.stringify(el.data('post')), el.data('text'), that.editPluginPostAjax(that), el.data('on-success'));
 | 
			
		||||
						break;
 | 
			
		||||
					case 'edit':
 | 
			
		||||
						that.editPlugin(that.options.urls.edit_plugin, that.options.plugin_name, that.options.plugin_breadcrumb);
 | 
			
		||||
						break;
 | 
			
		||||
					case 'copy-lang':
 | 
			
		||||
						that.copyPlugin(this.options, el.attr('data-language'));
 | 
			
		||||
						break;
 | 
			
		||||
					case 'copy':
 | 
			
		||||
						that.copyPlugin();
 | 
			
		||||
						break;
 | 
			
		||||
					case 'cut':
 | 
			
		||||
						that.cutPlugin();
 | 
			
		||||
						break;
 | 
			
		||||
					case 'delete':
 | 
			
		||||
						that.deletePlugin(that.options.urls.delete_plugin, that.options.plugin_name, that.options.plugin_breadcrumb);
 | 
			
		||||
						break;
 | 
			
		||||
					default:
 | 
			
		||||
						CMS.API.Toolbar._loader(false);
 | 
			
		||||
						CMS.API.Toolbar._delegate(el);
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			nav.find('input').bind('keyup keydown focus blur click', function (e) {
 | 
			
		||||
				if(e.type === 'focus') that.focused = true;
 | 
			
		||||
				if(e.type === 'blur' && !that.traverse) {
 | 
			
		||||
					that.focused = false;
 | 
			
		||||
					that._hideSubnav(nav);
 | 
			
		||||
				}
 | 
			
		||||
				if(e.type === 'keyup') {
 | 
			
		||||
					clearTimeout(that.timer);
 | 
			
		||||
					// keybound is not required
 | 
			
		||||
					that.timer = setTimeout(function () {
 | 
			
		||||
						that._searchSubnav(nav, $(e.currentTarget).val());
 | 
			
		||||
					}, 100);
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// set data attributes for original top positioning
 | 
			
		||||
			nav.find('.cms_submenu-dropdown').each(function () {
 | 
			
		||||
				$(this).data('top', $(this).css('top'))
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// prevent propagnation
 | 
			
		||||
			nav.bind(this.click, function (e) {
 | 
			
		||||
				e.stopPropagation();
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_showSubnav: function (nav) {
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var dropdown = nav.find('.cms_submenu-dropdown');
 | 
			
		||||
			var offset = parseInt(dropdown.data('top'));
 | 
			
		||||
 | 
			
		||||
			// clearing
 | 
			
		||||
			clearTimeout(this.timer);
 | 
			
		||||
 | 
			
		||||
			// add small delay before showing submenu
 | 
			
		||||
			this.timer = setTimeout(function () {
 | 
			
		||||
				// reset z indexes
 | 
			
		||||
				var reset = $('.cms_submenu').parentsUntil('.cms_dragarea');
 | 
			
		||||
				var scrollHint = nav.find('.cms_submenu-scroll-hint');
 | 
			
		||||
 | 
			
		||||
				reset.css('z-index', 0);
 | 
			
		||||
 | 
			
		||||
				var parents = nav.parentsUntil('.cms_dragarea');
 | 
			
		||||
					parents.css('z-index', 999);
 | 
			
		||||
 | 
			
		||||
				// show subnav
 | 
			
		||||
				nav.find('.cms_submenu-quicksearch').show();
 | 
			
		||||
 | 
			
		||||
				// set visible states
 | 
			
		||||
				nav.find('> .cms_submenu-dropdown').show().on('scroll', function () {
 | 
			
		||||
					scrollHint.fadeOut(100);
 | 
			
		||||
					$(this).off('scroll');
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
				// show scrollHint for FF on OSX
 | 
			
		||||
				window.console.log(nav[0], nav[0].scrollHeight);
 | 
			
		||||
				if(nav[0].scrollHeight > 245) scrollHint.show();
 | 
			
		||||
 | 
			
		||||
			}, 100);
 | 
			
		||||
 | 
			
		||||
			// add key events
 | 
			
		||||
			$(document).unbind('keydown.cms');
 | 
			
		||||
			$(document).bind('keydown.cms', function (e) {
 | 
			
		||||
				var anchors = nav.find('.cms_submenu-item:visible a');
 | 
			
		||||
				var index = anchors.index(anchors.filter(':focus'));
 | 
			
		||||
 | 
			
		||||
				// bind arrow down and tab keys
 | 
			
		||||
				if(e.keyCode === 40 || e.keyCode === 9) {
 | 
			
		||||
					that.traverse = true;
 | 
			
		||||
					e.preventDefault();
 | 
			
		||||
					if(index >= 0 && index < anchors.length - 1) {
 | 
			
		||||
						anchors.eq(index + 1).focus();
 | 
			
		||||
					} else {
 | 
			
		||||
						anchors.eq(0).focus();
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// bind arrow up keys
 | 
			
		||||
				if(e.keyCode === 38) {
 | 
			
		||||
					e.preventDefault();
 | 
			
		||||
					if(anchors.is(':focus')) {
 | 
			
		||||
						anchors.eq(index - 1).focus();
 | 
			
		||||
					} else {
 | 
			
		||||
						anchors.eq(anchors.length).focus();
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// hide subnav when hitting enter or escape
 | 
			
		||||
				if(e.keyCode === 13 || e.keyCode === 27) {
 | 
			
		||||
					that.traverse = false;
 | 
			
		||||
					nav.find('input').blur();
 | 
			
		||||
					that._hideSubnav(nav);
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// calculate subnav bounds
 | 
			
		||||
			if($(window).height() + $(window).scrollTop() - nav.offset().top - dropdown.height() <= 10 && nav.offset().top - dropdown.height() >= 0) {
 | 
			
		||||
				dropdown.css('top', 'auto');
 | 
			
		||||
				dropdown.css('bottom', offset);
 | 
			
		||||
				// if parent is within a plugin, add additional offset
 | 
			
		||||
				if(dropdown.closest('.cms_draggable').length) dropdown.css('bottom', offset - 1);
 | 
			
		||||
			} else {
 | 
			
		||||
				dropdown.css('top', offset);
 | 
			
		||||
				dropdown.css('bottom', 'auto');
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_hideSubnav: function (nav) {
 | 
			
		||||
			clearTimeout(this.timer);
 | 
			
		||||
 | 
			
		||||
			var that = this;
 | 
			
		||||
			// cancel if quicksearch is focues
 | 
			
		||||
			if(this.focused) return false;
 | 
			
		||||
 | 
			
		||||
			// set correct active state
 | 
			
		||||
			nav.closest('.cms_draggable').data('active', false);
 | 
			
		||||
 | 
			
		||||
			this.timer = setTimeout(function () {
 | 
			
		||||
				// set visible states
 | 
			
		||||
				nav.find('> .cms_submenu-dropdown').hide();
 | 
			
		||||
				nav.find('.cms_submenu-quicksearch').hide();
 | 
			
		||||
				// reset search
 | 
			
		||||
				nav.find('input').val('');
 | 
			
		||||
				that._searchSubnav(nav, '');
 | 
			
		||||
			}, this.timeout);
 | 
			
		||||
 | 
			
		||||
			// reset relativity
 | 
			
		||||
			$('.cms_dragbar').css('position', '');
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_searchSubnav: function (nav, value) {
 | 
			
		||||
			var items = nav.find('.cms_submenu-item');
 | 
			
		||||
			var titles = nav.find('.cms_submenu-item-title');
 | 
			
		||||
 | 
			
		||||
			// cancel if value is zero
 | 
			
		||||
			if(value === '') {
 | 
			
		||||
				items.add(titles).show();
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// loop through items and figure out if we need to hide items
 | 
			
		||||
			items.find('a, span').each(function (index, item) {
 | 
			
		||||
				item = $(item);
 | 
			
		||||
				var text = item.text().toLowerCase();
 | 
			
		||||
				var search = value.toLowerCase();
 | 
			
		||||
 | 
			
		||||
				(text.indexOf(search) >= 0) ? item.parent().show() : item.parent().hide();
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// check if a title is matching
 | 
			
		||||
			titles.filter(':visible').each(function (index, item) {
 | 
			
		||||
				titles.hide();
 | 
			
		||||
				$(item).nextUntil('.cms_submenu-item-title').show();
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// always display title of a category
 | 
			
		||||
			items.filter(':visible').each(function (index, item) {
 | 
			
		||||
				if($(item).prev().hasClass('cms_submenu-item-title')) {
 | 
			
		||||
					$(item).prev().show();
 | 
			
		||||
				} else {
 | 
			
		||||
					$(item).prevUntil('.cms_submenu-item-title').last().prev().show();
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// if there is no element visible, show only first categoriy
 | 
			
		||||
			nav.find('.cms_submenu-dropdown').show();
 | 
			
		||||
			if(items.add(titles).filter(':visible').length <= 0) {
 | 
			
		||||
				nav.find('.cms_submenu-dropdown').hide();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// hide scrollHint
 | 
			
		||||
			nav.find('.cms_submenu-scroll-hint').hide();
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_collapsables: function () {
 | 
			
		||||
			// one time setup
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var settings = CMS.settings;
 | 
			
		||||
			var draggable = $('.cms_draggable-' + this.options.plugin_id);
 | 
			
		||||
 | 
			
		||||
			// check which button should be shown for collapsemenu
 | 
			
		||||
			this.container.each(function (index, item) {
 | 
			
		||||
				var els = $(item).find('.cms_dragitem-collapsable');
 | 
			
		||||
				var open = els.filter('.cms_dragitem-expanded');
 | 
			
		||||
				if(els.length === open.length && (els.length + open.length !== 0)) {
 | 
			
		||||
					$(item).find('.cms_dragbar-title').addClass('cms_dragbar-title-expanded');
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
			// cancel here if its not a draggable
 | 
			
		||||
			if(!draggable.length) return false;
 | 
			
		||||
 | 
			
		||||
			// attach events to draggable
 | 
			
		||||
			draggable.find('> .cms_dragitem-collapsable').bind(this.click, function () {
 | 
			
		||||
				var el = $(this);
 | 
			
		||||
				var id = that._getId($(this).parent());
 | 
			
		||||
 | 
			
		||||
				var settings = CMS.settings;
 | 
			
		||||
					settings.states = settings.states || [];
 | 
			
		||||
 | 
			
		||||
				// collapsable function and save states
 | 
			
		||||
				if(el.hasClass('cms_dragitem-expanded')) {
 | 
			
		||||
					settings.states.splice($.inArray(id, settings.states), 1);
 | 
			
		||||
					el.removeClass('cms_dragitem-expanded').parent().find('> .cms_draggables').hide();
 | 
			
		||||
				} else {
 | 
			
		||||
					settings.states.push(id);
 | 
			
		||||
					el.addClass('cms_dragitem-expanded').parent().find('> .cms_draggables').show();
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// save settings
 | 
			
		||||
				CMS.API.Toolbar.setSettings(settings);
 | 
			
		||||
			});
 | 
			
		||||
			// adds double click event
 | 
			
		||||
			draggable.bind('dblclick', function (e) {
 | 
			
		||||
				e.stopPropagation();
 | 
			
		||||
				$('.cms_plugin-' + that._getId($(this))).trigger('dblclick');
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// only needs to be excecuted once
 | 
			
		||||
			if(CMS.Toolbar.ready) return false;
 | 
			
		||||
 | 
			
		||||
			// removing dublicate entries
 | 
			
		||||
			var sortedArr = settings.states.sort();
 | 
			
		||||
			var filteredArray = [];
 | 
			
		||||
			for(var i = 0; i < sortedArr.length; i++) {
 | 
			
		||||
				if(sortedArr[i] !== sortedArr[i + 1]) {
 | 
			
		||||
					filteredArray.push(sortedArr[i]);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			settings.states = filteredArray;
 | 
			
		||||
 | 
			
		||||
			// loop through the items
 | 
			
		||||
			$.each(CMS.settings.states, function (index, id) {
 | 
			
		||||
				var el = $('.cms_draggable-' + id);
 | 
			
		||||
				// only add this class to elements which have a draggable area
 | 
			
		||||
				if(el.find('.cms_draggables').length) {
 | 
			
		||||
					el.find('> .cms_draggables').show();
 | 
			
		||||
					el.find('> .cms_dragitem').addClass('cms_dragitem-expanded');
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// set global setup
 | 
			
		||||
			CMS.Toolbar.ready = true;
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_expandAll: function (el) {
 | 
			
		||||
			var items = el.closest('.cms_dragarea').find('.cms_dragitem-collapsable');
 | 
			
		||||
			// cancel if there are no items
 | 
			
		||||
			if(!items.length) return false;
 | 
			
		||||
			items.each(function () {
 | 
			
		||||
				if(!$(this).hasClass('cms_dragitem-expanded')) $(this).trigger('click.cms');
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			el.addClass('cms_dragbar-title-expanded');
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_collapseAll: function (el) {
 | 
			
		||||
			var items = el.closest('.cms_dragarea').find('.cms_dragitem-collapsable');
 | 
			
		||||
			items.each(function () {
 | 
			
		||||
				if($(this).hasClass('cms_dragitem-expanded')) $(this).trigger('click.cms');
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			el.removeClass('cms_dragbar-title-expanded');
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_getId: function (el) {
 | 
			
		||||
			return CMS.API.StructureBoard.getId(el);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_getIds: function (els) {
 | 
			
		||||
			return CMS.API.StructureBoard.getIds(els);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_showError: function (msg) {
 | 
			
		||||
			return CMS.API.Toolbar.showError(msg, true);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_showSuccess: function (el) {
 | 
			
		||||
			var tpl = $('<div class="cms_dragitem-success"></div>');
 | 
			
		||||
			el.append(tpl);
 | 
			
		||||
			// start animation
 | 
			
		||||
			tpl.fadeOut(function () {
 | 
			
		||||
				$(this).remove()
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
})(CMS.$);
 | 
			
		||||
							
								
								
									
										366
									
								
								static/cms/js/modules/cms.sideframe.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										366
									
								
								static/cms/js/modules/cms.sideframe.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,366 @@
 | 
			
		|||
/*##################################################|*/
 | 
			
		||||
/* #CMS# */
 | 
			
		||||
(function($) {
 | 
			
		||||
// CMS.$ will be passed for $
 | 
			
		||||
$(document).ready(function () {
 | 
			
		||||
	/*!
 | 
			
		||||
	 * Sideframe
 | 
			
		||||
	 * Controls a cms specific sideframe
 | 
			
		||||
	 */
 | 
			
		||||
	CMS.Sideframe = new CMS.Class({
 | 
			
		||||
 | 
			
		||||
		implement: [CMS.API.Helpers],
 | 
			
		||||
 | 
			
		||||
		options: {
 | 
			
		||||
			'onClose': false,
 | 
			
		||||
			'sideframeDuration': 300,
 | 
			
		||||
			'sideframeWidth': 320,
 | 
			
		||||
			'urls': {
 | 
			
		||||
				'css_sideframe': 'cms/css/cms.toolbar.sideframe.css'
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		initialize: function (options) {
 | 
			
		||||
			this.options = $.extend(true, {}, this.options, options);
 | 
			
		||||
			this.config = CMS.config;
 | 
			
		||||
			this.settings = CMS.settings;
 | 
			
		||||
 | 
			
		||||
			// elements
 | 
			
		||||
			this.sideframe = $('.cms_sideframe');
 | 
			
		||||
			this.body = $('html');
 | 
			
		||||
 | 
			
		||||
			// states
 | 
			
		||||
			this.click = (document.ontouchstart !== null) ? 'click.cms' : 'touchend.cms click.cms';
 | 
			
		||||
			this.enforceReload = false;
 | 
			
		||||
 | 
			
		||||
			// if the modal is initialized the first time, set the events
 | 
			
		||||
			if(!this.sideframe.data('ready')) this._events();
 | 
			
		||||
 | 
			
		||||
			// ready sideframe
 | 
			
		||||
			this.sideframe.data('ready', true);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// initial methods
 | 
			
		||||
		_events: function () {
 | 
			
		||||
			var that = this;
 | 
			
		||||
 | 
			
		||||
			// attach close event
 | 
			
		||||
			this.sideframe.find('.cms_sideframe-close').bind(this.click, function () {
 | 
			
		||||
				that.close(true);
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// attach hide event
 | 
			
		||||
			this.sideframe.find('.cms_sideframe-hide').bind(this.click, function () {
 | 
			
		||||
				if($(this).hasClass('cms_sideframe-hidden')) {
 | 
			
		||||
					that.settings.sideframe.hidden = false;
 | 
			
		||||
					that._show(that.settings.sideframe.position || that.options.sideframeWidth, true);
 | 
			
		||||
				} else {
 | 
			
		||||
					that.settings.sideframe.hidden = true;
 | 
			
		||||
					that._hide();
 | 
			
		||||
				}
 | 
			
		||||
				that.settings = that.setSettings(that.settings);
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// attach maximize event
 | 
			
		||||
			this.sideframe.find('.cms_sideframe-maximize').bind(this.click, function () {
 | 
			
		||||
				if($(this).hasClass('cms_sideframe-minimize')) {
 | 
			
		||||
					that.settings.sideframe.maximized = false;
 | 
			
		||||
					that._minimize();
 | 
			
		||||
				} else {
 | 
			
		||||
					that.settings.sideframe.maximized = true;
 | 
			
		||||
					that.settings.sideframe.hidden = false;
 | 
			
		||||
					that._maximize();
 | 
			
		||||
				}
 | 
			
		||||
				that.settings = that.setSettings(that.settings);
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			this.sideframe.find('.cms_sideframe-resize').bind('mousedown', function (e) {
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
				that._startResize();
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// stopper events
 | 
			
		||||
			$(document).bind('mouseup.cms', function () {
 | 
			
		||||
				that._stopResize();
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// public methods
 | 
			
		||||
		open: function (url, animate) {
 | 
			
		||||
			// prepare iframe
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var language = 'language=' + CMS.config.request.language;
 | 
			
		||||
			var page_id = 'page_id=' + CMS.config.request.page_id;
 | 
			
		||||
			var holder = this.sideframe.find('.cms_sideframe-frame');
 | 
			
		||||
			var initialized = false;
 | 
			
		||||
 | 
			
		||||
			// push required params if defined
 | 
			
		||||
			// only apply params on tree view
 | 
			
		||||
			if(url.indexOf(CMS.config.request.tree) >= 0) {
 | 
			
		||||
				var params = [];
 | 
			
		||||
				if(CMS.config.request.language) params.push(language);
 | 
			
		||||
				if(CMS.config.request.page_id) params.push(page_id);
 | 
			
		||||
				url = this._url(url, params);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			var iframe = $('<iframe src="'+url+'" class="" frameborder="0" />');
 | 
			
		||||
				iframe.hide();
 | 
			
		||||
			var width = this.settings.sideframe.position || this.options.sideframeWidth;
 | 
			
		||||
 | 
			
		||||
			// attach load event to iframe
 | 
			
		||||
			iframe.bind('load', function () {
 | 
			
		||||
				var contents = iframe.contents();
 | 
			
		||||
 | 
			
		||||
				// after iframe is loaded append css
 | 
			
		||||
				contents.find('head').append($('<link rel="stylesheet" type="text/css" href="' + that.config.urls.static + that.options.urls.css_sideframe + '" />'));
 | 
			
		||||
				// remove loader
 | 
			
		||||
				that.sideframe.find('.cms_sideframe-frame').removeClass('cms_loader');
 | 
			
		||||
				// than show
 | 
			
		||||
				iframe.show();
 | 
			
		||||
 | 
			
		||||
				// add debug infos
 | 
			
		||||
				if(that.config.debug) iframe.contents().find('body').addClass('cms_debug');
 | 
			
		||||
 | 
			
		||||
				// save url in settings
 | 
			
		||||
				that.settings.sideframe.url = iframe.get(0).contentWindow.location.href;
 | 
			
		||||
				that.settings = that.setSettings(that.settings);
 | 
			
		||||
 | 
			
		||||
				// bind extra events
 | 
			
		||||
				contents.find('body').bind(that.click, function () {
 | 
			
		||||
					$(document).trigger(that.click);
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
				// attach reload event
 | 
			
		||||
				if(initialized) that.reloadBrowser(false, false, true);
 | 
			
		||||
				initialized = true;
 | 
			
		||||
 | 
			
		||||
				// adding django hacks
 | 
			
		||||
				contents.find('.viewsitelink').attr('target', '_top');
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// cancel animation if sideframe is already shown
 | 
			
		||||
			if(this.sideframe.is(':visible')) {
 | 
			
		||||
				// sideframe is already open
 | 
			
		||||
				insertHolder(iframe);
 | 
			
		||||
				// reanimate the frame
 | 
			
		||||
				if(this.sideframe.outerWidth() < width) {
 | 
			
		||||
					// The user has performed an action that requires the
 | 
			
		||||
					// sideframe to be shown, this intent outweighs any
 | 
			
		||||
					// previous intent to minimize the frame.
 | 
			
		||||
					this.settings.sideframe.hidden = false;
 | 
			
		||||
					this._show(width, animate);
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				// load iframe after frame animation is done
 | 
			
		||||
				setTimeout(function () {
 | 
			
		||||
					insertHolder(iframe);
 | 
			
		||||
				}, this.options.sideframeDuration);
 | 
			
		||||
				// display the frame
 | 
			
		||||
				this._show(width, animate);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			function insertHolder(iframe) {
 | 
			
		||||
				// show iframe after animation
 | 
			
		||||
				that.sideframe.find('.cms_sideframe-frame').addClass('cms_loader');
 | 
			
		||||
				holder.html(iframe);
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		close: function () {
 | 
			
		||||
			this._hide(true);
 | 
			
		||||
 | 
			
		||||
			// remove url in settings
 | 
			
		||||
			this.settings.sideframe = {
 | 
			
		||||
				'url': null,
 | 
			
		||||
				'hidden': false,
 | 
			
		||||
				'maximized': false,
 | 
			
		||||
				'width': this.options.sideframeWidth
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			// resets
 | 
			
		||||
			this.sideframe.find('.cms_sideframe-maximize').removeClass('cms_sideframe-minimize');
 | 
			
		||||
			this.sideframe.find('.cms_sideframe-hide').show();
 | 
			
		||||
 | 
			
		||||
			// update settings
 | 
			
		||||
			this.settings = this.setSettings(this.settings);
 | 
			
		||||
 | 
			
		||||
			// handle refresh option
 | 
			
		||||
			this.reloadBrowser(this.options.onClose, false, true);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// private methods
 | 
			
		||||
		_show: function (width, animate) {
 | 
			
		||||
			// add class
 | 
			
		||||
			this.sideframe.find('.cms_sideframe-hide').removeClass('cms_sideframe-hidden');
 | 
			
		||||
			
 | 
			
		||||
			// make sure the close / hide / maximize controls appear, regardless of hidden / maximized state
 | 
			
		||||
			this.sideframe.show();
 | 
			
		||||
 | 
			
		||||
			// check if sideframe should be hidden
 | 
			
		||||
			if(this.settings.sideframe.hidden) this._hide();
 | 
			
		||||
 | 
			
		||||
			// check if sideframe should be maximized
 | 
			
		||||
			if(this.settings.sideframe.maximized) this._maximize();
 | 
			
		||||
 | 
			
		||||
			// otherwise do normal behaviour
 | 
			
		||||
			if(!this.settings.sideframe.hidden && !this.settings.sideframe.maximized) {
 | 
			
		||||
				if(animate) {
 | 
			
		||||
					this.sideframe.animate({ 'width': width }, this.options.sideframeDuration);
 | 
			
		||||
					this.body.animate({ 'margin-left': width }, this.options.sideframeDuration);
 | 
			
		||||
				} else {
 | 
			
		||||
					this.sideframe.animate({ 'width': width }, 0);
 | 
			
		||||
					this.body.animate({ 'margin-left': width }, 0);
 | 
			
		||||
					// reset width if larger than available space
 | 
			
		||||
					if(width >= $(window).width()) {
 | 
			
		||||
						this.sideframe.animate({ 'width': $(window).width() - 20 }, 0);
 | 
			
		||||
						this.body.animate({ 'margin-left': $(window).width() - 20 }, 0);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				this.sideframe.find('.cms_sideframe-btn').css('right', -20);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// lock toolbar, set timeout to make sure CMS.API is ready
 | 
			
		||||
			setTimeout(function () {
 | 
			
		||||
				CMS.API.Toolbar._lock(true);
 | 
			
		||||
				CMS.API.Toolbar._showToolbar(true);
 | 
			
		||||
			}, 100);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_hide: function (close) {
 | 
			
		||||
			// add class
 | 
			
		||||
			this.sideframe.find('.cms_sideframe-hide').addClass('cms_sideframe-hidden');
 | 
			
		||||
 | 
			
		||||
			var duration = this.options.sideframeDuration;
 | 
			
		||||
			// remove the iframe
 | 
			
		||||
			if(close && this.sideframe.width() <= 0) duration = 0;
 | 
			
		||||
			if(close) this.sideframe.find('iframe').remove();
 | 
			
		||||
			this.sideframe.animate({ 'width': 0 }, duration, function () {
 | 
			
		||||
				if(close) $(this).hide();
 | 
			
		||||
			});
 | 
			
		||||
			this.body.animate({ 'margin-left': 0 }, duration);
 | 
			
		||||
			this.sideframe.find('.cms_sideframe-frame').removeClass('cms_loader');
 | 
			
		||||
 | 
			
		||||
			// lock toolbar, set timeout to make sure CMS.API is ready
 | 
			
		||||
			setTimeout(function () {
 | 
			
		||||
				CMS.API.Toolbar._lock(false);
 | 
			
		||||
			}, 100);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_minimize: function (noPositionReset) {
 | 
			
		||||
			this.sideframe.find('.cms_sideframe-maximize').removeClass('cms_sideframe-minimize');
 | 
			
		||||
			this.sideframe.find('.cms_sideframe-hide').show();
 | 
			
		||||
 | 
			
		||||
			// reset to first state
 | 
			
		||||
			if(!noPositionReset) {
 | 
			
		||||
				this._show(this.settings.sideframe.position || this.options.sideframeWidth, true);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// remove event
 | 
			
		||||
			$(window).unbind('resize.cms.sideframe');
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_maximize: function () {
 | 
			
		||||
			var that = this;
 | 
			
		||||
 | 
			
		||||
			this.sideframe.find('.cms_sideframe-maximize').addClass('cms_sideframe-minimize');
 | 
			
		||||
			this.sideframe.find('.cms_sideframe-hide').hide();
 | 
			
		||||
 | 
			
		||||
			this.sideframe.find('.cms_sideframe-hide').removeClass('cms_sideframe-hidden').hide();
 | 
			
		||||
			// do custom animation
 | 
			
		||||
			this.sideframe.animate({ 'width': $(window).width() }, 0);
 | 
			
		||||
			this.body.animate({ 'margin-left': 0 }, 0);
 | 
			
		||||
			// invert icon position
 | 
			
		||||
			this.sideframe.find('.cms_sideframe-btn').css('right', -2);
 | 
			
		||||
			// attach resize event
 | 
			
		||||
			$(window).bind('resize.cms.sideframe', function () {
 | 
			
		||||
				that.sideframe.css('width', $(window).width());
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_startResize: function () {
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var outerOffset = 20;
 | 
			
		||||
			var timer = function () {};
 | 
			
		||||
			// this prevents the iframe from being focusable
 | 
			
		||||
			this.sideframe.find('.cms_sideframe-shim').css('z-index', 20);
 | 
			
		||||
			this._minimize(true);
 | 
			
		||||
 | 
			
		||||
			$(document).bind('mousemove.cms', function (e) {
 | 
			
		||||
				if(e.clientX <= 320) e.clientX = 320;
 | 
			
		||||
				if(e.clientX >= $(window).width() - outerOffset) e.clientX = $(window).width() - outerOffset;
 | 
			
		||||
 | 
			
		||||
				that.sideframe.css('width', e.clientX);
 | 
			
		||||
				that.body.css('margin-left', e.clientX);
 | 
			
		||||
 | 
			
		||||
				// update settings
 | 
			
		||||
				that.settings.sideframe.position = e.clientX;
 | 
			
		||||
 | 
			
		||||
				// trigger the resize event
 | 
			
		||||
				$(window).trigger('resize.sideframe');
 | 
			
		||||
 | 
			
		||||
				// save position
 | 
			
		||||
				clearTimeout(timer);
 | 
			
		||||
				timer = setTimeout(function () {
 | 
			
		||||
					that.settings = that.setSettings(that.settings);
 | 
			
		||||
				}, 500);
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_stopResize: function () {
 | 
			
		||||
			this.sideframe.find('.cms_sideframe-shim').css('z-index', 1);
 | 
			
		||||
 | 
			
		||||
			$(document).unbind('mousemove.cms');
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_url: function (url, params) {
 | 
			
		||||
			var arr = [];
 | 
			
		||||
			var keys = [];
 | 
			
		||||
			var values = [];
 | 
			
		||||
			var tmp = '';
 | 
			
		||||
			var urlArray = [];
 | 
			
		||||
			var urlParams = [];
 | 
			
		||||
			var origin = url;
 | 
			
		||||
 | 
			
		||||
			// return url if there is no param
 | 
			
		||||
			if(!(url.split('?').length <= 1 || window.JSON === undefined)) {
 | 
			
		||||
				// setup local vars
 | 
			
		||||
				urlArray = url.split('?');
 | 
			
		||||
				urlParams = urlArray[1].split('&');
 | 
			
		||||
				origin = urlArray[0];
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// loop through the available params
 | 
			
		||||
			$.each(urlParams, function (index, param) {
 | 
			
		||||
				arr.push({ 'param': param.split('=')[0], 'value': param.split('=')[1] });
 | 
			
		||||
			});
 | 
			
		||||
			// loop through the new params
 | 
			
		||||
			$.each(params, function (index, param) {
 | 
			
		||||
				arr.push({ 'param': param.split('=')[0], 'value': param.split('=')[1] });
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// merge manually because jquery...
 | 
			
		||||
			$.each(arr, function (index, item) {
 | 
			
		||||
				var i = $.inArray(item.param, keys);
 | 
			
		||||
 | 
			
		||||
				if(i === -1) {
 | 
			
		||||
					keys.push(item.param);
 | 
			
		||||
					values.push(item.value);
 | 
			
		||||
				} else {
 | 
			
		||||
					values[i] = item.value;
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// merge new url
 | 
			
		||||
			$.each(keys, function (index, key) {
 | 
			
		||||
				tmp += '&' + key + '=' + values[index];
 | 
			
		||||
			});
 | 
			
		||||
			tmp = tmp.replace('&', '?');
 | 
			
		||||
			url = origin + tmp;
 | 
			
		||||
 | 
			
		||||
			return url;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
})(CMS.$);
 | 
			
		||||
							
								
								
									
										493
									
								
								static/cms/js/modules/cms.structureboard.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										493
									
								
								static/cms/js/modules/cms.structureboard.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,493 @@
 | 
			
		|||
/*##################################################|*/
 | 
			
		||||
/* #CMS# */
 | 
			
		||||
(function($) {
 | 
			
		||||
// CMS.$ will be passed for $
 | 
			
		||||
$(document).ready(function () {
 | 
			
		||||
	/*!
 | 
			
		||||
	 * StructureBoard
 | 
			
		||||
	 * handles drag & drop, mode switching and
 | 
			
		||||
	 */
 | 
			
		||||
	CMS.StructureBoard = new CMS.Class({
 | 
			
		||||
 | 
			
		||||
		implement: [CMS.API.Helpers],
 | 
			
		||||
 | 
			
		||||
		options: {
 | 
			
		||||
			'speed': 300
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		initialize: function (options) {
 | 
			
		||||
			this.container = $('.cms_structure');
 | 
			
		||||
			this.options = $.extend(true, {}, this.options, options);
 | 
			
		||||
			this.config = CMS.config;
 | 
			
		||||
			this.settings = CMS.settings;
 | 
			
		||||
 | 
			
		||||
			// elements
 | 
			
		||||
			this.toolbar = $('#cms_toolbar');
 | 
			
		||||
			this.sortables = $('.cms_draggables'); // use global scope
 | 
			
		||||
			this.plugins = $('.cms_plugin');
 | 
			
		||||
			this.render_model = $('.cms_render_model');
 | 
			
		||||
			this.placeholders = $('.cms_placeholder');
 | 
			
		||||
			this.dragitems = $('.cms_draggable');
 | 
			
		||||
			this.dragareas = $('.cms_dragarea');
 | 
			
		||||
			this.dropareas = $('.cms_droppable');
 | 
			
		||||
			this.dimmer = this.container.find('.cms_structure-dimmer');
 | 
			
		||||
			this.clipboard = $('.cms_clipboard');
 | 
			
		||||
 | 
			
		||||
			// states
 | 
			
		||||
			this.click = (document.ontouchstart !== null) ? 'click.cms' : 'tap.cms click.cms';
 | 
			
		||||
			this.timer = function () {};
 | 
			
		||||
			this.interval = function () {};
 | 
			
		||||
			this.state = false;
 | 
			
		||||
			this.dragging = false;
 | 
			
		||||
 | 
			
		||||
			// setup initial stuff
 | 
			
		||||
			this._setup();
 | 
			
		||||
 | 
			
		||||
			// setup events
 | 
			
		||||
			this._events();
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// initial methods
 | 
			
		||||
		_setup: function () {
 | 
			
		||||
			var that = this;
 | 
			
		||||
 | 
			
		||||
			// cancel if there are no dragareas
 | 
			
		||||
			if(!this.dragareas.length) return false;
 | 
			
		||||
 | 
			
		||||
			// cancel if there is no structure / content switcher
 | 
			
		||||
			if(!this.toolbar.find('.cms_toolbar-item-cms-mode-switcher').length) return false;
 | 
			
		||||
 | 
			
		||||
			// setup toolbar mode
 | 
			
		||||
			if(this.settings.mode === 'structure') setTimeout(function () { that.show(true); }, 100);
 | 
			
		||||
 | 
			
		||||
			// check if modes should be visible
 | 
			
		||||
			if(this.placeholders.length) {
 | 
			
		||||
				this.toolbar.find('.cms_toolbar-item-cms-mode-switcher').show();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// add drag & drop functionality
 | 
			
		||||
			this._drag();
 | 
			
		||||
			// prevent click events to detect double click
 | 
			
		||||
			// this.preventEvents(this.plugins);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_events: function () {
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var modes = this.toolbar.find('.cms_toolbar-item-cms-mode-switcher a');
 | 
			
		||||
 | 
			
		||||
			// show edit mode
 | 
			
		||||
			modes.eq(1).bind(this.click, function (e) {
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
				// cancel if already active
 | 
			
		||||
				if(that.settings.mode === 'edit') return false;
 | 
			
		||||
				// otherwise hide
 | 
			
		||||
				that.hide();
 | 
			
		||||
			});
 | 
			
		||||
			// show structure mode
 | 
			
		||||
			modes.eq(0).bind(this.click, function (e) {
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
				// cancel if already active
 | 
			
		||||
				if(that.settings.mode === 'structure') return false;
 | 
			
		||||
				// otherwise show
 | 
			
		||||
				that.show();
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// keyboard handling
 | 
			
		||||
			$(document).bind('keydown', function (e) {
 | 
			
		||||
				// check if we have an important focus
 | 
			
		||||
				var fields = $('*:focus');
 | 
			
		||||
				// 32 = space
 | 
			
		||||
				if(e.keyCode === 32 && that.settings.mode === 'structure' && !fields.length) {
 | 
			
		||||
					// cancel if there is no structure / content switcher
 | 
			
		||||
					if(!that.toolbar.find('.cms_toolbar-item-cms-mode-switcher').length) return false;
 | 
			
		||||
					e.preventDefault();
 | 
			
		||||
					that.hide();
 | 
			
		||||
				} else if(e.keyCode === 32 && that.settings.mode === 'edit' && !fields.length) {
 | 
			
		||||
					// cancel if there is no structure / content switcher
 | 
			
		||||
					if(!that.toolbar.find('.cms_toolbar-item-cms-mode-switcher').length) return false;
 | 
			
		||||
					e.preventDefault();
 | 
			
		||||
					that.show();
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// public methods
 | 
			
		||||
		show: function (init) {
 | 
			
		||||
			// cancel show if live modus is active
 | 
			
		||||
			if(CMS.config.mode === 'live') return false;
 | 
			
		||||
 | 
			
		||||
			// set active item
 | 
			
		||||
			var modes = this.toolbar.find('.cms_toolbar-item-cms-mode-switcher a');
 | 
			
		||||
				modes.removeClass('cms_btn-active').eq(0).addClass('cms_btn-active');
 | 
			
		||||
 | 
			
		||||
			// show clipboard
 | 
			
		||||
			this.clipboard.css('opacity', 1).fadeIn(this.options.speed);
 | 
			
		||||
 | 
			
		||||
			// apply new settings
 | 
			
		||||
			this.settings.mode = 'structure';
 | 
			
		||||
			if(!init) this.settings = this.setSettings(this.settings);
 | 
			
		||||
 | 
			
		||||
			// ensure all elements are visible
 | 
			
		||||
			this.dragareas.show();
 | 
			
		||||
 | 
			
		||||
			// show canvas
 | 
			
		||||
			this._showBoard();
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		hide: function (init) {
 | 
			
		||||
			// cancel show if live modus is active
 | 
			
		||||
			if(CMS.config.mode === 'live') return false;
 | 
			
		||||
 | 
			
		||||
			// set active item
 | 
			
		||||
			var modes = this.toolbar.find('.cms_toolbar-item-cms-mode-switcher a');
 | 
			
		||||
				modes.removeClass('cms_btn-active').eq(1).addClass('cms_btn-active');
 | 
			
		||||
 | 
			
		||||
			// hide clipboard if in edit mode
 | 
			
		||||
			this.container.find('.cms_clipboard').hide();
 | 
			
		||||
 | 
			
		||||
			// hide clipboard
 | 
			
		||||
			this.clipboard.hide();
 | 
			
		||||
 | 
			
		||||
			this.settings.mode = 'edit';
 | 
			
		||||
			if(!init) this.settings = this.setSettings(this.settings);
 | 
			
		||||
 | 
			
		||||
			// hide canvas
 | 
			
		||||
			this._hideBoard();
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		getId: function (el) {
 | 
			
		||||
			// cancel if no element is defined
 | 
			
		||||
			if(el === undefined || el === null || el.length <= 0) return false;
 | 
			
		||||
 | 
			
		||||
			var id = null;
 | 
			
		||||
			var cls = el.attr('class').split(' ')[1];
 | 
			
		||||
 | 
			
		||||
			if(el.hasClass('cms_plugin')) {
 | 
			
		||||
				id = cls.replace('cms_plugin-', '');
 | 
			
		||||
			} else if(el.hasClass('cms_draggable')) {
 | 
			
		||||
				id = cls.replace('cms_draggable-', '');
 | 
			
		||||
			} else if(el.hasClass('cms_placeholder')) {
 | 
			
		||||
				id = cls.replace('cms_placeholder-', '');
 | 
			
		||||
			} else if(el.hasClass('cms_dragbar')) {
 | 
			
		||||
				id = cls.replace('cms_dragbar-', '');
 | 
			
		||||
			} else if(el.hasClass('cms_dragarea')) {
 | 
			
		||||
				id = cls.replace('cms_dragarea-', '');
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return id;
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		getIds: function (els) {
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var array = [];
 | 
			
		||||
			els.each(function () {
 | 
			
		||||
				array.push(that.getId($(this)));
 | 
			
		||||
			});
 | 
			
		||||
			return array;
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		setActive: function (id, state) {
 | 
			
		||||
			var that = this;
 | 
			
		||||
			// resets
 | 
			
		||||
			this.dragitems.removeClass('cms_draggable-selected');
 | 
			
		||||
			this.plugins.removeClass('cms_plugin-active');
 | 
			
		||||
 | 
			
		||||
			// only reset if no id is provided
 | 
			
		||||
			if(id === false) return false;
 | 
			
		||||
 | 
			
		||||
			// attach active class to current element
 | 
			
		||||
			var dragitem = $('.cms_draggable-' + id);
 | 
			
		||||
			var plugin = $('.cms_plugin-' + id);
 | 
			
		||||
 | 
			
		||||
			// if we switch from content to edit, show only a single plcaeholder
 | 
			
		||||
			if(state) {
 | 
			
		||||
				// quick show
 | 
			
		||||
				this._showBoard();
 | 
			
		||||
 | 
			
		||||
				// show clipboard
 | 
			
		||||
				this.clipboard.show().css('opacity', 0.2);
 | 
			
		||||
 | 
			
		||||
				// prevent default visibility
 | 
			
		||||
				this.dragareas.css('opacity', 0.2);
 | 
			
		||||
 | 
			
		||||
				// show single placeholder
 | 
			
		||||
				dragitem.closest('.cms_dragarea').show().css('opacity', 1);
 | 
			
		||||
 | 
			
		||||
			// otherwise hide and reset the board
 | 
			
		||||
			} else {
 | 
			
		||||
				this.hide();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// collapse all previous elements
 | 
			
		||||
			var collapsed = dragitem.parentsUntil('.cms_dragarea').siblings().not('.cms_dragitem-expanded');
 | 
			
		||||
				collapsed.trigger(this.click);
 | 
			
		||||
 | 
			
		||||
			// set new classes
 | 
			
		||||
			dragitem.addClass('cms_draggable-selected');
 | 
			
		||||
			plugin.addClass('cms_plugin-active');
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		preventEvents: function (elements) {
 | 
			
		||||
			var clicks = 0;
 | 
			
		||||
			var delay = 500;
 | 
			
		||||
			var timer = function () {};
 | 
			
		||||
 | 
			
		||||
			// unbind click event if already initialized
 | 
			
		||||
			elements.find('a').bind(this.click, function (e) {
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
 | 
			
		||||
				// increment
 | 
			
		||||
				clicks++;
 | 
			
		||||
 | 
			
		||||
				// single click
 | 
			
		||||
				if(clicks === 1) {
 | 
			
		||||
					timer = setTimeout(function () {
 | 
			
		||||
						clicks = 0;
 | 
			
		||||
						// cancel if link contains a hash
 | 
			
		||||
						if($(e.currentTarget).attr('href').indexOf('#') === 0) return false;
 | 
			
		||||
						// we need to redirect to the default behaviours
 | 
			
		||||
						// all events will be lost in edit mode, use '#' if href should not be triggered
 | 
			
		||||
						window.location.href = $(e.currentTarget).attr('href');
 | 
			
		||||
					}, delay);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// double click
 | 
			
		||||
				if(clicks === 2) {
 | 
			
		||||
					clearTimeout(timer);
 | 
			
		||||
					clicks = 0;
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// private methods
 | 
			
		||||
		_showBoard: function () {
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var timer = function () {};
 | 
			
		||||
 | 
			
		||||
			// show container
 | 
			
		||||
			this.container.show();
 | 
			
		||||
			this.dimmer.fadeIn(100);
 | 
			
		||||
			this.dragareas.css('opacity', 1);
 | 
			
		||||
 | 
			
		||||
			// add dimmer close
 | 
			
		||||
			this.dimmer.bind('mousedown mouseup', function (e) {
 | 
			
		||||
				// cancel on rightclick
 | 
			
		||||
				if(e.which === 3 || e.button === 2) return false;
 | 
			
		||||
				// proceed
 | 
			
		||||
				clearTimeout(timer);
 | 
			
		||||
				timer = setTimeout(function () {
 | 
			
		||||
					that.hide();
 | 
			
		||||
				}, 500);
 | 
			
		||||
 | 
			
		||||
				if(e.type === 'mouseup') clearTimeout(timer);
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			this.plugins.not(this.render_model).hide();
 | 
			
		||||
			this.placeholders.show();
 | 
			
		||||
 | 
			
		||||
			// attach event
 | 
			
		||||
			$(window).bind('resize.sideframe', function () {
 | 
			
		||||
				that._resizeBoard();
 | 
			
		||||
			}).trigger('resize.sideframe');
 | 
			
		||||
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_hideBoard: function () {
 | 
			
		||||
			// hide elements
 | 
			
		||||
			this.container.hide();
 | 
			
		||||
			this.plugins.show();
 | 
			
		||||
			this.placeholders.hide();
 | 
			
		||||
			this.dimmer.hide();
 | 
			
		||||
 | 
			
		||||
			// detach event
 | 
			
		||||
			$(window).unbind('resize.sideframe');
 | 
			
		||||
 | 
			
		||||
			// clear interval
 | 
			
		||||
			clearInterval(this.interval);
 | 
			
		||||
 | 
			
		||||
			$(window).trigger('structureboard_hidden.sideframe');
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_resizeBoard: function () {
 | 
			
		||||
			// calculate placeholder position
 | 
			
		||||
			var id = null;
 | 
			
		||||
			var area = null;
 | 
			
		||||
			var min = null;
 | 
			
		||||
			var areaParentOffset = null;
 | 
			
		||||
 | 
			
		||||
			// start calculating
 | 
			
		||||
			this.placeholders.each(function (index, item) {
 | 
			
		||||
				item = $(item);
 | 
			
		||||
				id = item.data('settings').placeholder_id;
 | 
			
		||||
				area = $('.cms_dragarea-' + id);
 | 
			
		||||
				// to calculate the correct offset, we need to set the
 | 
			
		||||
				// placeholders correct heights and than set the according position
 | 
			
		||||
				item.height(area.outerHeight(true));
 | 
			
		||||
				// set min width
 | 
			
		||||
				min = (item.width()) ? 0 : 150;
 | 
			
		||||
				// as area is "css positioned" and jquery offset function is relative to the
 | 
			
		||||
				// document (not the first relative/absolute parent) we need to substract
 | 
			
		||||
				// first relative/absolute parent offset.
 | 
			
		||||
				areaParentOffset = $(area).offsetParent().offset();
 | 
			
		||||
				area.css({
 | 
			
		||||
					'top': item.offset().top - areaParentOffset.top - 5,
 | 
			
		||||
					'left': item.offset().left - areaParentOffset.left - min,
 | 
			
		||||
					'width': item.width() + min
 | 
			
		||||
				});
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_drag: function () {
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var dropped = false;
 | 
			
		||||
			var droparea = null;
 | 
			
		||||
			var dropzone = null;
 | 
			
		||||
 | 
			
		||||
			this.sortables.nestedSortable({
 | 
			
		||||
				'items': '.cms_draggable',
 | 
			
		||||
				'handle': '.cms_dragitem',
 | 
			
		||||
				'placeholder': 'cms_droppable',
 | 
			
		||||
				'connectWith': this.sortables,
 | 
			
		||||
				'tolerance': 'pointer',
 | 
			
		||||
				'toleranceElement': '> div',
 | 
			
		||||
				'dropOnEmpty': true,
 | 
			
		||||
				'forcePlaceholderSize': true,
 | 
			
		||||
				'helper': 'clone',
 | 
			
		||||
				'appendTo': 'body',
 | 
			
		||||
				'cursor': 'move',
 | 
			
		||||
				'opacity': 0.4,
 | 
			
		||||
				'zIndex': 9999999,
 | 
			
		||||
				'delay': 100,
 | 
			
		||||
				'refreshPositions': true,
 | 
			
		||||
				// nestedSortable
 | 
			
		||||
				'listType': 'div.cms_draggables',
 | 
			
		||||
				'doNotClear': true,
 | 
			
		||||
				//'disableNestingClass': 'cms_draggable-disabled',
 | 
			
		||||
				//'errorClass': 'cms_draggable-disallowed',
 | 
			
		||||
				//'hoveringClass': 'cms_draggable-hover',
 | 
			
		||||
				// methods
 | 
			
		||||
				'start': function (e, ui) {
 | 
			
		||||
					that.dragging = true;
 | 
			
		||||
					// show empty
 | 
			
		||||
					$('.cms_dragbar-empty-wrapper').show();
 | 
			
		||||
					// ensure all menus are closed
 | 
			
		||||
					$('.cms_dragitem .cms_submenu').hide();
 | 
			
		||||
					// remove classes from empty dropzones
 | 
			
		||||
					$('.cms_dragbar-empty').removeClass('cms_draggable-disallowed');
 | 
			
		||||
					// fixes placeholder height
 | 
			
		||||
					ui.placeholder.height(ui.item.height());
 | 
			
		||||
					// show placeholder without entries
 | 
			
		||||
					$('.cms_draggables').each(function () {
 | 
			
		||||
						if($(this).children().length === 0) {
 | 
			
		||||
							$(this).show();
 | 
			
		||||
						}
 | 
			
		||||
					});
 | 
			
		||||
				},
 | 
			
		||||
 | 
			
		||||
				'stop': function (event, ui) {
 | 
			
		||||
					that.dragging = false;
 | 
			
		||||
					// hide empty
 | 
			
		||||
					$('.cms_dragbar-empty-wrapper').hide();
 | 
			
		||||
 | 
			
		||||
					// cancel if isAllowed returns false
 | 
			
		||||
					if(!that.state) return false;
 | 
			
		||||
 | 
			
		||||
					// handle dropped event
 | 
			
		||||
					if(dropped) {
 | 
			
		||||
						droparea.prepend(ui.item);
 | 
			
		||||
						dropped = false;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					// we pass the id to the updater which checks within the backend the correct place
 | 
			
		||||
					//var id = ui.item.attr('class').replace('cms_draggable cms_draggable-', '');
 | 
			
		||||
					var id = that.getId(ui.item);
 | 
			
		||||
					var plugin = $('.cms_plugin-' + id);
 | 
			
		||||
 | 
			
		||||
					// check if we copy/paste a plugin or not
 | 
			
		||||
					if(plugin.closest('.cms_clipboard').length) {
 | 
			
		||||
						plugin.trigger('cms.plugin.update');
 | 
			
		||||
					} else {
 | 
			
		||||
						plugin.trigger('cms.plugins.update');
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					// reset placeholder without entries
 | 
			
		||||
					$('.cms_draggables').each(function () {
 | 
			
		||||
						if($(this).children().length === 0) {
 | 
			
		||||
							$(this).hide();
 | 
			
		||||
						}
 | 
			
		||||
					});
 | 
			
		||||
				},
 | 
			
		||||
				'isAllowed': function(placeholder, placeholderParent, originalItem) {
 | 
			
		||||
					// cancel if action is excecuted
 | 
			
		||||
					if(CMS.API.locked) return false;
 | 
			
		||||
					// getting restriction array
 | 
			
		||||
					var bounds = [];
 | 
			
		||||
					// save original state events
 | 
			
		||||
					var original = $('.cms_plugin-' + that.getId(originalItem));
 | 
			
		||||
					// cancel if item has no settings
 | 
			
		||||
					if(original.length === 0 || original.data('settings') === null) return false;
 | 
			
		||||
					var type = original.data('settings').plugin_type;
 | 
			
		||||
					// prepare variables for bound
 | 
			
		||||
					var holderId = that.getId(placeholder.closest('.cms_dragarea'));
 | 
			
		||||
					var holder = $('.cms_placeholder-' + holderId);
 | 
			
		||||
					var plugin = $('.cms_plugin-' + that.getId(placeholder.closest('.cms_draggable')));
 | 
			
		||||
 | 
			
		||||
					// now set the correct bounds
 | 
			
		||||
					if(holder.length) bounds = holder.data('settings').plugin_restriction;
 | 
			
		||||
					if(plugin.length) bounds = plugin.data('settings').plugin_restriction;
 | 
			
		||||
					if(dropzone) bounds = dropzone.data('settings').plugin_restriction;
 | 
			
		||||
 | 
			
		||||
					// if parent has class disabled, dissalow drop
 | 
			
		||||
					if(placeholder.parent().hasClass('cms_draggable-disabled')) return false;
 | 
			
		||||
 | 
			
		||||
					// if restrictions is still empty, proceed
 | 
			
		||||
					that.state = (bounds.length <= 0 || $.inArray(type, bounds) !== -1) ? true : false;
 | 
			
		||||
 | 
			
		||||
					return that.state;
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// attach escape event to cancel dragging
 | 
			
		||||
			$(document).bind('keyup.cms', function(e, cancel){
 | 
			
		||||
				if(e.keyCode === 27 || cancel) {
 | 
			
		||||
					that.state = false;
 | 
			
		||||
					that.sortables.sortable('cancel');
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// define droppable helpers
 | 
			
		||||
			this.dropareas.droppable({
 | 
			
		||||
				'greedy': true,
 | 
			
		||||
				'accept': '.cms_draggable',
 | 
			
		||||
				'tolerance': 'pointer',
 | 
			
		||||
				'activeClass': 'cms_draggable-allowed',
 | 
			
		||||
				'hoverClass': 'cms_draggable-hover-allowed',
 | 
			
		||||
				'over': function (event) {
 | 
			
		||||
					dropzone = $('.cms_placeholder-' + that.getId($(event.target).parent().prev()));
 | 
			
		||||
					timer = setInterval(function () {
 | 
			
		||||
						// reset other empty placeholders
 | 
			
		||||
						$('.cms_dragbar-empty').removeClass('cms_draggable-disallowed');
 | 
			
		||||
						if(that.state) {
 | 
			
		||||
							$(event.target).removeClass('cms_draggable-disallowed');
 | 
			
		||||
						} else {
 | 
			
		||||
							$(event.target).addClass('cms_draggable-disallowed');
 | 
			
		||||
						}
 | 
			
		||||
					}, 10);
 | 
			
		||||
				},
 | 
			
		||||
				'out': function (event) {
 | 
			
		||||
					dropzone = null;
 | 
			
		||||
					$(event.target).removeClass('cms_draggable-disallowed');
 | 
			
		||||
					clearInterval(timer);
 | 
			
		||||
				},
 | 
			
		||||
				'drop': function (event) {
 | 
			
		||||
					dropped = true;
 | 
			
		||||
					droparea = $(event.target).parent().nextAll('.cms_draggables').first();
 | 
			
		||||
					clearInterval(timer);
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
})(CMS.$);
 | 
			
		||||
							
								
								
									
										512
									
								
								static/cms/js/modules/cms.toolbar.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										512
									
								
								static/cms/js/modules/cms.toolbar.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,512 @@
 | 
			
		|||
/*##################################################|*/
 | 
			
		||||
/* #CMS# */
 | 
			
		||||
(function($) {
 | 
			
		||||
// CMS.$ will be passed for $
 | 
			
		||||
$(document).ready(function () {
 | 
			
		||||
	/*!
 | 
			
		||||
	 * Toolbar
 | 
			
		||||
	 * Handles all features related to the toolbar
 | 
			
		||||
	 */
 | 
			
		||||
	CMS.Toolbar = new CMS.Class({
 | 
			
		||||
 | 
			
		||||
		implement: [CMS.API.Helpers],
 | 
			
		||||
 | 
			
		||||
		options: {
 | 
			
		||||
			'preventSwitch': false,
 | 
			
		||||
			'preventSwitchMessage': 'Switching is disabled.',
 | 
			
		||||
			'messageDelay': 2000
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		initialize: function (options) {
 | 
			
		||||
			this.container = $('#cms_toolbar');
 | 
			
		||||
			this.options = $.extend(true, {}, this.options, options);
 | 
			
		||||
			this.config = CMS.config;
 | 
			
		||||
			this.settings = CMS.settings;
 | 
			
		||||
 | 
			
		||||
			// elements
 | 
			
		||||
			this.body = $('html');
 | 
			
		||||
			this.toolbar = this.container.find('.cms_toolbar').hide();
 | 
			
		||||
			this.toolbarTrigger = this.container.find('.cms_toolbar-trigger');
 | 
			
		||||
			this.navigations = this.container.find('.cms_toolbar-item-navigation');
 | 
			
		||||
			this.buttons = this.container.find('.cms_toolbar-item-buttons');
 | 
			
		||||
			this.switcher = this.container.find('.cms_toolbar-item_switch');
 | 
			
		||||
			this.messages = this.container.find('.cms_messages');
 | 
			
		||||
			this.screenBlock = this.container.find('.cms_screenblock');
 | 
			
		||||
 | 
			
		||||
			// states
 | 
			
		||||
			this.click = 'click.cms';
 | 
			
		||||
			this.timer = function () {};
 | 
			
		||||
			this.lockToolbar = false;
 | 
			
		||||
 | 
			
		||||
			// setup initial stuff
 | 
			
		||||
			this._setup();
 | 
			
		||||
 | 
			
		||||
			// setup events
 | 
			
		||||
			this._events();
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// initial methods
 | 
			
		||||
		_setup: function () {
 | 
			
		||||
			// setup toolbar visibility, we need to reverse the options to set the correct state
 | 
			
		||||
			(this.settings.toolbar === 'expanded') ? this._showToolbar(0, true) : this._hideToolbar(0, true);
 | 
			
		||||
 | 
			
		||||
			// hide publish button
 | 
			
		||||
			var publishBtn = $('.cms_btn-publish').parent();
 | 
			
		||||
				publishBtn.hide();
 | 
			
		||||
			if($('.cms_btn-publish-active').length) publishBtn.show();
 | 
			
		||||
 | 
			
		||||
			// check if debug is true
 | 
			
		||||
			if(CMS.config.debug) this._debug();
 | 
			
		||||
 | 
			
		||||
			// check if there are messages and display them
 | 
			
		||||
			if(CMS.config.messages) this.openMessage(CMS.config.messages);
 | 
			
		||||
 | 
			
		||||
			// check if there are error messages and display them
 | 
			
		||||
			if(CMS.config.error) this.showError(CMS.config.error);
 | 
			
		||||
 | 
			
		||||
			// enforce open state if user is not logged in but requests the toolbar
 | 
			
		||||
			if(!CMS.config.auth || CMS.config.settings.version !== this.settings.version) {
 | 
			
		||||
				this.toggleToolbar(true);
 | 
			
		||||
				this.settings = this.setSettings(CMS.config.settings);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// should switcher indicate that there is an unpublished page?
 | 
			
		||||
			if(CMS.config.publisher) {
 | 
			
		||||
				this.openMessage(CMS.config.publisher, 'right');
 | 
			
		||||
				setInterval(function () {
 | 
			
		||||
					CMS.$('.cms_toolbar-item_switch').toggleClass('cms_toolbar-item_switch-highlight');
 | 
			
		||||
				}, this.options.messageDelay);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// open sideframe if it was previously opened
 | 
			
		||||
			if(this.settings.sideframe.url) {
 | 
			
		||||
				var sideframe = new CMS.Sideframe();
 | 
			
		||||
					sideframe.open(this.settings.sideframe.url, false);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// if there is a screenblock, do some resize magic
 | 
			
		||||
			if(this.screenBlock.length) this._screenBlock();
 | 
			
		||||
 | 
			
		||||
			// add toolbar ready class to body and fire event
 | 
			
		||||
			this.body.addClass('cms-ready');
 | 
			
		||||
			$(document).trigger('cms-ready');
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_events: function () {
 | 
			
		||||
			var that = this;
 | 
			
		||||
 | 
			
		||||
			// attach event to the trigger handler
 | 
			
		||||
			this.toolbarTrigger.bind(this.click, function (e) {
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
				that.toggleToolbar();
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// attach event to the navigation elements
 | 
			
		||||
			this.navigations.each(function () {
 | 
			
		||||
				var item = $(this);
 | 
			
		||||
				var lists = item.find('li');
 | 
			
		||||
				var root = 'cms_toolbar-item-navigation';
 | 
			
		||||
				var hover = 'cms_toolbar-item-navigation-hover';
 | 
			
		||||
				var disabled = 'cms_toolbar-item-navigation-disabled';
 | 
			
		||||
				var children = 'cms_toolbar-item-navigation-children';
 | 
			
		||||
 | 
			
		||||
				// remove events from first level
 | 
			
		||||
				item.find('a').bind(that.click, function (e) {
 | 
			
		||||
					e.preventDefault();
 | 
			
		||||
					if($(this).attr('href') !== ''
 | 
			
		||||
						&& $(this).attr('href') !== '#'
 | 
			
		||||
						&& !$(this).parent().hasClass(disabled)
 | 
			
		||||
						&& !$(this).parent().hasClass(disabled)) {
 | 
			
		||||
						that._delegate($(this));
 | 
			
		||||
						reset();
 | 
			
		||||
						return false;
 | 
			
		||||
					}
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
				// handle click states
 | 
			
		||||
				lists.bind(that.click, function (e) {
 | 
			
		||||
					e.stopPropagation();
 | 
			
		||||
					var el = $(this);
 | 
			
		||||
 | 
			
		||||
					// close if el is first item
 | 
			
		||||
					if(el.parent().hasClass(root) && el.hasClass(hover) || el.hasClass(disabled)) {
 | 
			
		||||
						reset();
 | 
			
		||||
						return false;
 | 
			
		||||
					} else {
 | 
			
		||||
						reset();
 | 
			
		||||
						el.addClass(hover);
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					// activate hover selection
 | 
			
		||||
					item.find('> li').bind('mouseenter', function () {
 | 
			
		||||
						// cancel if item is already active
 | 
			
		||||
						if($(this).hasClass(hover)) return false;
 | 
			
		||||
						$(this).trigger(that.click);
 | 
			
		||||
					});
 | 
			
		||||
 | 
			
		||||
					// create the document event
 | 
			
		||||
					$(document).bind(that.click, reset);
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
				// attach hover
 | 
			
		||||
				lists.find('li').bind('mouseenter mouseleave', function () {
 | 
			
		||||
					var el = $(this);
 | 
			
		||||
					var parent = el.closest('.cms_toolbar-item-navigation-children').add(el.parents('.cms_toolbar-item-navigation-children'));
 | 
			
		||||
					var hasChildren = el.hasClass(children) || parent.length;
 | 
			
		||||
 | 
			
		||||
					// do not attach hover effect if disabled
 | 
			
		||||
					// cancel event if element has already hover class
 | 
			
		||||
					if(el.hasClass(disabled) || el.hasClass(hover)) return false;
 | 
			
		||||
 | 
			
		||||
					// reset
 | 
			
		||||
					lists.find('li').removeClass(hover);
 | 
			
		||||
 | 
			
		||||
					// add hover effect
 | 
			
		||||
					el.addClass(hover);
 | 
			
		||||
 | 
			
		||||
					// handle children elements
 | 
			
		||||
					if(hasChildren) {
 | 
			
		||||
						el.find('> ul').show();
 | 
			
		||||
						// add parent class
 | 
			
		||||
						parent.addClass(hover);
 | 
			
		||||
					} else {
 | 
			
		||||
						lists.find('ul ul').hide();
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					// Remove stale submenus
 | 
			
		||||
					el.siblings().find('> ul').hide();
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
				// fix leave event
 | 
			
		||||
				lists.find('> ul').bind('mouseleave', function () {
 | 
			
		||||
					lists.find('li').removeClass(hover);
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
				// removes classes and events
 | 
			
		||||
				function reset() {
 | 
			
		||||
					lists.removeClass(hover);
 | 
			
		||||
					lists.find('ul ul').hide();
 | 
			
		||||
					item.find('> li').unbind('mouseenter');
 | 
			
		||||
					$(document).unbind(that.click);
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// attach event to the switcher elements
 | 
			
		||||
			this.switcher.each(function () {
 | 
			
		||||
				$(this).bind(that.click, function (e) {
 | 
			
		||||
					e.preventDefault();
 | 
			
		||||
					that._setSwitcher($(e.currentTarget));
 | 
			
		||||
				});
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// attach event for first page publish
 | 
			
		||||
			this.buttons.each(function () {
 | 
			
		||||
				var btn = $(this);
 | 
			
		||||
 | 
			
		||||
				// in case the button has a data-rel attribute
 | 
			
		||||
				if(btn.find('a').attr('data-rel')) {
 | 
			
		||||
					btn.on('click', function (e) {
 | 
			
		||||
						e.preventDefault();
 | 
			
		||||
						that._delegate($(this).find('a'));
 | 
			
		||||
					})
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// in case of the publish button
 | 
			
		||||
				btn.find('.cms_publish-page').bind(that.click, function (e) {
 | 
			
		||||
					if(!confirm(that.config.lang.publish)) e.preventDefault();
 | 
			
		||||
				});
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// public methods
 | 
			
		||||
		toggleToolbar: function (show) {
 | 
			
		||||
			// overwrite state when provided
 | 
			
		||||
			if(show) this.settings.toolbar = 'collapsed';
 | 
			
		||||
			// toggle bar
 | 
			
		||||
			(this.settings.toolbar === 'collapsed') ? this._showToolbar(200) : this._hideToolbar(200);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		openMessage: function (msg, dir, delay, error) {
 | 
			
		||||
			// set toolbar freeze
 | 
			
		||||
			this._lock(true);
 | 
			
		||||
 | 
			
		||||
			// add content to element
 | 
			
		||||
			this.messages.find('.cms_messages-inner').html(msg);
 | 
			
		||||
 | 
			
		||||
			// clear timeout
 | 
			
		||||
			clearTimeout(this.timer);
 | 
			
		||||
 | 
			
		||||
			// determine width
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var width = 320;
 | 
			
		||||
			var height = this.messages.outerHeight(true);
 | 
			
		||||
			var top = this.toolbar.outerHeight(true);
 | 
			
		||||
			var close = this.messages.find('.cms_messages-close');
 | 
			
		||||
				close.hide();
 | 
			
		||||
				close.bind(this.click, function () {
 | 
			
		||||
					that.closeMessage();
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
			// set top to 0 if toolbar is collapsed
 | 
			
		||||
			if(this.settings.toolbar === 'collapsed') top = 0;
 | 
			
		||||
 | 
			
		||||
			// do we need to add debug styles?
 | 
			
		||||
			if(this.config.debug) top = top + 5;
 | 
			
		||||
 | 
			
		||||
			// set correct position and show
 | 
			
		||||
			this.messages.css('top', -height).show();
 | 
			
		||||
 | 
			
		||||
			// error handling
 | 
			
		||||
			this.messages.removeClass('cms_messages-error');
 | 
			
		||||
			if(error) this.messages.addClass('cms_messages-error');
 | 
			
		||||
 | 
			
		||||
			// dir should be left, center, right
 | 
			
		||||
			dir = dir || 'center';
 | 
			
		||||
			// set correct direction and animation
 | 
			
		||||
			switch(dir) {
 | 
			
		||||
				case 'left':
 | 
			
		||||
					this.messages.css({
 | 
			
		||||
						'top': top,
 | 
			
		||||
						'left': -width,
 | 
			
		||||
						'right': 'auto',
 | 
			
		||||
						'margin-left': 0
 | 
			
		||||
					});
 | 
			
		||||
					this.messages.animate({ 'left': 0 });
 | 
			
		||||
					break;
 | 
			
		||||
				case 'right':
 | 
			
		||||
					this.messages.css({
 | 
			
		||||
						'top': top,
 | 
			
		||||
						'right': -width,
 | 
			
		||||
						'left': 'auto',
 | 
			
		||||
						'margin-left': 0
 | 
			
		||||
					});
 | 
			
		||||
					this.messages.animate({ 'right': 0 });
 | 
			
		||||
					break;
 | 
			
		||||
				default:
 | 
			
		||||
					this.messages.css({
 | 
			
		||||
						'left': '50%',
 | 
			
		||||
						'right': 'auto',
 | 
			
		||||
						'margin-left': -(width / 2)
 | 
			
		||||
					});
 | 
			
		||||
					this.messages.animate({ 'top': top });
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// cancel autohide if delay is 0
 | 
			
		||||
			if(delay === 0) {
 | 
			
		||||
				close.show();
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
			// add delay to hide
 | 
			
		||||
			this.timer = setTimeout(function () {
 | 
			
		||||
				that.closeMessage();
 | 
			
		||||
			}, delay || this.options.messageDelay);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		closeMessage: function () {
 | 
			
		||||
			this.messages.fadeOut(300);
 | 
			
		||||
			// unlock toolbar
 | 
			
		||||
			this._lock(false);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		openAjax: function (url, post, text, callback, onSuccess) {
 | 
			
		||||
			var that = this;
 | 
			
		||||
 | 
			
		||||
			// check if we have a confirmation text
 | 
			
		||||
			var question = (text) ? confirm(text) : true;
 | 
			
		||||
			// cancel if question has been denied
 | 
			
		||||
			if(!question) return false;
 | 
			
		||||
 | 
			
		||||
			// set loader
 | 
			
		||||
			this._loader(true);
 | 
			
		||||
 | 
			
		||||
			$.ajax({
 | 
			
		||||
				'type': 'POST',
 | 
			
		||||
				'url': url,
 | 
			
		||||
				'data': (post) ? JSON.parse(post) : {},
 | 
			
		||||
				'success': function (response) {
 | 
			
		||||
					CMS.API.locked = false;
 | 
			
		||||
 | 
			
		||||
					if(callback) {
 | 
			
		||||
						callback(that, response);
 | 
			
		||||
						that._loader(false);
 | 
			
		||||
					} else if(onSuccess) {
 | 
			
		||||
						CMS.API.Helpers.reloadBrowser(onSuccess, false, true);
 | 
			
		||||
					} else {
 | 
			
		||||
						// reload
 | 
			
		||||
						CMS.API.Helpers.reloadBrowser(false, false, true);
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				'error': function (jqXHR) {
 | 
			
		||||
					CMS.API.locked = false;
 | 
			
		||||
					that.showError(jqXHR.response + ' | ' + jqXHR.status + ' ' + jqXHR.statusText);
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		showError: function (msg, reload) {
 | 
			
		||||
			this.openMessage(msg, 'center', 0, true);
 | 
			
		||||
			// force reload if param is passed
 | 
			
		||||
			if(reload) CMS.API.Helpers.reloadBrowser(false, this.options.messageDelay);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// private methods
 | 
			
		||||
		_showToolbar: function (speed, init) {
 | 
			
		||||
			this.toolbarTrigger.addClass('cms_toolbar-trigger-expanded');
 | 
			
		||||
			this.toolbar.slideDown(speed);
 | 
			
		||||
			// animate html
 | 
			
		||||
			this.body.animate({ 'margin-top': (this.config.debug) ? 35 : 30 }, (init) ? 0 : speed, function () {
 | 
			
		||||
			    $(this).addClass('cms-toolbar-expanded')
 | 
			
		||||
			});
 | 
			
		||||
			// set messages top to toolbar height
 | 
			
		||||
			this.messages.css('top', 31);
 | 
			
		||||
			// set new settings
 | 
			
		||||
			this.settings.toolbar = 'expanded';
 | 
			
		||||
			if(!init) this.settings = this.setSettings(this.settings);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_hideToolbar: function (speed, init) {
 | 
			
		||||
			// cancel if sideframe is active
 | 
			
		||||
			if(this.lockToolbar) return false;
 | 
			
		||||
 | 
			
		||||
			this.toolbarTrigger.removeClass('cms_toolbar-trigger-expanded');
 | 
			
		||||
			this.toolbar.slideUp(speed);
 | 
			
		||||
			// animate html
 | 
			
		||||
			this.body.removeClass('cms-toolbar-expanded').animate({ 'margin-top': (this.config.debug) ? 5 : 0 }, speed);
 | 
			
		||||
			// set messages top to 0
 | 
			
		||||
			this.messages.css('top', 0);
 | 
			
		||||
			// set new settings
 | 
			
		||||
			this.settings.toolbar = 'collapsed';
 | 
			
		||||
			if(!init) this.settings = this.setSettings(this.settings);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_setSwitcher: function (el) {
 | 
			
		||||
			// save local vars
 | 
			
		||||
			var active = el.hasClass('cms_toolbar-item_switch-active');
 | 
			
		||||
			var anchor = el.find('a');
 | 
			
		||||
			var knob = el.find('.cms_toolbar-item_switch-knob');
 | 
			
		||||
			var duration = 300;
 | 
			
		||||
 | 
			
		||||
			// prevent if switchopstion is passed
 | 
			
		||||
			if(this.options.preventSwitch) {
 | 
			
		||||
				this.openMessage(this.options.preventSwitchMessage, 'right');
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// determin what to trigger
 | 
			
		||||
			if(active) {
 | 
			
		||||
				knob.animate({
 | 
			
		||||
					'right': anchor.outerWidth(true) - (knob.outerWidth(true) + 2)
 | 
			
		||||
				}, duration);
 | 
			
		||||
				// move anchor behind the knob
 | 
			
		||||
				anchor.css('z-index', 1).animate({
 | 
			
		||||
					'padding-top': 6,
 | 
			
		||||
					'padding-right': 14,
 | 
			
		||||
					'padding-bottom': 4,
 | 
			
		||||
					'padding-left': 28
 | 
			
		||||
				}, duration);
 | 
			
		||||
			} else {
 | 
			
		||||
				knob.animate({
 | 
			
		||||
					'left': anchor.outerWidth(true) - (knob.outerWidth(true) + 2)
 | 
			
		||||
				}, duration);
 | 
			
		||||
				// move anchor behind the knob
 | 
			
		||||
				anchor.css('z-index', 1).animate({
 | 
			
		||||
					'padding-top': 6,
 | 
			
		||||
					'padding-right': 28,
 | 
			
		||||
					'padding-bottom': 4,
 | 
			
		||||
					'padding-left': 14
 | 
			
		||||
				}, duration);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// reload
 | 
			
		||||
			setTimeout(function () {
 | 
			
		||||
				window.location.href = anchor.attr('href');
 | 
			
		||||
			}, duration);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_delegate: function (el) {
 | 
			
		||||
			// save local vars
 | 
			
		||||
			var target = el.data('rel');
 | 
			
		||||
 | 
			
		||||
			switch(target) {
 | 
			
		||||
				case 'modal':
 | 
			
		||||
					var modal = new CMS.Modal({'onClose': el.data('on-close')});
 | 
			
		||||
						modal.open(el.attr('href'), el.data('name'));
 | 
			
		||||
					break;
 | 
			
		||||
				case 'message':
 | 
			
		||||
					this.openMessage(el.data('text'));
 | 
			
		||||
					break;
 | 
			
		||||
				case 'sideframe':
 | 
			
		||||
					var sideframe = new CMS.Sideframe({'onClose': el.data('on-close')});
 | 
			
		||||
						sideframe.open(el.attr('href'), true);
 | 
			
		||||
					break;
 | 
			
		||||
				case 'ajax':
 | 
			
		||||
					this.openAjax(el.attr('href'), JSON.stringify(el.data('post')), el.data('text'), null, el.data('on-success'));
 | 
			
		||||
					break;
 | 
			
		||||
				default:
 | 
			
		||||
					window.location.href = el.attr('href');
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_lock: function (lock) {
 | 
			
		||||
			if(lock) {
 | 
			
		||||
				this.lockToolbar = true;
 | 
			
		||||
				// make button look disabled
 | 
			
		||||
				this.toolbarTrigger.css('opacity', 0.2);
 | 
			
		||||
			} else {
 | 
			
		||||
				this.lockToolbar = false;
 | 
			
		||||
				// make button look disabled
 | 
			
		||||
				this.toolbarTrigger.css('opacity', 1);
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_loader: function (loader) {
 | 
			
		||||
			if(loader) {
 | 
			
		||||
				this.toolbarTrigger.addClass('cms_toolbar-loader');
 | 
			
		||||
			} else {
 | 
			
		||||
				this.toolbarTrigger.removeClass('cms_toolbar-loader');
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_debug: function () {
 | 
			
		||||
			var that = this;
 | 
			
		||||
			var timeout = 1000;
 | 
			
		||||
			var timer = function () {};
 | 
			
		||||
 | 
			
		||||
			// bind message event
 | 
			
		||||
			var debug = this.container.find('.cms_debug-bar');
 | 
			
		||||
				debug.bind('mouseenter mouseleave', function (e) {
 | 
			
		||||
					clearTimeout(timer);
 | 
			
		||||
 | 
			
		||||
					if(e.type === 'mouseenter') {
 | 
			
		||||
						timer = setTimeout(function () {
 | 
			
		||||
							that.openMessage(that.config.lang.debug);
 | 
			
		||||
						}, timeout);
 | 
			
		||||
					}
 | 
			
		||||
				});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_screenBlock: function () {
 | 
			
		||||
			var interval = 20;
 | 
			
		||||
			var blocker = this.screenBlock;
 | 
			
		||||
			var sideframe = $('.cms_sideframe');
 | 
			
		||||
 | 
			
		||||
			// automatically resize screenblock window according to given attributes
 | 
			
		||||
			$(window).on('resize.cms.screenblock', function () {
 | 
			
		||||
				var width = $(this).width() - sideframe.width();
 | 
			
		||||
 | 
			
		||||
				blocker.css({
 | 
			
		||||
					'width': width,
 | 
			
		||||
					'height': $(window).height()
 | 
			
		||||
				});
 | 
			
		||||
			}).trigger('resize');
 | 
			
		||||
 | 
			
		||||
			// set update interval
 | 
			
		||||
			setInterval(function () {
 | 
			
		||||
				$(window).trigger('resize.cms.screenblock');
 | 
			
		||||
			}, interval);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
})(CMS.$);
 | 
			
		||||
							
								
								
									
										14
									
								
								static/cms/js/modules/jquery.ui.custom.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								static/cms/js/modules/jquery.ui.custom.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										613
									
								
								static/cms/js/modules/jquery.ui.nestedsortable.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										613
									
								
								static/cms/js/modules/jquery.ui.nestedsortable.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,613 @@
 | 
			
		|||
/*
 | 
			
		||||
 * jQuery UI Nested Sortable
 | 
			
		||||
 * v 2.0 / 29 oct 2012
 | 
			
		||||
 * http://mjsarfatti.com/sandbox/nestedSortable
 | 
			
		||||
 *
 | 
			
		||||
 * Depends on:
 | 
			
		||||
 *	 jquery.ui.sortable.js 1.10+
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2010-2013 Manuele J Sarfatti
 | 
			
		||||
 * Licensed under the MIT License
 | 
			
		||||
 * http://www.opensource.org/licenses/mit-license.php
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function($) {
 | 
			
		||||
 | 
			
		||||
	function isOverAxis( x, reference, size ) {
 | 
			
		||||
		return ( x > reference ) && ( x < ( reference + size ) );
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	$.widget("mjs.nestedSortable", $.extend({}, $.ui.sortable.prototype, {
 | 
			
		||||
 | 
			
		||||
		options: {
 | 
			
		||||
			doNotClear: false,
 | 
			
		||||
			expandOnHover: 700,
 | 
			
		||||
			isAllowed: function(placeholder, placeholderParent, originalItem) { return true; },
 | 
			
		||||
			isTree: false,
 | 
			
		||||
			listType: 'ol',
 | 
			
		||||
			maxLevels: 0,
 | 
			
		||||
			protectRoot: false,
 | 
			
		||||
			rootID: null,
 | 
			
		||||
			rtl: false,
 | 
			
		||||
			startCollapsed: false,
 | 
			
		||||
			tabSize: 20,
 | 
			
		||||
 | 
			
		||||
			branchClass: 'mjs-nestedSortable-branch',
 | 
			
		||||
			collapsedClass: 'mjs-nestedSortable-collapsed',
 | 
			
		||||
			disableNestingClass: 'mjs-nestedSortable-no-nesting',
 | 
			
		||||
			errorClass: 'mjs-nestedSortable-error',
 | 
			
		||||
			expandedClass: 'mjs-nestedSortable-expanded',
 | 
			
		||||
			hoveringClass: 'mjs-nestedSortable-hovering',
 | 
			
		||||
			leafClass: 'mjs-nestedSortable-leaf'
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_create: function() {
 | 
			
		||||
			this.element.data('ui-sortable', this.element.data('mjs-nestedSortable'));
 | 
			
		||||
 | 
			
		||||
			// mjs - prevent browser from freezing if the HTML is not correct
 | 
			
		||||
			if (!this.element.is(this.options.listType))
 | 
			
		||||
				throw new Error('nestedSortable: Please check that the listType option is set to your actual list type');
 | 
			
		||||
 | 
			
		||||
			// mjs - force 'intersect' tolerance method if we have a tree with expanding/collapsing functionality
 | 
			
		||||
			if (this.options.isTree && this.options.expandOnHover) {
 | 
			
		||||
				this.options.tolerance = 'intersect';
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			$.ui.sortable.prototype._create.apply(this, arguments);
 | 
			
		||||
 | 
			
		||||
			// mjs - prepare the tree by applying the right classes (the CSS is responsible for actual hide/show functionality)
 | 
			
		||||
			if (this.options.isTree) {
 | 
			
		||||
				var self = this;
 | 
			
		||||
				$(this.items).each(function() {
 | 
			
		||||
					var $li = this.item;
 | 
			
		||||
					if ($li.children(self.options.listType).length) {
 | 
			
		||||
						$li.addClass(self.options.branchClass);
 | 
			
		||||
						// expand/collapse class only if they have children
 | 
			
		||||
						if (self.options.startCollapsed) $li.addClass(self.options.collapsedClass);
 | 
			
		||||
						else $li.addClass(self.options.expandedClass);
 | 
			
		||||
					} else {
 | 
			
		||||
						$li.addClass(self.options.leafClass);
 | 
			
		||||
					}
 | 
			
		||||
				})
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_destroy: function() {
 | 
			
		||||
			this.element
 | 
			
		||||
				.removeData("mjs-nestedSortable")
 | 
			
		||||
				.removeData("ui-sortable");
 | 
			
		||||
			return $.ui.sortable.prototype._destroy.apply(this, arguments);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_mouseDrag: function(event) {
 | 
			
		||||
			var i, item, itemElement, intersection,
 | 
			
		||||
				o = this.options,
 | 
			
		||||
				scrolled = false;
 | 
			
		||||
 | 
			
		||||
			//Compute the helpers position
 | 
			
		||||
			this.position = this._generatePosition(event);
 | 
			
		||||
			this.positionAbs = this._convertPositionTo("absolute");
 | 
			
		||||
 | 
			
		||||
			if (!this.lastPositionAbs) {
 | 
			
		||||
				this.lastPositionAbs = this.positionAbs;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			//Do scrolling
 | 
			
		||||
			if(this.options.scroll) {
 | 
			
		||||
				if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {
 | 
			
		||||
 | 
			
		||||
					if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
 | 
			
		||||
						this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
 | 
			
		||||
					} else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
 | 
			
		||||
						this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
 | 
			
		||||
						this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
 | 
			
		||||
					} else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
 | 
			
		||||
						this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
				} else {
 | 
			
		||||
 | 
			
		||||
					if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
 | 
			
		||||
						scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
 | 
			
		||||
					} else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
 | 
			
		||||
						scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
 | 
			
		||||
						scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
 | 
			
		||||
					} else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
 | 
			
		||||
						scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
 | 
			
		||||
					$.ui.ddmanager.prepareOffsets(this, event);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			//Regenerate the absolute position used for position checks
 | 
			
		||||
			this.positionAbs = this._convertPositionTo("absolute");
 | 
			
		||||
 | 
			
		||||
			// mjs - find the top offset before rearrangement,
 | 
			
		||||
			var previousTopOffset = this.placeholder.offset().top;
 | 
			
		||||
 | 
			
		||||
			//Set the helper position
 | 
			
		||||
			if(!this.options.axis || this.options.axis !== "y") {
 | 
			
		||||
				this.helper[0].style.left = this.position.left+"px";
 | 
			
		||||
			}
 | 
			
		||||
			if(!this.options.axis || this.options.axis !== "x") {
 | 
			
		||||
				this.helper[0].style.top = this.position.top+"px";
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// mjs - check and reset hovering state at each cycle
 | 
			
		||||
			this.hovering = this.hovering ? this.hovering : null;
 | 
			
		||||
			this.mouseentered = this.mouseentered ? this.mouseentered : false;
 | 
			
		||||
 | 
			
		||||
			// mjs - let's start caching some variables
 | 
			
		||||
			var parentItem = (this.placeholder[0].parentNode.parentNode &&
 | 
			
		||||
							 $(this.placeholder[0].parentNode.parentNode).closest('.ui-sortable').length)
 | 
			
		||||
				       			? $(this.placeholder[0].parentNode.parentNode)
 | 
			
		||||
				       			: null,
 | 
			
		||||
			    level = this._getLevel(this.placeholder),
 | 
			
		||||
			    childLevels = this._getChildLevels(this.helper);
 | 
			
		||||
 | 
			
		||||
			var newList = document.createElement(o.listType);
 | 
			
		||||
 | 
			
		||||
			//Rearrange
 | 
			
		||||
			for (i = this.items.length - 1; i >= 0; i--) {
 | 
			
		||||
 | 
			
		||||
				//Cache variables and intersection, continue if no intersection
 | 
			
		||||
				item = this.items[i];
 | 
			
		||||
				itemElement = item.item[0];
 | 
			
		||||
				intersection = this._intersectsWithPointer(item);
 | 
			
		||||
				if (!intersection) {
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Only put the placeholder inside the current Container, skip all
 | 
			
		||||
				// items form other containers. This works because when moving
 | 
			
		||||
				// an item from one container to another the
 | 
			
		||||
				// currentContainer is switched before the placeholder is moved.
 | 
			
		||||
				//
 | 
			
		||||
				// Without this moving items in "sub-sortables" can cause the placeholder to jitter
 | 
			
		||||
				// beetween the outer and inner container.
 | 
			
		||||
				if (item.instance !== this.currentContainer) {
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// cannot intersect with itself
 | 
			
		||||
				// no useless actions that have been done before
 | 
			
		||||
				// no action if the item moved is the parent of the item checked
 | 
			
		||||
				if (itemElement !== this.currentItem[0] &&
 | 
			
		||||
					this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
 | 
			
		||||
					!$.contains(this.placeholder[0], itemElement) &&
 | 
			
		||||
					(this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
 | 
			
		||||
				) {
 | 
			
		||||
 | 
			
		||||
					// mjs - we are intersecting an element: trigger the mouseenter event and store this state
 | 
			
		||||
					if (!this.mouseentered) {
 | 
			
		||||
						$(itemElement).mouseenter();
 | 
			
		||||
						this.mouseentered = true;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					// mjs - if the element has children and they are hidden, show them after a delay (CSS responsible)
 | 
			
		||||
					if (o.isTree && $(itemElement).hasClass(o.collapsedClass) && o.expandOnHover) {
 | 
			
		||||
						if (!this.hovering) {
 | 
			
		||||
							$(itemElement).addClass(o.hoveringClass);
 | 
			
		||||
							var self = this;
 | 
			
		||||
							this.hovering = window.setTimeout(function() {
 | 
			
		||||
								$(itemElement).removeClass(o.collapsedClass).addClass(o.expandedClass);
 | 
			
		||||
								self.refreshPositions();
 | 
			
		||||
								self._trigger("expand", event, self._uiHash());
 | 
			
		||||
							}, o.expandOnHover);
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					this.direction = intersection == 1 ? "down" : "up";
 | 
			
		||||
 | 
			
		||||
					// mjs - rearrange the elements and reset timeouts and hovering state
 | 
			
		||||
					if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
 | 
			
		||||
						$(itemElement).mouseleave();
 | 
			
		||||
						this.mouseentered = false;
 | 
			
		||||
						$(itemElement).removeClass(o.hoveringClass);
 | 
			
		||||
						this.hovering && window.clearTimeout(this.hovering);
 | 
			
		||||
						this.hovering = null;
 | 
			
		||||
 | 
			
		||||
						// mjs - do not switch container if it's a root item and 'protectRoot' is true
 | 
			
		||||
						// or if it's not a root item but we are trying to make it root
 | 
			
		||||
						if (o.protectRoot
 | 
			
		||||
							&& ! (this.currentItem[0].parentNode == this.element[0] // it's a root item
 | 
			
		||||
								  && itemElement.parentNode != this.element[0]) // it's intersecting a non-root item
 | 
			
		||||
						) {
 | 
			
		||||
							if (this.currentItem[0].parentNode != this.element[0]
 | 
			
		||||
							   	&& itemElement.parentNode == this.element[0]
 | 
			
		||||
							) {
 | 
			
		||||
 | 
			
		||||
								if ( ! $(itemElement).children(o.listType).length) {
 | 
			
		||||
									itemElement.appendChild(newList);
 | 
			
		||||
									o.isTree && $(itemElement).removeClass(o.leafClass).addClass(o.branchClass + ' ' + o.expandedClass);
 | 
			
		||||
								}
 | 
			
		||||
 | 
			
		||||
								var a = this.direction === "down" ? $(itemElement).prev().children(o.listType) : $(itemElement).children(o.listType);
 | 
			
		||||
								if (a[0] !== undefined) {
 | 
			
		||||
									this._rearrange(event, null, a);
 | 
			
		||||
								}
 | 
			
		||||
 | 
			
		||||
							} else {
 | 
			
		||||
								this._rearrange(event, item);
 | 
			
		||||
							}
 | 
			
		||||
						} else if ( ! o.protectRoot) {
 | 
			
		||||
							this._rearrange(event, item);
 | 
			
		||||
						}
 | 
			
		||||
					} else {
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					// Clear emtpy ul's/ol's
 | 
			
		||||
					this._clearEmpty(itemElement);
 | 
			
		||||
 | 
			
		||||
					this._trigger("change", event, this._uiHash());
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// mjs - to find the previous sibling in the list, keep backtracking until we hit a valid list item.
 | 
			
		||||
			var previousItem = this.placeholder[0].previousSibling ? $(this.placeholder[0].previousSibling) : null;
 | 
			
		||||
			if (previousItem != null) {
 | 
			
		||||
				while (previousItem[0].nodeName.toLowerCase() != $(o.listType)[0].nodeName.toLowerCase() || previousItem[0] == this.currentItem[0] || previousItem[0] == this.helper[0]) {
 | 
			
		||||
					if (previousItem[0].previousSibling) {
 | 
			
		||||
						previousItem = $(previousItem[0].previousSibling);
 | 
			
		||||
					} else {
 | 
			
		||||
						previousItem = null;
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// mjs - to find the next sibling in the list, keep stepping forward until we hit a valid list item.
 | 
			
		||||
			var nextItem = this.placeholder[0].nextSibling ? $(this.placeholder[0].nextSibling) : null;
 | 
			
		||||
			if (nextItem != null) {
 | 
			
		||||
				while (nextItem[0].nodeName.toLowerCase() != $(o.listType)[0].nodeName.toLowerCase() || nextItem[0] == this.currentItem[0] || nextItem[0] == this.helper[0]) {
 | 
			
		||||
					if (nextItem[0].nextSibling) {
 | 
			
		||||
						nextItem = $(nextItem[0].nextSibling);
 | 
			
		||||
					} else {
 | 
			
		||||
						nextItem = null;
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			this.beyondMaxLevels = 0;
 | 
			
		||||
 | 
			
		||||
			// mjs - if the item is moved to the left, send it one level up but only if it's at the bottom of the list
 | 
			
		||||
			if (parentItem != null
 | 
			
		||||
				&& nextItem == null
 | 
			
		||||
				&& ! (o.protectRoot && parentItem[0].parentNode == this.element[0])
 | 
			
		||||
				&&
 | 
			
		||||
					(o.rtl && (this.positionAbs.left + this.helper.outerWidth() > parentItem.offset().left + parentItem.outerWidth())
 | 
			
		||||
					 || ! o.rtl && (this.positionAbs.left < parentItem.offset().left))
 | 
			
		||||
			) {
 | 
			
		||||
 | 
			
		||||
				parentItem.after(this.placeholder[0]);
 | 
			
		||||
				if (o.isTree && parentItem.children(o.listItem).children(o.listItem + ':visible:not(.ui-sortable-helper)').length < 1) {
 | 
			
		||||
					parentItem.removeClass(this.options.branchClass + ' ' + this.options.expandedClass)
 | 
			
		||||
							  .addClass(this.options.leafClass);
 | 
			
		||||
				}
 | 
			
		||||
				this._clearEmpty(parentItem[0]);
 | 
			
		||||
				this._trigger("change", event, this._uiHash());
 | 
			
		||||
			}
 | 
			
		||||
			// mjs - if the item is below a sibling and is moved to the right, make it a child of that sibling
 | 
			
		||||
			else if (previousItem != null
 | 
			
		||||
					 && ! previousItem.hasClass(o.disableNestingClass)
 | 
			
		||||
					 &&
 | 
			
		||||
						(previousItem.children(o.listType).length && previousItem.children(o.listType).is(':visible')
 | 
			
		||||
						 || ! previousItem.children(o.listType).length)
 | 
			
		||||
					 && ! (o.protectRoot && this.currentItem[0].parentNode == this.element[0])
 | 
			
		||||
					 &&
 | 
			
		||||
						(o.rtl && (this.positionAbs.left + this.helper.outerWidth() < previousItem.offset().left + previousItem.outerWidth() - o.tabSize)
 | 
			
		||||
						 || ! o.rtl && (this.positionAbs.left > previousItem.offset().left + o.tabSize))
 | 
			
		||||
			) {
 | 
			
		||||
 | 
			
		||||
				this._isAllowed(previousItem, level, level+childLevels+1);
 | 
			
		||||
 | 
			
		||||
				if (!previousItem.children(o.listType).length) {
 | 
			
		||||
					previousItem[0].appendChild(newList);
 | 
			
		||||
					o.isTree && previousItem.removeClass(o.leafClass).addClass(o.branchClass + ' ' + o.expandedClass);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
		        // mjs - if this item is being moved from the top, add it to the top of the list.
 | 
			
		||||
		        if (previousTopOffset && (previousTopOffset <= previousItem.offset().top)) {
 | 
			
		||||
		        	previousItem.children(o.listType).prepend(this.placeholder);
 | 
			
		||||
		        }
 | 
			
		||||
		        // mjs - otherwise, add it to the bottom of the list.
 | 
			
		||||
		        else if(previousItem.children(o.listType).length) {
 | 
			
		||||
					previousItem.children(o.listType)[0].appendChild(this.placeholder[0]);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				this._trigger("change", event, this._uiHash());
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				this._isAllowed(parentItem, level, level+childLevels);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			//Post events to containers
 | 
			
		||||
			this._contactContainers(event);
 | 
			
		||||
 | 
			
		||||
			//Interconnect with droppables
 | 
			
		||||
			if($.ui.ddmanager) {
 | 
			
		||||
				$.ui.ddmanager.drag(this, event);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			//Call callbacks
 | 
			
		||||
			this._trigger('sort', event, this._uiHash());
 | 
			
		||||
 | 
			
		||||
			this.lastPositionAbs = this.positionAbs;
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_mouseStop: function(event, noPropagation) {
 | 
			
		||||
 | 
			
		||||
			// mjs - if the item is in a position not allowed, send it back
 | 
			
		||||
			if (this.beyondMaxLevels) {
 | 
			
		||||
 | 
			
		||||
				this.placeholder.removeClass(this.options.errorClass);
 | 
			
		||||
 | 
			
		||||
				if (this.domPosition.prev) {
 | 
			
		||||
					$(this.domPosition.prev).after(this.placeholder);
 | 
			
		||||
				} else {
 | 
			
		||||
					$(this.domPosition.parent).prepend(this.placeholder);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				this._trigger("revert", event, this._uiHash());
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
			// mjs - clear the hovering timeout, just to be sure
 | 
			
		||||
			$('.'+this.options.hoveringClass).mouseleave().removeClass(this.options.hoveringClass);
 | 
			
		||||
			this.mouseentered = false;
 | 
			
		||||
			this.hovering && window.clearTimeout(this.hovering);
 | 
			
		||||
			this.hovering = null;
 | 
			
		||||
 | 
			
		||||
			$.ui.sortable.prototype._mouseStop.apply(this, arguments);
 | 
			
		||||
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// mjs - this function is slightly modified to make it easier to hover over a collapsed element and have it expand
 | 
			
		||||
		_intersectsWithSides: function(item) {
 | 
			
		||||
 | 
			
		||||
			var half = this.options.isTree ? .8 : .5;
 | 
			
		||||
 | 
			
		||||
			var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height*half), item.height),
 | 
			
		||||
				isOverTopHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top - (item.height*half), item.height),
 | 
			
		||||
				isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
 | 
			
		||||
				verticalDirection = this._getDragVerticalDirection(),
 | 
			
		||||
				horizontalDirection = this._getDragHorizontalDirection();
 | 
			
		||||
 | 
			
		||||
			if (this.floating && horizontalDirection) {
 | 
			
		||||
				return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf));
 | 
			
		||||
			} else {
 | 
			
		||||
				return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && isOverTopHalf));
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_contactContainers: function(event) {
 | 
			
		||||
 | 
			
		||||
			if (this.options.protectRoot && this.currentItem[0].parentNode == this.element[0] ) {
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			$.ui.sortable.prototype._contactContainers.apply(this, arguments);
 | 
			
		||||
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_clear: function(event, noPropagation) {
 | 
			
		||||
 | 
			
		||||
			$.ui.sortable.prototype._clear.apply(this, arguments);
 | 
			
		||||
 | 
			
		||||
			// mjs - clean last empty ul/ol
 | 
			
		||||
			for (var i = this.items.length - 1; i >= 0; i--) {
 | 
			
		||||
				var item = this.items[i].item[0];
 | 
			
		||||
				this._clearEmpty(item);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		serialize: function(options) {
 | 
			
		||||
 | 
			
		||||
			var o = $.extend({}, this.options, options),
 | 
			
		||||
				items = this._getItemsAsjQuery(o && o.connected),
 | 
			
		||||
			    str = [];
 | 
			
		||||
 | 
			
		||||
			$(items).each(function() {
 | 
			
		||||
				var res = ($(o.item || this).attr(o.attribute || 'id') || '')
 | 
			
		||||
						.match(o.expression || (/(.+)[-=_](.+)/)),
 | 
			
		||||
				    pid = ($(o.item || this).parent(o.listType)
 | 
			
		||||
						.parent(o.items)
 | 
			
		||||
						.attr(o.attribute || 'id') || '')
 | 
			
		||||
						.match(o.expression || (/(.+)[-=_](.+)/));
 | 
			
		||||
 | 
			
		||||
				if (res) {
 | 
			
		||||
					str.push(((o.key || res[1]) + '[' + (o.key && o.expression ? res[1] : res[2]) + ']')
 | 
			
		||||
						+ '='
 | 
			
		||||
						+ (pid ? (o.key && o.expression ? pid[1] : pid[2]) : o.rootID));
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			if(!str.length && o.key) {
 | 
			
		||||
				str.push(o.key + '=');
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return str.join('&');
 | 
			
		||||
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		toHierarchy: function(options) {
 | 
			
		||||
 | 
			
		||||
			var o = $.extend({}, this.options, options),
 | 
			
		||||
				sDepth = o.startDepthCount || 0,
 | 
			
		||||
			    ret = [];
 | 
			
		||||
 | 
			
		||||
			$(this.element).children(o.items).each(function () {
 | 
			
		||||
				var level = _recursiveItems(this);
 | 
			
		||||
				ret.push(level);
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			return ret;
 | 
			
		||||
 | 
			
		||||
			function _recursiveItems(item) {
 | 
			
		||||
				var id = ($(item).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
 | 
			
		||||
				if (id) {
 | 
			
		||||
					var currentItem = {"id" : id[2]};
 | 
			
		||||
					if ($(item).children(o.listType).children(o.items).length > 0) {
 | 
			
		||||
						currentItem.children = [];
 | 
			
		||||
						$(item).children(o.listType).children(o.items).each(function() {
 | 
			
		||||
							var level = _recursiveItems(this);
 | 
			
		||||
							currentItem.children.push(level);
 | 
			
		||||
						});
 | 
			
		||||
					}
 | 
			
		||||
					return currentItem;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		toArray: function(options) {
 | 
			
		||||
 | 
			
		||||
			var o = $.extend({}, this.options, options),
 | 
			
		||||
				sDepth = o.startDepthCount || 0,
 | 
			
		||||
			    ret = [],
 | 
			
		||||
			    left = 1;
 | 
			
		||||
 | 
			
		||||
			if (!o.excludeRoot) {
 | 
			
		||||
				ret.push({
 | 
			
		||||
					"item_id": o.rootID,
 | 
			
		||||
					"parent_id": null,
 | 
			
		||||
					"depth": sDepth,
 | 
			
		||||
					"left": left,
 | 
			
		||||
					"right": ($(o.items, this.element).length + 1) * 2
 | 
			
		||||
				});
 | 
			
		||||
				left++
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			$(this.element).children(o.items).each(function () {
 | 
			
		||||
				left = _recursiveArray(this, sDepth + 1, left);
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			ret = ret.sort(function(a,b){ return (a.left - b.left); });
 | 
			
		||||
 | 
			
		||||
			return ret;
 | 
			
		||||
 | 
			
		||||
			function _recursiveArray(item, depth, left) {
 | 
			
		||||
 | 
			
		||||
				var right = left + 1,
 | 
			
		||||
				    id,
 | 
			
		||||
				    pid;
 | 
			
		||||
 | 
			
		||||
				if ($(item).children(o.listType).children(o.items).length > 0) {
 | 
			
		||||
					depth ++;
 | 
			
		||||
					$(item).children(o.listType).children(o.items).each(function () {
 | 
			
		||||
						right = _recursiveArray($(this), depth, right);
 | 
			
		||||
					});
 | 
			
		||||
					depth --;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				id = ($(item).attr(o.attribute || 'id')).match(o.expression || (/(.+)[-=_](.+)/));
 | 
			
		||||
 | 
			
		||||
				if (depth === sDepth + 1) {
 | 
			
		||||
					pid = o.rootID;
 | 
			
		||||
				} else {
 | 
			
		||||
					var parentItem = ($(item).parent(o.listType)
 | 
			
		||||
											 .parent(o.items)
 | 
			
		||||
											 .attr(o.attribute || 'id'))
 | 
			
		||||
											 .match(o.expression || (/(.+)[-=_](.+)/));
 | 
			
		||||
					pid = parentItem[2];
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (id) {
 | 
			
		||||
						ret.push({"item_id": id[2], "parent_id": pid, "depth": depth, "left": left, "right": right});
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				left = right + 1;
 | 
			
		||||
				return left;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_clearEmpty: function(item) {
 | 
			
		||||
			var o = this.options;
 | 
			
		||||
 | 
			
		||||
			var emptyList = $(item).children(o.listType);
 | 
			
		||||
 | 
			
		||||
			if (emptyList.length && !emptyList.children().length && !o.doNotClear) {
 | 
			
		||||
				o.isTree && $(item).removeClass(o.branchClass + ' ' + o.expandedClass).addClass(o.leafClass);
 | 
			
		||||
				emptyList.remove();
 | 
			
		||||
			} else if (o.isTree && emptyList.length && emptyList.children().length && emptyList.is(':visible')) {
 | 
			
		||||
				$(item).removeClass(o.leafClass).addClass(o.branchClass + ' ' + o.expandedClass);
 | 
			
		||||
			} else if (o.isTree && emptyList.length && emptyList.children().length && !emptyList.is(':visible')) {
 | 
			
		||||
				$(item).removeClass(o.leafClass).addClass(o.branchClass + ' ' + o.collapsedClass);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_getLevel: function(item) {
 | 
			
		||||
 | 
			
		||||
			var level = 1;
 | 
			
		||||
 | 
			
		||||
			if (this.options.listType) {
 | 
			
		||||
				var list = item.closest(this.options.listType);
 | 
			
		||||
				while (list && list.length > 0 &&
 | 
			
		||||
                    	!list.is('.ui-sortable')) {
 | 
			
		||||
					level++;
 | 
			
		||||
					list = list.parent().closest(this.options.listType);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return level;
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_getChildLevels: function(parent, depth) {
 | 
			
		||||
			var self = this,
 | 
			
		||||
			    o = this.options,
 | 
			
		||||
			    result = 0;
 | 
			
		||||
			depth = depth || 0;
 | 
			
		||||
 | 
			
		||||
			$(parent).children(o.listType).children(o.items).each(function (index, child) {
 | 
			
		||||
					result = Math.max(self._getChildLevels(child, depth + 1), result);
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			return depth ? result + 1 : result;
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_isAllowed: function(parentItem, level, levels) {
 | 
			
		||||
			var o = this.options,
 | 
			
		||||
				maxLevels = this.placeholder.closest('.ui-sortable').nestedSortable('option', 'maxLevels'); // this takes into account the maxLevels set to the recipient list
 | 
			
		||||
 | 
			
		||||
			// mjs - is the root protected?
 | 
			
		||||
			// mjs - are we nesting too deep?
 | 
			
		||||
			if ( ! o.isAllowed(this.placeholder, parentItem, this.currentItem)) {
 | 
			
		||||
					this.placeholder.addClass(o.errorClass);
 | 
			
		||||
					if (maxLevels < levels && maxLevels != 0) {
 | 
			
		||||
						this.beyondMaxLevels = levels - maxLevels;
 | 
			
		||||
					} else {
 | 
			
		||||
						this.beyondMaxLevels = 1;
 | 
			
		||||
					}
 | 
			
		||||
			} else {
 | 
			
		||||
				if (maxLevels < levels && maxLevels != 0) {
 | 
			
		||||
					this.placeholder.addClass(o.errorClass);
 | 
			
		||||
					this.beyondMaxLevels = levels - maxLevels;
 | 
			
		||||
				} else {
 | 
			
		||||
					this.placeholder.removeClass(o.errorClass);
 | 
			
		||||
					this.beyondMaxLevels = 0;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}));
 | 
			
		||||
 | 
			
		||||
	$.mjs.nestedSortable.prototype.options = $.extend({}, $.ui.sortable.prototype.options, $.mjs.nestedSortable.prototype.options);
 | 
			
		||||
})(jQuery);
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue