775 lines
		
	
	
	
		
			23 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			775 lines
		
	
	
	
		
			23 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | /*##################################################|*/ | ||
|  | /* #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.$); |