new static files.

Signed-off-by: rscnt <rascnt@gmail.com>
This commit is contained in:
rascencio 2015-06-08 23:26:27 -06:00
commit bb68c32ba5
772 changed files with 71557 additions and 0 deletions

View 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.$);

View 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.$);

View 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.$);

View 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+"&amp;position="+position+"&amp;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.$);

View 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.$);

View 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('&', '&amp;');
// 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 || '&nbsp;');
// 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.$);

View 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.$);

View 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.$);

View 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.$);

View 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.$);

File diff suppressed because one or more lines are too long

View 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);