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