| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- /* global django */
- // IE<9 lacks Array.prototype.indexOf
- if (!Array.prototype.indexOf) {
- Array.prototype.indexOf = function(needle) {
- for (var i=0, l=this.length; i<l; ++i) {
- if (this[i] === needle) return i;
- }
- return -1;
- };
- }
- // https://github.com/jquery/jquery-ui/blob/master/ui/disable-selection.js
- django.jQuery.fn.extend({
- disableSelection: (function() {
- var eventType = 'onselectstart' in document.createElement('div') ? 'selectstart' : 'mousedown';
- return function() {
- return this.on(eventType + '.ui-disableSelection', function(event) {
- event.preventDefault();
- });
- };
- })(),
- enableSelection: function() {
- return this.off('.ui-disableSelection');
- }
- });
- django.jQuery(function($){
- // We are not on a changelist it seems.
- if (!document.getElementById('result_list')) return;
- var DraggableMPTTAdmin = null;
- function isExpandedNode(id) {
- return DraggableMPTTAdmin.collapsedNodes.indexOf(id) == -1;
- }
- function markNodeAsExpanded(id) {
- // remove itemId from array of collapsed nodes
- var idx = DraggableMPTTAdmin.collapsedNodes.indexOf(id);
- if(idx >= 0)
- DraggableMPTTAdmin.collapsedNodes.splice(idx, 1);
- }
- function markNodeAsCollapsed(id) {
- if(isExpandedNode(id))
- DraggableMPTTAdmin.collapsedNodes.push(id);
- }
- function treeNode(pk) {
- return $('.tree-node[data-pk="' + pk + '"]');
- }
- // toggle children
- function doToggle(id, show) {
- var children = DraggableMPTTAdmin.treeStructure[id] || [];
- for (var i=0; i<children.length; ++i) {
- var childId = children[i];
- if(show) {
- treeNode(childId).closest('tr').show();
- // only reveal children if current node is not collapsed
- if(isExpandedNode(childId)) {
- doToggle(childId, show);
- }
- } else {
- treeNode(childId).closest('tr').hide();
- // always recursively hide children
- doToggle(childId, show);
- }
- }
- }
- function rowLevel($row) {
- try {
- return $row.find('.tree-node').data('level') || 0;
- } catch (e) {
- return 0;
- }
- }
- /*
- * FeinCMS Drag-n-drop tree reordering.
- * Based upon code by bright4 for Radiant CMS, rewritten for
- * FeinCMS by Bjorn Post.
- *
- * September 2010
- */
- $.extend($.fn.feinTree = function() {
- $.each(DraggableMPTTAdmin.treeStructure, function(key, value) {
- treeNode(key).addClass('children');
- });
- $('div.drag-handle').bind('mousedown', function(event) {
- var BEFORE = 'before';
- var AFTER = 'after';
- var CHILD = 'child';
- var CHILD_PAD = DraggableMPTTAdmin.levelIndent;
- var originalRow = $(event.target).closest('tr');
- var rowHeight = originalRow.height();
- var moveTo = new Object();
- var resultListWidth = $('#result_list').width();
- $('body').addClass('dragging').disableSelection().bind('mousemove', function(event) {
- // Remove focus
- originalRow.blur();
- // attach dragged item to mouse
- var cloned = originalRow.html();
- if($('#ghost').length == 0) {
- $('<div id="ghost"></div>').appendTo('body');
- }
- $('#ghost').html(cloned).css({
- 'opacity': .8,
- 'position': 'absolute',
- 'top': event.pageY,
- 'left': event.pageX - 30,
- 'width': 600
- });
- // check on edge of screen
- if(event.pageY+100 > $(window).height()+$(window).scrollTop()) {
- $('html,body').stop().animate({scrollTop: $(window).scrollTop()+250 }, 500);
- } else if(event.pageY-50 < $(window).scrollTop()) {
- $('html,body').stop().animate({scrollTop: $(window).scrollTop()-250 }, 500);
- }
- // check if drag-line element already exists, else append
- if($('#drag-line').length < 1) {
- $('body').append('<div id="drag-line"><span></span></div>');
- }
- // loop trough all rows
- $('tr', originalRow.parent()).each(function(index, el) {
- var element = $(el),
- top = element.offset().top,
- next;
- // check if mouse is over a row
- if (event.pageY >= top && event.pageY < top + rowHeight) {
- var targetRow = null,
- targetLoc = null,
- elementLevel = rowLevel(element);
- if (event.pageY >= top && event.pageY < top + rowHeight / 3) {
- targetRow = element;
- targetLoc = BEFORE;
- } else if (event.pageY >= top + rowHeight / 3 && event.pageY < top + rowHeight * 2 / 3) {
- next = element.next();
- // there's no point in allowing adding children when there are some already
- // better move the items to the correct place right away
- if (!next.length || rowLevel(next) <= elementLevel) {
- targetRow = element;
- targetLoc = CHILD;
- }
- } else if (event.pageY >= top + rowHeight * 2 / 3 && event.pageY < top + rowHeight) {
- next = element.next();
- if (!next.length || rowLevel(next) <= elementLevel) {
- targetRow = element;
- targetLoc = AFTER;
- }
- }
- if(targetRow) {
- // Positioning relative to cell containing the link
- var offset = targetRow.find('th').offset();
- var left = offset.left
- + rowLevel(targetRow) * CHILD_PAD
- + (targetLoc == CHILD ? CHILD_PAD : 0)
- + 5; // Center of the circle aligns with start of link text (cell padding!)
- $('#drag-line').css({
- 'width': resultListWidth - left,
- 'left': left,
- 'top': offset.top + (targetLoc == BEFORE ? 0 : rowHeight)
- }).find('span').text(DraggableMPTTAdmin.messages[targetLoc] || '');
- // Store the found row and options
- moveTo.hovering = element;
- moveTo.relativeTo = targetRow;
- moveTo.side = targetLoc;
- return true;
- }
- }
- });
- });
- $('body').keydown(function(event) {
- if (event.which == '27') {
- $('#drag-line').remove();
- $('#ghost').remove();
- $('body').removeClass('dragging').enableSelection().unbind('mousemove').unbind('mouseup');
- event.preventDefault();
- }
- });
- $('body').bind('mouseup', function() {
- if(moveTo.relativeTo) {
- var cutItem = originalRow.find('.tree-node').data('pk');
- var pastedOn = moveTo.relativeTo.find('.tree-node').data('pk');
- // get out early if items are the same
- if(cutItem != pastedOn) {
- var isParent = (
- rowLevel(moveTo.relativeTo.next()) >
- rowLevel(moveTo.relativeTo));
- var position = '';
- // determine position
- if(moveTo.side == CHILD && !isParent) {
- position = 'last-child';
- } else if (moveTo.side == BEFORE) {
- position = 'left';
- } else {
- position = 'right';
- }
- $.ajax({
- complete: function() {
- window.location.reload();
- },
- data: {
- cmd: 'move_node',
- position: position,
- cut_item: cutItem,
- pasted_on: pastedOn
- },
- headers: {
- 'X-CSRFToken': $('input[type=hidden][name=csrfmiddlewaretoken]').val()
- },
- method: 'POST'
- });
- } else {
- $('#drag-line').remove();
- $('#ghost').remove();
- }
- $('body').removeClass('dragging').enableSelection().unbind('mousemove').unbind('mouseup');
- }
- });
- });
- return this;
- });
- /* Every time the user expands or collapses a part of the tree, we remember
- the current state of the tree so we can restore it on a reload. */
- function storeCollapsedNodes(nodes) {
- window.localStorage && window.localStorage.setItem(
- DraggableMPTTAdmin.storageName,
- JSON.stringify(nodes)
- );
- }
- function retrieveCollapsedNodes() {
- try {
- return JSON.parse(window.localStorage.getItem(
- DraggableMPTTAdmin.storageName
- ));
- } catch(e) {
- return null;
- }
- }
- function expandOrCollapseNode(item) {
- var show = true;
- if (!item.hasClass('children'))
- return;
- var itemId = item.data('pk');
- if (!isExpandedNode(itemId)) {
- item.removeClass('closed');
- markNodeAsExpanded(itemId);
- } else {
- item.addClass('closed');
- show = false;
- markNodeAsCollapsed(itemId);
- }
- storeCollapsedNodes(DraggableMPTTAdmin.collapsedNodes);
- doToggle(itemId, show);
- }
- function collapseTree() {
- var rlist = $("#result_list");
- rlist.hide();
- $('tbody tr', rlist).each(function(i, el) {
- var marker = $('.tree-node', el);
- if (marker.hasClass('children')) {
- var itemId = marker.data('pk');
- doToggle(itemId, false);
- marker.addClass('closed');
- markNodeAsCollapsed(itemId);
- }
- });
- storeCollapsedNodes(DraggableMPTTAdmin.collapsedNodes);
- rlist.show();
- return false;
- }
- function expandTree() {
- var rlist = $("#result_list");
- rlist.hide();
- $('tbody tr', rlist).each(function(i, el) {
- var marker = $('.tree-node', el);
- if (marker.hasClass('children')) {
- var itemId = $('.tree-node', el).data('pk');
- doToggle(itemId, true);
- marker.removeClass('closed');
- markNodeAsExpanded(itemId);
- }
- });
- storeCollapsedNodes([]);
- rlist.show();
- return false;
- }
- var changelistTab = function(elem, event, direction) {
- event.preventDefault();
- elem = $(elem);
- var ne = (direction > 0) ? elem.nextAll(':visible:first') : elem.prevAll(':visible:first');
- if(ne) {
- elem.attr('tabindex', -1);
- ne.attr('tabindex', '0');
- ne.focus();
- }
- };
- function keyboardNavigationHandler(event) {
- // On form element? Ignore.
- if (/textarea|select|input/i.test(event.target.nodeName))
- return;
- // console.log('keydown', this, event.keyCode);
- switch (event.keyCode) {
- case 40: // down
- changelistTab(this, event, 1);
- break;
- case 38: // up
- changelistTab(this, event, -1);
- break;
- case 37: // left
- case 39: // right
- expandOrCollapseNode($(this).find('.tree-node'));
- break;
- case 13: // return
- document.location = $('a', this).attr('href');
- break;
- default:
- break;
- }
- }
- function addObjectTool(title, handler) {
- var $a = $('<a href/>');
- $a.click(handler);
- $a.text(title);
- $a.prependTo('.object-tools').wrap('<li>');
- }
- // Some old browsers do not support JSON.parse (the only thing we require)
- var jsonParse = JSON.parse || function jsonParse(sJSON) { return eval('(' + sJSON + ')'); };
- DraggableMPTTAdmin = jsonParse(
- document.getElementById('draggable-admin-context').getAttribute('data-context'));
- addObjectTool(DraggableMPTTAdmin.messages.collapseTree, collapseTree);
- addObjectTool(DraggableMPTTAdmin.messages.expandTree, expandTree);
- // fire!
- var rlist = $("#result_list"),
- rlist_tbody = rlist.find('tbody');
- if ($('tbody tr', rlist).length > 1) {
- rlist_tbody.feinTree();
- rlist.find('.tree-node').on('click', function(event) {
- event.preventDefault();
- event.stopPropagation();
- expandOrCollapseNode($(this));
- });
- /* Enable focussing, put focus on first result, add handler for keyboard navigation */
- $('tr', rlist).attr('tabindex', -1);
- $('tbody tr:first', rlist).attr('tabindex', 0).focus();
- $('tr', rlist).keydown(keyboardNavigationHandler);
- DraggableMPTTAdmin.collapsedNodes = [];
- var storedNodes = retrieveCollapsedNodes();
- if (storedNodes) {
- for(var i=0; i<storedNodes.length; i++) {
- expandOrCollapseNode(treeNode(storedNodes[i]));
- }
- } else {
- if (!DraggableMPTTAdmin.expandTreeByDefault) {
- collapseTree();
- }
- }
- }
- });
|