app/assets/javascripts/cms/sitemap.js
//= require 'jquery'
//= require 'jquery.ui.all'
//= require 'jquery.cookie'
//= require 'bootstrap'
//= require 'cms/ajax'
//= require 'underscore'
//= require 'cms/new_content_button'
// Sitemap uses JQuery.Draggable/Droppable to handling moving elements, with custom code below.
// Open/Close are handled as code below.
var Sitemap = function() {
};
// Name of cookie that stores SectionNode ids that should be opened.
Sitemap.STATE = 'cms.sitemap.open_folders';
Sitemap.prototype.select = function(selectedRow) {
$('.nav-list-span').removeClass('active');
selectedRow.addClass('active');
newContentButton.updateButtons(selectedRow);
};
// Different Content types have different behaviors when double clicked.
Sitemap.prototype._doubleClick = function(event) {
var type = $(event.target).data('type');
switch(type) {
case 'section':
case 'link':
$('#properties-button')[0].click();
break;
default:
$('#edit-button')[0].click();
}
};
// @param [Number] node_id
// @param [Number] target_node_id
// @param [Number] position A 1 based position for order
Sitemap.prototype.moveTo = function(node_id, target_node_id, position) {
var path = "/cms/section_nodes/" + node_id + '/move_to_position'
$.cms_ajax.put({
url: path,
data: {
target_node_id: target_node_id,
position: position
},
success: function(result) {
//console.log(result);
}
});
};
// @param [Selector] Determines if a section is open.
Sitemap.prototype.isOpen = function(row) {
return row.find('.type-icon').hasClass('icon-folder-open');
};
// @param [Selector] link A selected link (<a>)
// @param [String] icon The full name of the icon (icon-folder-open)
Sitemap.prototype.changeIcon = function(row, icon) {
row.find('.type-icon').attr('class', 'type-icon').addClass(icon);
};
// @param [Number] id
Sitemap.prototype.saveAsOpened = function(id) {
$.cookieSet.add(Sitemap.STATE, id);
};
// @param [Number] id
Sitemap.prototype.saveAsClosed = function(id) {
$.cookieSet.remove(Sitemap.STATE, id);
};
// Reopen all sections that the user was last working with.
Sitemap.prototype.restoreOpenState = function() {
var section_node_ids = $.cookieSet.get(Sitemap.STATE);
_.each(section_node_ids, function(id) {
var row = $('.nav-list-span[data-id=' + id + ']');
sitemap.open(row, {animate: false});
});
};
// Determines if the selected row is a Folder or not.
Sitemap.prototype.isFolder = function(row) {
return row.data('type') == 'folder';
};
Sitemap.prototype.isClosable = function(row) {
return row.data('closable') == true;
};
// @param [Selector] link
// @param [Object] options
Sitemap.prototype.open = function(row, options) {
options = options || {}
_.defaults(options, {animate: true});
this.changeIcon(row, 'icon-folder-open');
var siblings = row.siblings('.children');
if (options.animate) {
siblings.slideToggle();
}
else {
siblings.show();
}
this.saveAsOpened(row.data('id'));
};
// Attempts to open the given row. Will skip if the item cannot or is already open.
Sitemap.prototype.attemptOpen = function(row, options) {
if (this.isClosable(row) && !this.isOpen(row)) {
this.open(row, options);
}
};
Sitemap.prototype.close = function(row) {
this.changeIcon(row, 'icon-folder');
row.siblings('.children').slideToggle();
this.saveAsClosed(row.data('id'));
};
Sitemap.prototype.toggleOpen = function(row) {
if (!this.isClosable(row)) {
return;
}
if (this.isOpen(row)) {
this.close(row);
} else {
this.open(row);
}
};
Sitemap.prototype.updateDepth = function(element, newDepth) {
var depthClass = "level-" + newDepth;
element.attr('class', 'ui-draggable ui-droppable nav-list-span').addClass(depthClass);
element.attr('data-depth', newDepth);
};
var sitemap = new Sitemap();
// Enable dragging of items around the sitemap.
jQuery(function($){
if ($('#sitemap').exists()) {
$('#sitemap .draggable').draggable({
containment: '#sitemap',
revert: true,
revertDuration: 0,
axis: 'y',
delay: 250,
cursor: 'move',
stack: '.nav-list-span'
});
$('#sitemap .nav-list-span').droppable({
hoverClass: "droppable",
drop: function(event, ui) {
var elementToMove = ui.draggable.parents('.nav-list').first();
var elementDroppedOn = $(this).parents('.nav-list').first();
var targetDepth = $(this).data('depth');
if (sitemap.isFolder($(this))) {
// Drop INTO sections
sitemap.attemptOpen($(this));
sitemap.updateDepth(ui.draggable, targetDepth + 1);
elementDroppedOn.find('li').first().append(elementToMove);
var newParentId = $(this).data('id');
} else {
sitemap.updateDepth(ui.draggable, targetDepth);
// Drop AFTER pages
var newParentId = elementDroppedOn.parents('.nav-list:first').find('.nav-list-span:first').data('id');
elementToMove.insertAfter(elementDroppedOn);
}
// Move item on server
var nodeIdToMove = ui.draggable.data('id');
var newPosition = elementToMove.index();
console.log("Move section_node", nodeIdToMove, " to parent:", newParentId, 'at position', newPosition);
sitemap.moveTo(nodeIdToMove, newParentId, newPosition);
// Need a manual delay otherwise the animation happens before the insert.
window.setTimeout(function() {
ui.draggable.effect({effect: 'highlight', duration: 500, color: '#0079c1'});
}, 250);
}
});
}
});
// Open/close folders when rows are clicked.
jQuery(function($){
// Ensure this only loads on sitemap page.
if ($('#sitemap').exists()) {
sitemap.restoreOpenState();
$('.nav-list-span').on('click', function(event) {
sitemap.toggleOpen($(this));
sitemap.select($(this));
});
}
});
// Make Sitemap filters show specific content types.
jQuery(function($){
$('#sitemap li[data-nodetype]').hide();
$('#filtershow').change(function() {
$('#sitemap li[data-nodetype]').slideUp();
var what = $(this).val();
if (what == "none") {
$('#sitemap li[data-nodetype]').slideUp();
} else if (what == "all") {
$('#sitemap li[data-nodetype]').slideDown();
$('#sitemap li[data-nodetype]').parents('li').children('a[data-toggle]').click();
} else {
$('#sitemap li[data-nodetype="' + what + '"]').slideDown();
$('#sitemap li[data-nodetype="' + what + '"]').parents('li').children('a[data-toggle]').click();
}
});
});