The previous commit inadvertently added parts of the browser treeview implementation.
This adds the rest (which still requires further work to make it do anything useful).pull/3/head
| 
						 | 
				
			
			@ -0,0 +1,549 @@
 | 
			
		|||
@charset "utf-8";
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * aciTree jQuery Plugin
 | 
			
		||||
 * http://acoderinsights.ro
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
.aciTree {
 | 
			
		||||
    outline: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* the big loader */
 | 
			
		||||
.aciTree.aciTreeLoad {
 | 
			
		||||
    background:url(../image/load-root.gif) center center no-repeat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeUl {
 | 
			
		||||
    list-style:none;
 | 
			
		||||
    margin:0;
 | 
			
		||||
    padding:0;
 | 
			
		||||
}
 | 
			
		||||
.aciTree .aciTreeLi {
 | 
			
		||||
    display:block;
 | 
			
		||||
    clear:both;
 | 
			
		||||
    white-space:nowrap;
 | 
			
		||||
}
 | 
			
		||||
.aciTree .aciTreeLine:focus {
 | 
			
		||||
    outline:none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeHidden {
 | 
			
		||||
    display:none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* the branch line */
 | 
			
		||||
.aciTree .aciTreeBranch {
 | 
			
		||||
    padding-left:20px; /* branch indent */
 | 
			
		||||
    background:url(../image/tree-branch.png) left 1px repeat-y;
 | 
			
		||||
}
 | 
			
		||||
.aciTree[dir=rtl] .aciTreeBranch {
 | 
			
		||||
    padding-left:0;
 | 
			
		||||
    padding-right:20px; /* branch indent */
 | 
			
		||||
    background:url(../image/tree-branch.png) right 1px repeat-y;
 | 
			
		||||
}
 | 
			
		||||
/* if the parent is the last child on his level (this is level based; added for #8 levels, if you need more ... add them as needed) */
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeLevel0.aciTreeLast .aciTreeBranch.aciTreeLevel0,
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeLevel1.aciTreeLast .aciTreeBranch.aciTreeLevel1,
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeLevel2.aciTreeLast .aciTreeBranch.aciTreeLevel2,
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeLevel3.aciTreeLast .aciTreeBranch.aciTreeLevel3,
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeLevel4.aciTreeLast .aciTreeBranch.aciTreeLevel4,
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeLevel5.aciTreeLast .aciTreeBranch.aciTreeLevel5,
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeLevel6.aciTreeLast .aciTreeBranch.aciTreeLevel6,
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeLevel7.aciTreeLast .aciTreeBranch.aciTreeLevel7,
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeLevel8.aciTreeLast .aciTreeBranch.aciTreeLevel8,
 | 
			
		||||
.aciTree.aciTreeNoBranches .aciTreeBranch {
 | 
			
		||||
    background:none;
 | 
			
		||||
}
 | 
			
		||||
/* the branch line behind the button (for the siblings) */
 | 
			
		||||
.aciTree .aciTreeEntry {
 | 
			
		||||
    overflow:hidden;
 | 
			
		||||
    background:url(../image/tree-branch.png) left 1px repeat-y;
 | 
			
		||||
}
 | 
			
		||||
.aciTree[dir=rtl] .aciTreeEntry {
 | 
			
		||||
    background:url(../image/tree-branch.png) right 1px repeat-y;
 | 
			
		||||
}
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeLast>.aciTreeLine .aciTreeEntry,
 | 
			
		||||
.aciTree.aciTreeNoBranches .aciTreeEntry {
 | 
			
		||||
    background:none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree.aciTreeBig .aciTreeEntry {
 | 
			
		||||
    padding:0 0 2px 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeButton, .aciTree .aciTreePush, .aciTree .aciTreeItem, .aciTree .aciTreeIcon, .aciTree .aciTreeText, .aciTree .aciTreeColumn {
 | 
			
		||||
    display:inline-block;
 | 
			
		||||
    height:20px;
 | 
			
		||||
    line-height:20px;
 | 
			
		||||
    font-family:Verdana, Geneva, sans-serif;
 | 
			
		||||
    font-size:11px;
 | 
			
		||||
    color:#000;
 | 
			
		||||
    vertical-align:top;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeBig .aciTreeText, .aciTree.aciTreeBig .aciTreeColumn {
 | 
			
		||||
    font-size:12px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeDisabled>.aciTreeLine .aciTreeText, .aciTree .aciTreeDisabled>.aciTreeLine .aciTreeColumn {
 | 
			
		||||
    color:#888;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeItem {
 | 
			
		||||
    padding:0 2px 0 2px;
 | 
			
		||||
    border:1px solid transparent;
 | 
			
		||||
    height:auto;
 | 
			
		||||
    white-space:normal;
 | 
			
		||||
    cursor:pointer;
 | 
			
		||||
    /* margin-right need to be set to icon width [.aciTree .aciTreeIcon = 20] +
 | 
			
		||||
    item padding [.aciTree .aciTreeItem = 4] (+ the width of all columns, if any) */
 | 
			
		||||
    margin-right:24px;
 | 
			
		||||
}
 | 
			
		||||
.aciTree[dir=rtl] .aciTreeItem{
 | 
			
		||||
    margin-right:0;
 | 
			
		||||
    /* margin-left need to be set to icon width [.aciTree .aciTreeIcon = 20] +
 | 
			
		||||
    item padding [.aciTree .aciTreeItem = 4] (+ the width of all columns, if any) */
 | 
			
		||||
    margin-left:24px;
 | 
			
		||||
}
 | 
			
		||||
.aciTree .aciTreeText {
 | 
			
		||||
    display:inline;
 | 
			
		||||
    height:auto;
 | 
			
		||||
}
 | 
			
		||||
.aciTree .aciTreeColumn {
 | 
			
		||||
    float:right;
 | 
			
		||||
    height:auto;
 | 
			
		||||
    white-space:normal;
 | 
			
		||||
    cursor:default;
 | 
			
		||||
}
 | 
			
		||||
.aciTree[dir=rtl] .aciTreeColumn {
 | 
			
		||||
    float:left;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* columns width/style (left to right, if any) */
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeColumn0 {
 | 
			
		||||
    width:80px;
 | 
			
		||||
}
 | 
			
		||||
.aciTree .aciTreeColumn1 {
 | 
			
		||||
    width:60px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* item selection */
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeLine.aciTreeHover .aciTreeItem {
 | 
			
		||||
    background-color:#EFF5FD;
 | 
			
		||||
    border:1px dashed #D9D9D9;
 | 
			
		||||
    -webkit-border-radius:3px;
 | 
			
		||||
    -moz-border-radius:3px;
 | 
			
		||||
    border-radius:3px;
 | 
			
		||||
}
 | 
			
		||||
.aciTree .aciTreeFocus>.aciTreeLine .aciTreeItem {
 | 
			
		||||
    /* not selected but with focus */
 | 
			
		||||
    border:1px solid #D9D9D9;
 | 
			
		||||
    -webkit-border-radius:3px;
 | 
			
		||||
    -moz-border-radius:3px;
 | 
			
		||||
    border-radius:3px;
 | 
			
		||||
}
 | 
			
		||||
.aciTree .aciTreeSelected>.aciTreeLine .aciTreeItem {
 | 
			
		||||
    background-color:#E8E8E8;
 | 
			
		||||
    border:1px dashed #D9D9D9;
 | 
			
		||||
    -webkit-border-radius:3px;
 | 
			
		||||
    -moz-border-radius:3px;
 | 
			
		||||
    border-radius:3px;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeFocus .aciTreeSelected>.aciTreeLine .aciTreeItem {
 | 
			
		||||
    background-color:#d0e5fe;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeFocus .aciTreeFocus>.aciTreeLine .aciTreeItem {
 | 
			
		||||
    /* not selected but with focus */
 | 
			
		||||
    border:1px solid #84acdd;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeFocus .aciTreeSelected.aciTreeFocus>.aciTreeLine .aciTreeItem {
 | 
			
		||||
    border:1px dashed #84acdd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* full row selection */
 | 
			
		||||
 | 
			
		||||
.aciTree.aciTreeFullRow>.aciTreeUl {
 | 
			
		||||
    margin:2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree.aciTreeFullRow .aciTreeLine {
 | 
			
		||||
    margin:-2px;
 | 
			
		||||
    border:1px solid transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree.aciTreeFullRow .aciTreeLine.aciTreeHover .aciTreeItem {
 | 
			
		||||
    background:none;
 | 
			
		||||
    border:1px solid transparent;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeFullRow .aciTreeFocus>.aciTreeLine {
 | 
			
		||||
    /* not selected but with focus */
 | 
			
		||||
    border:1px solid #D9D9D9;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeFullRow .aciTreeSelected>.aciTreeLine .aciTreeItem,
 | 
			
		||||
.aciTree.aciTreeFullRow .aciTreeFocus>.aciTreeLine .aciTreeItem {
 | 
			
		||||
    background:none;
 | 
			
		||||
    border:1px solid transparent;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeFullRow.aciTreeFocus .aciTreeSelected>.aciTreeLine .aciTreeItem {
 | 
			
		||||
    background:none;
 | 
			
		||||
    border:1px solid transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree.aciTreeFullRow .aciTreeLine.aciTreeHover {
 | 
			
		||||
    background: #e3edf9;
 | 
			
		||||
    background: -moz-linear-gradient(top,  #e3edf9 0%, #9cb7d8 100%);
 | 
			
		||||
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#e3edf9), color-stop(100%,#9cb7d8));
 | 
			
		||||
    background: -webkit-linear-gradient(top,  #e3edf9 0%,#9cb7d8 100%);
 | 
			
		||||
    background: -o-linear-gradient(top,  #e3edf9 0%,#9cb7d8 100%);
 | 
			
		||||
    background: -ms-linear-gradient(top,  #e3edf9 0%,#9cb7d8 100%);
 | 
			
		||||
    background: linear-gradient(to bottom,  #e3edf9 0%,#9cb7d8 100%);
 | 
			
		||||
    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#e3edf9', endColorstr='#9cb7d8',GradientType=0 );
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeFullRow .aciTreeSelected>.aciTreeLine {
 | 
			
		||||
    background: #f4f4f4;
 | 
			
		||||
    background: -moz-linear-gradient(top,  #f4f4f4 0%, #c6c6c6 100%);
 | 
			
		||||
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f4f4f4), color-stop(100%,#c6c6c6));
 | 
			
		||||
    background: -webkit-linear-gradient(top,  #f4f4f4 0%,#c6c6c6 100%);
 | 
			
		||||
    background: -o-linear-gradient(top,  #f4f4f4 0%,#c6c6c6 100%);
 | 
			
		||||
    background: -ms-linear-gradient(top,  #f4f4f4 0%,#c6c6c6 100%);
 | 
			
		||||
    background: linear-gradient(to bottom,  #f4f4f4 0%,#c6c6c6 100%);
 | 
			
		||||
    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f4f4f4', endColorstr='#c6c6c6',GradientType=0 );
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeFullRow.aciTreeFocus .aciTreeFocus>.aciTreeLine {
 | 
			
		||||
    /* not selected but with focus */
 | 
			
		||||
    border:1px solid #84acdd;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeFullRow.aciTreeFocus .aciTreeSelected>.aciTreeLine {
 | 
			
		||||
    border:1px solid transparent;
 | 
			
		||||
    background: #d0e5fe;
 | 
			
		||||
    background: -moz-linear-gradient(top,  #d0e5fe 0%, #84acdd 100%);
 | 
			
		||||
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#d0e5fe), color-stop(100%,#84acdd));
 | 
			
		||||
    background: -webkit-linear-gradient(top,  #d0e5fe 0%,#84acdd 100%);
 | 
			
		||||
    background: -o-linear-gradient(top,  #d0e5fe 0%,#84acdd 100%);
 | 
			
		||||
    background: -ms-linear-gradient(top,  #d0e5fe 0%,#84acdd 100%);
 | 
			
		||||
    background: linear-gradient(to bottom,  #d0e5fe 0%,#84acdd 100%);
 | 
			
		||||
    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#d0e5fe', endColorstr='#84acdd',GradientType=0 );
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeFullRow.aciTreeFocus .aciTreeSelected>.aciTreeLine.aciTreeHover,
 | 
			
		||||
.aciTree.aciTreeFullRow .aciTreeSelected>.aciTreeLine.aciTreeHover {
 | 
			
		||||
    background: #c3dbf7;
 | 
			
		||||
    background: -moz-linear-gradient(top,  #c3dbf7 0%, #84a9d6 100%);
 | 
			
		||||
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#c3dbf7), color-stop(100%,#84a9d6));
 | 
			
		||||
    background: -webkit-linear-gradient(top,  #c3dbf7 0%,#84a9d6 100%);
 | 
			
		||||
    background: -o-linear-gradient(top,  #c3dbf7 0%,#84a9d6 100%);
 | 
			
		||||
    background: -ms-linear-gradient(top,  #c3dbf7 0%,#84a9d6 100%);
 | 
			
		||||
    background: linear-gradient(to bottom,  #c3dbf7 0%,#84a9d6 100%);
 | 
			
		||||
    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#c3dbf7', endColorstr='#84a9d6',GradientType=0 );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* checkbox/radio tree */
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeCheckbox label, .aciTree .aciTreeRadio label {
 | 
			
		||||
    cursor:pointer;
 | 
			
		||||
}
 | 
			
		||||
.aciTree .aciTreeCheck {
 | 
			
		||||
    width:20px;
 | 
			
		||||
    height:20px;
 | 
			
		||||
    display:inline-block;
 | 
			
		||||
    margin:0 2px 0 2px;
 | 
			
		||||
    padding:0;
 | 
			
		||||
    vertical-align:text-bottom;
 | 
			
		||||
    background:url(../image/tree-check-small.png) 0 0 no-repeat;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeBig .aciTreeCheck {
 | 
			
		||||
    background:url(../image/tree-check-big.png) 0 0 no-repeat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree[dir=rtl] .aciTreeCheck {
 | 
			
		||||
    background:url(../image/tree-check-small-rtl.png) 0 0 no-repeat;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeBig[dir=rtl] .aciTreeCheck {
 | 
			
		||||
    background:url(../image/tree-check-big-rtl.png) 0 0 no-repeat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeCheckbox>.aciTreeLine .aciTreeCheck { background-position:-5px -65px; }
 | 
			
		||||
.aciTree .aciTreeCheckbox.aciTreeChecked>.aciTreeLine .aciTreeCheck { background-position:-5px -5px; }
 | 
			
		||||
.aciTree .aciTreeCheckbox.aciTreeChecked.aciTreeTristate>.aciTreeLine .aciTreeCheck { background-position:-5px -35px; }
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeCheckbox>.aciTreeLine.aciTreeHover .aciTreeCheck { background-position:-35px -65px; }
 | 
			
		||||
.aciTree .aciTreeCheckbox.aciTreeChecked>.aciTreeLine.aciTreeHover .aciTreeCheck { background-position:-35px -5px; }
 | 
			
		||||
.aciTree .aciTreeCheckbox.aciTreeChecked.aciTreeTristate>.aciTreeLine.aciTreeHover .aciTreeCheck { background-position:-35px -35px; }
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeCheckbox.aciTreeDisabled>.aciTreeLine .aciTreeCheck { background-position:-65px -65px; }
 | 
			
		||||
.aciTree .aciTreeCheckbox.aciTreeDisabled.aciTreeChecked>.aciTreeLine .aciTreeCheck { background-position:-65px -5px; }
 | 
			
		||||
.aciTree .aciTreeCheckbox.aciTreeDisabled.aciTreeChecked.aciTreeTristate>.aciTreeLine .aciTreeCheck { background-position:-65px -35px; }
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeRadio>.aciTreeLine .aciTreeCheck { background-position:-95px -65px; }
 | 
			
		||||
.aciTree .aciTreeRadio.aciTreeChecked>.aciTreeLine .aciTreeCheck { background-position:-95px -5px; }
 | 
			
		||||
.aciTree .aciTreeRadio.aciTreeChecked.aciTreeTristate>.aciTreeLine .aciTreeCheck { background-position:-95px -35px; }
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeRadio>.aciTreeLine.aciTreeHover .aciTreeCheck { background-position:-125px -65px; }
 | 
			
		||||
.aciTree .aciTreeRadio.aciTreeChecked>.aciTreeLine.aciTreeHover .aciTreeCheck { background-position:-125px -5px; }
 | 
			
		||||
.aciTree .aciTreeRadio.aciTreeChecked.aciTreeTristate>.aciTreeLine.aciTreeHover .aciTreeCheck { background-position:-125px -35px; }
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeRadio.aciTreeDisabled>.aciTreeLine .aciTreeCheck { background-position:-155px -65px; }
 | 
			
		||||
.aciTree .aciTreeRadio.aciTreeDisabled.aciTreeChecked>.aciTreeLine .aciTreeCheck { background-position:-155px -5px; }
 | 
			
		||||
.aciTree .aciTreeRadio.aciTreeDisabled.aciTreeChecked.aciTreeTristate>.aciTreeLine .aciTreeCheck { background-position:-155px -35px; }
 | 
			
		||||
 | 
			
		||||
/* inplace editable */
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeEdited input[type=text] {
 | 
			
		||||
    outline: none;
 | 
			
		||||
    border:1px solid #000;
 | 
			
		||||
    padding:0;
 | 
			
		||||
    margin:0;
 | 
			
		||||
    line-height:18px;
 | 
			
		||||
    height:18px;
 | 
			
		||||
    display:inline-block;
 | 
			
		||||
    font-family:Verdana, Geneva, sans-serif;
 | 
			
		||||
    font-size:11px;
 | 
			
		||||
    color:#000;
 | 
			
		||||
    vertical-align:top;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeBig .aciTreeEdited input[type=text] {
 | 
			
		||||
    font-size:12px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* sortable items */
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeChild {
 | 
			
		||||
    height:0;
 | 
			
		||||
    line-height:0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreePlaceholder {
 | 
			
		||||
    height:0;
 | 
			
		||||
    line-height:0;
 | 
			
		||||
    overflow:visible;
 | 
			
		||||
    position:relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreePlaceholder div {
 | 
			
		||||
    position:absolute;
 | 
			
		||||
    left:0;
 | 
			
		||||
    width:16px;
 | 
			
		||||
    height:16px;
 | 
			
		||||
    margin-left:20px;
 | 
			
		||||
    background:#fff url(../image/drag-drop.png) -7px -37px no-repeat;
 | 
			
		||||
    border:1px solid #999;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree[dir=rtl] .aciTreePlaceholder div {
 | 
			
		||||
    background:#fff url(../image/drag-drop-rtl.png) -7px -37px no-repeat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeChild .aciTreePlaceholder div {
 | 
			
		||||
    top:-20px;
 | 
			
		||||
    left:-20px;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeBig .aciTreeChild .aciTreePlaceholder div {
 | 
			
		||||
    top:-22px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreePlaceholder.aciTreeBefore div {
 | 
			
		||||
    top:2px;
 | 
			
		||||
    background-position:-7px -7px !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreePlaceholder.aciTreeAfter div {
 | 
			
		||||
    top:-20px;
 | 
			
		||||
    background-position:-7px -67px !important;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeBig .aciTreePlaceholder.aciTreeAfter div {
 | 
			
		||||
    top:-22px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree.aciTreeDragDrop .aciTreeItem, .aciTree.aciTreeDragDrop .aciTreeColumn,
 | 
			
		||||
.aciTree.aciTreeDragDrop .aciTreeCheckbox label, .aciTree.aciTreeDragDrop .aciTreeRadio label {
 | 
			
		||||
    cursor:inherit !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* this is level based; added for #8 levels, if you need more ... add them as needed */
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeLevel0 .aciTreePlaceholder div { margin-left:40px; }
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeLevel1 .aciTreePlaceholder div { margin-left:60px; }
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeLevel2 .aciTreePlaceholder div { margin-left:80px; }
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeLevel3 .aciTreePlaceholder div { margin-left:100px; }
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeLevel4 .aciTreePlaceholder div { margin-left:120px; }
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeLevel5 .aciTreePlaceholder div { margin-left:140px; }
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeLevel6 .aciTreePlaceholder div { margin-left:160px; }
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeLevel7 .aciTreePlaceholder div { margin-left:180px; }
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeLevel8 .aciTreePlaceholder div { margin-left:200px; }
 | 
			
		||||
 | 
			
		||||
.aciTree[dir=rtl] .aciTreePlaceholder div {
 | 
			
		||||
    left:auto;
 | 
			
		||||
    right:0;
 | 
			
		||||
    margin-left:0;
 | 
			
		||||
    margin-right:20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeChild .aciTreePlaceholder div {
 | 
			
		||||
    right:-20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* this is level based; added for #8 levels, if you need more ... add them as needed */
 | 
			
		||||
.aciTree[dir=rtl] .aciTreeLi.aciTreeLevel0 .aciTreePlaceholder div { margin-right:40px; }
 | 
			
		||||
.aciTree[dir=rtl] .aciTreeLi.aciTreeLevel1 .aciTreePlaceholder div { margin-right:60px; }
 | 
			
		||||
.aciTree[dir=rtl] .aciTreeLi.aciTreeLevel2 .aciTreePlaceholder div { margin-right:80px; }
 | 
			
		||||
.aciTree[dir=rtl] .aciTreeLi.aciTreeLevel3 .aciTreePlaceholder div { margin-right:100px; }
 | 
			
		||||
.aciTree[dir=rtl] .aciTreeLi.aciTreeLevel4 .aciTreePlaceholder div { margin-right:120px; }
 | 
			
		||||
.aciTree[dir=rtl] .aciTreeLi.aciTreeLevel5 .aciTreePlaceholder div { margin-right:140px; }
 | 
			
		||||
.aciTree[dir=rtl] .aciTreeLi.aciTreeLevel6 .aciTreePlaceholder div { margin-right:160px; }
 | 
			
		||||
.aciTree[dir=rtl] .aciTreeLi.aciTreeLevel7 .aciTreePlaceholder div { margin-right:180px; }
 | 
			
		||||
.aciTree[dir=rtl] .aciTreeLi.aciTreeLevel8 .aciTreePlaceholder div { margin-right:200px; }
 | 
			
		||||
 | 
			
		||||
.aciTreeHelper {
 | 
			
		||||
    position:absolute;
 | 
			
		||||
    max-width:300px;
 | 
			
		||||
    color:#000;
 | 
			
		||||
    background-color:#d0e5fe;
 | 
			
		||||
    border:1px dashed #84acdd;
 | 
			
		||||
    -webkit-border-radius:3px;
 | 
			
		||||
    -moz-border-radius:3px;
 | 
			
		||||
    border-radius:3px;
 | 
			
		||||
    padding:4px;
 | 
			
		||||
    margin:20px 0 0 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* default - item in the middle (comment the hover part to keep the same button image) */
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeButton, .aciTree .aciTreePush {
 | 
			
		||||
    width:18px;
 | 
			
		||||
    background:url(../image/tree-small.png) -7px -35px no-repeat;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeBig .aciTreeButton, .aciTree.aciTreeBig .aciTreePush {
 | 
			
		||||
    background:url(../image/tree-big.png) -7px -35px no-repeat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree[dir=rtl] .aciTreeButton, .aciTree[dir=rtl] .aciTreePush {
 | 
			
		||||
    background:url(../image/tree-small-rtl.png) -7px -35px no-repeat;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeBig[dir=rtl] .aciTreeButton, .aciTree.aciTreeBig[dir=rtl] .aciTreePush {
 | 
			
		||||
    background:url(../image/tree-big-rtl.png) -7px -35px no-repeat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree.aciTreeArrow .aciTreeButton, .aciTree.aciTreeArrow .aciTreePush {
 | 
			
		||||
    background:url(../image/tree-arrow-small.png) -7px -35px no-repeat;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeBig.aciTreeArrow .aciTreeButton, .aciTree.aciTreeBig.aciTreeArrow .aciTreePush {
 | 
			
		||||
    background:url(../image/tree-arrow-big.png) -7px -35px no-repeat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree.aciTreeArrow[dir=rtl] .aciTreeButton, .aciTree.aciTreeArrow[dir=rtl] .aciTreePush {
 | 
			
		||||
    background:url(../image/tree-arrow-small-rtl.png) -7px -35px no-repeat;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeBig.aciTreeArrow[dir=rtl] .aciTreeButton, .aciTree.aciTreeBig.aciTreeArrow[dir=rtl] .aciTreePush {
 | 
			
		||||
    background:url(../image/tree-arrow-big-rtl.png) -7px -35px no-repeat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree.aciTreeNoBranches .aciTreeButton,
 | 
			
		||||
.aciTree .aciTreeLeaf>.aciTreeLine .aciTreePush { background:none !important; }
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeInodeMaybe>.aciTreeLine .aciTreePush { background-position:-67px -5px !important; }
 | 
			
		||||
.aciTree .aciTreeInodeMaybe>.aciTreeLine .aciTreePush.aciTreeHover { background-position:-67px -35px !important; }
 | 
			
		||||
.aciTree .aciTreeInode>.aciTreeLine .aciTreePush { background-position:-97px -5px !important; }
 | 
			
		||||
.aciTree .aciTreeInode>.aciTreeLine .aciTreePush.aciTreeHover { background-position:-97px -35px !important; }
 | 
			
		||||
.aciTree .aciTreeOpen>.aciTreeLine .aciTreePush { background-position:-127px -5px !important; }
 | 
			
		||||
.aciTree .aciTreeOpen>.aciTreeLine .aciTreePush.aciTreeHover { background-position:-127px -35px !important; }
 | 
			
		||||
 | 
			
		||||
/* if it's the last item in list */
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeLi.aciTreeLast>.aciTreeLine .aciTreeButton { background-position:-37px -5px !important; }
 | 
			
		||||
 | 
			
		||||
/* the item loader */
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreePush>span {
 | 
			
		||||
    display:none;
 | 
			
		||||
    position:absolute;
 | 
			
		||||
    width:18px;
 | 
			
		||||
    height:18px;
 | 
			
		||||
    left:0;
 | 
			
		||||
    top:2px;
 | 
			
		||||
    background:url(../image/load-node.gif) 0 0 no-repeat;
 | 
			
		||||
}
 | 
			
		||||
.aciTree .aciTreeLoad>.aciTreeLine .aciTreePush {
 | 
			
		||||
    position:relative;
 | 
			
		||||
    /* uncomment next line to hide the button while loading */
 | 
			
		||||
    /*background:none !important;*/
 | 
			
		||||
}
 | 
			
		||||
.aciTree .aciTreeLoad>.aciTreeLine .aciTreePush>span {
 | 
			
		||||
    display:inline-block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* tree item icon */
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeIcon {
 | 
			
		||||
    width:20px;
 | 
			
		||||
    background:url(../image/tree-small.png) 0 0 no-repeat;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeBig .aciTreeIcon {
 | 
			
		||||
    background:url(../image/tree-big.png) 0 0 no-repeat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree[dir=rtl] .aciTreeIcon {
 | 
			
		||||
    width:16px;
 | 
			
		||||
    margin-left:4px;
 | 
			
		||||
    background:url(../image/tree-small-rtl.png) 0 0 no-repeat;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeBig[dir=rtl] .aciTreeIcon {
 | 
			
		||||
    background:url(../image/tree-big-rtl.png) 0 0 no-repeat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree.aciTreeArrow .aciTreeIcon { background:url(../image/tree-arrow-small.png) 0 0 no-repeat; }
 | 
			
		||||
.aciTree.aciTreeBig.aciTreeArrow .aciTreeIcon { background:url(../image/tree-arrow-big.png) 0 0 no-repeat; }
 | 
			
		||||
 | 
			
		||||
.aciTree.aciTreeArrow[dir=rtl] .aciTreeIcon { background:url(../image/tree-arrow-small-rtl.png) 0 0 no-repeat; }
 | 
			
		||||
.aciTree.aciTreeBig.aciTreeArrow[dir=rtl] .aciTreeIcon { background:url(../image/tree-arrow-big-rtl.png) 0 0 no-repeat; }
 | 
			
		||||
 | 
			
		||||
/* demo file/folder icon class */
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeIcon.folder {
 | 
			
		||||
    background-position:-157px -5px !important;
 | 
			
		||||
}
 | 
			
		||||
.aciTree .aciTreeLine.aciTreeHover .aciTreeIcon.folder {
 | 
			
		||||
    /* comment next line to keep the same icon on hover */
 | 
			
		||||
    background-position:-157px -35px !important;
 | 
			
		||||
}
 | 
			
		||||
.aciTree .aciTreeIcon.file {
 | 
			
		||||
    background-position:-187px -5px !important;
 | 
			
		||||
}
 | 
			
		||||
.aciTree .aciTreeLine.aciTreeHover .aciTreeIcon.file {
 | 
			
		||||
    /* comment next line to keep the same icon on hover */
 | 
			
		||||
    background-position:-187px -35px !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* demo row colors */
 | 
			
		||||
 | 
			
		||||
.aciTree.aciTreeColors .aciTreeOdd>.aciTreeLine {
 | 
			
		||||
    /* odd rows */
 | 
			
		||||
    background-color:#FFFFC4;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeColors .aciTreeEven>.aciTreeLine {
 | 
			
		||||
    /* even rows */
 | 
			
		||||
    background-color:#CAFFCA;
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeColors .aciTreeFirst>.aciTreeLine {
 | 
			
		||||
    /* first item on each level */
 | 
			
		||||
    /*background-color:#B0DFFF;*/
 | 
			
		||||
}
 | 
			
		||||
.aciTree.aciTreeColors .aciTreeLast>.aciTreeLine {
 | 
			
		||||
    /* last item on each level */
 | 
			
		||||
    /*background-color:#FFCEFF;*/
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* uncomment below to keep the item in one line and scroll the tree horizontally when needed */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeEntry {
 | 
			
		||||
    overflow:visible;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.aciTree .aciTreeItem {
 | 
			
		||||
    white-space:nowrap;
 | 
			
		||||
    margin-right:12px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
| 
		 After Width: | Height: | Size: 982 B  | 
| 
		 After Width: | Height: | Size: 908 B  | 
| 
		 After Width: | Height: | Size: 10 KiB  | 
| 
		 After Width: | Height: | Size: 1.7 KiB  | 
| 
		 After Width: | Height: | Size: 8.6 KiB  | 
| 
		 After Width: | Height: | Size: 3.8 KiB  | 
| 
		 After Width: | Height: | Size: 3.7 KiB  | 
| 
		 After Width: | Height: | Size: 2.7 KiB  | 
| 
		 After Width: | Height: | Size: 2.5 KiB  | 
| 
		 After Width: | Height: | Size: 3.7 KiB  | 
| 
		 After Width: | Height: | Size: 3.6 KiB  | 
| 
		 After Width: | Height: | Size: 235 B  | 
| 
		 After Width: | Height: | Size: 7.9 KiB  | 
| 
		 After Width: | Height: | Size: 7.6 KiB  | 
| 
		 After Width: | Height: | Size: 3.9 KiB  | 
| 
		 After Width: | Height: | Size: 3.6 KiB  | 
| 
		 After Width: | Height: | Size: 2.3 KiB  | 
| 
		 After Width: | Height: | Size: 2.3 KiB  | 
| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
 | 
			
		||||
/*
 | 
			
		||||
 * aciFragment jQuery Plugin v1.1.0
 | 
			
		||||
 * http://acoderinsights.ro
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2013 Dragos Ursu
 | 
			
		||||
 * Dual licensed under the MIT or GPL Version 2 licenses.
 | 
			
		||||
 *
 | 
			
		||||
 * Require jQuery Library >= v1.7.1 http://jquery.com
 | 
			
		||||
 * + aciPlugin >= v1.1.1 https://github.com/dragosu/jquery-aciPlugin
 | 
			
		||||
 *
 | 
			
		||||
 * Date: Apr Fri 26 18:00 2013 +0200
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function(e,t,n){var r={anchor:"anchor",poolDelay:250,scroll:{duration:"medium",easing:"linear"}};var i={__extend:function(){e.extend(this._instance,{lastHash:null,lastParsed:null,parsed:{},anchor:true,timeOut:null,"native":"onhashchange"in t&&(t.document.documentMode===n||t.document.documentMode>7)})},init:function(){var n=this;if(this.wasInit()){return}if(this._instance.native){e(t).bind("hashchange"+this._instance.nameSpace,function(){n._trigger()})}else{this._change()}this._instance.anchor=true;this._trigger();this._super()},_trigger:function(){this._instance.jQuery.trigger("acifragment",[this,this._instance.anchor]);this._instance.anchor=false},_change:function(){var e=this;var n=t.location.hash;if(n!=this._instance.lastHash){this._trigger();this._instance.lastHash=n}this._instance.timeOut=t.setTimeout(function(){e._change()},this._instance.options.poolDelay)},scroll:function(){var n=this.get(this._instance.options.anchor);if(n&&n.length){var r=e("#"+n+":first");if(!r.length){r=e('[name="'+n+'"]:first')}if(r.length){var i=r.get(0).getBoundingClientRect();var s=e(t).scrollLeft()+i.left,o=e(t).scrollTop()+i.top;if(this._instance.options.scroll){e("html,body").stop(true).animate({scrollLeft:s,scrollTop:o},this._instance.options.scroll)}else{t.scrollTo(s,o)}}}},click:function(e,t){var n=e.attr("href");if(n){var r=this.parse(n);this.update(r);if(t&&this.hasAnchor(r)){this.scroll()}}},parse:function(e){var n=e.indexOf("#"),r={};if(n!=-1){e=e.substr(n+1);var i=e.split("&"),s;for(var o in i){s=i[o].split("=");if(s.length>1){r[t.decodeURIComponent(s[0])]=t.decodeURIComponent(s[1])}else{r[this._instance.options.anchor]=t.decodeURIComponent(s[0])}}}return r},hasAnchor:function(e){return e[this._instance.options.anchor]&&e[this._instance.options.anchor].length>0},setAnchor:function(e){this.set(this._instance.options.anchor,e)},getAnchor:function(e){return this.get(this._instance.options.anchor,e)},parseHash:function(){var e=t.location.hash;if(e==this._instance.lastParsed){return this._instance.parsed}var n=this.parse(e);this._instance.parsed=n;this._instance.lastParsed=e;return n},get:function(e,r){var i=this.parseHash();if(i[e]!==null&&i[e]!==n&&t.String(i[e]).length){return i[e]}else{return r}},replace:function(e,r){var i=[];for(var s in e){if(e[s]!==null&&e[s]!==n&&t.String(e[s]).length){i[i.length]=t.encodeURIComponent(s)+"="+t.encodeURIComponent(e[s])}}if(!r&&this.hasAnchor(e)){this._instance.anchor=true}var o=t.location.hash;if(i.length){t.location.hash="#"+i.join("&")}else if(t.history&&t.history.pushState){t.history.pushState("",t.document.title,t.location.pathname+t.location.search)}else{t.location.hash=""}if(t.location.hash==o){this._trigger()}},update:function(e){var t=this.parseHash();for(var n in e){t[n]=e[n]}if(this.hasAnchor(e)){this._instance.anchor=true}this.replace(t,true)},set:function(e,t){var n=this.parseHash();n[e]=t;if(e==this._instance.options.anchor){this._instance.anchor=true}this.replace(n,true)},destroy:function(){if(!this.wasInit()){return}if(this._instance.native){e(t).unbind(this._instance.nameSpace)}t.clearTimeout(this._instance.timeOut);this._super()}};aciPluginClass.plugins.aciFragment=aciPluginClass.aciPluginUi.extend(i,"aciFragment");aciPluginClass.publish("aciFragment",r)})(jQuery,this);
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
 | 
			
		||||
/*
 | 
			
		||||
 * aciPlugin little jQuery plugin helper v1.5.1
 | 
			
		||||
 * http://acoderinsights.ro
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2013 Dragos Ursu
 | 
			
		||||
 * Dual licensed under the MIT or GPL Version 2 licenses.
 | 
			
		||||
 *
 | 
			
		||||
 * Require jQuery Library >= v1.2.3 http://jquery.com
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function(d,c,e){if(typeof aciPluginClass!=="undefined"){return}var a;this.aciPluginClass=function(){};aciPluginClass.extend=function(g,j){i.extend=arguments.callee;function i(){if(a){this._instance={};return this.__construct.apply(this,arguments)}}a=false;i.prototype=new this();a=true;var h=this.prototype;for(var f in g){i.prototype[f]=((typeof g[f]=="function")&&(f!="proxy"))?(function(k){return function(){var p=this._parent;this._parent=h;var n=this._super;this._super=h[k];var o=this._private;if(this._instance&&j){var m=this._instance._private;if(m[j]===e){m[j]={nameSpace:"."+j}}this._private=m[j]}var l=g[k].apply(this,arguments);this._parent=p;this._super=n;this._private=o;return l}})(f):g[f]}return i};var b=0;aciPluginClass.aciPluginUi=aciPluginClass.extend({__construct:function(k,l,i,h,j){var f="."+k;var g=l.data(f);if(g){this._instance=g._instance;return g.__request(i,h,j)}l.data(f,this);d.extend(true,this._instance,{_private:{},nameSpace:f,jQuery:l,options:d.extend(true,{},d.fn[k].defaults,(typeof i=="object")?i:{}),index:b++,wasInit:false});this.__extend();return this.__request(i,h,j)},__extend:function(){},__request:function(g,f,h){if((g===e)||(typeof g=="object")){if(this._instance.options.autoInit){this.init()}}else{if(typeof g=="string"){switch(g){case"init":this.init();break;case"api":return{object:this};case"options":if(f===e){return{object:this.options()}}else{if(typeof f=="string"){return{object:this.options(f)}}else{this.options(f)}}break;case"option":this.option(f,h);break;case"destroy":this.destroy();break}}}return this._instance.jQuery},proxy:function(j,h){var m=c.Array.prototype.slice;var f=m.call(arguments,2);var i=this,g=i._parent,l=i._super,k=i._private;return function(){i._parent=g;i._super=l;i._private=k;return j.apply(i,h?f.concat([this],m.call(arguments)):f.concat(m.call(arguments)))}},init:function(){if(!this._instance.wasInit){this._instance.wasInit=true;return true}return false},wasInit:function(){return this._instance.wasInit},__parent:function(h,f,l){var m=f.split(".");if(m.length>1){var j=h,k;for(var g in m){k=j;j=j[m[g]]}l.name=m[g];return k}l.name=f;return h},options:function(f){if(f){var i={name:null};var h;if(typeof f=="string"){h=this.__parent(this._instance.options,f,i);return h[i.name]}else{for(var g in f){h=this.__parent(this._instance.options,g,i);h[i.name]=f[g]}}}else{return this._instance.options}},option:function(g,i){var h={name:null};var f=this.__parent(this._instance.options,g,h);f[h.name]=i},destroy:function(){if(this._instance.wasInit){this._instance.wasInit=false;this._instance.jQuery.removeData(this._instance.nameSpace);return true}return false}});aciPluginClass.plugins={};aciPluginClass.publish=function(f,g){d.fn[f]=function(j,m,n){var h=null;for(var l=0,k=this.length;l<k;l++){h=new aciPluginClass.plugins[f](f,d(this[l]),j,m,n);if(!(h instanceof d)){return h.object}}return this};d.fn[f].defaults=d.extend(true,{autoInit:true},(typeof g=="object")?g:{})};aciPluginClass.defaults=function(f,g){d.extend(true,d.fn[f].defaults,(typeof g=="object")?g:{})}})(jQuery,this);
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,483 @@
 | 
			
		|||
 | 
			
		||||
/*
 | 
			
		||||
 * aciTree jQuery Plugin v4.5.0-rc.7
 | 
			
		||||
 * http://acoderinsights.ro
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2014 Dragos Ursu
 | 
			
		||||
 * Dual licensed under the MIT or GPL Version 2 licenses.
 | 
			
		||||
 *
 | 
			
		||||
 * Require jQuery Library >= v1.9.0 http://jquery.com
 | 
			
		||||
 * + aciPlugin >= v1.5.1 https://github.com/dragosu/jquery-aciPlugin
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This extension adds checkbox support to aciTree,
 | 
			
		||||
 * should be used with the selectable extension.
 | 
			
		||||
 *
 | 
			
		||||
 * The are a few extra properties for the item data:
 | 
			
		||||
 *
 | 
			
		||||
 * {
 | 
			
		||||
 *   ...
 | 
			
		||||
 *   checkbox: true,                    // TRUE (default) means the item will have a checkbox (can be omitted if the `radio` extension is not used)
 | 
			
		||||
 *   checked: false,                    // if should be checked or not
 | 
			
		||||
 *   ...
 | 
			
		||||
 * }
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function($, window, undefined) {
 | 
			
		||||
 | 
			
		||||
    // extra default options
 | 
			
		||||
 | 
			
		||||
    var options = {
 | 
			
		||||
        checkbox: false,                // if TRUE then each item will have a checkbox
 | 
			
		||||
        checkboxChain: true,
 | 
			
		||||
        // if TRUE the selection will propagate to the parents/children
 | 
			
		||||
        // if -1 the selection will propagate only to parents
 | 
			
		||||
        // if +1 the selection will propagate only to children
 | 
			
		||||
        // if FALSE the selection will not propagate in any way
 | 
			
		||||
        checkboxBreak: true,            // if TRUE then a missing checkbox will break the chaining
 | 
			
		||||
        checkboxClick: false            // if TRUE then a click will trigger a state change only when made over the checkbox itself
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // aciTree checkbox extension
 | 
			
		||||
 | 
			
		||||
    var aciTree_checkbox = {
 | 
			
		||||
        // init checkbox
 | 
			
		||||
        _checkboxInit: function() {
 | 
			
		||||
            this._instance.jQuery.bind('acitree' + this._private.nameSpace, function(event, api, item, eventName, options) {
 | 
			
		||||
                switch (eventName) {
 | 
			
		||||
                    case 'loaded':
 | 
			
		||||
                        // check/update on item load
 | 
			
		||||
                        api._checkboxLoad(item);
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            }).bind('keydown' + this._private.nameSpace, this.proxy(function(e) {
 | 
			
		||||
                switch (e.which) {
 | 
			
		||||
                    case 32: // space
 | 
			
		||||
                        // support `selectable` extension
 | 
			
		||||
                        if (this.extSelectable && this.extSelectable() && !e.ctrlKey) {
 | 
			
		||||
                            var item = this.focused();
 | 
			
		||||
                            if (this.hasCheckbox(item) && this.isEnabled(item)) {
 | 
			
		||||
                                if (this.isChecked(item)) {
 | 
			
		||||
                                    this.uncheck(item);
 | 
			
		||||
                                } else {
 | 
			
		||||
                                    this.check(item);
 | 
			
		||||
                                }
 | 
			
		||||
                                e.stopImmediatePropagation();
 | 
			
		||||
                                // prevent page scroll
 | 
			
		||||
                                e.preventDefault();
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            })).on('click' + this._private.nameSpace, '.aciTreeItem', this.proxy(function(e) {
 | 
			
		||||
                if (!this._instance.options.checkboxClick || $(e.target).is('.aciTreeCheck')) {
 | 
			
		||||
                    var item = this.itemFrom(e.target);
 | 
			
		||||
                    if (this.hasCheckbox(item) && this.isEnabled(item) && (!this.extSelectable || !this.extSelectable() || (!e.ctrlKey && !e.shiftKey))) {
 | 
			
		||||
                        // change state on click
 | 
			
		||||
                        if (this.isChecked(item)) {
 | 
			
		||||
                            this.uncheck(item);
 | 
			
		||||
                        } else {
 | 
			
		||||
                            this.check(item);
 | 
			
		||||
                        }
 | 
			
		||||
                        e.preventDefault();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }));
 | 
			
		||||
        },
 | 
			
		||||
        // override `_initHook`
 | 
			
		||||
        _initHook: function() {
 | 
			
		||||
            if (this.extCheckbox()) {
 | 
			
		||||
                this._checkboxInit();
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super();
 | 
			
		||||
        },
 | 
			
		||||
        // override `_itemHook`
 | 
			
		||||
        _itemHook: function(parent, item, itemData, level) {
 | 
			
		||||
            if (this.extCheckbox()) {
 | 
			
		||||
                // support `radio` extension
 | 
			
		||||
                var radio = this.extRadio && this.hasRadio(item);
 | 
			
		||||
                if (!radio && (itemData.checkbox || ((itemData.checkbox === undefined) && (!this.extRadio || !this.extRadio())))) {
 | 
			
		||||
                    this._checkboxDOM.add(item, itemData);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super(parent, item, itemData, level);
 | 
			
		||||
        },
 | 
			
		||||
        // low level DOM functions
 | 
			
		||||
        _checkboxDOM: {
 | 
			
		||||
            // add item checkbox
 | 
			
		||||
            add: function(item, itemData) {
 | 
			
		||||
                domApi.addClass(item[0], itemData.checked ? ['aciTreeCheckbox', 'aciTreeChecked'] : 'aciTreeCheckbox');
 | 
			
		||||
                var text = domApi.childrenByClass(item[0].firstChild, 'aciTreeText');
 | 
			
		||||
                var parent = text.parentNode;
 | 
			
		||||
                var label = window.document.createElement('LABEL');
 | 
			
		||||
                var check = window.document.createElement('SPAN');
 | 
			
		||||
                check.className = 'aciTreeCheck';
 | 
			
		||||
                label.appendChild(check);
 | 
			
		||||
                label.appendChild(text);
 | 
			
		||||
                parent.appendChild(label);
 | 
			
		||||
                item[0].firstChild.setAttribute('aria-checked', !!itemData.checked);
 | 
			
		||||
            },
 | 
			
		||||
            // remove item checkbox
 | 
			
		||||
            remove: function(item) {
 | 
			
		||||
                domApi.removeClass(item[0], ['aciTreeCheckbox', 'aciTreeChecked', 'aciTreeTristate']);
 | 
			
		||||
                var text = domApi.childrenByClass(item[0].firstChild, 'aciTreeText');
 | 
			
		||||
                var label = text.parentNode;
 | 
			
		||||
                var parent = label.parentNode;
 | 
			
		||||
                parent.replaceChild(text, label)
 | 
			
		||||
                item[0].firstChild.removeAttribute('aria-checked');
 | 
			
		||||
            },
 | 
			
		||||
            // (un)check items
 | 
			
		||||
            check: function(items, state) {
 | 
			
		||||
                domApi.toggleListClass(items.toArray(), 'aciTreeChecked', state, function(node) {
 | 
			
		||||
                    node.firstChild.setAttribute('aria-checked', state);
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
            // (un)set tristate items
 | 
			
		||||
            tristate: function(items, state) {
 | 
			
		||||
                domApi.toggleListClass(items.toArray(), 'aciTreeTristate', state);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // update items on load, starting from the loaded node
 | 
			
		||||
        _checkboxLoad: function(item) {
 | 
			
		||||
            if (this._instance.options.checkboxChain === false) {
 | 
			
		||||
                // do not update on load
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            var state = undefined;
 | 
			
		||||
            if (this.hasCheckbox(item)) {
 | 
			
		||||
                if (this.isChecked(item)) {
 | 
			
		||||
                    if (!this.checkboxes(this.children(item, false, true), true).length) {
 | 
			
		||||
                        // the item is checked but no children are, check them all
 | 
			
		||||
                        state = true;
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    // the item is not checked, uncheck all children
 | 
			
		||||
                    state = false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            this._checkboxUpdate(item, state);
 | 
			
		||||
        },
 | 
			
		||||
        // get children list
 | 
			
		||||
        _checkboxChildren: function(item) {
 | 
			
		||||
            if (this._instance.options.checkboxBreak) {
 | 
			
		||||
                var list = [];
 | 
			
		||||
                var process = this.proxy(function(item) {
 | 
			
		||||
                    var children = this.children(item, false, true);
 | 
			
		||||
                    children.each(this.proxy(function(element) {
 | 
			
		||||
                        var item = $(element);
 | 
			
		||||
                        // break on missing checkbox
 | 
			
		||||
                        if (this.hasCheckbox(item)) {
 | 
			
		||||
                            list.push(element);
 | 
			
		||||
                            process(item);
 | 
			
		||||
                        }
 | 
			
		||||
                    }, true));
 | 
			
		||||
                });
 | 
			
		||||
                process(item);
 | 
			
		||||
                return $(list);
 | 
			
		||||
            } else {
 | 
			
		||||
                var children = this.children(item, true, true);
 | 
			
		||||
                return this.checkboxes(children);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // update checkbox state
 | 
			
		||||
        _checkboxUpdate: function(item, state) {
 | 
			
		||||
            // update children
 | 
			
		||||
            var checkDown = this.proxy(function(item, count, state) {
 | 
			
		||||
                var children = this.children(item, false, true);
 | 
			
		||||
                var total = 0;
 | 
			
		||||
                var checked = 0;
 | 
			
		||||
                children.each(this.proxy(function(element) {
 | 
			
		||||
                    var item = $(element);
 | 
			
		||||
                    var subCount = {
 | 
			
		||||
                        total: 0,
 | 
			
		||||
                        checked: 0
 | 
			
		||||
                    };
 | 
			
		||||
                    if (this.hasCheckbox(item)) {
 | 
			
		||||
                        if ((state !== undefined) && (this._instance.options.checkboxChain !== -1)) {
 | 
			
		||||
                            this._checkboxDOM.check(item, state);
 | 
			
		||||
                        }
 | 
			
		||||
                        total++;
 | 
			
		||||
                        if (this.isChecked(item)) {
 | 
			
		||||
                            checked++;
 | 
			
		||||
                        }
 | 
			
		||||
                        checkDown(item, subCount, state);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        if (this._instance.options.checkboxBreak) {
 | 
			
		||||
                            var reCount = {
 | 
			
		||||
                                total: 0,
 | 
			
		||||
                                checked: 0
 | 
			
		||||
                            };
 | 
			
		||||
                            checkDown(item, reCount);
 | 
			
		||||
                        } else {
 | 
			
		||||
                            checkDown(item, subCount, state);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    total += subCount.total;
 | 
			
		||||
                    checked += subCount.checked;
 | 
			
		||||
                }, true));
 | 
			
		||||
                if (item) {
 | 
			
		||||
                    this._checkboxDOM.tristate(item, (checked > 0) && (checked != total));
 | 
			
		||||
                    count.total += total;
 | 
			
		||||
                    count.checked += checked;
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            var count = {
 | 
			
		||||
                total: 0,
 | 
			
		||||
                checked: 0
 | 
			
		||||
            };
 | 
			
		||||
            checkDown(item, count, state);
 | 
			
		||||
            // update parents
 | 
			
		||||
            var checkUp = this.proxy(function(item, tristate, state) {
 | 
			
		||||
                var parent = this.parent(item);
 | 
			
		||||
                if (parent.length) {
 | 
			
		||||
                    if (!tristate) {
 | 
			
		||||
                        var children = this._checkboxChildren(parent);
 | 
			
		||||
                        var checked = this.checkboxes(children, true).length;
 | 
			
		||||
                        var tristate = (checked > 0) && (checked != children.length);
 | 
			
		||||
                    }
 | 
			
		||||
                    if (this.hasCheckbox(parent)) {
 | 
			
		||||
                        if ((state !== undefined) && (this._instance.options.checkboxChain !== 1)) {
 | 
			
		||||
                            this._checkboxDOM.check(parent, tristate ? true : state);
 | 
			
		||||
                        }
 | 
			
		||||
                        this._checkboxDOM.tristate(parent, tristate);
 | 
			
		||||
                        checkUp(parent, tristate, state);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        if (this._instance.options.checkboxBreak) {
 | 
			
		||||
                            checkUp(parent);
 | 
			
		||||
                        } else {
 | 
			
		||||
                            checkUp(parent, tristate, state);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            checkUp(item, undefined, state);
 | 
			
		||||
        },
 | 
			
		||||
        // test if item have a checkbox
 | 
			
		||||
        hasCheckbox: function(item) {
 | 
			
		||||
            return item && domApi.hasClass(item[0], 'aciTreeCheckbox');
 | 
			
		||||
        },
 | 
			
		||||
        // add checkbox
 | 
			
		||||
        addCheckbox: function(item, options) {
 | 
			
		||||
            options = this._options(options, 'checkboxadded', 'addcheckboxfail', 'wascheckbox', item);
 | 
			
		||||
            if (this.isItem(item)) {
 | 
			
		||||
                // a way to cancel the operation
 | 
			
		||||
                if (!this._trigger(item, 'beforeaddcheckbox', options)) {
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                if (this.hasCheckbox(item)) {
 | 
			
		||||
                    this._notify(item, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    var process = function() {
 | 
			
		||||
                        this._checkboxDOM.add(item, {
 | 
			
		||||
                        });
 | 
			
		||||
                        this._success(item, options);
 | 
			
		||||
                    };
 | 
			
		||||
                    // support `radio` extension
 | 
			
		||||
                    if (this.extRadio && this.hasRadio(item)) {
 | 
			
		||||
                        // remove radio first
 | 
			
		||||
                        this.removeRadio(item, this._inner(options, {
 | 
			
		||||
                            success: process,
 | 
			
		||||
                            fail: options.fail
 | 
			
		||||
                        }));
 | 
			
		||||
                    } else {
 | 
			
		||||
                        process.apply(this);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                this._fail(item, options);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // remove checkbox
 | 
			
		||||
        removeCheckbox: function(item, options) {
 | 
			
		||||
            options = this._options(options, 'checkboxremoved', 'removecheckboxfail', 'notcheckbox', item);
 | 
			
		||||
            if (this.isItem(item)) {
 | 
			
		||||
                // a way to cancel the operation
 | 
			
		||||
                if (!this._trigger(item, 'beforeremovecheckbox', options)) {
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                if (this.hasCheckbox(item)) {
 | 
			
		||||
                    this._checkboxDOM.remove(item);
 | 
			
		||||
                    this._success(item, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._notify(item, options);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                this._fail(item, options);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // test if it's checked
 | 
			
		||||
        isChecked: function(item) {
 | 
			
		||||
            if (this.hasCheckbox(item)) {
 | 
			
		||||
                return domApi.hasClass(item[0], 'aciTreeChecked');
 | 
			
		||||
            }
 | 
			
		||||
            // support `radio` extension
 | 
			
		||||
            if (this._super) {
 | 
			
		||||
                // call the parent
 | 
			
		||||
                return this._super(item);
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        },
 | 
			
		||||
        // check checkbox
 | 
			
		||||
        check: function(item, options) {
 | 
			
		||||
            if (this.extCheckbox && this.hasCheckbox(item)) {
 | 
			
		||||
                options = this._options(options, 'checked', 'checkfail', 'waschecked', item);
 | 
			
		||||
                // a way to cancel the operation
 | 
			
		||||
                if (!this._trigger(item, 'beforecheck', options)) {
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                if (this.isChecked(item)) {
 | 
			
		||||
                    this._notify(item, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._checkboxDOM.check(item, true);
 | 
			
		||||
                    if (this._instance.options.checkboxChain !== false) {
 | 
			
		||||
                        // chain them
 | 
			
		||||
                        this._checkboxUpdate(item, true);
 | 
			
		||||
                    }
 | 
			
		||||
                    this._success(item, options);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                // support `radio` extension
 | 
			
		||||
                if (this._super) {
 | 
			
		||||
                    // call the parent
 | 
			
		||||
                    this._super(item, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._trigger(item, 'checkfail', options);
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // uncheck checkbox
 | 
			
		||||
        uncheck: function(item, options) {
 | 
			
		||||
            if (this.extCheckbox && this.hasCheckbox(item)) {
 | 
			
		||||
                options = this._options(options, 'unchecked', 'uncheckfail', 'notchecked', item);
 | 
			
		||||
                // a way to cancel the operation
 | 
			
		||||
                if (!this._trigger(item, 'beforeuncheck', options)) {
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                if (this.isChecked(item)) {
 | 
			
		||||
                    this._checkboxDOM.check(item, false);
 | 
			
		||||
                    if (this._instance.options.checkboxChain !== false) {
 | 
			
		||||
                        // chain them
 | 
			
		||||
                        this._checkboxUpdate(item, false);
 | 
			
		||||
                    }
 | 
			
		||||
                    this._success(item, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._notify(item, options);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                // support `radio` extension
 | 
			
		||||
                if (this._super) {
 | 
			
		||||
                    // call the parent
 | 
			
		||||
                    this._super(item, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._trigger(item, 'uncheckfail', options);
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // filter items with checkbox by state (if set)
 | 
			
		||||
        checkboxes: function(items, state) {
 | 
			
		||||
            if (state !== undefined) {
 | 
			
		||||
                return $(domApi.withClass(items.toArray(), state ? ['aciTreeCheckbox', 'aciTreeChecked'] : 'aciTreeCheckbox', state ? null : 'aciTreeChecked'));
 | 
			
		||||
            }
 | 
			
		||||
            return $(domApi.withClass(items.toArray(), 'aciTreeCheckbox'));
 | 
			
		||||
        },
 | 
			
		||||
        // override `_serialize`
 | 
			
		||||
        _serialize: function(item, callback) {
 | 
			
		||||
            var data = this._super(item, callback);
 | 
			
		||||
            if (data && this.extCheckbox()) {
 | 
			
		||||
                if (data.hasOwnProperty('checkbox')) {
 | 
			
		||||
                    data.checkbox = this.hasCheckbox(item);
 | 
			
		||||
                    data.checked = this.isChecked(item);
 | 
			
		||||
                } else if (this.hasCheckbox(item)) {
 | 
			
		||||
                    if (this.extRadio && this.extRadio()) {
 | 
			
		||||
                        data.checkbox = true;
 | 
			
		||||
                    }
 | 
			
		||||
                    data.checked = this.isChecked(item);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return data;
 | 
			
		||||
        },
 | 
			
		||||
        // override `serialize`
 | 
			
		||||
        serialize: function(item, what, callback) {
 | 
			
		||||
            if (what == 'checkbox') {
 | 
			
		||||
                var serialized = '';
 | 
			
		||||
                var children = this.children(item, true, true);
 | 
			
		||||
                this.checkboxes(children, true).each(this.proxy(function(element) {
 | 
			
		||||
                    var item = $(element);
 | 
			
		||||
                    if (callback) {
 | 
			
		||||
                        serialized += callback.call(this, item, what, this.getId(item));
 | 
			
		||||
                    } else {
 | 
			
		||||
                        serialized += this._instance.options.serialize.call(this, item, what, this.getId(item));
 | 
			
		||||
                    }
 | 
			
		||||
                }, true));
 | 
			
		||||
                return serialized;
 | 
			
		||||
            }
 | 
			
		||||
            return this._super(item, what, callback);
 | 
			
		||||
        },
 | 
			
		||||
        // test if item is in tristate
 | 
			
		||||
        isTristate: function(item) {
 | 
			
		||||
            return item && domApi.hasClass(item[0], 'aciTreeTristate');
 | 
			
		||||
        },
 | 
			
		||||
        // filter tristate items
 | 
			
		||||
        tristate: function(items) {
 | 
			
		||||
            return $(domApi.withClass(items.toArray(), 'aciTreeTristate'));
 | 
			
		||||
        },
 | 
			
		||||
        // test if checkbox is enabled
 | 
			
		||||
        extCheckbox: function() {
 | 
			
		||||
            return this._instance.options.checkbox;
 | 
			
		||||
        },
 | 
			
		||||
        // override set `option`
 | 
			
		||||
        option: function(option, value) {
 | 
			
		||||
            if (this.wasInit() && !this.isLocked()) {
 | 
			
		||||
                if ((option == 'checkbox') && (value != this.extCheckbox())) {
 | 
			
		||||
                    if (value) {
 | 
			
		||||
                        this._checkboxInit();
 | 
			
		||||
                    } else {
 | 
			
		||||
                        this._checkboxDone();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super(option, value);
 | 
			
		||||
        },
 | 
			
		||||
        // done checkbox
 | 
			
		||||
        _checkboxDone: function(destroy) {
 | 
			
		||||
            this._instance.jQuery.unbind(this._private.nameSpace);
 | 
			
		||||
            this._instance.jQuery.off(this._private.nameSpace, '.aciTreeItem');
 | 
			
		||||
            if (!destroy) {
 | 
			
		||||
                // remove checkboxes
 | 
			
		||||
                this.checkboxes(this.children(null, true, true)).each(this.proxy(function(element) {
 | 
			
		||||
                    this.removeCheckbox($(element));
 | 
			
		||||
                }, true));
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // override `_destroyHook`
 | 
			
		||||
        _destroyHook: function(unloaded) {
 | 
			
		||||
            if (unloaded) {
 | 
			
		||||
                this._checkboxDone(true);
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super(unloaded);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // extend the base aciTree class and add the checkbox stuff
 | 
			
		||||
    aciPluginClass.plugins.aciTree = aciPluginClass.plugins.aciTree.extend(aciTree_checkbox, 'aciTreeCheckbox');
 | 
			
		||||
 | 
			
		||||
    // add extra default options
 | 
			
		||||
    aciPluginClass.defaults('aciTree', options);
 | 
			
		||||
 | 
			
		||||
    // for internal access
 | 
			
		||||
    var domApi = aciPluginClass.plugins.aciTree_dom;
 | 
			
		||||
 | 
			
		||||
})(jQuery, this);
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,250 @@
 | 
			
		|||
 | 
			
		||||
/*
 | 
			
		||||
 * aciTree jQuery Plugin v4.5.0-rc.7
 | 
			
		||||
 * http://acoderinsights.ro
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2014 Dragos Ursu
 | 
			
		||||
 * Dual licensed under the MIT or GPL Version 2 licenses.
 | 
			
		||||
 *
 | 
			
		||||
 * Require jQuery Library >= v1.9.0 http://jquery.com
 | 
			
		||||
 * + aciPlugin >= v1.5.1 https://github.com/dragosu/jquery-aciPlugin
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This extension adds multiple column support to aciTree.
 | 
			
		||||
 *
 | 
			
		||||
 * The `columnData` option is used to tell what are the columns and show one or
 | 
			
		||||
 * more values that will be read from the item data object.
 | 
			
		||||
 *
 | 
			
		||||
 * Column data is an array of column definitions, each column definition is
 | 
			
		||||
 * an object:
 | 
			
		||||
 *
 | 
			
		||||
 * {
 | 
			
		||||
 *   width: 100,
 | 
			
		||||
 *   props: 'column_x',
 | 
			
		||||
 *   value: 'default'
 | 
			
		||||
 * }
 | 
			
		||||
 *
 | 
			
		||||
 * where the `width` is the column width in [px], if undefined - then the value
 | 
			
		||||
 * from the CSS will be used; the `props` is the property name that will be
 | 
			
		||||
 * read from the item data, if undefined (or the `item-data[column.props]`
 | 
			
		||||
 * is undefined) then a default value will be set for the column: the `value`.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function($, window, undefined) {
 | 
			
		||||
 | 
			
		||||
    // extra default options
 | 
			
		||||
 | 
			
		||||
    var options = {
 | 
			
		||||
        columnData: []                  // column definitions list
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // aciTree columns extension
 | 
			
		||||
    // adds item columns, set width with CSS or using the API
 | 
			
		||||
 | 
			
		||||
    var aciTree_column = {
 | 
			
		||||
        __extend: function() {
 | 
			
		||||
            // add extra data
 | 
			
		||||
            $.extend(this._private, {
 | 
			
		||||
                propsIndex: { // column index cache
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super();
 | 
			
		||||
        },
 | 
			
		||||
        // override `_initHook`
 | 
			
		||||
        _initHook: function() {
 | 
			
		||||
            if (this._instance.options.columnData.length) {
 | 
			
		||||
                // check column width
 | 
			
		||||
                var found = false, data;
 | 
			
		||||
                for (var i in this._instance.options.columnData) {
 | 
			
		||||
                    data = this._instance.options.columnData[i];
 | 
			
		||||
                    if (data.width !== undefined) {
 | 
			
		||||
                        // update column width
 | 
			
		||||
                        this._updateCss('.aciTree.aciTree' + this._instance.index + ' .aciTreeColumn' + i, 'width:' + data.width + 'px;');
 | 
			
		||||
                        found = true;
 | 
			
		||||
                    }
 | 
			
		||||
                    this._private.propsIndex[data.props] = i;
 | 
			
		||||
                }
 | 
			
		||||
                if (found) {
 | 
			
		||||
                    // at least a column width set
 | 
			
		||||
                    this._updateWidth();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super();
 | 
			
		||||
        },
 | 
			
		||||
        // read property value from a CSS class name
 | 
			
		||||
        _getCss: function(className, property, numeric) {
 | 
			
		||||
            var id = '_getCss_' + window.String(className).replace(/[^a-z0-9_-]/ig, '_');
 | 
			
		||||
            var test = $('body').find('#' + id);
 | 
			
		||||
            if (!test.length) {
 | 
			
		||||
                if (className instanceof Array) {
 | 
			
		||||
                    var style = '', end = '';
 | 
			
		||||
                    for (var i in className) {
 | 
			
		||||
                        style += '<div class="' + className[i] + '">';
 | 
			
		||||
                        end += '</div>';
 | 
			
		||||
                    }
 | 
			
		||||
                    style += end;
 | 
			
		||||
                } else {
 | 
			
		||||
                    var style = '<div class="' + className + '"></div>';
 | 
			
		||||
                }
 | 
			
		||||
                $('body').append('<div id="' + id + '" style="position:relative;display:inline-block;width:0px;height:0px;line-height:0px;overflow:hidden">' + style + '</div>');
 | 
			
		||||
                test = $('body').find('#' + id);
 | 
			
		||||
            }
 | 
			
		||||
            var value = test.find('*:last').css(property);
 | 
			
		||||
            if (numeric) {
 | 
			
		||||
                value = parseInt(value);
 | 
			
		||||
                if (isNaN(value)) {
 | 
			
		||||
                    value = null;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return value;
 | 
			
		||||
        },
 | 
			
		||||
        // dynamically change a CSS class definition
 | 
			
		||||
        _updateCss: function(className, definition) {
 | 
			
		||||
            var id = '_updateCss_' + window.String(className).replace('>', '_gt_').replace(/[^a-z0-9_-]/ig, '_');
 | 
			
		||||
            var style = '<style id="' + id + '" type="text/css">' + className + '{' + definition + '}</style>';
 | 
			
		||||
            var test = $('body').find('#' + id);
 | 
			
		||||
            if (test.length) {
 | 
			
		||||
                test.replaceWith(style);
 | 
			
		||||
            } else {
 | 
			
		||||
                $('body').prepend(style);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // get column width
 | 
			
		||||
        // `index` is the #0 based column index
 | 
			
		||||
        getWidth: function(index) {
 | 
			
		||||
            if ((index >= 0) && (index < this.columns())) {
 | 
			
		||||
                return this._getCss(['aciTree aciTree' + this._instance.index, 'aciTreeColumn' + index], 'width', true);
 | 
			
		||||
            }
 | 
			
		||||
            return null;
 | 
			
		||||
        },
 | 
			
		||||
        // set column width
 | 
			
		||||
        // `index` is the #0 based column index
 | 
			
		||||
        setWidth: function(index, width) {
 | 
			
		||||
            if ((index >= 0) && (index < this.columns())) {
 | 
			
		||||
                this._updateCss('.aciTree.aciTree' + this._instance.index + ' .aciTreeColumn' + index, 'width:' + width + 'px;');
 | 
			
		||||
                this._updateWidth();
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // update item margins
 | 
			
		||||
        _updateWidth: function() {
 | 
			
		||||
            var width = 0;
 | 
			
		||||
            for (var i in this._instance.options.columnData) {
 | 
			
		||||
                if (this.isColumn(i)) {
 | 
			
		||||
                    width += this.getWidth(i);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            var icon = this._getCss(['aciTree', 'aciTreeIcon'], 'width', true);
 | 
			
		||||
            // add item padding
 | 
			
		||||
            width += this._getCss(['aciTree', 'aciTreeItem'], 'padding-left', true) + this._getCss(['aciTree', 'aciTreeItem'], 'padding-right', true);
 | 
			
		||||
            this._updateCss('.aciTree.aciTree' + this._instance.index + ' .aciTreeItem', 'margin-right:' + (icon + width) + 'px;');
 | 
			
		||||
            this._updateCss('.aciTree[dir=rtl].aciTree' + this._instance.index + ' .aciTreeItem', 'margin-right:0;margin-left:' + (icon + width) + 'px;');
 | 
			
		||||
        },
 | 
			
		||||
        // test if column is visible
 | 
			
		||||
        // `index` is the #0 based column index
 | 
			
		||||
        isColumn: function(index) {
 | 
			
		||||
            if ((index >= 0) && (index < this.columns())) {
 | 
			
		||||
                return this._getCss(['aciTree aciTree' + this._instance.index, 'aciTreeColumn' + index], 'display') != 'none';
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        },
 | 
			
		||||
        // get column index by `props`
 | 
			
		||||
        // return -1 if the column does not exists
 | 
			
		||||
        columnIndex: function(props) {
 | 
			
		||||
            if (this._private.propsIndex[props] !== undefined) {
 | 
			
		||||
                return this._private.propsIndex[props];
 | 
			
		||||
            }
 | 
			
		||||
            return -1;
 | 
			
		||||
        },
 | 
			
		||||
        // get the column count
 | 
			
		||||
        columns: function() {
 | 
			
		||||
            return this._instance.options.columnData.length;
 | 
			
		||||
        },
 | 
			
		||||
        // set column to be visible or hidden
 | 
			
		||||
        // `index` is the #0 based column index
 | 
			
		||||
        // if `show` is undefined then the column visibility will be toggled
 | 
			
		||||
        toggleColumn: function(index, show) {
 | 
			
		||||
            if ((index >= 0) && (index < this.columns())) {
 | 
			
		||||
                if (show === undefined) {
 | 
			
		||||
                    var show = !this.isColumn(index);
 | 
			
		||||
                }
 | 
			
		||||
                this._updateCss('.aciTree.aciTree' + this._instance.index + ' .aciTreeColumn' + index, 'display:' + (show ? 'inherit' : 'none') + ';');
 | 
			
		||||
                this._updateWidth();
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // override `_itemHook`
 | 
			
		||||
        _itemHook: function(parent, item, itemData, level) {
 | 
			
		||||
            if (this.columns()) {
 | 
			
		||||
                var position = domApi.childrenByClass(item[0].firstChild, 'aciTreeEntry'), data, column;
 | 
			
		||||
                for (var i in this._instance.options.columnData) {
 | 
			
		||||
                    data = this._instance.options.columnData[i];
 | 
			
		||||
                    column = this._createColumn(itemData, data, i);
 | 
			
		||||
                    position.insertBefore(column, position.firstChild);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super(parent, item, itemData, level);
 | 
			
		||||
        },
 | 
			
		||||
        // create column markup
 | 
			
		||||
        // `itemData` item data object
 | 
			
		||||
        // `columnData` column data definition
 | 
			
		||||
        // `index` is the #0 based column index
 | 
			
		||||
        _createColumn: function(itemData, columnData, index) {
 | 
			
		||||
            var value = columnData.props && (itemData[columnData.props] !== undefined) ? itemData[columnData.props] :
 | 
			
		||||
                    ((columnData.value === undefined) ? '' : columnData.value);
 | 
			
		||||
            var column = window.document.createElement('DIV');
 | 
			
		||||
            column.className = 'aciTreeColumn aciTreeColumn' + index;
 | 
			
		||||
            column.innerHTML = value.length ? value : ' ';
 | 
			
		||||
            return column;
 | 
			
		||||
        },
 | 
			
		||||
        // set column content
 | 
			
		||||
        // `options.index` the #0 based column index
 | 
			
		||||
        // `options.value` is the new content
 | 
			
		||||
        // `options.oldValue` will keep the old content
 | 
			
		||||
        setColumn: function(item, options) {
 | 
			
		||||
            options = this._options(options, 'columnset', 'columnfail', 'wascolumn', item);
 | 
			
		||||
            if (this.isItem(item) && (options.index >= 0) && (options.index < this.columns())) {
 | 
			
		||||
                // a way to cancel the operation
 | 
			
		||||
                if (!this._trigger(item, 'beforecolumn', options)) {
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                var data = this.itemData(item);
 | 
			
		||||
                // keep the old one
 | 
			
		||||
                options.oldValue = data[this._instance.options.columnData[options.index].props];
 | 
			
		||||
                if (options.value == options.oldValue) {
 | 
			
		||||
                    this._notify(item, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    // set the column
 | 
			
		||||
                    item.children('.aciTreeLine').find('.aciTreeColumn' + options.index).html(options.value);
 | 
			
		||||
                    // remember this one
 | 
			
		||||
                    data[this._instance.options.columnData[options.index].props] = options.value;
 | 
			
		||||
                    this._success(item, options);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                this._fail(item, options);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // get column content
 | 
			
		||||
        getColumn: function(item, index) {
 | 
			
		||||
            if ((index >= 0) && (index < this.columns())) {
 | 
			
		||||
                var data = this.itemData(item);
 | 
			
		||||
                return data ? data[this._instance.options.columnData[index].props] : null;
 | 
			
		||||
            }
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // extend the base aciTree class and add the columns stuff
 | 
			
		||||
    aciPluginClass.plugins.aciTree = aciPluginClass.plugins.aciTree.extend(aciTree_column, 'aciTreeColumn');
 | 
			
		||||
 | 
			
		||||
    // add extra default options
 | 
			
		||||
    aciPluginClass.defaults('aciTree', options);
 | 
			
		||||
 | 
			
		||||
    // for internal access
 | 
			
		||||
    var domApi = aciPluginClass.plugins.aciTree_dom;
 | 
			
		||||
 | 
			
		||||
})(jQuery, this);
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,87 @@
 | 
			
		|||
 | 
			
		||||
/*
 | 
			
		||||
 * aciTree jQuery Plugin v4.5.0-rc.7
 | 
			
		||||
 * http://acoderinsights.ro
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2014 Dragos Ursu
 | 
			
		||||
 * Dual licensed under the MIT or GPL Version 2 licenses.
 | 
			
		||||
 *
 | 
			
		||||
 * Require jQuery Library >= v1.9.0 http://jquery.com
 | 
			
		||||
 * + aciPlugin >= v1.5.1 https://github.com/dragosu/jquery-aciPlugin
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This extension adds debug capabilities, for now it's just a log of the aciTree events.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function($, window, undefined) {
 | 
			
		||||
 | 
			
		||||
    // extra default options
 | 
			
		||||
 | 
			
		||||
    var options = {
 | 
			
		||||
        logTo: null        // selector for the element where to log the errors to
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // aciTree debug extension
 | 
			
		||||
 | 
			
		||||
    var aciTree_debug = {
 | 
			
		||||
        __extend: function() {
 | 
			
		||||
            $.extend(this._private, {
 | 
			
		||||
                logTo: null
 | 
			
		||||
            });
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super();
 | 
			
		||||
        },
 | 
			
		||||
        // init debug
 | 
			
		||||
        _debugInit: function() {
 | 
			
		||||
            if (this._instance.options.logTo) {
 | 
			
		||||
                this._private.logTo = $(this._instance.options.logTo);
 | 
			
		||||
            }
 | 
			
		||||
            this._instance.jQuery.bind('acitree' + this._private.nameSpace, this.proxy(function(event, api, item, eventName, options) {
 | 
			
		||||
                var message = 'aciTree event:' + eventName + ' for:' + (item ? api.getId(item) : 'ROOT') + ' uid:' + options.uid +
 | 
			
		||||
                        ' success:' + (options.success ? 'Y' : 'N') + ' fail:' + (options.fail ? 'Y' : 'N') + ' expand:' + (options.expand ? 'Y' : 'N') +
 | 
			
		||||
                        ' collapse:' + (options.collapse ? 'Y' : 'N') + ' unique:' + (options.unique ? 'Y' : 'N') + ' animated:' + (options.unanimated ? 'N' : 'Y');
 | 
			
		||||
                if (this._private.logTo) {
 | 
			
		||||
                    this._private.logTo.prepend(message.replace(/([^\s]+:)/g, '<span style="color:#888">$1</span>') + '<br>');
 | 
			
		||||
                } else if (console && console.log) {
 | 
			
		||||
                    console.log(message);
 | 
			
		||||
                } else {
 | 
			
		||||
                    throw new Error(message);
 | 
			
		||||
                }
 | 
			
		||||
            }));
 | 
			
		||||
        },
 | 
			
		||||
        // override `_initHook`
 | 
			
		||||
        _initHook: function() {
 | 
			
		||||
            this._debugInit();
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super();
 | 
			
		||||
        },
 | 
			
		||||
        // override set `option`
 | 
			
		||||
        option: function(option, value) {
 | 
			
		||||
            if (option == 'logTo') {
 | 
			
		||||
                this._private.logTo = value ? $(value) : null;
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super(option, value);
 | 
			
		||||
        },
 | 
			
		||||
        // done debug
 | 
			
		||||
        _debugDone: function() {
 | 
			
		||||
            this._instance.jQuery.unbind(this._private.nameSpace);
 | 
			
		||||
        },
 | 
			
		||||
        // override _destroyHook
 | 
			
		||||
        _destroyHook: function(unloaded) {
 | 
			
		||||
            if (unloaded) {
 | 
			
		||||
                this._debugDone();
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super(unloaded);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // extend the base aciTree class and add the hash stuff
 | 
			
		||||
    aciPluginClass.plugins.aciTree = aciPluginClass.plugins.aciTree.extend(aciTree_debug, 'aciTreeDebug');
 | 
			
		||||
 | 
			
		||||
    // add extra default options
 | 
			
		||||
    aciPluginClass.defaults('aciTree', options);
 | 
			
		||||
 | 
			
		||||
})(jQuery, this);
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,660 @@
 | 
			
		|||
 | 
			
		||||
/*
 | 
			
		||||
 * aciTree jQuery Plugin v4.5.0-rc.7
 | 
			
		||||
 * http://acoderinsights.ro
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2014 Dragos Ursu
 | 
			
		||||
 * Dual licensed under the MIT or GPL Version 2 licenses.
 | 
			
		||||
 *
 | 
			
		||||
 * Require jQuery Library >= v1.9.0 http://jquery.com
 | 
			
		||||
 * + aciPlugin >= v1.5.1 https://github.com/dragosu/jquery-aciPlugin
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The aciTree low-level DOM functions.
 | 
			
		||||
 *
 | 
			
		||||
 * A collection of functions optimised for aciTree DOM structure.
 | 
			
		||||
 *
 | 
			
		||||
 * Need to be included before the aciTree core and after aciPlugin.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
aciPluginClass.plugins.aciTree_dom = {
 | 
			
		||||
    // get the UL container from a LI
 | 
			
		||||
    // `node` must be valid LI DOM node
 | 
			
		||||
    // can return NULL
 | 
			
		||||
    container: function(node) {
 | 
			
		||||
        var container = node.lastChild;
 | 
			
		||||
        if (container && (container.nodeName == 'UL')) {
 | 
			
		||||
            return container;
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    },
 | 
			
		||||
    // get the first children from a LI (with filtering)
 | 
			
		||||
    // `node` must be valid LI DOM node
 | 
			
		||||
    // `callback` can return FALSE to skip a node
 | 
			
		||||
    // can return NULL
 | 
			
		||||
    firstChild: function(node, callback) {
 | 
			
		||||
        var container = this.container(node);
 | 
			
		||||
        if (container) {
 | 
			
		||||
            var firstChild = container.firstChild;
 | 
			
		||||
            if (callback) {
 | 
			
		||||
                while (firstChild && !callback.call(this, firstChild)) {
 | 
			
		||||
                    firstChild = firstChild.nextSibling;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return firstChild;
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    },
 | 
			
		||||
    // get the last children from a LI (with filtering)
 | 
			
		||||
    // `node` must be valid LI DOM node
 | 
			
		||||
    // `callback` can return FALSE to skip a node
 | 
			
		||||
    // can return NULL
 | 
			
		||||
    lastChild: function(node, callback) {
 | 
			
		||||
        var container = this.container(node);
 | 
			
		||||
        if (container) {
 | 
			
		||||
            var lastChild = container.lastChild;
 | 
			
		||||
            if (callback) {
 | 
			
		||||
                while (lastChild && !callback.call(this, lastChild)) {
 | 
			
		||||
                    lastChild = lastChild.previousSibling;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return lastChild;
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    },
 | 
			
		||||
    // get the previous LI sibling (with filtering)
 | 
			
		||||
    // `node` must be valid LI DOM node
 | 
			
		||||
    // `callback` can return FALSE to skip a node
 | 
			
		||||
    // can return NULL
 | 
			
		||||
    prev: function(node, callback) {
 | 
			
		||||
        var previous = node.previousSibling;
 | 
			
		||||
        if (callback) {
 | 
			
		||||
            while (previous && !callback.call(this, previous)) {
 | 
			
		||||
                previous = previous.previousSibling;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return previous;
 | 
			
		||||
    },
 | 
			
		||||
    // get the next LI sibling (with filtering)
 | 
			
		||||
    // `node` must be valid LI DOM node
 | 
			
		||||
    // `callback` can return FALSE to skip a node
 | 
			
		||||
    // can return NULL
 | 
			
		||||
    next: function(node, callback) {
 | 
			
		||||
        var next = node.nextSibling;
 | 
			
		||||
        if (callback) {
 | 
			
		||||
            while (next && !callback.call(this, next)) {
 | 
			
		||||
                next = next.nextSibling;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return next;
 | 
			
		||||
    },
 | 
			
		||||
    // get the previous LI in tree order (with filtering)
 | 
			
		||||
    // `node` must be valid LI DOM node
 | 
			
		||||
    // `callback` can return FALSE to skip a node or NULL to prevent drill down/skip the node
 | 
			
		||||
    // can return NULL
 | 
			
		||||
    prevAll: function(node, callback) {
 | 
			
		||||
        var previous, lastChild, drillDown, match, prev, parent;
 | 
			
		||||
        while (true) {
 | 
			
		||||
            previous = this.prev(node);
 | 
			
		||||
            if (previous) {
 | 
			
		||||
                if (callback) {
 | 
			
		||||
                    match = callback.call(this, previous);
 | 
			
		||||
                    if (match === null) {
 | 
			
		||||
                        node = previous;
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                lastChild = this.lastChild(previous);
 | 
			
		||||
                if (lastChild) {
 | 
			
		||||
                    if (callback && (callback.call(this, lastChild) === null)) {
 | 
			
		||||
                        node = lastChild;
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
                    prev = false;
 | 
			
		||||
                    while (drillDown = this.lastChild(lastChild)) {
 | 
			
		||||
                        lastChild = drillDown;
 | 
			
		||||
                        if (callback) {
 | 
			
		||||
                            match = callback.call(this, lastChild);
 | 
			
		||||
                            if (match === null) {
 | 
			
		||||
                                node = lastChild;
 | 
			
		||||
                                prev = true;
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    if (prev) {
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
                    if (callback) {
 | 
			
		||||
                        match = callback.call(this, lastChild);
 | 
			
		||||
                        if (match) {
 | 
			
		||||
                            return lastChild;
 | 
			
		||||
                        } else if (match !== null) {
 | 
			
		||||
                            node = lastChild;
 | 
			
		||||
                            continue;
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        return lastChild;
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    if (!callback || match) {
 | 
			
		||||
                        return previous;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        node = previous;
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            parent = this.parent(node);
 | 
			
		||||
            if (parent) {
 | 
			
		||||
                if (callback) {
 | 
			
		||||
                    match = callback.call(this, parent);
 | 
			
		||||
                    if (match) {
 | 
			
		||||
                        return parent;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        node = parent;
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    return parent;
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    },
 | 
			
		||||
    // get the next LI in tree order (with filtering)
 | 
			
		||||
    // `node` must be valid LI DOM node
 | 
			
		||||
    // `callback` can return FALSE to skip a node or NULL to prevent drill down/skip the node
 | 
			
		||||
    // can return NULL
 | 
			
		||||
    nextAll: function(node, callback) {
 | 
			
		||||
        var firstChild, match, next, parent, child;
 | 
			
		||||
        while (true) {
 | 
			
		||||
            firstChild = this.firstChild(node);
 | 
			
		||||
            if (firstChild) {
 | 
			
		||||
                if (callback) {
 | 
			
		||||
                    match = callback.call(this, firstChild);
 | 
			
		||||
                    if (match) {
 | 
			
		||||
                        return firstChild;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        node = firstChild;
 | 
			
		||||
                        if (match !== null) {
 | 
			
		||||
                            continue;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    return firstChild;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            while (true) {
 | 
			
		||||
                next = this.next(node);
 | 
			
		||||
                if (next) {
 | 
			
		||||
                    if (callback) {
 | 
			
		||||
                        match = callback.call(this, next);
 | 
			
		||||
                        if (match) {
 | 
			
		||||
                            return next;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            node = next;
 | 
			
		||||
                            if (match !== null) {
 | 
			
		||||
                                break;
 | 
			
		||||
                            } else {
 | 
			
		||||
                                continue;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        return next;
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    parent = node;
 | 
			
		||||
                    child = null;
 | 
			
		||||
                    while (parent = this.parent(parent)) {
 | 
			
		||||
                        next = this.next(parent);
 | 
			
		||||
                        if (next) {
 | 
			
		||||
                            if (callback) {
 | 
			
		||||
                                match = callback.call(this, next);
 | 
			
		||||
                                if (match) {
 | 
			
		||||
                                    return next;
 | 
			
		||||
                                } else {
 | 
			
		||||
                                    node = next;
 | 
			
		||||
                                    if (match !== null) {
 | 
			
		||||
                                        child = true;
 | 
			
		||||
                                    } else {
 | 
			
		||||
                                        child = false;
 | 
			
		||||
                                    }
 | 
			
		||||
                                    break;
 | 
			
		||||
                                }
 | 
			
		||||
                            } else {
 | 
			
		||||
                                return next;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    if (child !== null) {
 | 
			
		||||
                        if (child) {
 | 
			
		||||
                            break;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            continue;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    return null;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    },
 | 
			
		||||
    // get the first LI in tree order (with filtering)
 | 
			
		||||
    // `node` must be valid LI DOM node
 | 
			
		||||
    // `callback` can return FALSE to skip a node or NULL to prevent drill down/skip the node
 | 
			
		||||
    // can return NULL
 | 
			
		||||
    first: function(node, callback) {
 | 
			
		||||
        var container = this.container(node);
 | 
			
		||||
        if (container) {
 | 
			
		||||
            var firstChild = container.firstChild;
 | 
			
		||||
            if (firstChild) {
 | 
			
		||||
                if (callback && !callback.call(this, firstChild)) {
 | 
			
		||||
                    return this.nextAll(firstChild, callback);
 | 
			
		||||
                }
 | 
			
		||||
                return firstChild;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    },
 | 
			
		||||
    // get the last LI in tree order (with filtering)
 | 
			
		||||
    // `node` must be valid LI DOM node
 | 
			
		||||
    // `callback` can return FALSE to skip a node or NULL to prevent drill down/skip the node
 | 
			
		||||
    // can return NULL
 | 
			
		||||
    last: function(node, callback) {
 | 
			
		||||
        var container = this.container(node);
 | 
			
		||||
        if (container) {
 | 
			
		||||
            var lastChild = container.lastChild;
 | 
			
		||||
            if (lastChild) {
 | 
			
		||||
                if (callback && (callback.call(this, lastChild) === null)) {
 | 
			
		||||
                    return this.prevAll(lastChild, callback);
 | 
			
		||||
                } else {
 | 
			
		||||
                    var drillDown;
 | 
			
		||||
                    while (drillDown = this.lastChild(lastChild)) {
 | 
			
		||||
                        lastChild = drillDown;
 | 
			
		||||
                    }
 | 
			
		||||
                    if (callback && !callback.call(this, lastChild)) {
 | 
			
		||||
                        return this.prevAll(lastChild, callback);
 | 
			
		||||
                    }
 | 
			
		||||
                    return lastChild;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    },
 | 
			
		||||
    // get the children LI from the node
 | 
			
		||||
    // `node` must be valid LI DOM node
 | 
			
		||||
    // `drillDown` if TRUE all children are returned
 | 
			
		||||
    // `callback` can return FALSE to skip a node or NULL to prevent drill down/skip the node
 | 
			
		||||
    children: function(node, drillDown, callback) {
 | 
			
		||||
        var children = [], levels = [], match, next, skip;
 | 
			
		||||
        var firstChild = this.firstChild(node);
 | 
			
		||||
        if (firstChild) {
 | 
			
		||||
            while (true) {
 | 
			
		||||
                skip = false;
 | 
			
		||||
                do {
 | 
			
		||||
                    if (callback) {
 | 
			
		||||
                        match = callback.call(this, firstChild);
 | 
			
		||||
                        if (match) {
 | 
			
		||||
                            children.push(firstChild);
 | 
			
		||||
                        }
 | 
			
		||||
                        if (drillDown && (match !== null)) {
 | 
			
		||||
                            next = this.firstChild(firstChild);
 | 
			
		||||
                            if (next) {
 | 
			
		||||
                                levels.push(firstChild);
 | 
			
		||||
                                firstChild = next;
 | 
			
		||||
                                skip = true;
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        children.push(firstChild);
 | 
			
		||||
                        if (drillDown) {
 | 
			
		||||
                            next = this.firstChild(firstChild);
 | 
			
		||||
                            if (next) {
 | 
			
		||||
                                levels.push(firstChild);
 | 
			
		||||
                                firstChild = next;
 | 
			
		||||
                                skip = true;
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                } while (firstChild = firstChild.nextSibling);
 | 
			
		||||
                if (!skip) {
 | 
			
		||||
                    while (firstChild = levels.pop()) {
 | 
			
		||||
                        firstChild = firstChild.nextSibling;
 | 
			
		||||
                        if (firstChild) {
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    if (!firstChild) {
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return children;
 | 
			
		||||
    },
 | 
			
		||||
    // get a children from the node
 | 
			
		||||
    // `node` must be valid DOM node
 | 
			
		||||
    // `callback` can return FALSE to skip a node or NULL to stop the search
 | 
			
		||||
    // can return NULL
 | 
			
		||||
    childrenTill: function(node, callback) {
 | 
			
		||||
        var levels = [], match, next, skip;
 | 
			
		||||
        var firstChild = node.firstChild;
 | 
			
		||||
        if (firstChild) {
 | 
			
		||||
            while (true) {
 | 
			
		||||
                skip = false;
 | 
			
		||||
                do {
 | 
			
		||||
                    match = callback.call(this, firstChild);
 | 
			
		||||
                    if (match) {
 | 
			
		||||
                        return firstChild;
 | 
			
		||||
                    } else if (match === null) {
 | 
			
		||||
                        return null;
 | 
			
		||||
                    }
 | 
			
		||||
                    next = firstChild.firstChild;
 | 
			
		||||
                    if (next) {
 | 
			
		||||
                        levels.push(firstChild);
 | 
			
		||||
                        firstChild = next;
 | 
			
		||||
                        skip = true;
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                } while (firstChild = firstChild.nextSibling);
 | 
			
		||||
                if (!skip) {
 | 
			
		||||
                    while (firstChild = levels.pop()) {
 | 
			
		||||
                        firstChild = firstChild.nextSibling;
 | 
			
		||||
                        if (firstChild) {
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    if (!firstChild) {
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    },
 | 
			
		||||
    // get a children from the node having a class
 | 
			
		||||
    // `node` must be valid DOM node
 | 
			
		||||
    // `className` String or Array to check for
 | 
			
		||||
    // can return NULL
 | 
			
		||||
    childrenByClass: function(node, className) {
 | 
			
		||||
        if (node.getElementsByClassName) {
 | 
			
		||||
            var list = node.getElementsByClassName(className instanceof Array ? className.join(' ') : className);
 | 
			
		||||
            return list ? list[0] : null;
 | 
			
		||||
        } else {
 | 
			
		||||
            return this.childrenTill(node, function(node) {
 | 
			
		||||
                return this.hasClass(node, className);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    // get the parent LI from the children LI
 | 
			
		||||
    // `node` must be valid LI DOM node
 | 
			
		||||
    // can return NULL
 | 
			
		||||
    parent: function(node) {
 | 
			
		||||
        var parent = node.parentNode.parentNode;
 | 
			
		||||
        if (parent && (parent.nodeName == 'LI')) {
 | 
			
		||||
            return parent;
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    },
 | 
			
		||||
    // get the parent LI from any children
 | 
			
		||||
    // `node` must be valid children of a LI DOM node
 | 
			
		||||
    // can return NULL
 | 
			
		||||
    parentFrom: function(node) {
 | 
			
		||||
        while (node.nodeName != 'LI') {
 | 
			
		||||
            node = node.parentNode;
 | 
			
		||||
            if (!node) {
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return node;
 | 
			
		||||
    },
 | 
			
		||||
    // get a parent from the node
 | 
			
		||||
    // `node` must be valid DOM node
 | 
			
		||||
    // `callback` can return FALSE to skip a node or NULL to stop the search
 | 
			
		||||
    // can return NULL
 | 
			
		||||
    parentTill: function(node, callback) {
 | 
			
		||||
        var match;
 | 
			
		||||
        while (node = node.parentNode) {
 | 
			
		||||
            match = callback.call(this, node);
 | 
			
		||||
            if (match) {
 | 
			
		||||
                return node;
 | 
			
		||||
            } else if (match === null) {
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    },
 | 
			
		||||
    // get a parent from the node having a class
 | 
			
		||||
    // `node` must be valid DOM node
 | 
			
		||||
    // `className` String or Array to check for
 | 
			
		||||
    // can return NULL
 | 
			
		||||
    parentByClass: function(node, className) {
 | 
			
		||||
        return this.parentTill(node, function(node) {
 | 
			
		||||
            return this.hasClass(node, className);
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
    // test if node has class(es)
 | 
			
		||||
    // `className` String or Array to check for
 | 
			
		||||
    // `withOut` String or Array to exclude with
 | 
			
		||||
    hasClass: function(node, className, withOut) {
 | 
			
		||||
        var oldClass = ' ' + node.className + ' ';
 | 
			
		||||
        if (withOut instanceof Array) {
 | 
			
		||||
            for (var i = 0; i < withOut.length; i++) {
 | 
			
		||||
                if (oldClass.indexOf(' ' + withOut[i] + ' ') != -1) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if (withOut && oldClass.indexOf(' ' + withOut + ' ') != -1) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (className instanceof Array) {
 | 
			
		||||
            for (var i = 0; i < className.length; i++) {
 | 
			
		||||
                if (oldClass.indexOf(' ' + className[i] + ' ') == -1) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if (className && oldClass.indexOf(' ' + className + ' ') == -1) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
    // filter nodes with class(es)
 | 
			
		||||
    // `nodes` Array of DOM nodes
 | 
			
		||||
    // @see `hasClass`
 | 
			
		||||
    withClass: function(nodes, className, withOut) {
 | 
			
		||||
        var filter = [];
 | 
			
		||||
        for (var i = 0; i < nodes.length; i++) {
 | 
			
		||||
            if (this.hasClass(nodes[i], className, withOut)) {
 | 
			
		||||
                filter.push(nodes[i]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return filter;
 | 
			
		||||
    },
 | 
			
		||||
    // test if node has any class(es)
 | 
			
		||||
    // `className` String or Array to check for (any class)
 | 
			
		||||
    // `withOut` String or Array to exclude with
 | 
			
		||||
    hasAnyClass: function(node, className, withOut) {
 | 
			
		||||
        var oldClass = ' ' + node.className + ' ';
 | 
			
		||||
        if (withOut instanceof Array) {
 | 
			
		||||
            for (var i = 0; i < withOut.length; i++) {
 | 
			
		||||
                if (oldClass.indexOf(' ' + withOut[i] + ' ') != -1) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if (withOut && oldClass.indexOf(' ' + withOut + ' ') != -1) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (className instanceof Array) {
 | 
			
		||||
            for (var i = 0; i < className.length; i++) {
 | 
			
		||||
                if (oldClass.indexOf(' ' + className[i] + ' ') != -1) {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if (className && oldClass.indexOf(' ' + className + ' ') != -1) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
    // filter nodes with any class(es)
 | 
			
		||||
    // `nodes` Array of DOM nodes
 | 
			
		||||
    // @see `hasAnyClass`
 | 
			
		||||
    withAnyClass: function(nodes, className, withOut) {
 | 
			
		||||
        var filter = [];
 | 
			
		||||
        for (var i = 0; i < nodes.length; i++) {
 | 
			
		||||
            if (this.hasAnyClass(nodes[i], className, withOut)) {
 | 
			
		||||
                filter.push(nodes[i]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return filter;
 | 
			
		||||
    },
 | 
			
		||||
    // add class(es) to node
 | 
			
		||||
    // `node` must be valid DOM node
 | 
			
		||||
    // `className` String or Array to add
 | 
			
		||||
    // return TRUE if className changed
 | 
			
		||||
    addClass: function(node, className) {
 | 
			
		||||
        var oldClass = ' ' + node.className + ' ', append = '';
 | 
			
		||||
        if (className instanceof Array) {
 | 
			
		||||
            for (var i = 0; i < className.length; i++) {
 | 
			
		||||
                if (oldClass.indexOf(' ' + className[i] + ' ') == -1) {
 | 
			
		||||
                    append += ' ' + className[i];
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if (oldClass.indexOf(' ' + className + ' ') == -1) {
 | 
			
		||||
                append += ' ' + className;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (append) {
 | 
			
		||||
            node.className = node.className + append;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
    // add class(es) to nodes
 | 
			
		||||
    // `nodes` Array of DOM nodes
 | 
			
		||||
    // @see `addClass`
 | 
			
		||||
    addListClass: function(nodes, className, callback) {
 | 
			
		||||
        for (var i = 0; i < nodes.length; i++) {
 | 
			
		||||
            this.addClass(nodes[i], className);
 | 
			
		||||
            if (callback) {
 | 
			
		||||
                callback.call(this, nodes[i]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    // remove class(es) from node
 | 
			
		||||
    // `node` must be valid DOM node
 | 
			
		||||
    // `className` String or Array to remove
 | 
			
		||||
    // return TRUE if className changed
 | 
			
		||||
    removeClass: function(node, className) {
 | 
			
		||||
        var oldClass = ' ' + node.className + ' ';
 | 
			
		||||
        if (className instanceof Array) {
 | 
			
		||||
            for (var i = 0; i < className.length; i++) {
 | 
			
		||||
                oldClass = oldClass.replace(' ' + className[i] + ' ', ' ');
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            oldClass = oldClass.replace(' ' + className + ' ', ' ');
 | 
			
		||||
        }
 | 
			
		||||
        oldClass = oldClass.substr(1, oldClass.length - 2);
 | 
			
		||||
        if (node.className != oldClass) {
 | 
			
		||||
            node.className = oldClass;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
    // remove class(es) from nodes
 | 
			
		||||
    // `nodes` Array of DOM nodes
 | 
			
		||||
    // @see `removeClass`
 | 
			
		||||
    removeListClass: function(nodes, className, callback) {
 | 
			
		||||
        for (var i = 0; i < nodes.length; i++) {
 | 
			
		||||
            this.removeClass(nodes[i], className);
 | 
			
		||||
            if (callback) {
 | 
			
		||||
                callback.call(this, nodes[i]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    // toggle node class(es)
 | 
			
		||||
    // `node` must be valid DOM node
 | 
			
		||||
    // `className` String or Array to toggle
 | 
			
		||||
    // `add` TRUE to add them
 | 
			
		||||
    // return TRUE if className changed
 | 
			
		||||
    toggleClass: function(node, className, add) {
 | 
			
		||||
        if (add) {
 | 
			
		||||
            return this.addClass(node, className);
 | 
			
		||||
        } else {
 | 
			
		||||
            return this.removeClass(node, className);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    // toggle nodes class(es)
 | 
			
		||||
    // `nodes` Array of DOM nodes
 | 
			
		||||
    // @see `toggleClass`
 | 
			
		||||
    toggleListClass: function(nodes, className, add, callback) {
 | 
			
		||||
        for (var i = 0; i < nodes.length; i++) {
 | 
			
		||||
            this.toggleClass(nodes[i], className, add);
 | 
			
		||||
            if (callback) {
 | 
			
		||||
                callback.call(this, nodes[i]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    // add/remove and keep old class(es)
 | 
			
		||||
    // `node` must be valid DOM node
 | 
			
		||||
    // `addClass` String or Array to add
 | 
			
		||||
    // `removeClass` String or Array to remove
 | 
			
		||||
    // return TRUE if className changed
 | 
			
		||||
    addRemoveClass: function(node, addClass, removeClass) {
 | 
			
		||||
        var oldClass = ' ' + node.className + ' ';
 | 
			
		||||
        if (removeClass) {
 | 
			
		||||
            if (removeClass instanceof Array) {
 | 
			
		||||
                for (var i = 0; i < removeClass.length; i++) {
 | 
			
		||||
                    oldClass = oldClass.replace(' ' + removeClass[i] + ' ', ' ');
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                oldClass = oldClass.replace(' ' + removeClass + ' ', ' ');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (addClass) {
 | 
			
		||||
            var append = '';
 | 
			
		||||
            if (addClass instanceof Array) {
 | 
			
		||||
                for (var i = 0; i < addClass.length; i++) {
 | 
			
		||||
                    if (oldClass.indexOf(' ' + addClass[i] + ' ') == -1) {
 | 
			
		||||
                        append += addClass[i] + ' ';
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                if (oldClass.indexOf(' ' + addClass + ' ') == -1) {
 | 
			
		||||
                    append += addClass + ' ';
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            oldClass += append;
 | 
			
		||||
        }
 | 
			
		||||
        oldClass = oldClass.substr(1, oldClass.length - 2);
 | 
			
		||||
        if (node.className != oldClass) {
 | 
			
		||||
            node.className = oldClass;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
    // add/remove and keep old class(es)
 | 
			
		||||
    // `nodes` Array of DOM nodes
 | 
			
		||||
    // @see `addRemoveClass`
 | 
			
		||||
    addRemoveListClass: function(nodes, addClass, removeClass, callback) {
 | 
			
		||||
        for (var i = 0; i < nodes.length; i++) {
 | 
			
		||||
            this.addRemoveClass(nodes[i], addClass, removeClass);
 | 
			
		||||
            if (callback) {
 | 
			
		||||
                callback.call(this, nodes[i]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,294 @@
 | 
			
		|||
 | 
			
		||||
/*
 | 
			
		||||
 * aciTree jQuery Plugin v4.5.0-rc.7
 | 
			
		||||
 * http://acoderinsights.ro
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2014 Dragos Ursu
 | 
			
		||||
 * Dual licensed under the MIT or GPL Version 2 licenses.
 | 
			
		||||
 *
 | 
			
		||||
 * Require jQuery Library >= v1.9.0 http://jquery.com
 | 
			
		||||
 * + aciPlugin >= v1.5.1 https://github.com/dragosu/jquery-aciPlugin
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This extension adds inplace edit support to aciTree,
 | 
			
		||||
 * should be used with the selectable extension.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function($, window, undefined) {
 | 
			
		||||
 | 
			
		||||
    // extra default options
 | 
			
		||||
 | 
			
		||||
    var options = {
 | 
			
		||||
        editable: false,                // if TRUE then each item will be inplace editable
 | 
			
		||||
        editDelay: 250                  // how many [ms] to wait (with mouse down) before starting the edit (on mouse release)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // aciTree editable extension
 | 
			
		||||
    // add inplace item editing by pressing F2 key or mouse click (to enter edit mode)
 | 
			
		||||
    // press enter/escape to save/cancel the text edit
 | 
			
		||||
 | 
			
		||||
    var aciTree_editable = {
 | 
			
		||||
        __extend: function() {
 | 
			
		||||
            // add extra data
 | 
			
		||||
            $.extend(this._private, {
 | 
			
		||||
                editTimestamp: null
 | 
			
		||||
            });
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super();
 | 
			
		||||
        },
 | 
			
		||||
        // init editable
 | 
			
		||||
        _editableInit: function() {
 | 
			
		||||
            this._instance.jQuery.bind('acitree' + this._private.nameSpace, function(event, api, item, eventName, options) {
 | 
			
		||||
                switch (eventName) {
 | 
			
		||||
                    case 'blurred':
 | 
			
		||||
                        // support `selectable` extension
 | 
			
		||||
                        var item = api.edited();
 | 
			
		||||
                        if (item.length) {
 | 
			
		||||
                            // cancel edit/save the changes
 | 
			
		||||
                            api.endEdit();
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 'deselected':
 | 
			
		||||
                        // support `selectable` extension
 | 
			
		||||
                        if (api.isEdited(item)) {
 | 
			
		||||
                            // cancel edit/save the changes
 | 
			
		||||
                            api.endEdit();
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            }).bind('click' + this._private.nameSpace, this.proxy(function() {
 | 
			
		||||
                // click on the tree
 | 
			
		||||
                var item = this.edited();
 | 
			
		||||
                if (item.length) {
 | 
			
		||||
                    // cancel edit/save the changes
 | 
			
		||||
                    this.endEdit();
 | 
			
		||||
                }
 | 
			
		||||
            })).bind('keydown' + this._private.nameSpace, this.proxy(function(e) {
 | 
			
		||||
                switch (e.which) {
 | 
			
		||||
                    case 113: // F2
 | 
			
		||||
                        // support `selectable` extension
 | 
			
		||||
                        if (this.extSelectable && this.extSelectable()) {
 | 
			
		||||
                            var item = this.focused();
 | 
			
		||||
                            if (item.length && !this.isEdited(item) && this.isEnabled(item)) {
 | 
			
		||||
                                // enable edit on F2 key
 | 
			
		||||
                                this.edit(item);
 | 
			
		||||
                                // prevent default F2 key function
 | 
			
		||||
                                e.preventDefault();
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            })).on('mousedown' + this._private.nameSpace, '.aciTreeItem', this.proxy(function(e) {
 | 
			
		||||
                if ($(e.target).is('.aciTreeItem,.aciTreeText')) {
 | 
			
		||||
                    this._private.editTimestamp = $.now();
 | 
			
		||||
                }
 | 
			
		||||
            })).on('mouseup' + this._private.nameSpace, '.aciTreeItem', this.proxy(function(e) {
 | 
			
		||||
                if ($(e.target).is('.aciTreeItem,.aciTreeText')) {
 | 
			
		||||
                    var passed = $.now() - this._private.editTimestamp;
 | 
			
		||||
                    // start edit only after N [ms] but before N * 4 [ms] have passed
 | 
			
		||||
                    if ((passed > this._instance.options.editDelay) && (passed < this._instance.options.editDelay * 4)) {
 | 
			
		||||
                        var item = this.itemFrom(e.target);
 | 
			
		||||
                        if ((!this.extSelectable || !this.extSelectable() || (this.isFocused(item) && (this.selected().length == 1))) && this.isEnabled(item)) {
 | 
			
		||||
                            // edit on mouseup
 | 
			
		||||
                            this.edit(item);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            })).on('keydown' + this._private.nameSpace, 'input[type=text]', this.proxy(function(e) {
 | 
			
		||||
                // key handling
 | 
			
		||||
                switch (e.which) {
 | 
			
		||||
                    case 13: // enter
 | 
			
		||||
                        this.itemFrom(e.target).focus();
 | 
			
		||||
                        this.endEdit();
 | 
			
		||||
                        e.stopPropagation();
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 27: // escape
 | 
			
		||||
                        this.itemFrom(e.target).focus();
 | 
			
		||||
                        this.endEdit({
 | 
			
		||||
                            save: false
 | 
			
		||||
                        });
 | 
			
		||||
                        e.stopPropagation();
 | 
			
		||||
                        // prevent default action on ESC
 | 
			
		||||
                        e.preventDefault();
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 38: // up
 | 
			
		||||
                    case 40: // down
 | 
			
		||||
                    case 37: // left
 | 
			
		||||
                    case 39: // right
 | 
			
		||||
                    case 33: // pgup
 | 
			
		||||
                    case 34: // pgdown
 | 
			
		||||
                    case 36: // home
 | 
			
		||||
                    case 35: // end
 | 
			
		||||
                    case 32: // space
 | 
			
		||||
                    case 107: // numpad [+]
 | 
			
		||||
                    case 109: // numpad [-]
 | 
			
		||||
                    case 106: // numpad [*]
 | 
			
		||||
                        e.stopPropagation();
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            })).on('blur' + this._private.nameSpace, 'input[type=text]', this.proxy(function() {
 | 
			
		||||
                if (!this.extSelectable || !this.extSelectable()) {
 | 
			
		||||
                    // cancel edit/save the changes
 | 
			
		||||
                    this.endEdit();
 | 
			
		||||
                }
 | 
			
		||||
            })).on('click' + this._private.nameSpace + ' dblclick' + this._private.nameSpace, 'input[type=text]', function(e) {
 | 
			
		||||
                e.stopPropagation();
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
        // override `_initHook`
 | 
			
		||||
        _initHook: function() {
 | 
			
		||||
            if (this.extEditable()) {
 | 
			
		||||
                this._editableInit();
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super();
 | 
			
		||||
        },
 | 
			
		||||
        // low level DOM functions
 | 
			
		||||
        _editableDOM: {
 | 
			
		||||
            // add edit field
 | 
			
		||||
            add: function(item) {
 | 
			
		||||
                var line = item.addClass('aciTreeEdited').children('.aciTreeLine');
 | 
			
		||||
                line.find('.aciTreeText').html('<input id="aciTree-editable-tree-item" type="text" value="" style="-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;-o-user-select:text;user-select:text" />');
 | 
			
		||||
                line.find('label').attr('for', 'aciTree-editable-tree-item');
 | 
			
		||||
                this._editableDOM.get(item).val(this.getLabel(item));
 | 
			
		||||
            },
 | 
			
		||||
            // remove edit field
 | 
			
		||||
            remove: function(item, label) {
 | 
			
		||||
                var line = item.removeClass('aciTreeEdited').children('.aciTreeLine');
 | 
			
		||||
                line.find('.aciTreeText').html(this.getLabel(item));
 | 
			
		||||
                line.find('label').removeAttr('for');
 | 
			
		||||
            },
 | 
			
		||||
            // return edit field
 | 
			
		||||
            get: function(item) {
 | 
			
		||||
                return item ? item.children('.aciTreeLine').find('input[type=text]') : $([]);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // get edited item
 | 
			
		||||
        edited: function() {
 | 
			
		||||
            return this._instance.jQuery.find('.aciTreeEdited');
 | 
			
		||||
        },
 | 
			
		||||
        // test if item is edited
 | 
			
		||||
        isEdited: function(item) {
 | 
			
		||||
            return item && domApi.hasClass(item[0], 'aciTreeEdited');
 | 
			
		||||
        },
 | 
			
		||||
        // set focus to the input
 | 
			
		||||
        _focusEdit: function(item) {
 | 
			
		||||
            var field = this._editableDOM.get(item).focus().trigger('click')[0];
 | 
			
		||||
            if (field) {
 | 
			
		||||
                if (typeof field.selectionStart == 'number') {
 | 
			
		||||
                    field.selectionStart = field.selectionEnd = field.value.length;
 | 
			
		||||
                } else if (field.createTextRange !== undefined) {
 | 
			
		||||
                    var range = field.createTextRange();
 | 
			
		||||
                    range.collapse(false);
 | 
			
		||||
                    range.select();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // override `setLabel`
 | 
			
		||||
        setLabel: function(item, options) {
 | 
			
		||||
            if (!this.extEditable() || !this.isEdited(item)) {
 | 
			
		||||
                // call the parent
 | 
			
		||||
                this._super(item, options);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // edit item inplace
 | 
			
		||||
        edit: function(item, options) {
 | 
			
		||||
            options = this._options(options, 'edit', 'editfail', 'wasedit', item);
 | 
			
		||||
            if (this.extEditable() && this.isItem(item)) {
 | 
			
		||||
                // a way to cancel the operation
 | 
			
		||||
                if (!this._trigger(item, 'beforeedit', options)) {
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                var edited = this.edited();
 | 
			
		||||
                if (edited.length) {
 | 
			
		||||
                    if (edited[0] == item[0]) {
 | 
			
		||||
                        this._notify(item, options);
 | 
			
		||||
                        return;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        this._editableDOM.remove.call(this, edited);
 | 
			
		||||
                        this._trigger(edited, 'endedit', options);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                this._editableDOM.add.call(this, item);
 | 
			
		||||
                this._focusEdit(item);
 | 
			
		||||
                this._success(item, options);
 | 
			
		||||
            } else {
 | 
			
		||||
                this._fail(item, options);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // end edit
 | 
			
		||||
        // `options.save` when set to FALSE will not save the changes
 | 
			
		||||
        endEdit: function(options) {
 | 
			
		||||
            var item = this.edited();
 | 
			
		||||
            options = this._options(options, 'edited', 'endeditfail', 'endedit', item);
 | 
			
		||||
            if (this.extEditable() && this.isItem(item)) {
 | 
			
		||||
                // a way to cancel the operation
 | 
			
		||||
                if (!this._trigger(item, 'beforeendedit', options)) {
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                var text = this._editableDOM.get(item).val();
 | 
			
		||||
                this._editableDOM.remove.call(this, item);
 | 
			
		||||
                if ((options.save === undefined) || options.save) {
 | 
			
		||||
                    this.setLabel(item, {
 | 
			
		||||
                        label: text
 | 
			
		||||
                    });
 | 
			
		||||
                    this._success(item, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._notify(item, options);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                this._fail(item, options);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // test if editable is enabled
 | 
			
		||||
        extEditable: function() {
 | 
			
		||||
            return this._instance.options.editable;
 | 
			
		||||
        },
 | 
			
		||||
        // override set `option`
 | 
			
		||||
        option: function(option, value) {
 | 
			
		||||
            if (this.wasInit() && !this.isLocked()) {
 | 
			
		||||
                if ((option == 'editable') && (value != this.extEditable())) {
 | 
			
		||||
                    if (value) {
 | 
			
		||||
                        this._editableInit();
 | 
			
		||||
                    } else {
 | 
			
		||||
                        this._editableDone();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super(option, value);
 | 
			
		||||
        },
 | 
			
		||||
        // done editable
 | 
			
		||||
        _editableDone: function() {
 | 
			
		||||
            this._instance.jQuery.unbind(this._private.nameSpace);
 | 
			
		||||
            this._instance.jQuery.off(this._private.nameSpace, '.aciTreeItem');
 | 
			
		||||
            this._instance.jQuery.off(this._private.nameSpace, 'input[type=text]');
 | 
			
		||||
            var edited = this.edited();
 | 
			
		||||
            if (edited.length) {
 | 
			
		||||
                this.endEdit();
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // override `_destroyHook`
 | 
			
		||||
        _destroyHook: function(unloaded) {
 | 
			
		||||
            if (unloaded) {
 | 
			
		||||
                this._editableDone();
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super(unloaded);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // extend the base aciTree class and add the editable stuff
 | 
			
		||||
    aciPluginClass.plugins.aciTree = aciPluginClass.plugins.aciTree.extend(aciTree_editable, 'aciTreeEditable');
 | 
			
		||||
 | 
			
		||||
    // add extra default options
 | 
			
		||||
    aciPluginClass.defaults('aciTree', options);
 | 
			
		||||
 | 
			
		||||
    // for internal access
 | 
			
		||||
    var domApi = aciPluginClass.plugins.aciTree_dom;
 | 
			
		||||
 | 
			
		||||
})(jQuery, this);
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,170 @@
 | 
			
		|||
 | 
			
		||||
/*
 | 
			
		||||
 * aciTree jQuery Plugin v4.5.0-rc.7
 | 
			
		||||
 * http://acoderinsights.ro
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2014 Dragos Ursu
 | 
			
		||||
 * Dual licensed under the MIT or GPL Version 2 licenses.
 | 
			
		||||
 *
 | 
			
		||||
 * Require jQuery Library >= v1.9.0 http://jquery.com
 | 
			
		||||
 * + aciPlugin >= v1.5.1 https://github.com/dragosu/jquery-aciPlugin
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This extension adds hash/fragment support using aciFragment, it opens/select item(s) based on variables stored in the fragment part of the URL.
 | 
			
		||||
 * The states are loaded from the URL fragment and set on treeview init. Multiple item IDs separated with ";" are supported for
 | 
			
		||||
 * opening/selecting deep items (if loading nodes is required).
 | 
			
		||||
 * Require aciFragment https://github.com/dragosu/jquery-aciFragment and the utils extension for finding items by ID.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function($, window, undefined) {
 | 
			
		||||
 | 
			
		||||
    // extra default options
 | 
			
		||||
 | 
			
		||||
    var options = {
 | 
			
		||||
        selectHash: null,        // hash key name to select a item (item path IDs as key value, multiple item IDs separated with a ";")
 | 
			
		||||
        openHash: null           // hash key name to open item(s) (item path IDs as key value, multiple item IDs separated with a ";")
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // aciTree hash extension
 | 
			
		||||
    // select/open items based on IDs stored in the fragment of the current URL
 | 
			
		||||
 | 
			
		||||
    var aciTree_hash = {
 | 
			
		||||
        __extend: function() {
 | 
			
		||||
            $.extend(this._private, {
 | 
			
		||||
                lastSelect: null,
 | 
			
		||||
                lastOpen: null,
 | 
			
		||||
                // store `aciFragment` api
 | 
			
		||||
                hashApi: null
 | 
			
		||||
            });
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super();
 | 
			
		||||
        },
 | 
			
		||||
        // init hash
 | 
			
		||||
        _hashInit: function() {
 | 
			
		||||
            // init `aciFragment`
 | 
			
		||||
            this._instance.jQuery.aciFragment();
 | 
			
		||||
            this._private.hashApi = this._instance.jQuery.aciFragment('api');
 | 
			
		||||
            this._instance.jQuery.bind('acitree' + this._private.nameSpace, function(event, api, item, eventName, options) {
 | 
			
		||||
                switch (eventName) {
 | 
			
		||||
                    case 'init':
 | 
			
		||||
                        api._hashRestore();
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            }).bind('acifragment' + this._private.nameSpace, this.proxy(function(event, api, anchorChanged) {
 | 
			
		||||
                event.stopPropagation();
 | 
			
		||||
                this._hashRestore();
 | 
			
		||||
            }));
 | 
			
		||||
        },
 | 
			
		||||
        // override `_initHook`
 | 
			
		||||
        _initHook: function() {
 | 
			
		||||
            if (this.extHast()) {
 | 
			
		||||
                this._hashInit();
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super();
 | 
			
		||||
        },
 | 
			
		||||
        // restore item states from hash
 | 
			
		||||
        _hashRestore: function() {
 | 
			
		||||
            var queue = this._instance.queue;
 | 
			
		||||
            var process = function(opened) {
 | 
			
		||||
                // open all hash items
 | 
			
		||||
                for (var i in opened) {
 | 
			
		||||
                    (function(id) {
 | 
			
		||||
                        // add item to queue
 | 
			
		||||
                        queue.push(function(complete) {
 | 
			
		||||
                            this.search(null, {
 | 
			
		||||
                                success: function(item) {
 | 
			
		||||
                                    this.open(item, {
 | 
			
		||||
                                        uid: 'ui.hash',
 | 
			
		||||
                                        success: complete,
 | 
			
		||||
                                        fail: complete
 | 
			
		||||
                                    });
 | 
			
		||||
                                },
 | 
			
		||||
                                fail: complete,
 | 
			
		||||
                                search: id
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                    })(opened[i]);
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
            if (this._instance.options.openHash) {
 | 
			
		||||
                var hash = this._private.hashApi.get(this._instance.options.openHash, '');
 | 
			
		||||
                if (hash.length && (hash != this._private.lastOpen)) {
 | 
			
		||||
                    this._private.lastOpen = hash;
 | 
			
		||||
                    var opened = hash.split(';');
 | 
			
		||||
                    process(opened);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // support `selectable` extension
 | 
			
		||||
            if (this._instance.options.selectHash && this.extSelectable && this.extSelectable()) {
 | 
			
		||||
                var hash = this._private.hashApi.get(this._instance.options.selectHash, '');
 | 
			
		||||
                if (hash.length && (hash != this._private.lastSelect)) {
 | 
			
		||||
                    this._private.lastSelect = hash;
 | 
			
		||||
                    var opened = hash.split(';');
 | 
			
		||||
                    var selected = opened.pop();
 | 
			
		||||
                    process(opened);
 | 
			
		||||
                    if (selected) {
 | 
			
		||||
                        // select item
 | 
			
		||||
                        queue.push(function(complete) {
 | 
			
		||||
                            this.search(null, {
 | 
			
		||||
                                success: function(item) {
 | 
			
		||||
                                    this.select(item, {
 | 
			
		||||
                                        uid: 'ui.hash',
 | 
			
		||||
                                        success: function(item) {
 | 
			
		||||
                                            this.setVisible(item, {
 | 
			
		||||
                                                center: true
 | 
			
		||||
                                            });
 | 
			
		||||
                                            complete();
 | 
			
		||||
                                        },
 | 
			
		||||
                                        fail: complete
 | 
			
		||||
                                    });
 | 
			
		||||
                                },
 | 
			
		||||
                                fail: complete,
 | 
			
		||||
                                search: selected
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // test if hash is enabled
 | 
			
		||||
        extHast: function() {
 | 
			
		||||
            return this._instance.options.selectHash || this._instance.options.openHash;
 | 
			
		||||
        },
 | 
			
		||||
        // override set option
 | 
			
		||||
        option: function(option, value) {
 | 
			
		||||
            var hash = this.extHast();
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super(option, value);
 | 
			
		||||
            if (this.extHast() != hash) {
 | 
			
		||||
                if (hash) {
 | 
			
		||||
                    this._hashDone();
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._hashInit();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // done hash
 | 
			
		||||
        _hashDone: function() {
 | 
			
		||||
            this._instance.jQuery.unbind(this._private.nameSpace);
 | 
			
		||||
            this._private.hashApi = null;
 | 
			
		||||
            this._instance.jQuery.aciFragment('destroy');
 | 
			
		||||
        },
 | 
			
		||||
        // override `_destroyHook`
 | 
			
		||||
        _destroyHook: function(unloaded) {
 | 
			
		||||
            if (unloaded) {
 | 
			
		||||
                this._hashDone();
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super(unloaded);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // extend the base aciTree class and add the hash stuff
 | 
			
		||||
    aciPluginClass.plugins.aciTree = aciPluginClass.plugins.aciTree.extend(aciTree_hash, 'aciTreeHash');
 | 
			
		||||
 | 
			
		||||
    // add extra default options
 | 
			
		||||
    aciPluginClass.defaults('aciTree', options);
 | 
			
		||||
 | 
			
		||||
})(jQuery, this);
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,290 @@
 | 
			
		|||
 | 
			
		||||
/*
 | 
			
		||||
 * aciTree jQuery Plugin v4.5.0-rc.7
 | 
			
		||||
 * http://acoderinsights.ro
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2014 Dragos Ursu
 | 
			
		||||
 * Dual licensed under the MIT or GPL Version 2 licenses.
 | 
			
		||||
 *
 | 
			
		||||
 * Require jQuery Library >= v1.9.0 http://jquery.com
 | 
			
		||||
 * + aciPlugin >= v1.5.1 https://github.com/dragosu/jquery-aciPlugin
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This extension adds save/restore support for item states (open/selected) using local storage.
 | 
			
		||||
 * The states are saved on item select/open and restored on treeview init.
 | 
			
		||||
 * Require jStorage https://github.com/andris9/jStorage and the utils extension for finding items by ID.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function($, window, undefined) {
 | 
			
		||||
 | 
			
		||||
    // extra default options
 | 
			
		||||
 | 
			
		||||
    var options = {
 | 
			
		||||
        persist: null           // the storage key name to keep the states (should be unique/treeview)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // aciTree persist extension
 | 
			
		||||
    // save/restore item state in/from local storage
 | 
			
		||||
 | 
			
		||||
    var aciTree_persist = {
 | 
			
		||||
        __extend: function() {
 | 
			
		||||
            $.extend(this._private, {
 | 
			
		||||
                // timeouts for the save operation
 | 
			
		||||
                selectTimeout: null,
 | 
			
		||||
                focusTimeout: null,
 | 
			
		||||
                openTimeout: null
 | 
			
		||||
            });
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super();
 | 
			
		||||
        },
 | 
			
		||||
        // init persist
 | 
			
		||||
        _initPersist: function() {
 | 
			
		||||
            this._instance.jQuery.bind('acitree' + this._private.nameSpace, function(event, api, item, eventName, options) {
 | 
			
		||||
                if (options.uid == 'ui.persist') {
 | 
			
		||||
                    // skip processing itself
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                switch (eventName) {
 | 
			
		||||
                    case 'init':
 | 
			
		||||
                        api._persistRestore();
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 'selected':
 | 
			
		||||
                    case 'deselected':
 | 
			
		||||
                        // support `selectable` extension
 | 
			
		||||
                        api._persistLater('selected');
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 'focus':
 | 
			
		||||
                    case 'blur':
 | 
			
		||||
                        // support `selectable` extension
 | 
			
		||||
                        api._persistLater('focused');
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 'opened':
 | 
			
		||||
                    case 'closed':
 | 
			
		||||
                        api._persistLater('opened');
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
        // override `_initHook`
 | 
			
		||||
        _initHook: function() {
 | 
			
		||||
            if (this.extPersist()) {
 | 
			
		||||
                this._initPersist();
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super();
 | 
			
		||||
        },
 | 
			
		||||
        // persist states
 | 
			
		||||
        _persistLater: function(type) {
 | 
			
		||||
            switch (type) {
 | 
			
		||||
                case 'selected':
 | 
			
		||||
                    window.clearTimeout(this._private.selectTimeout);
 | 
			
		||||
                    this._private.selectTimeout = window.setTimeout(this.proxy(function() {
 | 
			
		||||
                        this._persistSelected();
 | 
			
		||||
                    }), 250);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 'focused':
 | 
			
		||||
                    window.clearTimeout(this._private.focusTimeout);
 | 
			
		||||
                    this._private.focusTimeout = window.setTimeout(this.proxy(function() {
 | 
			
		||||
                        this._persistFocused();
 | 
			
		||||
                    }), 250);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 'opened':
 | 
			
		||||
                    window.clearTimeout(this._private.openTimeout);
 | 
			
		||||
                    this._private.openTimeout = window.setTimeout(this.proxy(function() {
 | 
			
		||||
                        this._persistOpened();
 | 
			
		||||
                    }), 250);
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // restore item states
 | 
			
		||||
        _persistRestore: function() {
 | 
			
		||||
            var queue = new this._queue(this, this._instance.options.queue);
 | 
			
		||||
            var task = new this._task(queue, function(complete) {
 | 
			
		||||
                // support `selectable` extension
 | 
			
		||||
                if (this.extSelectable && this.extSelectable()) {
 | 
			
		||||
                    var selected = $.jStorage.get('aciTree_' + this._instance.options.persist + '_selected');
 | 
			
		||||
                    if (selected instanceof Array) {
 | 
			
		||||
                        // select all saved items
 | 
			
		||||
                        for (var i in selected) {
 | 
			
		||||
                            (function(path) {
 | 
			
		||||
                                queue.push(function(complete) {
 | 
			
		||||
                                    this.searchPath(null, {
 | 
			
		||||
                                        success: function(item) {
 | 
			
		||||
                                            this.select(item, {
 | 
			
		||||
                                                uid: 'ui.persist',
 | 
			
		||||
                                                success: function() {
 | 
			
		||||
                                                    complete();
 | 
			
		||||
                                                },
 | 
			
		||||
                                                fail: complete,
 | 
			
		||||
                                                focus: false
 | 
			
		||||
                                            });
 | 
			
		||||
                                        },
 | 
			
		||||
                                        fail: complete,
 | 
			
		||||
                                        path: path.split(';')
 | 
			
		||||
                                    });
 | 
			
		||||
                                });
 | 
			
		||||
                            })(selected[i]);
 | 
			
		||||
                            if (!this._instance.options.multiSelectable) {
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    var focused = $.jStorage.get('aciTree_' + this._instance.options.persist + '_focused');
 | 
			
		||||
                    if (focused instanceof Array) {
 | 
			
		||||
                        // focus all saved items
 | 
			
		||||
                        for (var i in focused) {
 | 
			
		||||
                            (function(path) {
 | 
			
		||||
                                queue.push(function(complete) {
 | 
			
		||||
                                    this.searchPath(null, {
 | 
			
		||||
                                        success: function(item) {
 | 
			
		||||
                                            this.focus(item, {
 | 
			
		||||
                                                uid: 'ui.persist',
 | 
			
		||||
                                                success: function(item) {
 | 
			
		||||
                                                    this.setVisible(item, {
 | 
			
		||||
                                                        center: true
 | 
			
		||||
                                                    });
 | 
			
		||||
                                                    complete();
 | 
			
		||||
                                                },
 | 
			
		||||
                                                fail: complete
 | 
			
		||||
                                            });
 | 
			
		||||
                                        },
 | 
			
		||||
                                        fail: complete,
 | 
			
		||||
                                        path: path.split(';')
 | 
			
		||||
                                    });
 | 
			
		||||
                                });
 | 
			
		||||
                            })(focused[i]);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                complete();
 | 
			
		||||
            });
 | 
			
		||||
            var opened = $.jStorage.get('aciTree_' + this._instance.options.persist + '_opened');
 | 
			
		||||
            if (opened instanceof Array) {
 | 
			
		||||
                // open all saved items
 | 
			
		||||
                for (var i in opened) {
 | 
			
		||||
                    (function(path) {
 | 
			
		||||
                        // add item to queue
 | 
			
		||||
                        task.push(function(complete) {
 | 
			
		||||
                            this.searchPath(null, {
 | 
			
		||||
                                success: function(item) {
 | 
			
		||||
                                    this.open(item, {
 | 
			
		||||
                                        uid: 'ui.persist',
 | 
			
		||||
                                        success: complete,
 | 
			
		||||
                                        fail: complete
 | 
			
		||||
                                    });
 | 
			
		||||
                                },
 | 
			
		||||
                                fail: complete,
 | 
			
		||||
                                path: path.split(';'),
 | 
			
		||||
                                load: true
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                    })(opened[i]);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // persist selected items
 | 
			
		||||
        _persistSelected: function() {
 | 
			
		||||
            // support `selectable` extension
 | 
			
		||||
            if (this.extSelectable && this.extSelectable()) {
 | 
			
		||||
                var selected = [];
 | 
			
		||||
                this.selected().each(this.proxy(function(element) {
 | 
			
		||||
                    var item = $(element);
 | 
			
		||||
                    var path = this.pathId(item);
 | 
			
		||||
                    path.push(this.getId(item));
 | 
			
		||||
                    selected.push(path.join(';'));
 | 
			
		||||
                }, true));
 | 
			
		||||
                $.jStorage.set('aciTree_' + this._instance.options.persist + '_selected', selected);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // persist focused item
 | 
			
		||||
        _persistFocused: function() {
 | 
			
		||||
            // support `selectable` extension
 | 
			
		||||
            if (this.extSelectable && this.extSelectable()) {
 | 
			
		||||
                var focused = [];
 | 
			
		||||
                this.focused().each(this.proxy(function(element) {
 | 
			
		||||
                    var item = $(element);
 | 
			
		||||
                    var path = this.pathId(item);
 | 
			
		||||
                    path.push(this.getId(item));
 | 
			
		||||
                    focused.push(path.join(';'));
 | 
			
		||||
                }, true));
 | 
			
		||||
                $.jStorage.set('aciTree_' + this._instance.options.persist + '_focused', focused);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // persist opened items
 | 
			
		||||
        _persistOpened: function() {
 | 
			
		||||
            var opened = [];
 | 
			
		||||
            this.inodes(this.children(null, true), true).each(this.proxy(function(element) {
 | 
			
		||||
                var item = $(element);
 | 
			
		||||
                if (this.isOpenPath(item)) {
 | 
			
		||||
                    var path = this.pathId(item);
 | 
			
		||||
                    path.push(this.getId(item));
 | 
			
		||||
                    opened.push(path.join(';'));
 | 
			
		||||
                }
 | 
			
		||||
            }, true));
 | 
			
		||||
            $.jStorage.set('aciTree_' + this._instance.options.persist + '_opened', opened);
 | 
			
		||||
        },
 | 
			
		||||
        // test if there is any saved data
 | 
			
		||||
        isPersist: function() {
 | 
			
		||||
            if (this.extPersist()) {
 | 
			
		||||
                var selected = $.jStorage.get('aciTree_' + this._instance.options.persist + '_selected');
 | 
			
		||||
                if (selected instanceof Array) {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                var focused = $.jStorage.get('aciTree_' + this._instance.options.persist + '_focused');
 | 
			
		||||
                if (focused instanceof Array) {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                var opened = $.jStorage.get('aciTree_' + this._instance.options.persist + '_opened');
 | 
			
		||||
                if (opened instanceof Array) {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        },
 | 
			
		||||
        // remove any saved states
 | 
			
		||||
        unpersist: function() {
 | 
			
		||||
            if (this.extPersist()) {
 | 
			
		||||
                $.jStorage.deleteKey('aciTree_' + this._instance.options.persist + '_selected');
 | 
			
		||||
                $.jStorage.deleteKey('aciTree_' + this._instance.options.persist + '_focused');
 | 
			
		||||
                $.jStorage.deleteKey('aciTree_' + this._instance.options.persist + '_opened');
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // test if persist is enabled
 | 
			
		||||
        extPersist: function() {
 | 
			
		||||
            return this._instance.options.persist;
 | 
			
		||||
        },
 | 
			
		||||
        // override set `option`
 | 
			
		||||
        option: function(option, value) {
 | 
			
		||||
            var persist = this.extPersist();
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super(option, value);
 | 
			
		||||
            if (this.extPersist() != persist) {
 | 
			
		||||
                if (persist) {
 | 
			
		||||
                    this._donePersist();
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._initPersist();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // done persist
 | 
			
		||||
        _donePersist: function() {
 | 
			
		||||
            this._instance.jQuery.unbind(this._private.nameSpace);
 | 
			
		||||
        },
 | 
			
		||||
        // override `_destroyHook`
 | 
			
		||||
        _destroyHook: function(unloaded) {
 | 
			
		||||
            if (unloaded) {
 | 
			
		||||
                this._donePersist();
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super(unloaded);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // extend the base aciTree class and add the persist stuff
 | 
			
		||||
    aciPluginClass.plugins.aciTree = aciPluginClass.plugins.aciTree.extend(aciTree_persist, 'aciTreePersist');
 | 
			
		||||
 | 
			
		||||
    // add extra default options
 | 
			
		||||
    aciPluginClass.defaults('aciTree', options);
 | 
			
		||||
 | 
			
		||||
})(jQuery, this);
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,471 @@
 | 
			
		|||
 | 
			
		||||
/*
 | 
			
		||||
 * aciTree jQuery Plugin v4.5.0-rc.7
 | 
			
		||||
 * http://acoderinsights.ro
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2014 Dragos Ursu
 | 
			
		||||
 * Dual licensed under the MIT or GPL Version 2 licenses.
 | 
			
		||||
 *
 | 
			
		||||
 * Require jQuery Library >= v1.9.0 http://jquery.com
 | 
			
		||||
 * + aciPlugin >= v1.5.1 https://github.com/dragosu/jquery-aciPlugin
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This extension adds radio-button support to aciTree,
 | 
			
		||||
 * should be used with the selectable extension.
 | 
			
		||||
 *
 | 
			
		||||
 * The are a few extra properties for the item data:
 | 
			
		||||
 *
 | 
			
		||||
 * {
 | 
			
		||||
 *   ...
 | 
			
		||||
 *   radio: true,                       // TRUE (default) means the item will have a radio button (can be omitted if the `checkbox` extension is not used)
 | 
			
		||||
 *   checked: false,                    // if should be checked or not
 | 
			
		||||
 *   ...
 | 
			
		||||
 * }
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function($, window, undefined) {
 | 
			
		||||
 | 
			
		||||
    // extra default options
 | 
			
		||||
 | 
			
		||||
    var options = {
 | 
			
		||||
        radio: false,                   // if TRUE then each item will have a radio button
 | 
			
		||||
        radioChain: true,               // if TRUE the selection will propagate to the parents/children
 | 
			
		||||
        radioBreak: true,               // if TRUE then a missing radio button will break the chaining
 | 
			
		||||
        radioClick: false               // if TRUE then a click will trigger a state change only when made over the radio-button itself
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // aciTree radio extension
 | 
			
		||||
 | 
			
		||||
    var aciTree_radio = {
 | 
			
		||||
        // init radio
 | 
			
		||||
        _radioInit: function() {
 | 
			
		||||
            this._instance.jQuery.bind('acitree' + this._private.nameSpace, function(event, api, item, eventName, options) {
 | 
			
		||||
                switch (eventName) {
 | 
			
		||||
                    case 'loaded':
 | 
			
		||||
                        if (item) {
 | 
			
		||||
                            // check/update on item load
 | 
			
		||||
                            api._radioLoad(item);
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            }).bind('keydown' + this._private.nameSpace, this.proxy(function(e) {
 | 
			
		||||
                switch (e.which) {
 | 
			
		||||
                    case 32: // space
 | 
			
		||||
                        // support `selectable` extension
 | 
			
		||||
                        if (this.extSelectable && this.extSelectable() && !e.ctrlKey) {
 | 
			
		||||
                            var item = this.focused();
 | 
			
		||||
                            if (this.hasRadio(item) && this.isEnabled(item)) {
 | 
			
		||||
                                if (!this.isChecked(item)) {
 | 
			
		||||
                                    this.check(item);
 | 
			
		||||
                                }
 | 
			
		||||
                                e.stopImmediatePropagation();
 | 
			
		||||
                                // prevent page scroll
 | 
			
		||||
                                e.preventDefault();
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            })).on('click' + this._private.nameSpace, '.aciTreeItem', this.proxy(function(e) {
 | 
			
		||||
                if (!this._instance.options.radioClick || $(e.target).is('.aciTreeCheck')) {
 | 
			
		||||
                    var item = this.itemFrom(e.target);
 | 
			
		||||
                    if (this.hasRadio(item) && this.isEnabled(item) && (!this.extSelectable || !this.extSelectable() || (!e.ctrlKey && !e.shiftKey))) {
 | 
			
		||||
                        // change state on click
 | 
			
		||||
                        if (!this.isChecked(item)) {
 | 
			
		||||
                            this.check(item);
 | 
			
		||||
                        }
 | 
			
		||||
                        e.preventDefault();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }));
 | 
			
		||||
        },
 | 
			
		||||
        // override `_initHook`
 | 
			
		||||
        _initHook: function() {
 | 
			
		||||
            if (this.extRadio()) {
 | 
			
		||||
                this._radioInit();
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super();
 | 
			
		||||
        },
 | 
			
		||||
        // override `_itemHook`
 | 
			
		||||
        _itemHook: function(parent, item, itemData, level) {
 | 
			
		||||
            if (this.extRadio()) {
 | 
			
		||||
                // support `checkbox` extension
 | 
			
		||||
                var checkbox = this.extCheckbox && this.hasCheckbox(item);
 | 
			
		||||
                if (!checkbox && (itemData.radio || ((itemData.radio === undefined) && (!this.extCheckbox || !this.extCheckbox())))) {
 | 
			
		||||
                    this._radioDOM.add(item, itemData);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super(parent, item, itemData, level);
 | 
			
		||||
        },
 | 
			
		||||
        // low level DOM functions
 | 
			
		||||
        _radioDOM: {
 | 
			
		||||
            // add item radio
 | 
			
		||||
            add: function(item, itemData) {
 | 
			
		||||
                domApi.addClass(item[0], itemData.checked ? ['aciTreeRadio', 'aciTreeChecked'] : 'aciTreeRadio');
 | 
			
		||||
                var text = domApi.childrenByClass(item[0].firstChild, 'aciTreeText');
 | 
			
		||||
                var parent = text.parentNode;
 | 
			
		||||
                var label = window.document.createElement('LABEL');
 | 
			
		||||
                var check = window.document.createElement('SPAN');
 | 
			
		||||
                check.className = 'aciTreeCheck';
 | 
			
		||||
                label.appendChild(check);
 | 
			
		||||
                label.appendChild(text);
 | 
			
		||||
                parent.appendChild(label);
 | 
			
		||||
                item[0].firstChild.setAttribute('aria-checked', !!itemData.checked);
 | 
			
		||||
            },
 | 
			
		||||
            // remove item radio
 | 
			
		||||
            remove: function(item) {
 | 
			
		||||
                domApi.removeClass(item[0], ['aciTreeRadio', 'aciTreeChecked']);
 | 
			
		||||
                var text = domApi.childrenByClass(item[0].firstChild, 'aciTreeText');
 | 
			
		||||
                var label = text.parentNode;
 | 
			
		||||
                var parent = label.parentNode;
 | 
			
		||||
                parent.replaceChild(text, label)
 | 
			
		||||
                item[0].firstChild.removeAttribute('aria-checked');
 | 
			
		||||
            },
 | 
			
		||||
            // (un)check items
 | 
			
		||||
            check: function(items, state) {
 | 
			
		||||
                domApi.toggleListClass(items.toArray(), 'aciTreeChecked', state, function(node) {
 | 
			
		||||
                    node.firstChild.setAttribute('aria-checked', state);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // update item on load
 | 
			
		||||
        _radioLoad: function(item) {
 | 
			
		||||
            if (!this._instance.options.radioChain) {
 | 
			
		||||
                // do not update on load
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            if (this.hasRadio(item)) {
 | 
			
		||||
                if (this.isChecked(item)) {
 | 
			
		||||
                    if (!this.radios(this.children(item, false, true), true).length) {
 | 
			
		||||
                        // the item is checked but no children are, check the children
 | 
			
		||||
                        this._radioUpdate(item, true);
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    // the item is not checked, uncheck children
 | 
			
		||||
                    this._radioUpdate(item);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // get children list
 | 
			
		||||
        _radioChildren: function(item) {
 | 
			
		||||
            if (this._instance.options.radioBreak) {
 | 
			
		||||
                var list = [];
 | 
			
		||||
                var process = this.proxy(function(item) {
 | 
			
		||||
                    var children = this.children(item, false, true);
 | 
			
		||||
                    children.each(this.proxy(function(element) {
 | 
			
		||||
                        var item = $(element);
 | 
			
		||||
                        // break on missing radio
 | 
			
		||||
                        if (this.hasRadio(item)) {
 | 
			
		||||
                            list.push(element);
 | 
			
		||||
                            process(item);
 | 
			
		||||
                        }
 | 
			
		||||
                    }, true));
 | 
			
		||||
                });
 | 
			
		||||
                process(item);
 | 
			
		||||
                return $(list);
 | 
			
		||||
            } else {
 | 
			
		||||
                var children = this.children(item, true, true);
 | 
			
		||||
                return this.radios(children);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // get children across items
 | 
			
		||||
        _radioLevel: function(items) {
 | 
			
		||||
            var list = [];
 | 
			
		||||
            items.each(this.proxy(function(element) {
 | 
			
		||||
                var item = $(element);
 | 
			
		||||
                var children = this.children(item, false, true);
 | 
			
		||||
                children.each(this.proxy(function(element) {
 | 
			
		||||
                    var item = $(element);
 | 
			
		||||
                    if (!this._instance.options.radioBreak || this.hasRadio(item)) {
 | 
			
		||||
                        list.push(element);
 | 
			
		||||
                    }
 | 
			
		||||
                }, true));
 | 
			
		||||
            }, true));
 | 
			
		||||
            return $(list);
 | 
			
		||||
        },
 | 
			
		||||
        // update radio state
 | 
			
		||||
        _radioUpdate: function(item, state) {
 | 
			
		||||
            // update siblings
 | 
			
		||||
            var siblings = this.proxy(function(item) {
 | 
			
		||||
                var siblings = this.siblings(item, true);
 | 
			
		||||
                this._radioDOM.check(this.radios(siblings), false);
 | 
			
		||||
                siblings.each(this.proxy(function(element) {
 | 
			
		||||
                    var item = $(element);
 | 
			
		||||
                    if (!this._instance.options.radioBreak || this.hasRadio(item)) {
 | 
			
		||||
                        this._radioDOM.check(this._radioChildren(item), false);
 | 
			
		||||
                    }
 | 
			
		||||
                }, true));
 | 
			
		||||
            });
 | 
			
		||||
            if (state) {
 | 
			
		||||
                siblings(item);
 | 
			
		||||
            }
 | 
			
		||||
            // update children
 | 
			
		||||
            var checkDown = this.proxy(function(item) {
 | 
			
		||||
                var children = this._radioLevel(item);
 | 
			
		||||
                var radios = this.radios(children);
 | 
			
		||||
                if (radios.length) {
 | 
			
		||||
                    var checked = this.radios(children, true);
 | 
			
		||||
                    if (checked.length) {
 | 
			
		||||
                        checked = checked.first();
 | 
			
		||||
                        this._radioDOM.check(checked, true);
 | 
			
		||||
                        siblings(checked);
 | 
			
		||||
                        checkDown(checked);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        checked = radios.first();
 | 
			
		||||
                        this._radioDOM.check(checked, true);
 | 
			
		||||
                        siblings(checked);
 | 
			
		||||
                        checkDown(checked);
 | 
			
		||||
                    }
 | 
			
		||||
                } else if (children.length) {
 | 
			
		||||
                    checkDown(children);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            if (state) {
 | 
			
		||||
                checkDown(item);
 | 
			
		||||
            } else {
 | 
			
		||||
                this._radioDOM.check(this._radioChildren(item), false);
 | 
			
		||||
            }
 | 
			
		||||
            // update parents
 | 
			
		||||
            var checkUp = this.proxy(function(item) {
 | 
			
		||||
                var parent = this.parent(item);
 | 
			
		||||
                if (parent.length) {
 | 
			
		||||
                    if (this.hasRadio(parent)) {
 | 
			
		||||
                        if (state) {
 | 
			
		||||
                            siblings(parent);
 | 
			
		||||
                        }
 | 
			
		||||
                        this._radioDOM.check(parent, state);
 | 
			
		||||
                        checkUp(parent);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        if (!this._instance.options.radioBreak) {
 | 
			
		||||
                            if (state) {
 | 
			
		||||
                                siblings(parent);
 | 
			
		||||
                            }
 | 
			
		||||
                            checkUp(parent);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            if (state !== undefined) {
 | 
			
		||||
                checkUp(item);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // test if item have a radio
 | 
			
		||||
        hasRadio: function(item) {
 | 
			
		||||
            return item && domApi.hasClass(item[0], 'aciTreeRadio');
 | 
			
		||||
        },
 | 
			
		||||
        // add radio button
 | 
			
		||||
        addRadio: function(item, options) {
 | 
			
		||||
            options = this._options(options, 'radioadded', 'addradiofail', 'wasradio', item);
 | 
			
		||||
            if (this.isItem(item)) {
 | 
			
		||||
                // a way to cancel the operation
 | 
			
		||||
                if (!this._trigger(item, 'beforeaddradio', options)) {
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                if (this.hasRadio(item)) {
 | 
			
		||||
                    this._notify(item, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    var process = function() {
 | 
			
		||||
                        this._radioDOM.add(item, {
 | 
			
		||||
                        });
 | 
			
		||||
                        this._success(item, options);
 | 
			
		||||
                    };
 | 
			
		||||
                    // support `checkbox` extension
 | 
			
		||||
                    if (this.extCheckbox && this.hasCheckbox(item)) {
 | 
			
		||||
                        // remove checkbox first
 | 
			
		||||
                        this.removeCheckbox(item, this._inner(options, {
 | 
			
		||||
                            success: process,
 | 
			
		||||
                            fail: options.fail
 | 
			
		||||
                        }));
 | 
			
		||||
                    } else {
 | 
			
		||||
                        process.apply(this);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                this._fail(item, options);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // remove radio button
 | 
			
		||||
        removeRadio: function(item, options) {
 | 
			
		||||
            options = this._options(options, 'radioremoved', 'removeradiofail', 'notradio', item);
 | 
			
		||||
            if (this.isItem(item)) {
 | 
			
		||||
                // a way to cancel the operation
 | 
			
		||||
                if (!this._trigger(item, 'beforeremoveradio', options)) {
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                if (this.hasRadio(item)) {
 | 
			
		||||
                    this._radioDOM.remove(item);
 | 
			
		||||
                    this._success(item, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._notify(item, options);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                this._fail(item, options);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // test if it's checked
 | 
			
		||||
        isChecked: function(item) {
 | 
			
		||||
            if (this.hasRadio(item)) {
 | 
			
		||||
                return domApi.hasClass(item[0], 'aciTreeChecked');
 | 
			
		||||
            }
 | 
			
		||||
            // support `checkbox` extension
 | 
			
		||||
            if (this._super) {
 | 
			
		||||
                // call the parent
 | 
			
		||||
                return this._super(item);
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        },
 | 
			
		||||
        // check radio button
 | 
			
		||||
        check: function(item, options) {
 | 
			
		||||
            if (this.extRadio && this.hasRadio(item)) {
 | 
			
		||||
                options = this._options(options, 'checked', 'checkfail', 'waschecked', item);
 | 
			
		||||
                // a way to cancel the operation
 | 
			
		||||
                if (!this._trigger(item, 'beforecheck', options)) {
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                if (this.isChecked(item)) {
 | 
			
		||||
                    this._notify(item, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._radioDOM.check(item, true);
 | 
			
		||||
                    if (this._instance.options.radioChain) {
 | 
			
		||||
                        // chain them
 | 
			
		||||
                        this._radioUpdate(item, true);
 | 
			
		||||
                    }
 | 
			
		||||
                    this._success(item, options);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                // support `checkbox` extension
 | 
			
		||||
                if (this._super) {
 | 
			
		||||
                    // call the parent
 | 
			
		||||
                    this._super(item, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._trigger(item, 'checkfail', options);
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // uncheck radio button
 | 
			
		||||
        uncheck: function(item, options) {
 | 
			
		||||
            if (this.extRadio && this.hasRadio(item)) {
 | 
			
		||||
                options = this._options(options, 'unchecked', 'uncheckfail', 'notchecked', item);
 | 
			
		||||
                // a way to cancel the operation
 | 
			
		||||
                if (!this._trigger(item, 'beforeuncheck', options)) {
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                if (this.isChecked(item)) {
 | 
			
		||||
                    this._radioDOM.check(item, false);
 | 
			
		||||
                    if (this._instance.options.radioChain) {
 | 
			
		||||
                        // chain them
 | 
			
		||||
                        this._radioUpdate(item, false);
 | 
			
		||||
                    }
 | 
			
		||||
                    this._success(item, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._notify(item, options);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                // support `checkbox` extension
 | 
			
		||||
                if (this._super) {
 | 
			
		||||
                    // call the parent
 | 
			
		||||
                    this._super(item, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._trigger(item, 'uncheckfail', options);
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // filter items with radio by state (if set)
 | 
			
		||||
        radios: function(items, state) {
 | 
			
		||||
            if (state !== undefined) {
 | 
			
		||||
                return $(domApi.withClass(items.toArray(), state ? ['aciTreeRadio', 'aciTreeChecked'] : 'aciTreeRadio', state ? null : 'aciTreeChecked'));
 | 
			
		||||
            }
 | 
			
		||||
            return $(domApi.withClass(items.toArray(), 'aciTreeRadio'));
 | 
			
		||||
        },
 | 
			
		||||
        // override `_serialize`
 | 
			
		||||
        _serialize: function(item, callback) {
 | 
			
		||||
            var data = this._super(item, callback);
 | 
			
		||||
            if (data && this.extRadio()) {
 | 
			
		||||
                if (data.hasOwnProperty('radio')) {
 | 
			
		||||
                    data.radio = this.hasRadio(item);
 | 
			
		||||
                    data.checked = this.isChecked(item);
 | 
			
		||||
                } else if (this.hasRadio(item)) {
 | 
			
		||||
                    if (this.extCheckbox && this.extCheckbox()) {
 | 
			
		||||
                        data.radio = true;
 | 
			
		||||
                    }
 | 
			
		||||
                    data.checked = this.isChecked(item);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return data;
 | 
			
		||||
        },
 | 
			
		||||
        // override `serialize`
 | 
			
		||||
        serialize: function(item, what, callback) {
 | 
			
		||||
            if (what == 'radio') {
 | 
			
		||||
                var serialized = '';
 | 
			
		||||
                var children = this.children(item, true, true);
 | 
			
		||||
                this.radios(children, true).each(this.proxy(function(element) {
 | 
			
		||||
                    var item = $(element);
 | 
			
		||||
                    if (callback) {
 | 
			
		||||
                        serialized += callback.call(this, item, what, this.getId(item));
 | 
			
		||||
                    } else {
 | 
			
		||||
                        serialized += this._instance.options.serialize.call(this, item, what, this.getId(item));
 | 
			
		||||
                    }
 | 
			
		||||
                }, true));
 | 
			
		||||
                return serialized;
 | 
			
		||||
            }
 | 
			
		||||
            return this._super(item, what, callback);
 | 
			
		||||
        },
 | 
			
		||||
        // test if radio is enabled
 | 
			
		||||
        extRadio: function() {
 | 
			
		||||
            return this._instance.options.radio;
 | 
			
		||||
        },
 | 
			
		||||
        // override set `option`
 | 
			
		||||
        option: function(option, value) {
 | 
			
		||||
            if (this.wasInit() && !this.isLocked()) {
 | 
			
		||||
                if ((option == 'radio') && (value != this.extRadio())) {
 | 
			
		||||
                    if (value) {
 | 
			
		||||
                        this._radioInit();
 | 
			
		||||
                    } else {
 | 
			
		||||
                        this._radioDone();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super(option, value);
 | 
			
		||||
        },
 | 
			
		||||
        // done radio
 | 
			
		||||
        _radioDone: function(destroy) {
 | 
			
		||||
            this._instance.jQuery.unbind(this._private.nameSpace);
 | 
			
		||||
            this._instance.jQuery.off(this._private.nameSpace, '.aciTreeItem');
 | 
			
		||||
            if (!destroy) {
 | 
			
		||||
                // remove radios
 | 
			
		||||
                this.radios(this.children(null, true, true)).each(this.proxy(function(element) {
 | 
			
		||||
                    this.removeRadio($(element));
 | 
			
		||||
                }, true));
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // override `_destroyHook`
 | 
			
		||||
        _destroyHook: function(unloaded) {
 | 
			
		||||
            if (unloaded) {
 | 
			
		||||
                this._radioDone(true);
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super(unloaded);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // extend the base aciTree class and add the radio stuff
 | 
			
		||||
    aciPluginClass.plugins.aciTree = aciPluginClass.plugins.aciTree.extend(aciTree_radio, 'aciTreeRadio');
 | 
			
		||||
 | 
			
		||||
    // add extra default options
 | 
			
		||||
    aciPluginClass.defaults('aciTree', options);
 | 
			
		||||
 | 
			
		||||
    // for internal access
 | 
			
		||||
    var domApi = aciPluginClass.plugins.aciTree_dom;
 | 
			
		||||
 | 
			
		||||
})(jQuery, this);
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,739 @@
 | 
			
		|||
 | 
			
		||||
/*
 | 
			
		||||
 * aciTree jQuery Plugin v4.5.0-rc.7
 | 
			
		||||
 * http://acoderinsights.ro
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2014 Dragos Ursu
 | 
			
		||||
 * Dual licensed under the MIT or GPL Version 2 licenses.
 | 
			
		||||
 *
 | 
			
		||||
 * Require jQuery Library >= v1.9.0 http://jquery.com
 | 
			
		||||
 * + aciPlugin >= v1.5.1 https://github.com/dragosu/jquery-aciPlugin
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This extension adds item selection/keyboard navigation to aciTree and need to
 | 
			
		||||
 * be always included if you care about accessibility.
 | 
			
		||||
 *
 | 
			
		||||
 * There is an extra property for the item data:
 | 
			
		||||
 *
 | 
			
		||||
 * {
 | 
			
		||||
 *   ...
 | 
			
		||||
 *   selected: false,                    // TRUE means the item will be selected
 | 
			
		||||
 *   ...
 | 
			
		||||
 * }
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function($, window, undefined) {
 | 
			
		||||
 | 
			
		||||
    // extra default options
 | 
			
		||||
 | 
			
		||||
    var options = {
 | 
			
		||||
        selectable: true,               // if TRUE then one item can be selected (and the tree navigation with the keyboard will be enabled)
 | 
			
		||||
        multiSelectable: false,         // if TRUE then multiple items can be selected at a time
 | 
			
		||||
        // the 'tabIndex' attribute need to be >= 0 set on the tree container (by default will be set to 0)
 | 
			
		||||
        fullRow: false,                 // if TRUE then the selection will be made on the entire row (the CSS should reflect this)
 | 
			
		||||
        textSelection: false            // if FALSE then the item text can't be selected
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // aciTree selectable extension
 | 
			
		||||
    // adds item selection & keyboard navigation (left/right, up/down, pageup/pagedown, home/end, space, enter, escape)
 | 
			
		||||
    // dblclick also toggles the item
 | 
			
		||||
 | 
			
		||||
    var aciTree_selectable = {
 | 
			
		||||
        __extend: function() {
 | 
			
		||||
            // add extra data
 | 
			
		||||
            $.extend(this._instance, {
 | 
			
		||||
                focus: false
 | 
			
		||||
            });
 | 
			
		||||
            $.extend(this._private, {
 | 
			
		||||
                blurTimeout: null,
 | 
			
		||||
                spinPoint: null // the selected item to operate against when using the shift key with selection
 | 
			
		||||
            });
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super();
 | 
			
		||||
        },
 | 
			
		||||
        // test if has focus
 | 
			
		||||
        hasFocus: function() {
 | 
			
		||||
            return this._instance.focus;
 | 
			
		||||
        },
 | 
			
		||||
        // init selectable
 | 
			
		||||
        _selectableInit: function() {
 | 
			
		||||
            if (this._instance.jQuery.attr('tabindex') === undefined) {
 | 
			
		||||
                // ensure the tree can get focus
 | 
			
		||||
                this._instance.jQuery.attr('tabindex', 0);
 | 
			
		||||
            }
 | 
			
		||||
            if (!this._instance.options.textSelection) {
 | 
			
		||||
                // disable text selection
 | 
			
		||||
                this._selectable(false);
 | 
			
		||||
            }
 | 
			
		||||
            this._instance.jQuery.bind('acitree' + this._private.nameSpace, function(event, api, item, eventName, options) {
 | 
			
		||||
                switch (eventName) {
 | 
			
		||||
                    case 'closed':
 | 
			
		||||
                        var focused = api.focused();
 | 
			
		||||
                        if (api.isChildren(item, focused)) {
 | 
			
		||||
                            // move focus to parent on close
 | 
			
		||||
                            api._focusOne(item);
 | 
			
		||||
                        }
 | 
			
		||||
                        // deselect children on parent close
 | 
			
		||||
                        api.children(item, true).each(api.proxy(function(element) {
 | 
			
		||||
                            var item = $(element);
 | 
			
		||||
                            if (this.isSelected(item)) {
 | 
			
		||||
                                this.deselect(item);
 | 
			
		||||
                            }
 | 
			
		||||
                        }, true));
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            }).bind('focusin' + this._private.nameSpace, this.proxy(function() {
 | 
			
		||||
                // handle tree focus
 | 
			
		||||
                window.clearTimeout(this._private.blurTimeout);
 | 
			
		||||
                if (!this.hasFocus()) {
 | 
			
		||||
                    this._instance.focus = true;
 | 
			
		||||
                    domApi.addClass(this._instance.jQuery[0], 'aciTreeFocus');
 | 
			
		||||
                    this._trigger(null, 'focused');
 | 
			
		||||
                }
 | 
			
		||||
            })).bind('focusout' + this._private.nameSpace, this.proxy(function() {
 | 
			
		||||
                // handle tree focus
 | 
			
		||||
                window.clearTimeout(this._private.blurTimeout);
 | 
			
		||||
                this._private.blurTimeout = window.setTimeout(this.proxy(function() {
 | 
			
		||||
                    if (this.hasFocus()) {
 | 
			
		||||
                        this._instance.focus = false;
 | 
			
		||||
                        domApi.removeClass(this._instance.jQuery[0], 'aciTreeFocus');
 | 
			
		||||
                        this._trigger(null, 'blurred');
 | 
			
		||||
                    }
 | 
			
		||||
                }), 10);
 | 
			
		||||
            })).bind('keydown' + this._private.nameSpace, this.proxy(function(e) {
 | 
			
		||||
                if (!this.hasFocus()) {
 | 
			
		||||
                    // do not handle if we do not have focus
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                var focused = this.focused();
 | 
			
		||||
                if (focused.length && this.isBusy(focused)) {
 | 
			
		||||
                    // skip when busy
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
                var item = $([]);
 | 
			
		||||
                switch (e.which) {
 | 
			
		||||
                    case 65: // aA
 | 
			
		||||
                        if (this._instance.options.multiSelectable && e.ctrlKey) {
 | 
			
		||||
                            // select all visible items
 | 
			
		||||
                            var select = this.visible(this.enabled(this.children(null, true))).not(this.selected());
 | 
			
		||||
                            select.each(this.proxy(function(element) {
 | 
			
		||||
                                this.select($(element), {
 | 
			
		||||
                                    focus: false
 | 
			
		||||
                                });
 | 
			
		||||
                            }, true));
 | 
			
		||||
                            if (!this.focused().length) {
 | 
			
		||||
                                // ensure one item has focus
 | 
			
		||||
                                this._focusOne(this.visible(select, true).first());
 | 
			
		||||
                            }
 | 
			
		||||
                            // prevent default action
 | 
			
		||||
                            e.preventDefault();
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 38: // up
 | 
			
		||||
                        item = focused.length ? this._prev(focused) : this.first();
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 40: // down
 | 
			
		||||
                        item = focused.length ? this._next(focused) : this.first();
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 37: // left
 | 
			
		||||
                        if (focused.length) {
 | 
			
		||||
                            if (this.isOpen(focused)) {
 | 
			
		||||
                                item = focused;
 | 
			
		||||
                                // close the item
 | 
			
		||||
                                this.close(focused, {
 | 
			
		||||
                                    collapse: this._instance.options.collapse,
 | 
			
		||||
                                    expand: this._instance.options.expand,
 | 
			
		||||
                                    unique: this._instance.options.unique
 | 
			
		||||
                                });
 | 
			
		||||
                            } else {
 | 
			
		||||
                                item = this.parent(focused);
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            item = this._first();
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 39: // right
 | 
			
		||||
                        if (focused.length) {
 | 
			
		||||
                            if (this.isInode(focused) && this.isClosed(focused)) {
 | 
			
		||||
                                item = focused;
 | 
			
		||||
                                // open the item
 | 
			
		||||
                                this.open(focused, {
 | 
			
		||||
                                    collapse: this._instance.options.collapse,
 | 
			
		||||
                                    expand: this._instance.options.expand,
 | 
			
		||||
                                    unique: this._instance.options.unique
 | 
			
		||||
                                });
 | 
			
		||||
                            } else {
 | 
			
		||||
                                item = this.first(focused);
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            item = this._first();
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 33: // pgup
 | 
			
		||||
                        item = focused.length ? this._prevPage(focused) : this._first();
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 34: // pgdown
 | 
			
		||||
                        item = focused.length ? this._nextPage(focused) : this._first();
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 36: // home
 | 
			
		||||
                        item = this._first();
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 35: // end
 | 
			
		||||
                        item = this._last();
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 13: // enter
 | 
			
		||||
                    case 107: // numpad [+]
 | 
			
		||||
                        item = focused;
 | 
			
		||||
                        if (this.isInode(focused) && this.isClosed(focused)) {
 | 
			
		||||
                            // open the item
 | 
			
		||||
                            this.open(focused, {
 | 
			
		||||
                                collapse: this._instance.options.collapse,
 | 
			
		||||
                                expand: this._instance.options.expand,
 | 
			
		||||
                                unique: this._instance.options.unique
 | 
			
		||||
                            });
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 27: // escape
 | 
			
		||||
                    case 109: // numpad [-]
 | 
			
		||||
                        item = focused;
 | 
			
		||||
                        if (this.isOpen(focused)) {
 | 
			
		||||
                            // close the item
 | 
			
		||||
                            this.close(focused, {
 | 
			
		||||
                                collapse: this._instance.options.collapse,
 | 
			
		||||
                                expand: this._instance.options.expand,
 | 
			
		||||
                                unique: this._instance.options.unique
 | 
			
		||||
                            });
 | 
			
		||||
                        }
 | 
			
		||||
                        if (e.which == 27) {
 | 
			
		||||
                            // prevent default action on ESC
 | 
			
		||||
                            e.preventDefault();
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 32: // space
 | 
			
		||||
                        item = focused;
 | 
			
		||||
                        if (this.isInode(focused) && !e.ctrlKey) {
 | 
			
		||||
                            // toggle the item
 | 
			
		||||
                            this.toggle(focused, {
 | 
			
		||||
                                collapse: this._instance.options.collapse,
 | 
			
		||||
                                expand: this._instance.options.expand,
 | 
			
		||||
                                unique: this._instance.options.unique
 | 
			
		||||
                            });
 | 
			
		||||
                        }
 | 
			
		||||
                        // prevent page scroll
 | 
			
		||||
                        e.preventDefault();
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 106: // numpad [*]
 | 
			
		||||
                        item = focused;
 | 
			
		||||
                        if (this.isInode(focused)) {
 | 
			
		||||
                            // open all children
 | 
			
		||||
                            this.open(focused, {
 | 
			
		||||
                                collapse: this._instance.options.collapse,
 | 
			
		||||
                                expand: true,
 | 
			
		||||
                                unique: this._instance.options.unique
 | 
			
		||||
                            });
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
                if (item.length) {
 | 
			
		||||
                    if (this._instance.options.multiSelectable && !e.ctrlKey && !e.shiftKey) {
 | 
			
		||||
                        // unselect others
 | 
			
		||||
                        this._unselect(this.selected().not(item));
 | 
			
		||||
                    }
 | 
			
		||||
                    if (!this.isVisible(item)) {
 | 
			
		||||
                        // bring it into view
 | 
			
		||||
                        this.setVisible(item);
 | 
			
		||||
                    }
 | 
			
		||||
                    if (e.ctrlKey) {
 | 
			
		||||
                        if ((e.which == 32) && this.isEnabled(item)) { // space
 | 
			
		||||
                            if (this.isSelected(item)) {
 | 
			
		||||
                                this.deselect(item);
 | 
			
		||||
                            } else {
 | 
			
		||||
                                this.select(item);
 | 
			
		||||
                            }
 | 
			
		||||
                            // remember for later
 | 
			
		||||
                            this._private.spinPoint = item;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            this._focusOne(item);
 | 
			
		||||
                        }
 | 
			
		||||
                    } else if (e.shiftKey) {
 | 
			
		||||
                        this._shiftSelect(item);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        if (!this.isSelected(item) && this.isEnabled(item)) {
 | 
			
		||||
                            this.select(item);
 | 
			
		||||
                        } else {
 | 
			
		||||
                            this._focusOne(item);
 | 
			
		||||
                        }
 | 
			
		||||
                        // remember for later
 | 
			
		||||
                        this._private.spinPoint = item;
 | 
			
		||||
                    }
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }));
 | 
			
		||||
            this._fullRow(this._instance.options.fullRow);
 | 
			
		||||
            this._multiSelectable(this._instance.options.multiSelectable);
 | 
			
		||||
        },
 | 
			
		||||
        // change full row mode
 | 
			
		||||
        _fullRow: function(state) {
 | 
			
		||||
            this._instance.jQuery.off(this._private.nameSpace, '.aciTreeLine,.aciTreeItem').off(this._private.nameSpace, '.aciTreeItem');
 | 
			
		||||
            this._instance.jQuery.on('mousedown' + this._private.nameSpace + ' click' + this._private.nameSpace, state ? '.aciTreeLine,.aciTreeItem' : '.aciTreeItem', this.proxy(function(e) {
 | 
			
		||||
                var item = this.itemFrom(e.target);
 | 
			
		||||
                if (!this.isVisible(item)) {
 | 
			
		||||
                    this.setVisible(item);
 | 
			
		||||
                }
 | 
			
		||||
                if (e.ctrlKey) {
 | 
			
		||||
                    if (e.type == 'click') {
 | 
			
		||||
                        if (this.isEnabled(item)) {
 | 
			
		||||
                            // (de)select item
 | 
			
		||||
                            if (this.isSelected(item)) {
 | 
			
		||||
                                this.deselect(item);
 | 
			
		||||
                                this._focusOne(item);
 | 
			
		||||
                            } else {
 | 
			
		||||
                                this.select(item);
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            this._focusOne(item);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                } else if (this._instance.options.multiSelectable && e.shiftKey) {
 | 
			
		||||
                    this._shiftSelect(item);
 | 
			
		||||
                } else {
 | 
			
		||||
                    if (this._instance.options.multiSelectable && (!this.isSelected(item) || (e.type == 'click'))) {
 | 
			
		||||
                        // deselect all other (keep the old focus)
 | 
			
		||||
                        this._unselect(this.selected().not(item));
 | 
			
		||||
                    }
 | 
			
		||||
                    this._selectOne(item);
 | 
			
		||||
                }
 | 
			
		||||
                if (!e.shiftKey) {
 | 
			
		||||
                    this._private.spinPoint = item;
 | 
			
		||||
                }
 | 
			
		||||
            })).on('dblclick' + this._private.nameSpace, state ? '.aciTreeLine,.aciTreeItem' : '.aciTreeItem', this.proxy(function(e) {
 | 
			
		||||
                var item = this.itemFrom(e.target);
 | 
			
		||||
                if (this.isInode(item)) {
 | 
			
		||||
                    // toggle the item
 | 
			
		||||
                    this.toggle(item, {
 | 
			
		||||
                        collapse: this._instance.options.collapse,
 | 
			
		||||
                        expand: this._instance.options.expand,
 | 
			
		||||
                        unique: this._instance.options.unique
 | 
			
		||||
                    });
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }));
 | 
			
		||||
            if (state) {
 | 
			
		||||
                domApi.addClass(this._instance.jQuery[0], 'aciTreeFullRow');
 | 
			
		||||
            } else {
 | 
			
		||||
                domApi.removeClass(this._instance.jQuery[0], 'aciTreeFullRow');
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // change selection mode
 | 
			
		||||
        _multiSelectable: function(state) {
 | 
			
		||||
            if (state) {
 | 
			
		||||
                this._instance.jQuery.attr('aria-multiselectable', true);
 | 
			
		||||
            } else {
 | 
			
		||||
                var focused = this.focused();
 | 
			
		||||
                this._unselect(this.selected().not(focused));
 | 
			
		||||
                this._instance.jQuery.removeAttr('aria-multiselectable');
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // process `shift` key selection
 | 
			
		||||
        _shiftSelect: function(item) {
 | 
			
		||||
            var spinPoint = this._private.spinPoint;
 | 
			
		||||
            if (!spinPoint || !$.contains(this._instance.jQuery[0], spinPoint[0]) || !this.isOpenPath(spinPoint)) {
 | 
			
		||||
                spinPoint = this.focused();
 | 
			
		||||
            }
 | 
			
		||||
            if (spinPoint.length) {
 | 
			
		||||
                // select a range of items
 | 
			
		||||
                var select = [item[0]], start = spinPoint[0], found = false, stop = item[0];
 | 
			
		||||
                var visible = this.visible(this.children(null, true));
 | 
			
		||||
                visible.each(this.proxy(function(element) {
 | 
			
		||||
                    // find what items to select
 | 
			
		||||
                    if (found) {
 | 
			
		||||
                        if (this.isEnabled($(element))) {
 | 
			
		||||
                            select.push(element);
 | 
			
		||||
                        }
 | 
			
		||||
                        if ((element == start) || (element == stop)) {
 | 
			
		||||
                            return false;
 | 
			
		||||
                        }
 | 
			
		||||
                    } else if ((element == start) || (element == stop)) {
 | 
			
		||||
                        if (this.isEnabled($(element))) {
 | 
			
		||||
                            select.push(element);
 | 
			
		||||
                        }
 | 
			
		||||
                        if ((element == start) && (element == stop)) {
 | 
			
		||||
                            return false;
 | 
			
		||||
                        }
 | 
			
		||||
                        found = true;
 | 
			
		||||
                    }
 | 
			
		||||
                }, true));
 | 
			
		||||
                this._unselect(this.selected().not(select));
 | 
			
		||||
                // select the items
 | 
			
		||||
                $(select).not(item).each(this.proxy(function(element) {
 | 
			
		||||
                    var item = $(element);
 | 
			
		||||
                    if (!this.isSelected(item)) {
 | 
			
		||||
                        // select item (keep the old focus)
 | 
			
		||||
                        this.select(item, {
 | 
			
		||||
                            focus: false
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                }, true));
 | 
			
		||||
            }
 | 
			
		||||
            this._selectOne(item);
 | 
			
		||||
        },
 | 
			
		||||
        // override `_initHook`
 | 
			
		||||
        _initHook: function() {
 | 
			
		||||
            if (this.extSelectable()) {
 | 
			
		||||
                this._selectableInit();
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super();
 | 
			
		||||
        },
 | 
			
		||||
        // override `_itemHook`
 | 
			
		||||
        _itemHook: function(parent, item, itemData, level) {
 | 
			
		||||
            if (this.extSelectable() && itemData.selected) {
 | 
			
		||||
                this._selectableDOM.select(item, true);
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super(parent, item, itemData, level);
 | 
			
		||||
        },
 | 
			
		||||
        // low level DOM functions
 | 
			
		||||
        _selectableDOM: {
 | 
			
		||||
            // (de)select one or more items
 | 
			
		||||
            select: function(items, state) {
 | 
			
		||||
                if (state) {
 | 
			
		||||
                    domApi.addListClass(items.toArray(), 'aciTreeSelected', function(node) {
 | 
			
		||||
                        node.firstChild.setAttribute('aria-selected', true);
 | 
			
		||||
                    });
 | 
			
		||||
                } else {
 | 
			
		||||
                    domApi.removeListClass(items.toArray(), 'aciTreeSelected', function(node) {
 | 
			
		||||
                        node.firstChild.setAttribute('aria-selected', false);
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            // focus one item, unfocus one or more items
 | 
			
		||||
            focus: function(items, state) {
 | 
			
		||||
                if (state) {
 | 
			
		||||
                    domApi.addClass(items[0], 'aciTreeFocus');
 | 
			
		||||
                    items[0].firstChild.focus();
 | 
			
		||||
                } else {
 | 
			
		||||
                    domApi.removeListClass(items.toArray(), 'aciTreeFocus');
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // make element (un)selectable
 | 
			
		||||
        _selectable: function(state) {
 | 
			
		||||
            if (state) {
 | 
			
		||||
                this._instance.jQuery.css({
 | 
			
		||||
                    '-webkit-user-select': 'text',
 | 
			
		||||
                    '-moz-user-select': 'text',
 | 
			
		||||
                    '-ms-user-select': 'text',
 | 
			
		||||
                    '-o-user-select': 'text',
 | 
			
		||||
                    'user-select': 'text'
 | 
			
		||||
                }).attr({
 | 
			
		||||
                    'unselectable': null,
 | 
			
		||||
                    'onselectstart': null
 | 
			
		||||
                }).unbind('selectstart' + this._private.nameSpace);
 | 
			
		||||
            } else {
 | 
			
		||||
                this._instance.jQuery.css({
 | 
			
		||||
                    '-webkit-user-select': 'none',
 | 
			
		||||
                    '-moz-user-select': '-moz-none',
 | 
			
		||||
                    '-ms-user-select': 'none',
 | 
			
		||||
                    '-o-user-select': 'none',
 | 
			
		||||
                    'user-select': 'none'
 | 
			
		||||
                }).attr({
 | 
			
		||||
                    'unselectable': 'on',
 | 
			
		||||
                    'onselectstart': 'return false'
 | 
			
		||||
                }).bind('selectstart' + this._private.nameSpace, function(e) {
 | 
			
		||||
                    if (!$(e.target).is('input,textarea')) {
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // get first visible item
 | 
			
		||||
        _first: function() {
 | 
			
		||||
            return $(domApi.first(this._instance.jQuery[0], function(node) {
 | 
			
		||||
                return this.hasClass(node, 'aciTreeVisible') ? true : null;
 | 
			
		||||
            }));
 | 
			
		||||
        },
 | 
			
		||||
        // get last visible item
 | 
			
		||||
        _last: function() {
 | 
			
		||||
            return $(domApi.last(this._instance.jQuery[0], function(node) {
 | 
			
		||||
                return this.hasClass(node, 'aciTreeVisible') ? true : null;
 | 
			
		||||
            }));
 | 
			
		||||
        },
 | 
			
		||||
        // get previous visible starting with item
 | 
			
		||||
        _prev: function(item) {
 | 
			
		||||
            return $(domApi.prevAll(item[0], function(node) {
 | 
			
		||||
                return this.hasClass(node, 'aciTreeVisible') ? true : null;
 | 
			
		||||
            }));
 | 
			
		||||
        },
 | 
			
		||||
        // get next visible starting with item
 | 
			
		||||
        _next: function(item) {
 | 
			
		||||
            return $(domApi.nextAll(item[0], function(node) {
 | 
			
		||||
                return this.hasClass(node, 'aciTreeVisible') ? true : null;
 | 
			
		||||
            }));
 | 
			
		||||
        },
 | 
			
		||||
        // get previous page starting with item
 | 
			
		||||
        _prevPage: function(item) {
 | 
			
		||||
            var space = this._instance.jQuery.height();
 | 
			
		||||
            var now = item[0].firstChild.offsetHeight;
 | 
			
		||||
            var prev = item, last = $();
 | 
			
		||||
            while (now < space) {
 | 
			
		||||
                prev = this._prev(prev);
 | 
			
		||||
                if (prev[0]) {
 | 
			
		||||
                    now += prev[0].firstChild.offsetHeight;
 | 
			
		||||
                    last = prev;
 | 
			
		||||
                } else {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return last;
 | 
			
		||||
        },
 | 
			
		||||
        // get next page starting with item
 | 
			
		||||
        _nextPage: function(item) {
 | 
			
		||||
            var space = this._instance.jQuery.height();
 | 
			
		||||
            var now = item[0].firstChild.offsetHeight;
 | 
			
		||||
            var next = item, last = $();
 | 
			
		||||
            while (now < space) {
 | 
			
		||||
                next = this._next(next);
 | 
			
		||||
                if (next[0]) {
 | 
			
		||||
                    now += next[0].firstChild.offsetHeight;
 | 
			
		||||
                    last = next;
 | 
			
		||||
                } else {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return last;
 | 
			
		||||
        },
 | 
			
		||||
        // select one item
 | 
			
		||||
        _selectOne: function(item) {
 | 
			
		||||
            if (this.isSelected(item)) {
 | 
			
		||||
                this._focusOne(item);
 | 
			
		||||
            } else {
 | 
			
		||||
                if (this.isEnabled(item)) {
 | 
			
		||||
                    // select the item
 | 
			
		||||
                    this.select(item);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._focusOne(item);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // unselect the items
 | 
			
		||||
        _unselect: function(items) {
 | 
			
		||||
            items.each(this.proxy(function(element) {
 | 
			
		||||
                this.deselect($(element));
 | 
			
		||||
            }, true));
 | 
			
		||||
        },
 | 
			
		||||
        // focus one item
 | 
			
		||||
        _focusOne: function(item) {
 | 
			
		||||
            if (!this._instance.options.multiSelectable) {
 | 
			
		||||
                this._unselect(this.selected().not(item));
 | 
			
		||||
            }
 | 
			
		||||
            if (!this.isFocused(item)) {
 | 
			
		||||
                this.focus(item);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // select item
 | 
			
		||||
        // `options.focus` when set to FALSE will not set the focus
 | 
			
		||||
        // `options.oldSelected` will keep the old selected items
 | 
			
		||||
        select: function(item, options) {
 | 
			
		||||
            options = this._options(options, 'selected', 'selectfail', 'wasselected', item);
 | 
			
		||||
            if (this.extSelectable() && this.isItem(item)) {
 | 
			
		||||
                // a way to cancel the operation
 | 
			
		||||
                if (!this._trigger(item, 'beforeselect', options)) {
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                // keep the old ones
 | 
			
		||||
                options.oldSelected = this.selected();
 | 
			
		||||
                if (!this._instance.options.multiSelectable) {
 | 
			
		||||
                    // deselect all other
 | 
			
		||||
                    var unselect = options.oldSelected.not(item);
 | 
			
		||||
                    this._selectableDOM.select(unselect, false);
 | 
			
		||||
                    unselect.each(this.proxy(function(element) {
 | 
			
		||||
                        this._trigger($(element), 'deselected', options);
 | 
			
		||||
                    }, true));
 | 
			
		||||
                }
 | 
			
		||||
                if (this.isSelected(item)) {
 | 
			
		||||
                    this._notify(item, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._selectableDOM.select(item, true);
 | 
			
		||||
                    this._success(item, options);
 | 
			
		||||
                }
 | 
			
		||||
                // process focus
 | 
			
		||||
                if ((options.focus === undefined) || options.focus) {
 | 
			
		||||
                    if (!this.isFocused(item) || options.focus) {
 | 
			
		||||
                        this.focus(item, this._inner(options));
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                this._fail(item, options);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // deselect item
 | 
			
		||||
        deselect: function(item, options) {
 | 
			
		||||
            options = this._options(options, 'deselected', 'deselectfail', 'notselected', item);
 | 
			
		||||
            if (this.extSelectable() && this.isItem(item)) {
 | 
			
		||||
                // a way to cancel the operation
 | 
			
		||||
                if (!this._trigger(item, 'beforedeselect', options)) {
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                if (this.isSelected(item)) {
 | 
			
		||||
                    this._selectableDOM.select(item, false);
 | 
			
		||||
                    this._success(item, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._notify(item, options);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                this._fail(item, options);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // set `virtual` focus
 | 
			
		||||
        // `options.oldFocused` will keep the old focused item
 | 
			
		||||
        focus: function(item, options) {
 | 
			
		||||
            options = this._options(options, 'focus', 'focusfail', 'wasfocused', item);
 | 
			
		||||
            if (this.extSelectable() && this.isItem(item)) {
 | 
			
		||||
                // a way to cancel the operation
 | 
			
		||||
                if (!this._trigger(item, 'beforefocus', options)) {
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                // keep the old ones
 | 
			
		||||
                options.oldFocused = this.focused();
 | 
			
		||||
                // blur all other
 | 
			
		||||
                var unfocus = options.oldFocused.not(item);
 | 
			
		||||
                this._selectableDOM.focus(unfocus, false);
 | 
			
		||||
                // unfocus all others
 | 
			
		||||
                unfocus.each(this.proxy(function(element) {
 | 
			
		||||
                    this._trigger($(element), 'blur', options);
 | 
			
		||||
                }, true));
 | 
			
		||||
                if (this.isFocused(item)) {
 | 
			
		||||
                    this._notify(item, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._selectableDOM.focus(item, true);
 | 
			
		||||
                    this._success(item, options);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                this._fail(item, options);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // remove `virtual` focus
 | 
			
		||||
        blur: function(item, options) {
 | 
			
		||||
            options = this._options(options, 'blur', 'blurfail', 'notfocused', item);
 | 
			
		||||
            if (this.extSelectable() && this.isItem(item)) {
 | 
			
		||||
                // a way to cancel the operation
 | 
			
		||||
                if (!this._trigger(item, 'beforeblur', options)) {
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                if (this.isFocused(item)) {
 | 
			
		||||
                    this._selectableDOM.focus(item, false);
 | 
			
		||||
                    this._success(item, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._notify(item, options);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                this._fail(item, options);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // get selected items
 | 
			
		||||
        selected: function() {
 | 
			
		||||
            return this._instance.jQuery.find('.aciTreeSelected');
 | 
			
		||||
        },
 | 
			
		||||
        // override `_serialize`
 | 
			
		||||
        _serialize: function(item, callback) {
 | 
			
		||||
            // call the parent
 | 
			
		||||
            var data = this._super(item, callback);
 | 
			
		||||
            if (data && this.extSelectable()) {
 | 
			
		||||
                if (data.hasOwnProperty('selected')) {
 | 
			
		||||
                    data.selected = this.isSelected(item);
 | 
			
		||||
                } else if (this.isSelected(item)) {
 | 
			
		||||
                    data.selected = true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return data;
 | 
			
		||||
        },
 | 
			
		||||
        // test if item is selected
 | 
			
		||||
        isSelected: function(item) {
 | 
			
		||||
            return item && domApi.hasClass(item[0], 'aciTreeSelected');
 | 
			
		||||
        },
 | 
			
		||||
        // return the focused item
 | 
			
		||||
        focused: function() {
 | 
			
		||||
            return this._instance.jQuery.find('.aciTreeFocus');
 | 
			
		||||
        },
 | 
			
		||||
        // test if item is focused
 | 
			
		||||
        isFocused: function(item) {
 | 
			
		||||
            return item && domApi.hasClass(item[0], 'aciTreeFocus');
 | 
			
		||||
        },
 | 
			
		||||
        // test if selectable is enabled
 | 
			
		||||
        extSelectable: function() {
 | 
			
		||||
            return this._instance.options.selectable;
 | 
			
		||||
        },
 | 
			
		||||
        // override set `option`
 | 
			
		||||
        option: function(option, value) {
 | 
			
		||||
            if (this.wasInit() && !this.isLocked()) {
 | 
			
		||||
                if ((option == 'selectable') && (value != this.extSelectable())) {
 | 
			
		||||
                    if (value) {
 | 
			
		||||
                        this._selectableInit();
 | 
			
		||||
                    } else {
 | 
			
		||||
                        this._selectableDone();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                if ((option == 'multiSelectable') && (value != this._instance.options.multiSelectable)) {
 | 
			
		||||
                    this._multiSelectable(value);
 | 
			
		||||
                }
 | 
			
		||||
                if ((option == 'fullRow') && (value != this._instance.options.fullRow)) {
 | 
			
		||||
                    this._fullRow(value);
 | 
			
		||||
                }
 | 
			
		||||
                if ((option == 'textSelection') && (value != this._instance.options.textSelection)) {
 | 
			
		||||
                    this._selectable(value);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super(option, value);
 | 
			
		||||
        },
 | 
			
		||||
        // done selectable
 | 
			
		||||
        _selectableDone: function(destroy) {
 | 
			
		||||
            if (this._instance.jQuery.attr('tabindex') == 0) {
 | 
			
		||||
                this._instance.jQuery.removeAttr('tabindex');
 | 
			
		||||
            }
 | 
			
		||||
            if (!this._instance.options.textSelection) {
 | 
			
		||||
                this._selectable(true);
 | 
			
		||||
            }
 | 
			
		||||
            this._instance.jQuery.unbind(this._private.nameSpace);
 | 
			
		||||
            this._instance.jQuery.off(this._private.nameSpace, '.aciTreeLine,.aciTreeItem').off(this._private.nameSpace, '.aciTreeItem');
 | 
			
		||||
            domApi.removeClass(this._instance.jQuery[0], ['aciTreeFocus', 'aciTreeFullRow']);
 | 
			
		||||
            this._instance.jQuery.removeAttr('aria-multiselectable');
 | 
			
		||||
            this._instance.focus = false;
 | 
			
		||||
            this._private.spinPoint = null;
 | 
			
		||||
            if (!destroy) {
 | 
			
		||||
                // remove selection
 | 
			
		||||
                this._unselect(this.selected());
 | 
			
		||||
                var focused = this.focused();
 | 
			
		||||
                if (focused.length) {
 | 
			
		||||
                    this.blur(focused);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // override `_destroyHook`
 | 
			
		||||
        _destroyHook: function(unloaded) {
 | 
			
		||||
            if (unloaded) {
 | 
			
		||||
                this._selectableDone(true);
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super(unloaded);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // extend the base aciTree class and add the selectable stuff
 | 
			
		||||
    aciPluginClass.plugins.aciTree = aciPluginClass.plugins.aciTree.extend(aciTree_selectable, 'aciTreeSelectable');
 | 
			
		||||
 | 
			
		||||
    // add extra default options
 | 
			
		||||
    aciPluginClass.defaults('aciTree', options);
 | 
			
		||||
 | 
			
		||||
    // for internal access
 | 
			
		||||
    var domApi = aciPluginClass.plugins.aciTree_dom;
 | 
			
		||||
 | 
			
		||||
})(jQuery, this);
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,339 @@
 | 
			
		|||
 | 
			
		||||
/*
 | 
			
		||||
 * aciTree jQuery Plugin v4.5.0-rc.7
 | 
			
		||||
 * http://acoderinsights.ro
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2014 Dragos Ursu
 | 
			
		||||
 * Dual licensed under the MIT or GPL Version 2 licenses.
 | 
			
		||||
 *
 | 
			
		||||
 * Require jQuery Library >= v1.9.0 http://jquery.com
 | 
			
		||||
 * + aciPlugin >= v1.5.1 https://github.com/dragosu/jquery-aciPlugin
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This extension adds the possibility to sort the tree items.
 | 
			
		||||
 * Require aciSortable https://github.com/dragosu/jquery-aciSortable and the utils extension for reordering items.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function($, window, undefined) {
 | 
			
		||||
 | 
			
		||||
    // extra default options
 | 
			
		||||
 | 
			
		||||
    var options = {
 | 
			
		||||
        sortable: false,             // if TRUE then the tree items can be sorted
 | 
			
		||||
        sortDelay: 750,              // how many [ms] before opening a inode on hovering when in drag
 | 
			
		||||
        // called by the `aciSortable` inside the `drag` callback
 | 
			
		||||
        sortDrag: function(item, placeholder, isValid, helper) {
 | 
			
		||||
            if (!isValid) {
 | 
			
		||||
                var move = this.getLabel(item);
 | 
			
		||||
                if (this._private.dragDrop && (this._private.dragDrop.length > 1)) {
 | 
			
		||||
                    move += ' and #' + (this._private.dragDrop.length - 1) + ' more';
 | 
			
		||||
                }
 | 
			
		||||
                helper.html(move);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // called by the `aciSortable` inside the `valid` callback
 | 
			
		||||
        sortValid: function(item, hover, before, isContainer, placeholder, helper) {
 | 
			
		||||
            var move = this.getLabel(item);
 | 
			
		||||
            if (this._private.dragDrop.length > 1) {
 | 
			
		||||
                move += ' and #' + (this._private.dragDrop.length - 1) + ' more';
 | 
			
		||||
            }
 | 
			
		||||
            if (isContainer) {
 | 
			
		||||
                helper.html('move ' + move + ' to ' + this.getLabel(this.itemFrom(hover)));
 | 
			
		||||
                placeholder.removeClass('aciTreeAfter aciTreeBefore');
 | 
			
		||||
            } else if (before !== null) {
 | 
			
		||||
                if (before) {
 | 
			
		||||
                    helper.html('move ' + move + ' before ' + this.getLabel(hover));
 | 
			
		||||
                    placeholder.removeClass('aciTreeAfter').addClass('aciTreeBefore');
 | 
			
		||||
                } else {
 | 
			
		||||
                    helper.html('move ' + move + ' after ' + this.getLabel(hover));
 | 
			
		||||
                    placeholder.removeClass('aciTreeBefore').addClass('aciTreeAfter');
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // aciTree sortable extension
 | 
			
		||||
 | 
			
		||||
    var aciTree_sortable = {
 | 
			
		||||
        __extend: function() {
 | 
			
		||||
            // add extra data
 | 
			
		||||
            $.extend(this._private, {
 | 
			
		||||
                openTimeout: null,
 | 
			
		||||
                dragDrop: null // the items used in drag & drop
 | 
			
		||||
            });
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super();
 | 
			
		||||
        },
 | 
			
		||||
        // init sortable
 | 
			
		||||
        _sortableInit: function() {
 | 
			
		||||
            this._instance.jQuery.aciSortable({
 | 
			
		||||
                container: '.aciTreeUl',
 | 
			
		||||
                item: '.aciTreeLi',
 | 
			
		||||
                child: 50,
 | 
			
		||||
                childHolder: '<ul class="aciTreeUl aciTreeChild"></ul>',
 | 
			
		||||
                childHolderSelector: '.aciTreeChild',
 | 
			
		||||
                placeholder: '<li class="aciTreeLi aciTreePlaceholder"><div></div></li>',
 | 
			
		||||
                placeholderSelector: '.aciTreePlaceholder',
 | 
			
		||||
                helper: '<div class="aciTreeHelper"></div>',
 | 
			
		||||
                helperSelector: '.aciTreeHelper',
 | 
			
		||||
                // just before drag start
 | 
			
		||||
                before: this.proxy(function(item) {
 | 
			
		||||
                    // init before drag
 | 
			
		||||
                    if (!this._initDrag(item)) {
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
                    // a way to cancel the operation
 | 
			
		||||
                    if (!this._trigger(item, 'beforedrag')) {
 | 
			
		||||
                        this._trigger(item, 'dragfail');
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
                    return true;
 | 
			
		||||
                }),
 | 
			
		||||
                // just after drag start, before dragging
 | 
			
		||||
                start: this.proxy(function(item, placeholder, helper) {
 | 
			
		||||
                    this._instance.jQuery.addClass('aciTreeDragDrop');
 | 
			
		||||
                    helper.stop(true).css('opacity', 1);
 | 
			
		||||
                }),
 | 
			
		||||
                // when in drag
 | 
			
		||||
                drag: this.proxy(function(item, placeholder, isValid, helper) {
 | 
			
		||||
                    if (!isValid) {
 | 
			
		||||
                        window.clearTimeout(this._private.openTimeout);
 | 
			
		||||
                    }
 | 
			
		||||
                    if (this._instance.options.sortDrag) {
 | 
			
		||||
                        this._instance.options.sortDrag.apply(this, arguments);
 | 
			
		||||
                    }
 | 
			
		||||
                }),
 | 
			
		||||
                // to check the drop target (when the placeholder is repositioned)
 | 
			
		||||
                valid: this.proxy(function(item, hover, before, isContainer, placeholder, helper) {
 | 
			
		||||
                    window.clearTimeout(this._private.openTimeout);
 | 
			
		||||
                    if (!this._checkDrop(item, hover, before, isContainer, placeholder, helper)) {
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
                    var options = this._options({
 | 
			
		||||
                        hover: hover,
 | 
			
		||||
                        before: before,
 | 
			
		||||
                        isContainer: isContainer,
 | 
			
		||||
                        placeholder: placeholder,
 | 
			
		||||
                        helper: helper
 | 
			
		||||
                    });
 | 
			
		||||
                    // a way to cancel the operation
 | 
			
		||||
                    if (!this._trigger(item, 'checkdrop', options)) {
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
                    if (this.isInode(hover) && !this.isOpen(hover)) {
 | 
			
		||||
                        this._private.openTimeout = window.setTimeout(this.proxy(function() {
 | 
			
		||||
                            this.open(hover);
 | 
			
		||||
                        }), this._instance.options.sortDelay);
 | 
			
		||||
                    }
 | 
			
		||||
                    if (this._instance.options.sortValid) {
 | 
			
		||||
                        this._instance.options.sortValid.apply(this, arguments);
 | 
			
		||||
                    }
 | 
			
		||||
                    return true;
 | 
			
		||||
                }),
 | 
			
		||||
                // when dragged as child
 | 
			
		||||
                create: this.proxy(function(api, item, hover) {
 | 
			
		||||
                    if (this.isLeaf(hover)) {
 | 
			
		||||
                        hover.append(api._instance.options.childHolder);
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                    return false;
 | 
			
		||||
                }, true),
 | 
			
		||||
                // on drag end
 | 
			
		||||
                end: this.proxy(function(item, hover, placeholder, helper) {
 | 
			
		||||
                    window.clearTimeout(this._private.openTimeout);
 | 
			
		||||
                    var options = {
 | 
			
		||||
                        placeholder: placeholder,
 | 
			
		||||
                        helper: helper
 | 
			
		||||
                    };
 | 
			
		||||
                    options = this._options(options, 'sorted', 'dropfail', null, item);
 | 
			
		||||
                    if (placeholder.parent().length) {
 | 
			
		||||
                        var prev = this.prev(placeholder, true);
 | 
			
		||||
                        if (prev.length) {
 | 
			
		||||
                            // add after a item
 | 
			
		||||
                            placeholder.detach();
 | 
			
		||||
                            var items = $(this._private.dragDrop.get().reverse());
 | 
			
		||||
                            this._private.dragDrop = null;
 | 
			
		||||
                            items.each(this.proxy(function(element) {
 | 
			
		||||
                                this.moveAfter($(element), this._inner(options, {
 | 
			
		||||
                                    success: options.success,
 | 
			
		||||
                                    fail: options.fail,
 | 
			
		||||
                                    after: prev
 | 
			
		||||
                                }));
 | 
			
		||||
                            }, true));
 | 
			
		||||
                        } else {
 | 
			
		||||
                            var next = this.next(placeholder, true);
 | 
			
		||||
                            if (next.length) {
 | 
			
		||||
                                // add before a item
 | 
			
		||||
                                placeholder.detach();
 | 
			
		||||
                                var items = $(this._private.dragDrop.get().reverse());
 | 
			
		||||
                                this._private.dragDrop = null;
 | 
			
		||||
                                items.each(this.proxy(function(element) {
 | 
			
		||||
                                    this.moveBefore($(element), this._inner(options, {
 | 
			
		||||
                                        success: options.success,
 | 
			
		||||
                                        fail: options.fail,
 | 
			
		||||
                                        before: next
 | 
			
		||||
                                    }));
 | 
			
		||||
                                }, true));
 | 
			
		||||
                            } else {
 | 
			
		||||
                                // add as a child
 | 
			
		||||
                                var parent = this.parent(placeholder);
 | 
			
		||||
                                var container = placeholder.parent();
 | 
			
		||||
                                placeholder.detach();
 | 
			
		||||
                                container.remove();
 | 
			
		||||
                                if (this.isLeaf(parent)) {
 | 
			
		||||
                                    // we can set asChild only for leaves
 | 
			
		||||
                                    var items = this._private.dragDrop;
 | 
			
		||||
                                    this.asChild(items.eq(0), this._inner(options, {
 | 
			
		||||
                                        success: function() {
 | 
			
		||||
                                            this._success(item, options);
 | 
			
		||||
                                            this.open(parent);
 | 
			
		||||
                                            items.filter(':gt(0)').each(this.proxy(function(element) {
 | 
			
		||||
                                                this.moveAfter($(element), this._inner(options, {
 | 
			
		||||
                                                    success: options.success,
 | 
			
		||||
                                                    fail: options.fail,
 | 
			
		||||
                                                    after: this.last(parent)
 | 
			
		||||
                                                }));
 | 
			
		||||
                                            }, true));
 | 
			
		||||
                                        },
 | 
			
		||||
                                        fail: options.fail,
 | 
			
		||||
                                        parent: parent
 | 
			
		||||
                                    }));
 | 
			
		||||
                                } else {
 | 
			
		||||
                                    this._fail(item, options);
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        this._fail(item, options);
 | 
			
		||||
                    }
 | 
			
		||||
                    this._private.dragDrop = null;
 | 
			
		||||
                    if (helper.parent().length) {
 | 
			
		||||
                        // the helper is inserted in the DOM
 | 
			
		||||
                        var top = $(window).scrollTop();
 | 
			
		||||
                        var left = $(window).scrollLeft();
 | 
			
		||||
                        var rect = item[0].getBoundingClientRect();
 | 
			
		||||
                        // animate helper to item position
 | 
			
		||||
                        helper.animate({
 | 
			
		||||
                            top: rect.top + top,
 | 
			
		||||
                            left: rect.left + left,
 | 
			
		||||
                            opacity: 0
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            complete: function() {
 | 
			
		||||
                                // detach the helper when completed
 | 
			
		||||
                                helper.detach();
 | 
			
		||||
                            }
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                    this._instance.jQuery.removeClass('aciTreeDragDrop');
 | 
			
		||||
                })
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
        // override `_initHook`
 | 
			
		||||
        _initHook: function() {
 | 
			
		||||
            if (this.extSortable()) {
 | 
			
		||||
                this._sortableInit();
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super();
 | 
			
		||||
        },
 | 
			
		||||
        // reduce items by removing the childrens
 | 
			
		||||
        _parents: function(items) {
 | 
			
		||||
            var len = items.length, a, b, remove = [];
 | 
			
		||||
            for (var i = 0; i < len - 1; i++) {
 | 
			
		||||
                a = items.eq(i);
 | 
			
		||||
                for (var j = i + 1; j < len; j++) {
 | 
			
		||||
                    b = items.eq(j);
 | 
			
		||||
                    if (this.isChildren(a, b)) {
 | 
			
		||||
                        remove.push(items[j]);
 | 
			
		||||
                    } else if (this.isChildren(b, a)) {
 | 
			
		||||
                        remove.push(items[i]);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return items.not(remove);
 | 
			
		||||
        },
 | 
			
		||||
        // called before drag start
 | 
			
		||||
        _initDrag: function(item) {
 | 
			
		||||
            // support `selectable` extension
 | 
			
		||||
            if (this.extSelectable && this.extSelectable()) {
 | 
			
		||||
                if (!this.hasFocus()) {
 | 
			
		||||
                    this._instance.jQuery.focus();
 | 
			
		||||
                }
 | 
			
		||||
                if (!this.isEnabled(item)) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
                var drag = this.selected();
 | 
			
		||||
                if (drag.length) {
 | 
			
		||||
                    if (!this.isSelected(item)) {
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    drag = item;
 | 
			
		||||
                }
 | 
			
		||||
                this._private.dragDrop = this._parents(drag);
 | 
			
		||||
            } else {
 | 
			
		||||
                this._instance.jQuery.focus();
 | 
			
		||||
                this._private.dragDrop = item;
 | 
			
		||||
            }
 | 
			
		||||
            return true;
 | 
			
		||||
        },
 | 
			
		||||
        // check the drop target
 | 
			
		||||
        _checkDrop: function(item, hover, before, isContainer, placeholder, helper) {
 | 
			
		||||
            var items = this._private.dragDrop;
 | 
			
		||||
            if (!items) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            var test = this.itemFrom(hover);
 | 
			
		||||
            if (items.is(test) || items.has(test[0]).length) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            if (!isContainer) {
 | 
			
		||||
                test = before ? this.prev(hover) : this.next(hover);
 | 
			
		||||
                if (items.is(test)) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return true;
 | 
			
		||||
        },
 | 
			
		||||
        // test if sortable is enabled
 | 
			
		||||
        extSortable: function() {
 | 
			
		||||
            return this._instance.options.sortable;
 | 
			
		||||
        },
 | 
			
		||||
        // override set `option`
 | 
			
		||||
        option: function(option, value) {
 | 
			
		||||
            if (this.wasInit() && !this.isLocked()) {
 | 
			
		||||
                if ((option == 'sortable') && (value != this.extSortable())) {
 | 
			
		||||
                    if (value) {
 | 
			
		||||
                        this._sortableInit();
 | 
			
		||||
                    } else {
 | 
			
		||||
                        this._sortableDone();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super(option, value);
 | 
			
		||||
        },
 | 
			
		||||
        // done sortable
 | 
			
		||||
        _sortableDone: function() {
 | 
			
		||||
            this._instance.jQuery.unbind(this._private.nameSpace);
 | 
			
		||||
            this._instance.jQuery.aciSortable('destroy');
 | 
			
		||||
        },
 | 
			
		||||
        // override `_destroyHook`
 | 
			
		||||
        _destroyHook: function(unloaded) {
 | 
			
		||||
            if (unloaded) {
 | 
			
		||||
                this._sortableDone();
 | 
			
		||||
            }
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super(unloaded);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // extend the base aciTree class and add the sortable stuff
 | 
			
		||||
    aciPluginClass.plugins.aciTree = aciPluginClass.plugins.aciTree.extend(aciTree_sortable, 'aciTreeSortable');
 | 
			
		||||
 | 
			
		||||
    // add extra default options
 | 
			
		||||
    aciPluginClass.defaults('aciTree', options);
 | 
			
		||||
 | 
			
		||||
})(jQuery, this);
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,746 @@
 | 
			
		|||
 | 
			
		||||
/*
 | 
			
		||||
 * aciTree jQuery Plugin v4.5.0-rc.7
 | 
			
		||||
 * http://acoderinsights.ro
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2014 Dragos Ursu
 | 
			
		||||
 * Dual licensed under the MIT or GPL Version 2 licenses.
 | 
			
		||||
 *
 | 
			
		||||
 * Require jQuery Library >= v1.9.0 http://jquery.com
 | 
			
		||||
 * + aciPlugin >= v1.5.1 https://github.com/dragosu/jquery-aciPlugin
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * A few utility functions for aciTree.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
(function($, window, undefined) {
 | 
			
		||||
 | 
			
		||||
    // extra default options
 | 
			
		||||
 | 
			
		||||
    var options = {
 | 
			
		||||
        // called when items need to be filtered, for each tree item
 | 
			
		||||
        // return TRUE/FALSE to include/exclude items on filtering
 | 
			
		||||
        filterHook: function(item, search, regexp) {
 | 
			
		||||
            return search.length ? regexp.test(window.String(this.getLabel(item))) : true;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // aciTree utils extension
 | 
			
		||||
    // adds item update option, branch processing, moving items & item swapping, item search by ID
 | 
			
		||||
 | 
			
		||||
    var aciTree_utils = {
 | 
			
		||||
        __extend: function() {
 | 
			
		||||
            // add extra data
 | 
			
		||||
            $.extend(this._instance, {
 | 
			
		||||
                filter: new this._queue(this, this._instance.options.queue)
 | 
			
		||||
            });
 | 
			
		||||
            // stop queue until needed
 | 
			
		||||
            this._instance.filter.destroy();
 | 
			
		||||
            // call the parent
 | 
			
		||||
            this._super();
 | 
			
		||||
        },
 | 
			
		||||
        // call the `callback` function (item) for each children of item
 | 
			
		||||
        // when `load` is TRUE will also try to load nodes
 | 
			
		||||
        branch: function(item, callback, load) {
 | 
			
		||||
            var queue = this._instance.queue;
 | 
			
		||||
            var process = this.proxy(function(item, callback, next) {
 | 
			
		||||
                var child = next ? this.next(item) : this.first(item);
 | 
			
		||||
                if (child.length) {
 | 
			
		||||
                    if (this.isInode(child)) {
 | 
			
		||||
                        if (this.wasLoad(child)) {
 | 
			
		||||
                            queue.push(function(complete) {
 | 
			
		||||
                                callback.call(this, child);
 | 
			
		||||
                                process(child, callback);
 | 
			
		||||
                                process(child, callback, true);
 | 
			
		||||
                                complete();
 | 
			
		||||
                            });
 | 
			
		||||
                        } else if (load) {
 | 
			
		||||
                            // load the item first
 | 
			
		||||
                            this.ajaxLoad(child, {
 | 
			
		||||
                                success: function() {
 | 
			
		||||
                                    callback.call(this, child);
 | 
			
		||||
                                    process(child, callback);
 | 
			
		||||
                                    process(child, callback, true);
 | 
			
		||||
                                },
 | 
			
		||||
                                fail: function() {
 | 
			
		||||
                                    process(child, callback, true);
 | 
			
		||||
                                }
 | 
			
		||||
                            });
 | 
			
		||||
                        } else {
 | 
			
		||||
                            queue.push(function(complete) {
 | 
			
		||||
                                callback.call(this, child);
 | 
			
		||||
                                process(child, callback, true);
 | 
			
		||||
                                complete();
 | 
			
		||||
                            });
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        queue.push(function(complete) {
 | 
			
		||||
                            callback.call(this, child);
 | 
			
		||||
                            process(child, callback, true);
 | 
			
		||||
                            complete();
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            process(item, callback);
 | 
			
		||||
        },
 | 
			
		||||
        // swap two items (they can't be parent & children)
 | 
			
		||||
        // `options.item1` & `options.item2` are the swapped items
 | 
			
		||||
        swap: function(options) {
 | 
			
		||||
            options = this._options(options, null, 'swapfail', null, null);
 | 
			
		||||
            var item1 = options.item1;
 | 
			
		||||
            var item2 = options.item2;
 | 
			
		||||
            if (this.isItem(item1) && this.isItem(item2) && !this.isChildren(item1, item2) && !this.isChildren(item2, item1) && (item1[0] != item2[0])) {
 | 
			
		||||
                // a way to cancel the operation
 | 
			
		||||
                if (!this._trigger(null, 'beforeswap', options)) {
 | 
			
		||||
                    this._fail(null, options);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                var prev = this.prev(item1);
 | 
			
		||||
                if (prev.length) {
 | 
			
		||||
                    if (item2[0] == prev[0]) {
 | 
			
		||||
                        item2.before(item1);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        item1.insertAfter(item2);
 | 
			
		||||
                        item2.insertAfter(prev);
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    var next = this.next(item1);
 | 
			
		||||
                    if (next.length) {
 | 
			
		||||
                        if (item2[0] == next[0]) {
 | 
			
		||||
                            item2.after(item1);
 | 
			
		||||
                        } else {
 | 
			
		||||
                            item1.insertAfter(item2);
 | 
			
		||||
                            item2.insertBefore(next);
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        var parent = item1.parent();
 | 
			
		||||
                        item1.insertAfter(item2);
 | 
			
		||||
                        parent.append(item2);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                // update item states
 | 
			
		||||
                this._updateLevel(item1);
 | 
			
		||||
                var parent = this.parent(item1);
 | 
			
		||||
                this._setFirstLast(parent.length ? parent : null, item1);
 | 
			
		||||
                this._updateHidden(item1);
 | 
			
		||||
                this._updateLevel(item2);
 | 
			
		||||
                parent = this.parent(item2);
 | 
			
		||||
                this._setFirstLast(parent.length ? parent : null, item2);
 | 
			
		||||
                this._updateHidden(item2);
 | 
			
		||||
                this._setOddEven(item1.add(item2));
 | 
			
		||||
                this._trigger(null, 'swapped', options);
 | 
			
		||||
                this._success(null, options);
 | 
			
		||||
            } else {
 | 
			
		||||
                this._fail(null, options);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // update item level
 | 
			
		||||
        _updateItemLevel: function(item, fromLevel, toLevel) {
 | 
			
		||||
            domApi.addRemoveClass(item[0], 'aciTreeLevel' + toLevel, 'aciTreeLevel' + fromLevel);
 | 
			
		||||
            var line = item[0].firstChild;
 | 
			
		||||
            line.setAttribute('aria-level', toLevel + 1);
 | 
			
		||||
            var entry = domApi.childrenByClass(line, 'aciTreeEntry');
 | 
			
		||||
            if (fromLevel < toLevel) {
 | 
			
		||||
                line = entry.parentNode;
 | 
			
		||||
                var branch;
 | 
			
		||||
                for (var i = fromLevel; i < toLevel; i++) {
 | 
			
		||||
                    branch = window.document.createElement('DIV');
 | 
			
		||||
                    line.appendChild(branch);
 | 
			
		||||
                    branch.className = 'aciTreeBranch aciTreeLevel' + i;
 | 
			
		||||
                    line = branch;
 | 
			
		||||
                }
 | 
			
		||||
                line.appendChild(entry);
 | 
			
		||||
            } else {
 | 
			
		||||
                var branch = entry;
 | 
			
		||||
                for (var i = toLevel; i <= fromLevel; i++) {
 | 
			
		||||
                    branch = branch.parentNode;
 | 
			
		||||
                }
 | 
			
		||||
                branch.removeChild(branch.firstChild);
 | 
			
		||||
                branch.appendChild(entry);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // update child level
 | 
			
		||||
        _updateChildLevel: function(item, fromLevel, toLevel) {
 | 
			
		||||
            this.children(item, false, true).each(this.proxy(function(element) {
 | 
			
		||||
                var item = $(element);
 | 
			
		||||
                this._updateItemLevel(item, fromLevel, toLevel);
 | 
			
		||||
                if (this.isInode(item)) {
 | 
			
		||||
                    this._updateChildLevel(item, fromLevel + 1, toLevel + 1);
 | 
			
		||||
                }
 | 
			
		||||
            }, true));
 | 
			
		||||
        },
 | 
			
		||||
        // update item level
 | 
			
		||||
        _updateLevel: function(item) {
 | 
			
		||||
            var level = this.level(item);
 | 
			
		||||
            var found = window.parseInt(item.attr('class').match(/aciTreeLevel[0-9]+/)[0].match(/[0-9]+/));
 | 
			
		||||
            if (level != found) {
 | 
			
		||||
                this._updateItemLevel(item, found, level);
 | 
			
		||||
                this._updateChildLevel(item, found + 1, level + 1);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // move item up
 | 
			
		||||
        moveUp: function(item, options) {
 | 
			
		||||
            options = this._options(options);
 | 
			
		||||
            options.index = window.Math.max(this.getIndex(item) - 1, 0);
 | 
			
		||||
            this.setIndex(item, options);
 | 
			
		||||
        },
 | 
			
		||||
        // move item down
 | 
			
		||||
        moveDown: function(item, options) {
 | 
			
		||||
            options = this._options(options);
 | 
			
		||||
            options.index = window.Math.min(this.getIndex(item) + 1, this.siblings(item).length);
 | 
			
		||||
            this.setIndex(item, options);
 | 
			
		||||
        },
 | 
			
		||||
        // move item in first position
 | 
			
		||||
        moveFirst: function(item, options) {
 | 
			
		||||
            options = this._options(options);
 | 
			
		||||
            options.index = 0;
 | 
			
		||||
            this.setIndex(item, options);
 | 
			
		||||
        },
 | 
			
		||||
        // move item in last position
 | 
			
		||||
        moveLast: function(item, options) {
 | 
			
		||||
            options = this._options(options);
 | 
			
		||||
            options.index = this.siblings(item).length;
 | 
			
		||||
            this.setIndex(item, options);
 | 
			
		||||
        },
 | 
			
		||||
        // move item before another (they can't be parent & children)
 | 
			
		||||
        // `options.before` is the element before which the item will be moved
 | 
			
		||||
        moveBefore: function(item, options) {
 | 
			
		||||
            options = this._options(options, null, 'movefail', 'wasbefore', item);
 | 
			
		||||
            var before = options.before;
 | 
			
		||||
            if (this.isItem(item) && this.isItem(before) && !this.isChildren(item, before) && (item[0] != before[0])) {
 | 
			
		||||
                // a way to cancel the operation
 | 
			
		||||
                if (!this._trigger(item, 'beforemove', options)) {
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                if (this.prev(before, true)[0] == item[0]) {
 | 
			
		||||
                    this._notify(item, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    var parent = this.parent(item);
 | 
			
		||||
                    var prev = this.prev(item, true);
 | 
			
		||||
                    if (!prev.length) {
 | 
			
		||||
                        prev = parent.length ? parent : this.first();
 | 
			
		||||
                    }
 | 
			
		||||
                    item.insertBefore(before);
 | 
			
		||||
                    if (parent.length && !this.hasChildren(parent, true)) {
 | 
			
		||||
                        this.setLeaf(parent);
 | 
			
		||||
                    }
 | 
			
		||||
                    this._updateLevel(item);
 | 
			
		||||
                    // update item states
 | 
			
		||||
                    this._setFirstLast(parent.length ? parent : null);
 | 
			
		||||
                    parent = this.parent(item);
 | 
			
		||||
                    this._setFirstLast(parent.length ? parent : null, item.add(before));
 | 
			
		||||
                    this._updateHidden(item);
 | 
			
		||||
                    this._setOddEven(item.add(before).add(prev));
 | 
			
		||||
                    this._trigger(item, 'moved', options);
 | 
			
		||||
                    this._success(item, options);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                this._fail(item, options);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // move item after another (they can't be parent & children)
 | 
			
		||||
        // `options.after` is the element after which the item will be moved
 | 
			
		||||
        moveAfter: function(item, options) {
 | 
			
		||||
            options = this._options(options, null, 'movefail', 'wasafter', item);
 | 
			
		||||
            var after = options.after;
 | 
			
		||||
            if (this.isItem(item) && this.isItem(after) && !this.isChildren(item, after) && (item[0] != after[0])) {
 | 
			
		||||
                // a way to cancel the operation
 | 
			
		||||
                if (!this._trigger(item, 'beforemove', options)) {
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                if (this.next(after, true)[0] == item[0]) {
 | 
			
		||||
                    this._notify(item, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    var parent = this.parent(item);
 | 
			
		||||
                    var prev = this.prev(item, true);
 | 
			
		||||
                    if (!prev.length) {
 | 
			
		||||
                        prev = parent.length ? parent : this.first();
 | 
			
		||||
                    }
 | 
			
		||||
                    item.insertAfter(after);
 | 
			
		||||
                    if (parent.length && !this.hasChildren(parent, true)) {
 | 
			
		||||
                        this.setLeaf(parent);
 | 
			
		||||
                    }
 | 
			
		||||
                    this._updateLevel(item);
 | 
			
		||||
                    this._setFirstLast(parent.length ? parent : null);
 | 
			
		||||
                    parent = this.parent(item);
 | 
			
		||||
                    this._setFirstLast(parent.length ? parent : null, item.add(after));
 | 
			
		||||
                    this._updateHidden(item);
 | 
			
		||||
                    this._setOddEven(item.add(after).add(prev));
 | 
			
		||||
                    this._trigger(item, 'moved', options);
 | 
			
		||||
                    this._success(item, options);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                this._fail(item, options);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // move item to be a child of another (they can't be parent & children and the targeted parent item must be empty)
 | 
			
		||||
        // `options.parent` is the parent element on which the item will be added
 | 
			
		||||
        asChild: function(item, options) {
 | 
			
		||||
            options = this._options(options, null, 'childfail', null, item);
 | 
			
		||||
            var parent = options.parent;
 | 
			
		||||
            if (this.isItem(item) && this.isItem(parent) && !this.isChildren(item, parent) && !this.hasChildren(parent, true) && (item[0] != parent[0])) {
 | 
			
		||||
                // a way to cancel the operation
 | 
			
		||||
                if (!this._trigger(item, 'beforechild', options)) {
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                var process = function() {
 | 
			
		||||
                    var oldParent = this.parent(item);
 | 
			
		||||
                    var prev = this.prev(item);
 | 
			
		||||
                    if (!prev.length) {
 | 
			
		||||
                        prev = oldParent.length ? oldParent : this.first();
 | 
			
		||||
                    }
 | 
			
		||||
                    var container = this._createContainer(parent);
 | 
			
		||||
                    container.append(item);
 | 
			
		||||
                    if (oldParent.length && !this.hasChildren(oldParent, true)) {
 | 
			
		||||
                        // no more children
 | 
			
		||||
                        this.setLeaf(oldParent);
 | 
			
		||||
                    }
 | 
			
		||||
                    // update item states
 | 
			
		||||
                    this._updateLevel(item);
 | 
			
		||||
                    this._setFirstLast(oldParent.length ? oldParent : null);
 | 
			
		||||
                    this._setFirstLast(parent.length ? parent : null, item);
 | 
			
		||||
                    this._updateHidden(item);
 | 
			
		||||
                    this._setOddEven(item.add(prev));
 | 
			
		||||
                    this._trigger(item, 'childset', options);
 | 
			
		||||
                    this._success(item, options);
 | 
			
		||||
                };
 | 
			
		||||
                if (this.isInode(parent)) {
 | 
			
		||||
                    process.apply(this);
 | 
			
		||||
                } else {
 | 
			
		||||
                    // set as inode first
 | 
			
		||||
                    this.setInode(parent, this._inner(options, {
 | 
			
		||||
                        success: process,
 | 
			
		||||
                        fail: options.fail
 | 
			
		||||
                    }));
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                this._fail(item, options);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // search a `path` ID from a parent
 | 
			
		||||
        _search: function(parent, pathId) {
 | 
			
		||||
            var items = this.children(parent);
 | 
			
		||||
            var item, id, length, found, exact = false;
 | 
			
		||||
            for (var i = 0, size = items.length; i < size; i++) {
 | 
			
		||||
                item = items.eq(i);
 | 
			
		||||
                id = window.String(this.getId(item));
 | 
			
		||||
                length = id.length;
 | 
			
		||||
                if (length) {
 | 
			
		||||
                    if (id == pathId.substr(0, length)) {
 | 
			
		||||
                        found = item;
 | 
			
		||||
                        exact = pathId.length == length;
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (found) {
 | 
			
		||||
                if (!exact) {
 | 
			
		||||
                    // try to search children
 | 
			
		||||
                    var child = this._search(found, pathId);
 | 
			
		||||
                    if (child) {
 | 
			
		||||
                        return child;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                return {
 | 
			
		||||
                    item: found,
 | 
			
		||||
                    exact: exact
 | 
			
		||||
                };
 | 
			
		||||
            } else {
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // search items by ID
 | 
			
		||||
        // `options.id` is the ID to search for
 | 
			
		||||
        // if `path` is TRUE then the search will be more optimized
 | 
			
		||||
        // and reduced to the first branch that matches the ID
 | 
			
		||||
        // but the ID must be set like a path otherwise will not work
 | 
			
		||||
        // if `load` is TRUE will also try to load nodes (works only when `path` is TRUE)
 | 
			
		||||
        searchId: function(path, load, options) {
 | 
			
		||||
            options = this._options(options);
 | 
			
		||||
            var id = options.id;
 | 
			
		||||
            if (path) {
 | 
			
		||||
                if (load) {
 | 
			
		||||
                    var process = this.proxy(function(item) {
 | 
			
		||||
                        var found = this._search(item, id);
 | 
			
		||||
                        if (found) {
 | 
			
		||||
                            if (found.exact) {
 | 
			
		||||
                                this._success(found.item, options);
 | 
			
		||||
                            } else {
 | 
			
		||||
                                if (this.wasLoad(found.item)) {
 | 
			
		||||
                                    this._fail(item, options);
 | 
			
		||||
                                } else {
 | 
			
		||||
                                    // load the item
 | 
			
		||||
                                    this.ajaxLoad(found.item, this._inner(options, {
 | 
			
		||||
                                        success: function() {
 | 
			
		||||
                                            process(found.item);
 | 
			
		||||
                                        },
 | 
			
		||||
                                        fail: options.fail
 | 
			
		||||
                                    }));
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            this._fail(item, options);
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                    process();
 | 
			
		||||
                } else {
 | 
			
		||||
                    var found = this._search(null, id);
 | 
			
		||||
                    if (found && found.exact) {
 | 
			
		||||
                        this._success(found.item, options);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        this._fail(null, options);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                var found = $();
 | 
			
		||||
                this._instance.jQuery.find('.aciTreeLi').each(this.proxy(function(element) {
 | 
			
		||||
                    if (id == this.getId($(element))) {
 | 
			
		||||
                        found = $(element);
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
                }, true));
 | 
			
		||||
                if (found.length) {
 | 
			
		||||
                    this._success(found, options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._fail(null, options);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // search nodes by ID or custom property starting from item
 | 
			
		||||
        // `options.search` is the value to be searched
 | 
			
		||||
        // `options.load` if TRUE will try to load nodes
 | 
			
		||||
        // `options.callback` function (item, search) return TRUE for the custom match
 | 
			
		||||
        // `options.results` will keep the search results
 | 
			
		||||
        search: function(item, options) {
 | 
			
		||||
            var results = [];
 | 
			
		||||
            options = this._options(options);
 | 
			
		||||
            var task = new this._task(new this._queue(this, this._instance.options.queue), function(complete) {
 | 
			
		||||
                // run this at the end
 | 
			
		||||
                if (results.length) {
 | 
			
		||||
                    options.results = $(results);
 | 
			
		||||
                    this._success($(results[0]), options);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                }
 | 
			
		||||
                complete();
 | 
			
		||||
            });
 | 
			
		||||
            var children = this.proxy(function(item) {
 | 
			
		||||
                this.children(item, false, true).each(this.proxy(function(element) {
 | 
			
		||||
                    if (options.callback) {
 | 
			
		||||
                        // custom search
 | 
			
		||||
                        var match = options.callback.call(this, $(element), options.search);
 | 
			
		||||
                        if (match) {
 | 
			
		||||
                            results.push(element);
 | 
			
		||||
                        } else if (match === null) {
 | 
			
		||||
                            // skip childrens
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                    } else if (this.getId($(element)) == options.search) {
 | 
			
		||||
                        // default ID match
 | 
			
		||||
                        results.push(element);
 | 
			
		||||
                    }
 | 
			
		||||
                    if (this.isInode($(element))) {
 | 
			
		||||
                        // process children
 | 
			
		||||
                        task.push(function(complete) {
 | 
			
		||||
                            search($(element));
 | 
			
		||||
                            complete();
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                }, true));
 | 
			
		||||
            });
 | 
			
		||||
            var search = this.proxy(function(item) {
 | 
			
		||||
                if (this.wasLoad(item)) {
 | 
			
		||||
                    // process children
 | 
			
		||||
                    task.push(function(complete) {
 | 
			
		||||
                        children(item);
 | 
			
		||||
                        complete();
 | 
			
		||||
                    });
 | 
			
		||||
                } else if (options.load) {
 | 
			
		||||
                    task.push(function(complete) {
 | 
			
		||||
                        // load the item first
 | 
			
		||||
                        this.ajaxLoad(item, {
 | 
			
		||||
                            success: function() {
 | 
			
		||||
                                children(item);
 | 
			
		||||
                                complete();
 | 
			
		||||
                            },
 | 
			
		||||
                            fail: complete
 | 
			
		||||
                        });
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            // run the search
 | 
			
		||||
            task.push(function(complete) {
 | 
			
		||||
                search(item);
 | 
			
		||||
                complete();
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
        // search node by a list of IDs starting from item
 | 
			
		||||
        // `options.path` is a list of IDs to be searched - the path to the node
 | 
			
		||||
        // `options.load` if TRUE will try to load nodes
 | 
			
		||||
        searchPath: function(item, options) {
 | 
			
		||||
            options = this._options(options);
 | 
			
		||||
            var path = options.path;
 | 
			
		||||
            var search = this.proxy(function(item, id) {
 | 
			
		||||
                this.search(item, {
 | 
			
		||||
                    success: function(item) {
 | 
			
		||||
                        if (path.length) {
 | 
			
		||||
                            search(item, path.shift());
 | 
			
		||||
                        } else {
 | 
			
		||||
                            this._success(item, options);
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    fail: function() {
 | 
			
		||||
                        this._fail(item, options);
 | 
			
		||||
                    },
 | 
			
		||||
                    search: id,
 | 
			
		||||
                    load: options.load,
 | 
			
		||||
                    callback: function(item, search) {
 | 
			
		||||
                        // prevent drill-down
 | 
			
		||||
                        return (this.getId(item) == search) ? true : null;
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
            search(item, path.shift());
 | 
			
		||||
        },
 | 
			
		||||
        // get item path IDs starting from the top parent (ROOT)
 | 
			
		||||
        // when `reverse` is TRUE returns the IDs in reverse order
 | 
			
		||||
        pathId: function(item, reverse) {
 | 
			
		||||
            var path = this.path(item, reverse), id = [];
 | 
			
		||||
            path.each(this.proxy(function(element) {
 | 
			
		||||
                id.push(this.getId($(element)));
 | 
			
		||||
            }, true));
 | 
			
		||||
            return id;
 | 
			
		||||
        },
 | 
			
		||||
        // escape string and return RegExp
 | 
			
		||||
        _regexp: function(search) {
 | 
			
		||||
            return new window.RegExp(window.String(search).replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').replace(/\x08/g, '\\x08'), 'i');
 | 
			
		||||
        },
 | 
			
		||||
        // filter the tree items based on search criteria
 | 
			
		||||
        // `options.search` is the keyword
 | 
			
		||||
        // `options.first` will be the first matched item (if any)
 | 
			
		||||
        filter: function(item, options) {
 | 
			
		||||
            options = this._options(options, null, 'filterfail', null, item);
 | 
			
		||||
            if (!item || this.isItem(item)) {
 | 
			
		||||
                // a way to cancel the operation
 | 
			
		||||
                if (!this._trigger(item, 'beforefilter', options)) {
 | 
			
		||||
                    this._fail(item, options);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                var search = window.String(options.search);
 | 
			
		||||
                var regexp = this._regexp(search);
 | 
			
		||||
                var first = null;
 | 
			
		||||
                this._instance.filter.init();
 | 
			
		||||
                var task = new this._task(this._instance.filter, function(complete) {
 | 
			
		||||
                    // run this at the end
 | 
			
		||||
                    this._instance.filter.destroy();
 | 
			
		||||
                    options.first = first;
 | 
			
		||||
                    this._setOddEven();
 | 
			
		||||
                    this._trigger(item, 'filtered', options);
 | 
			
		||||
                    this._success(item, options);
 | 
			
		||||
                    complete();
 | 
			
		||||
                });
 | 
			
		||||
                // process children
 | 
			
		||||
                var process = this.proxy(function(parent) {
 | 
			
		||||
                    var children = this.children(parent, false, true);
 | 
			
		||||
                    var found = false;
 | 
			
		||||
                    children.each(this.proxy(function(element) {
 | 
			
		||||
                        var item = $(element);
 | 
			
		||||
                        if (this._instance.options.filterHook.call(this, item, search, regexp)) {
 | 
			
		||||
                            if (!first) {
 | 
			
		||||
                                first = item;
 | 
			
		||||
                            }
 | 
			
		||||
                            found = true;
 | 
			
		||||
                            domApi.removeClass(item[0], 'aciTreeHidden');
 | 
			
		||||
                        } else {
 | 
			
		||||
                            domApi.addRemoveClass(item[0], 'aciTreeHidden', 'aciTreeVisible');
 | 
			
		||||
                        }
 | 
			
		||||
                        if (this.isInode(item)) {
 | 
			
		||||
                            // continue with the children
 | 
			
		||||
                            task.push(function(complete) {
 | 
			
		||||
                                process(item);
 | 
			
		||||
                                complete();
 | 
			
		||||
                            });
 | 
			
		||||
                        }
 | 
			
		||||
                    }, true));
 | 
			
		||||
                    if (found) {
 | 
			
		||||
                        // update item states
 | 
			
		||||
                        if (parent && this.isHidden(parent)) {
 | 
			
		||||
                            this._showHidden(parent);
 | 
			
		||||
                        }
 | 
			
		||||
                        if (!parent || (this.isOpenPath(parent) && this.isOpen(parent))) {
 | 
			
		||||
                            children.not('.aciTreeHidden').addClass('aciTreeVisible');
 | 
			
		||||
                        }
 | 
			
		||||
                        this._setFirstLast(parent, this._getFirstLast(parent));
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
                task.push(function(complete) {
 | 
			
		||||
                    process(item);
 | 
			
		||||
                    complete();
 | 
			
		||||
                });
 | 
			
		||||
            } else {
 | 
			
		||||
                this._fail(item, options);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // call the `callback` function (item) for the first item
 | 
			
		||||
        _firstAll: function(callback) {
 | 
			
		||||
            callback.call(this, this.first());
 | 
			
		||||
        },
 | 
			
		||||
        // call the `callback` function (item) for the last item
 | 
			
		||||
        // when `load` is TRUE will also try to load nodes
 | 
			
		||||
        _lastAll: function(item, callback, load) {
 | 
			
		||||
            if (item) {
 | 
			
		||||
                if (this.isInode(item)) {
 | 
			
		||||
                    if (this.wasLoad(item)) {
 | 
			
		||||
                        this._lastAll(this.last(item), callback, load);
 | 
			
		||||
                        return;
 | 
			
		||||
                    } else if (load) {
 | 
			
		||||
                        this.ajaxLoad(item, {
 | 
			
		||||
                            success: function() {
 | 
			
		||||
                                this._lastAll(this.last(item), callback, load);
 | 
			
		||||
                            },
 | 
			
		||||
                            fail: function() {
 | 
			
		||||
                                callback.call(this, item);
 | 
			
		||||
                            }
 | 
			
		||||
                        });
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                callback.call(this, item);
 | 
			
		||||
            } else {
 | 
			
		||||
                callback.call(this, this.last());
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // call the `callback` function (item) for the next item from tree
 | 
			
		||||
        // when `load` is TRUE will also try to load nodes
 | 
			
		||||
        _nextAll: function(item, callback, load) {
 | 
			
		||||
            if (item) {
 | 
			
		||||
                if (this.isInode(item)) {
 | 
			
		||||
                    if (this.wasLoad(item)) {
 | 
			
		||||
                        callback.call(this, this.first(item));
 | 
			
		||||
                        return;
 | 
			
		||||
                    } else if (load) {
 | 
			
		||||
                        this.ajaxLoad(item, {
 | 
			
		||||
                            success: function() {
 | 
			
		||||
                                callback.call(this, this.first(item));
 | 
			
		||||
                            },
 | 
			
		||||
                            fail: function() {
 | 
			
		||||
                                this._nextAll(item, callback, load);
 | 
			
		||||
                            }
 | 
			
		||||
                        });
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                var next = this.next(item);
 | 
			
		||||
                if (next.length) {
 | 
			
		||||
                    callback.call(this, next);
 | 
			
		||||
                } else {
 | 
			
		||||
                    // search next by parents
 | 
			
		||||
                    var search = this.proxy(function(item) {
 | 
			
		||||
                        var parent = this.parent(item);
 | 
			
		||||
                        if (parent.length) {
 | 
			
		||||
                            var next = this.next(parent);
 | 
			
		||||
                            if (next.length) {
 | 
			
		||||
                                return next;
 | 
			
		||||
                            } else {
 | 
			
		||||
                                return search(parent);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        return null;
 | 
			
		||||
                    });
 | 
			
		||||
                    callback.call(this, search(item));
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                callback.call(this, this.first());
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // call the `callback` function (item) for the previous item from tree
 | 
			
		||||
        // when `load` is TRUE will also try to load nodes
 | 
			
		||||
        _prevAll: function(item, callback, load) {
 | 
			
		||||
            if (item) {
 | 
			
		||||
                var prev = this.prev(item);
 | 
			
		||||
                if (prev.length) {
 | 
			
		||||
                    if (this.isInode(prev)) {
 | 
			
		||||
                        this._lastAll(prev, callback, load);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        callback.call(this, prev);
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    var parent = this.parent(item);
 | 
			
		||||
                    callback.call(this, parent.length ? parent : null);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                callback.call(this, this.last());
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // call the `callback` function (item) with the previous found item based on search criteria
 | 
			
		||||
        // `search` is the keyword
 | 
			
		||||
        prevMatch: function(item, search, callback) {
 | 
			
		||||
            var regexp = this._regexp(search);
 | 
			
		||||
            this._instance.filter.init();
 | 
			
		||||
            var task = new this._task(this._instance.filter, function(complete) {
 | 
			
		||||
                this._instance.filter.destroy();
 | 
			
		||||
                complete();
 | 
			
		||||
            });
 | 
			
		||||
            var process = function(item) {
 | 
			
		||||
                task.push(function(complete) {
 | 
			
		||||
                    this._prevAll(item, function(item) {
 | 
			
		||||
                        if (item) {
 | 
			
		||||
                            if (this._instance.options.filterHook.call(this, item, search, regexp)) {
 | 
			
		||||
                                callback.call(this, item);
 | 
			
		||||
                            } else {
 | 
			
		||||
                                process(item);
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            callback.call(this, null);
 | 
			
		||||
                        }
 | 
			
		||||
                        complete();
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            };
 | 
			
		||||
            process(this.isItem(item) ? item : null);
 | 
			
		||||
        },
 | 
			
		||||
        // call the `callback` function (item) with the next found item based on search criteria
 | 
			
		||||
        // `search` is the keyword
 | 
			
		||||
        nextMatch: function(item, search, callback) {
 | 
			
		||||
            var regexp = this._regexp(search);
 | 
			
		||||
            this._instance.filter.init();
 | 
			
		||||
            var task = new this._task(this._instance.filter, function(complete) {
 | 
			
		||||
                this._instance.filter.destroy();
 | 
			
		||||
                complete();
 | 
			
		||||
            });
 | 
			
		||||
            var process = function(item) {
 | 
			
		||||
                task.push(function(complete) {
 | 
			
		||||
                    this._nextAll(item, function(item) {
 | 
			
		||||
                        if (item) {
 | 
			
		||||
                            if (this._instance.options.filterHook.call(this, item, search, regexp)) {
 | 
			
		||||
                                callback.call(this, item);
 | 
			
		||||
                            } else {
 | 
			
		||||
                                process(item);
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            callback.call(this, null);
 | 
			
		||||
                        }
 | 
			
		||||
                        complete();
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            };
 | 
			
		||||
            process(this.isItem(item) ? item : null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // extend the base aciTree class and add the utils stuff
 | 
			
		||||
    aciPluginClass.plugins.aciTree = aciPluginClass.plugins.aciTree.extend(aciTree_utils, 'aciTreeUtils');
 | 
			
		||||
 | 
			
		||||
    // add extra default options
 | 
			
		||||
    aciPluginClass.defaults('aciTree', options);
 | 
			
		||||
 | 
			
		||||
    // for internal access
 | 
			
		||||
    var domApi = aciPluginClass.plugins.aciTree_dom;
 | 
			
		||||
 | 
			
		||||
})(jQuery, this);
 | 
			
		||||
| 
						 | 
				
			
			@ -24,3 +24,12 @@ iframe {
 | 
			
		|||
.CodeMirror, .CodeMirror-gutters {
 | 
			
		||||
    height: 100% !important; 
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
/* Padding for the treeview */
 | 
			
		||||
.browser-browser-pane {
 | 
			
		||||
    padding-left: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.icon-servers {
 | 
			
		||||
    background: url('/static/servers.png') 0 0 no-repeat !important;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||