2013-02-05 17 views
0

我有一個窗體,您可以生成一個可排序的菜單結構。我想將第一個項目作爲父項目,其後所有項目都是子項目。我已經實現了這種可視化,但我還需要確保代碼結構是正確的。jQuery nestedSortable - 如何使第一個項目根和子項的根子

在我的選項中,我注意到protectRoot和rootID不起作用,但我不認爲它會影響代碼中的任何內容。

的jsfiddle http://jsfiddle.net/clintongreen/EazX7/

JS

// Nested Sortable Plugin 
/* 
* jQuery UI Nested Sortablefdfv 
* v 1.3.4/28 apr 2011 
* http://mjsarfatti.com/sandbox/nestedSortable 
* 
* Depends: 
*  jquery.ui.sortable.js 1.8+ 
* 
* License CC BY-SA 3.0 
* Copyright 2010-2011, Manuele J Sarfatti 
*/ 

(function($) { 

$.widget("ui.nestedSortable", $.extend({}, $.ui.sortable.prototype, { 

    options: { 
     tabSize: 20, 
     disableNesting: 'ui-nestedSortable-no-nesting', 
     errorClass: 'ui-nestedSortable-error', 
     listType: 'ol', 
     maxLevels: 0, 
     noJumpFix: 0 
    }, 

    _create: function(){ 
     if (this.noJumpFix == false) 
      this.element.height(this.element.height()); 
     this.element.data('sortable', this.element.data('nestedSortable')); 
     return $.ui.sortable.prototype._create.apply(this, arguments); 
    }, 



    _mouseDrag: function(event) { 

     //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) { 
      var o = this.options, scrolled = false; 
      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"); 

     //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'; 

     //Rearrange 
     for (var i = this.items.length - 1; i >= 0; i--) { 

      //Cache variables and intersection, continue if no intersection 
      var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item); 
      if (!intersection) continue; 

      if(itemElement != this.currentItem[0] //cannot intersect with itself 
       && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before 
       && !$.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked 
       && (this.options.type == 'semi-dynamic' ? !$.contains(this.element[0], itemElement) : true) 
       //&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container 
      ) { 

       this.direction = intersection == 1 ? "down" : "up"; 

       if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) { 
        this._rearrange(event, item); 
       } else { 
        break; 
       } 

       // Clear emtpy ul's/ol's 
       this._clearEmpty(itemElement); 

       this._trigger("change", event, this._uiHash()); 
       break; 
      } 
     } 

     var parentItem = (this.placeholder[0].parentNode.parentNode && $(this.placeholder[0].parentNode.parentNode).closest('.ui-sortable').length) ? $(this.placeholder[0].parentNode.parentNode) : null; 
     var level = this._getLevel(this.placeholder); 
     var childLevels = this._getChildLevels(this.helper); 
     var previousItem = this.placeholder[0].previousSibling ? $(this.placeholder[0].previousSibling) : null; 
     if (previousItem != null) { 
      while (previousItem[0].nodeName.toLowerCase() != 'li' || previousItem[0] == this.currentItem[0]) { 
       if (previousItem[0].previousSibling) { 
        previousItem = $(previousItem[0].previousSibling); 
       } else { 
        previousItem = null; 
        break; 
       } 
      } 
     } 

     newList = document.createElement(o.listType); 

     this.beyondMaxLevels = 0; 

     // If the item is moved to the left, send it to its parent level 
     if (parentItem != null && this.positionAbs.left < parentItem.offset().left) { 
      parentItem.after(this.placeholder[0]); 
      this._clearEmpty(parentItem[0]); 
      this._trigger("change", event, this._uiHash()); 
     } 
     // If the item is below another one and is moved to the right, make it a children of it 
     else if (previousItem != null && this.positionAbs.left > previousItem.offset().left + o.tabSize) { 
      this._isAllowed(previousItem, level+childLevels+1); 
      if (!previousItem.children(o.listType).length) { 
       previousItem[0].appendChild(newList); 
      } 
      previousItem.children(o.listType)[0].appendChild(this.placeholder[0]); 
      this._trigger("change", event, this._uiHash()); 
     } 
     else { 
      this._isAllowed(parentItem, 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) { 

     // If the item is in a position not allowed, send it back 
     if (this.beyondMaxLevels) { 
      var parent = this.placeholder.parent().closest(this.options.items); 

      for (var i = this.beyondMaxLevels - 1; i > 0; i--) { 
       parent = parent.parent().closest(this.options.items); 
      } 

      this.placeholder.removeClass(this.options.errorClass); 
      parent.after(this.placeholder); 
      this._trigger("change", event, this._uiHash()); 
     } 

     $.ui.sortable.prototype._mouseStop.apply(this, arguments); 

    }, 

    serialize: function(o) { 

     var items = this._getItemsAsjQuery(o && o.connected); 
     var str = []; o = o || {}; 

     $(items).each(function() { 
      var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/)); 
      var pid = ($(o.item || this).parent(o.listType).parent('li').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]) : 'root')); 
     }); 

     if(!str.length && o.key) { 
      str.push(o.key + '='); 
     } 

     return str.join('&'); 

    }, 

    toHierarchy: function(o) { 

     o = o || {}; 
     var sDepth = o.startDepthCount || 0; 
     var ret = []; 

     $(this.element).children('li').each(function() { 
      var level = _recursiveItems($(this)); 
      ret.push(level); 
     }); 

     return ret; 

     function _recursiveItems(li) { 
      var id = ($(li).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/)); 
      if (id != null) { 
       var item = {"id" : id[2]}; 
       if ($(li).children(o.listType).children('li').length > 0) { 
        item.children = []; 
        $(li).children(o.listType).children('li').each(function() { 
         var level = _recursiveItems($(this)); 
         item.children.push(level); 
        }); 
       } 
       return item; 
      } 
     } 
    }, 

    toArray: function(o) { 

     o = o || {}; 
     var sDepth = o.startDepthCount || 0; 
     var ret = []; 
     var left = 2; 

     ret.push({"item_id": 'root', "parent_id": 'none', "depth": sDepth, "left": '1', "right": ($('li', this.element).length + 1) * 2}); 

     $(this.element).children('li').each(function() { 
      left = _recursiveArray(this, sDepth + 1, left); 
     }); 

     function _sortByLeft(a,b) { 
      return a['left'] - b['left']; 
     } 
     ret = ret.sort(_sortByLeft); 

     return ret; 

     function _recursiveArray(item, depth, left) { 

      right = left + 1; 

      if ($(item).children(o.listType).children('li').length > 0) { 
       depth ++; 
       $(item).children(o.listType).children('li').each(function() { 
        right = _recursiveArray($(this), depth, right); 
       }); 
       depth --; 
      } 

      id = ($(item).attr(o.attribute || 'id')).match(o.expression || (/(.+)[-=_](.+)/)); 

      if (depth === sDepth + 1) pid = 'root'; 
      else { 
       parentItem = ($(item).parent(o.listType).parent('li').attr('id')).match(o.expression || (/(.+)[-=_](.+)/)); 
       pid = parentItem[2]; 
      } 

      if (id != null) { 
        ret.push({"item_id": id[2], "parent_id": pid, "depth": depth, "left": left, "right": right}); 
      } 

      return left = right + 1; 
     } 

    }, 

    _clear: function(event, noPropagation) { 

     $.ui.sortable.prototype._clear.apply(this, arguments); 

     // 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); 
     } 
     return true; 

    }, 

    _clearEmpty: function(item) { 

     if (item.children[1] && item.children[1].children.length == 0) { 
      item.removeChild(item.children[1]); 
     } 

    }, 

    _getLevel: function(item) { 

     var level = 1; 

     if (this.options.listType) { 
       var list = item.closest(this.options.listType); 
       while (!list.is('.ui-sortable')/* && level < this.options.maxLevels*/) { 
         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, levels) { 
     var o = this.options 
     // Are we trying to nest under a no-nest or are we nesting too deep? 
     if (parentItem == null || !(parentItem.hasClass(o.disableNesting))) { 
      if (o.maxLevels < levels && o.maxLevels != 0) { 
       this.placeholder.addClass(o.errorClass); 
       this.beyondMaxLevels = levels - o.maxLevels; 
      } else { 
       this.placeholder.removeClass(o.errorClass); 
       this.beyondMaxLevels = 0; 
      } 
     } else { 
      this.placeholder.addClass(o.errorClass); 
      if (o.maxLevels < levels && o.maxLevels != 0) { 
       this.beyondMaxLevels = levels - o.maxLevels; 
      } else { 
       this.beyondMaxLevels = 1; 
      } 
     } 
    } 
})); 

$.ui.nestedSortable.prototype.options = $.extend({}, $.ui.sortable.prototype.options, $.ui.nestedSortable.prototype.options); 
})(jQuery); 

// Create Div 
$(".add_menu_item").live('click', function() { 
var value = $(this).prev().val(); 
if (value.length) { 
    var newDiv = $('<div id="toggleshow' + "0" + numToggle++ +'" class="div_menu_button"></div>'); 
    var showDiv = $('<div id="show'+ "0" + numShow++ +'" class="menu_button_info">Haywood Tjibloumi</div>'); 
    $('#created_buttons_list').append(
     newDiv.val(value).text(value)); 
     newDiv.wrap("<li></li>"); 
     newDiv.append(showDiv); 
} 

}); 
    var numToggle = 0; 
    var numShow = 0; 


    // Nested Divs Options 
    $('ol#created_buttons_list').nestedSortable({ 
     disableNesting: 'no-nest', 
     protectRoot: true, 
     rootID: '#theroot', 
     forcePlaceholderSize: true, 
     handle: 'div', 
     helper: 'clone', 
     items: 'li:not(.dontsortme)', 
     maxLevels: 10, 
     opacity: .6, 
     placeholder: 'placeholder', 
     revert: 250, 
     tabSize: 25, 
     tolerance: 'pointer', 
     toleranceElement: '> div' 
}); 


    // Toggle Hide/SHow 
    $('#toggleshow').live('click', function() {$('#show').slideToggle('slow', function() {});}); 
    $('#toggleshow00').live('click', function() {$('#show00').slideToggle('slow', function() {});}); 
    $('#toggleshow01').live('click',function() {$('#show01').slideToggle('slow', function() {});}); 
    $('#toggleshow02').live('click',function() {$('#show02').slideToggle('slow', function() {});}); 
    $('#toggleshow03').live('click',function() {$('#show03').slideToggle('slow', function() {});}); 
    $('#toggleshow04').live('click',function() {$('#show04').slideToggle('slow', function() {});}); 
    $('#toggleshow05').live('click',function() {$('#show05').slideToggle('slow', function() {});}); 

// Indent first item 
$("input.add_menu_item").live('click', function(){ 
    $("#created_buttons_list li:first").css('margin-left','0px').addClass('dontsortme'); 
}); 

CSS

form#create_menu_item{ width:920px; } 
form#create_menu_item input#new_menu_name{ padding:5px; float:left; margin:0 10px 10px 0; } 
form#create_menu_item input.add_menu_item{font-size:11px; width:60px; height:27px; display:block; -moz-border-radius:3px; -webkit-border-radius:3px; -o-border-radius:3px; border-radius:3px; background:#f5f5f5; background: -moz-linear-gradient(100% 100% 90deg, #eee, #fcfcfc); background: -webkit-linear-gradient(#fcfcfc, #eee) !important; background: -o-linear-gradient(#fcfcfc, #eee);border:1px solid #ccc;color:#666;padding-bottom:3px;float:left;} 
div.div_menu_button{font-size:12px;width:295px;height:16px;display:block;-moz-border-radius:3px; -webkit-border-radius:3px; -o-border-radius:3px; border-radius:3px;background:#f5f5f5; background: -moz-linear-gradient(100% 100% 90deg, #eee, #fcfcfc); background: -webkit-linear-gradient(#fcfcfc, #eee) !important; background: -o-linear-gradient(#fcfcfc, #eee);border:1px solid #ccc;color:#666;padding:10px;margin:0 0 10px 0;} 
div#created_buttons{ width:680px; border:1px solid #eee; min-height:400px; padding:10px;} 
.clear{ clear:both;} 
#show, #show00, #show01, #show02, #show03, #show04, #show05 { display:none;} 
.ui-nestedSortable-error { background:#fbe3e4; color:#8a1f11;} 
ol#created_buttons_list{ margin: 0; padding: 0; padding-left: 30px;} 
ol#created_buttons_list, ol#created_buttons_list ol { margin: 0 0 0 25px; padding: 0; list-style-type: none;} 
ol#created_buttons_list { margin: 10px 0 10px 0;} 
#created_buttons_list li { margin: 7px 0 0 0; padding: 0;} 
#created_buttons_list li div { padding: 10px; margin: 0; cursor: move;} 
.placeholder { background-color: #f9f9f9; border:1px dashed #ccc;} 
#created_buttons li{margin-left: 25px; padding-left: 25px;} 

HTML

 <div> 
      <form id="create_menu_item"> 
      <ul class="add_remove_list"> 
       <li><h4>Add Menu Item</h4></li> 
       <li><input id="new_menu_name" type="text" name="new_menu_name" placeholder="Please enter your menu title"> 
        <input class="add_menu_item" name="add_menu_item" value="Add" type="button"> 
       </li> 
       <li class="clear"><h4>Menu Items</h4></li> 
        <li><div id="created_buttons"> <ol id="created_buttons_list"> </ol> </div>       
       </li> 
      </ul> 
       </form> 
     </div> 
+1

評論爲什麼這是downvoted將是有用的 –

回答

0

.live從v1.7開始在jQuery中被棄用,並且在v1.9中被刪除。

您應該將其替換爲.on()

.on有2個簽名綁定的事件處理程序,而.live只有1

如果該元素存在於你要綁定的時候,你做這樣的:

$('.element').on('click', function(){ 
    ....... 
}); 

你甚至可以使用簡寫:

$('.element').click(function(){ 
    ......... 
}); 

如果該元素當時不存在或將添加新元素(這是什麼.live被正常使用)的,你需要使用「事件代理」:

$(document).on('click', '.element', function(){ 
    ........ 
}); 

注意:您要綁定到最接近的靜態元素,不總是document

與此同時,jQuery Migrate plugin可用於恢復.live()功能,如果您將jQuery升級到最新版本。

+0

謝謝羅伊,我會檢討.live功能。乾杯 –

相關問題