@ -13,7 +13,7 @@
} ( function ( $ , undefined ) {
"use strict" ;
/ * !
* jsTree 3.3 .4
* jsTree 3.3 .7
* http : //jstree.com/
*
* Copyright ( c ) 2014 Ivan Bozhanov ( http : //vakata.com)
@ -54,7 +54,7 @@
* specifies the jstree version in use
* @ name $ . jstree . version
* /
version : '3.3.4 ' ,
version : '3.3.7 ' ,
/ * *
* holds all the default options used when creating new instances
* @ name $ . jstree . defaults
@ -430,10 +430,90 @@
* /
force_text : false ,
/ * *
* Should the node should be toggled if the text is double clicked . Defaults to ` true `
* Should the node be toggled if the text is double clicked . Defaults to ` true `
* @ name $ . jstree . defaults . core . dblclick_toggle
* /
dblclick_toggle : true
dblclick_toggle : true ,
/ * *
* Should the loaded nodes be part of the state . Defaults to ` false `
* @ name $ . jstree . defaults . core . loaded_state
* /
loaded_state : false ,
/ * *
* Should the last active node be focused when the tree container is blurred and the focused again . This helps working with screen readers . Defaults to ` true `
* @ name $ . jstree . defaults . core . restore_focus
* /
restore_focus : true ,
/ * *
* Default keyboard shortcuts ( an object where each key is the button name or combo - like 'enter' , 'ctrl-space' , 'p' , etc and the value is the function to execute in the instance ' s scope )
* @ name $ . jstree . defaults . core . keyboard
* /
keyboard : {
'ctrl-space' : function ( e ) {
// aria defines space only with Ctrl
e . type = "click" ;
$ ( e . currentTarget ) . trigger ( e ) ;
} ,
'enter' : function ( e ) {
// enter
e . type = "click" ;
$ ( e . currentTarget ) . trigger ( e ) ;
} ,
'left' : function ( e ) {
// left
e . preventDefault ( ) ;
if ( this . is_open ( e . currentTarget ) ) {
this . close_node ( e . currentTarget ) ;
}
else {
var o = this . get_parent ( e . currentTarget ) ;
if ( o && o . id !== $ . jstree . root ) { this . get_node ( o , true ) . children ( '.jstree-anchor' ) . focus ( ) ; }
}
} ,
'up' : function ( e ) {
// up
e . preventDefault ( ) ;
var o = this . get_prev_dom ( e . currentTarget ) ;
if ( o && o . length ) { o . children ( '.jstree-anchor' ) . focus ( ) ; }
} ,
'right' : function ( e ) {
// right
e . preventDefault ( ) ;
if ( this . is_closed ( e . currentTarget ) ) {
this . open_node ( e . currentTarget , function ( o ) { this . get_node ( o , true ) . children ( '.jstree-anchor' ) . focus ( ) ; } ) ;
}
else if ( this . is_open ( e . currentTarget ) ) {
var o = this . get_node ( e . currentTarget , true ) . children ( '.jstree-children' ) [ 0 ] ;
if ( o ) { $ ( this . _firstChild ( o ) ) . children ( '.jstree-anchor' ) . focus ( ) ; }
}
} ,
'down' : function ( e ) {
// down
e . preventDefault ( ) ;
var o = this . get_next_dom ( e . currentTarget ) ;
if ( o && o . length ) { o . children ( '.jstree-anchor' ) . focus ( ) ; }
} ,
'*' : function ( e ) {
// aria defines * on numpad as open_all - not very common
this . open_all ( ) ;
} ,
'home' : function ( e ) {
// home
e . preventDefault ( ) ;
var o = this . _firstChild ( this . get_container_ul ( ) [ 0 ] ) ;
if ( o ) { $ ( o ) . children ( '.jstree-anchor' ) . filter ( ':visible' ) . focus ( ) ; }
} ,
'end' : function ( e ) {
// end
e . preventDefault ( ) ;
this . element . find ( '.jstree-anchor' ) . filter ( ':visible' ) . last ( ) . focus ( ) ;
} ,
'f2' : function ( e ) {
// f2 - safe to include - if check_callback is false it will fail
e . preventDefault ( ) ;
this . edit ( e . currentTarget ) ;
}
}
} ;
$ . jstree . core . prototype = {
/ * *
@ -548,7 +628,9 @@
this . teardown ( ) ;
} ,
/ * *
* Create prototype node
* Create a prototype node
* @ name _create_prototype_node ( )
* @ return { DOMElement }
* /
_create_prototype_node : function ( ) {
var _node = document . createElement ( 'LI' ) , _temp1 , _temp2 ;
@ -570,6 +652,48 @@
return _node ;
} ,
_kbevent_to_func : function ( e ) {
var keys = {
8 : "Backspace" , 9 : "Tab" , 13 : "Return" , 19 : "Pause" , 27 : "Esc" ,
32 : "Space" , 33 : "PageUp" , 34 : "PageDown" , 35 : "End" , 36 : "Home" ,
37 : "Left" , 38 : "Up" , 39 : "Right" , 40 : "Down" , 44 : "Print" , 45 : "Insert" ,
46 : "Delete" , 96 : "Numpad0" , 97 : "Numpad1" , 98 : "Numpad2" , 99 : "Numpad3" ,
100 : "Numpad4" , 101 : "Numpad5" , 102 : "Numpad6" , 103 : "Numpad7" ,
104 : "Numpad8" , 105 : "Numpad9" , '-13' : "NumpadEnter" , 112 : "F1" ,
113 : "F2" , 114 : "F3" , 115 : "F4" , 116 : "F5" , 117 : "F6" , 118 : "F7" ,
119 : "F8" , 120 : "F9" , 121 : "F10" , 122 : "F11" , 123 : "F12" , 144 : "Numlock" ,
145 : "Scrolllock" , 16 : 'Shift' , 17 : 'Ctrl' , 18 : 'Alt' ,
48 : '0' , 49 : '1' , 50 : '2' , 51 : '3' , 52 : '4' , 53 : '5' ,
54 : '6' , 55 : '7' , 56 : '8' , 57 : '9' , 59 : ';' , 61 : '=' , 65 : 'a' ,
66 : 'b' , 67 : 'c' , 68 : 'd' , 69 : 'e' , 70 : 'f' , 71 : 'g' , 72 : 'h' ,
73 : 'i' , 74 : 'j' , 75 : 'k' , 76 : 'l' , 77 : 'm' , 78 : 'n' , 79 : 'o' ,
80 : 'p' , 81 : 'q' , 82 : 'r' , 83 : 's' , 84 : 't' , 85 : 'u' , 86 : 'v' ,
87 : 'w' , 88 : 'x' , 89 : 'y' , 90 : 'z' , 107 : '+' , 109 : '-' , 110 : '.' ,
186 : ';' , 187 : '=' , 188 : ',' , 189 : '-' , 190 : '.' , 191 : '/' , 192 : '`' ,
219 : '[' , 220 : '\\' , 221 : ']' , 222 : "'" , 111 : '/' , 106 : '*' , 173 : '-'
} ;
var parts = [ ] ;
if ( e . ctrlKey ) { parts . push ( 'ctrl' ) ; }
if ( e . altKey ) { parts . push ( 'alt' ) ; }
if ( e . shiftKey ) { parts . push ( 'shift' ) ; }
parts . push ( keys [ e . which ] || e . which ) ;
parts = parts . sort ( ) . join ( '-' ) . toLowerCase ( ) ;
var kb = this . settings . core . keyboard , i , tmp ;
for ( i in kb ) {
if ( kb . hasOwnProperty ( i ) ) {
tmp = i ;
if ( tmp !== '-' && tmp !== '+' ) {
tmp = tmp . replace ( '--' , '-MINUS' ) . replace ( '+-' , '-MINUS' ) . replace ( '++' , '-PLUS' ) . replace ( '-+' , '-PLUS' ) ;
tmp = tmp . split ( /-|\+/ ) . sort ( ) . join ( '-' ) . replace ( 'MINUS' , '-' ) . replace ( 'PLUS' , '+' ) . toLowerCase ( ) ;
}
if ( tmp === parts ) {
return kb [ i ] ;
}
}
}
return null ;
} ,
/ * *
* part of the destroying of an instance . Used internally .
* @ private
@ -635,83 +759,16 @@
} , this ) )
. on ( 'keydown.jstree' , '.jstree-anchor' , $ . proxy ( function ( e ) {
if ( e . target . tagName && e . target . tagName . toLowerCase ( ) === "input" ) { return true ; }
if ( e . which !== 32 && e . which !== 13 && ( e . shiftKey || e . ctrlKey || e . altKey || e . metaKey ) ) { return true ; }
var o = null ;
if ( this . _data . core . rtl ) {
if ( e . which === 37 ) { e . which = 39 ; }
else if ( e . which === 39 ) { e . which = 37 ; }
}
switch ( e . which ) {
case 32 : // aria defines space only with Ctrl
if ( e . ctrlKey ) {
e . type = "click" ;
$ ( e . currentTarget ) . trigger ( e ) ;
}
break ;
case 13 : // enter
e . type = "click" ;
$ ( e . currentTarget ) . trigger ( e ) ;
break ;
case 37 : // left
e . preventDefault ( ) ;
if ( this . is_open ( e . currentTarget ) ) {
this . close_node ( e . currentTarget ) ;
}
else {
o = this . get_parent ( e . currentTarget ) ;
if ( o && o . id !== $ . jstree . root ) { this . get_node ( o , true ) . children ( '.jstree-anchor' ) . focus ( ) ; }
}
break ;
case 38 : // up
e . preventDefault ( ) ;
o = this . get_prev_dom ( e . currentTarget ) ;
if ( o && o . length ) { o . children ( '.jstree-anchor' ) . focus ( ) ; }
break ;
case 39 : // right
e . preventDefault ( ) ;
if ( this . is_closed ( e . currentTarget ) ) {
this . open_node ( e . currentTarget , function ( o ) { this . get_node ( o , true ) . children ( '.jstree-anchor' ) . focus ( ) ; } ) ;
}
else if ( this . is_open ( e . currentTarget ) ) {
o = this . get_node ( e . currentTarget , true ) . children ( '.jstree-children' ) [ 0 ] ;
if ( o ) { $ ( this . _firstChild ( o ) ) . children ( '.jstree-anchor' ) . focus ( ) ; }
}
break ;
case 40 : // down
e . preventDefault ( ) ;
o = this . get_next_dom ( e . currentTarget ) ;
if ( o && o . length ) { o . children ( '.jstree-anchor' ) . focus ( ) ; }
break ;
case 106 : // aria defines * on numpad as open_all - not very common
this . open_all ( ) ;
break ;
case 36 : // home
e . preventDefault ( ) ;
o = this . _firstChild ( this . get_container_ul ( ) [ 0 ] ) ;
if ( o ) { $ ( o ) . children ( '.jstree-anchor' ) . filter ( ':visible' ) . focus ( ) ; }
break ;
case 35 : // end
e . preventDefault ( ) ;
this . element . find ( '.jstree-anchor' ) . filter ( ':visible' ) . last ( ) . focus ( ) ;
break ;
case 113 : // f2 - safe to include - if check_callback is false it will fail
e . preventDefault ( ) ;
this . edit ( e . currentTarget ) ;
break ;
default :
break ;
/ * !
// delete
case 46 :
e . preventDefault ( ) ;
o = this . get_node ( e . currentTarget ) ;
if ( o && o . id && o . id !== $ . jstree . root ) {
o = this . is_selected ( o ) ? this . get_selected ( ) : o ;
this . delete_node ( o ) ;
}
break ;
* /
var f = this . _kbevent_to_func ( e ) ;
if ( f ) {
var r = f . call ( this , e ) ;
if ( r === false || r === true ) {
return r ;
}
}
} , this ) )
. on ( "load_node.jstree" , $ . proxy ( function ( e , data ) {
@ -845,7 +902,7 @@
this . element . attr ( 'tabindex' , '-1' ) ;
} , this ) )
. on ( 'focus.jstree' , $ . proxy ( function ( ) {
if ( + ( new Date ( ) ) - was_click > 500 && ! this . _data . core . focused ) {
if ( + ( new Date ( ) ) - was_click > 500 && ! this . _data . core . focused && this . settings . core . restore_focus ) {
was_click = 0 ;
var act = this . get_node ( this . element . attr ( 'aria-activedescendant' ) , true ) ;
if ( act ) {
@ -966,6 +1023,9 @@
if ( obj && obj . id ) {
obj = obj . id ;
}
if ( obj instanceof $ && obj . length && obj [ 0 ] . id ) {
obj = obj [ 0 ] . id ;
}
var dom ;
try {
if ( this . _model . data [ obj ] ) {
@ -977,10 +1037,10 @@
else if ( typeof obj === "string" && ( dom = $ ( '#' + obj . replace ( $ . jstree . idregex , '\\$&' ) , this . element ) ) . length && this . _model . data [ dom . closest ( '.jstree-node' ) . attr ( 'id' ) ] ) {
obj = this . _model . data [ dom . closest ( '.jstree-node' ) . attr ( 'id' ) ] ;
}
else if ( ( dom = $ ( obj , this . element ) ) . length && this . _model . data [ dom . closest ( '.jstree-node' ) . attr ( 'id' ) ] ) {
else if ( ( dom = this . element . find ( obj ) ) . length && this . _model . data [ dom . closest ( '.jstree-node' ) . attr ( 'id' ) ] ) {
obj = this . _model . data [ dom . closest ( '.jstree-node' ) . attr ( 'id' ) ] ;
}
else if ( ( dom = $ ( obj , this . element ) ) . length && dom . hasClass ( 'jstree' ) ) {
else if ( ( dom = this . element . find ( obj ) ) . length && dom . hasClass ( 'jstree' ) ) {
obj = this . _model . data [ $ . jstree . root ] ;
}
else {
@ -1114,7 +1174,7 @@
return obj . parent ;
} ,
/ * *
* get a jQuery collection of all the children of a node ( node must be rendered )
* get a jQuery collection of all the children of a node ( node must be rendered ) , returns false on error
* @ name get_children_dom ( obj )
* @ param { mixed } obj
* @ return { jQuery }
@ -1274,7 +1334,7 @@
return true ;
} ,
/ * *
* load an array of nodes ( will also load unavailable nodes as soon as the appear in the structure ) . Used internally .
* load an array of nodes ( will also load unavailable nodes as soon as they appear in the structure ) . Used internally .
* @ private
* @ name _load_nodes ( nodes [ , callback ] )
* @ param { array } nodes
@ -1453,7 +1513,7 @@
* /
_node_changed : function ( obj ) {
obj = this . get_node ( obj ) ;
if ( obj ) {
if ( obj && $ . inArray ( obj . id , this . _model . changed ) === - 1 ) {
this . _model . changed . push ( obj . id ) ;
}
} ,
@ -1545,6 +1605,7 @@
't_cnt' : this . _cnt ,
'sel' : this . _data . core . selected
} ,
inst = this ,
func = function ( data , undefined ) {
if ( data . data ) { data = data . data ; }
var dat = data . dat ,
@ -1755,10 +1816,21 @@
if ( ! dat [ i ] . children ) {
dat [ i ] . children = [ ] ;
}
if ( ! dat [ i ] . state ) {
dat [ i ] . state = { } ;
}
m [ dat [ i ] . id . toString ( ) ] = dat [ i ] ;
}
// 2) populate children (foreach)
for ( i = 0 , j = dat . length ; i < j ; i ++ ) {
if ( ! m [ dat [ i ] . parent . toString ( ) ] ) {
if ( typeof inst !== "undefined" ) {
inst . _data . core . last_error = { 'error' : 'parse' , 'plugin' : 'core' , 'id' : 'core_07' , 'reason' : 'Node with invalid parent' , 'data' : JSON . stringify ( { 'id' : dat [ i ] . id . toString ( ) , 'parent' : dat [ i ] . parent . toString ( ) } ) } ;
inst . settings . core . error . call ( inst , inst . _data . core . last_error ) ;
}
continue ;
}
m [ dat [ i ] . parent . toString ( ) ] . children . push ( dat [ i ] . id . toString ( ) ) ;
// populate parent.children_d
p . children_d . push ( dat [ i ] . id . toString ( ) ) ;
@ -2259,7 +2331,7 @@
this . element . empty ( ) . append ( f ) ;
//this.get_container_ul()[0].appendChild(f);
}
if ( fe !== null ) {
if ( fe !== null && this . settings . core . restore_focus ) {
tmp = this . get_node ( fe , true ) ;
if ( tmp && tmp . length && tmp . children ( '.jstree-anchor' ) [ 0 ] !== document . activeElement ) {
tmp . children ( '.jstree-anchor' ) . focus ( ) ;
@ -2435,6 +2507,9 @@
if ( obj . state . hidden ) {
c += ' jstree-hidden' ;
}
if ( obj . state . loading ) {
c += ' jstree-loading' ;
}
if ( obj . state . loaded && ! has_children ) {
c += ' jstree-leaf' ;
}
@ -2539,7 +2614,7 @@
return node ;
} ,
/ * *
* opens a node , revaling its children . If the node is not loaded it will be loaded and opened once ready .
* opens a node , reve aling its children . If the node is not loaded it will be loaded and opened once ready .
* @ name open_node ( obj [ , callback , animation ] )
* @ param { mixed } obj the node to open
* @ param { Function } callback a function to execute once the node is opened
@ -2743,7 +2818,7 @@
}
} ,
/ * *
* opens all nodes within a node ( or the tree ) , revaling their children . If the node is not loaded it will be loaded and opened once ready .
* opens all nodes within a node ( or the tree ) , reve aling their children . If the node is not loaded it will be loaded and opened once ready .
* @ name open_all ( [ obj , animation , original_obj ] )
* @ param { mixed } obj the node to open recursively , omit to open all nodes in the tree
* @ param { Number } animation the animation duration in milliseconds when opening the nodes , the default is no animation
@ -2784,7 +2859,7 @@
}
} ,
/ * *
* closes all nodes within a node ( or the tree ) , revaling their children
* closes all nodes within a node ( or the tree ) , reve aling their children
* @ name close_all ( [ obj , animation ] )
* @ param { mixed } obj the node to close recursively , omit to close all nodes in the tree
* @ param { Number } animation the animation duration in milliseconds when closing the nodes , the default is no animation
@ -3360,6 +3435,7 @@
var state = {
'core' : {
'open' : [ ] ,
'loaded' : [ ] ,
'scroll' : {
'left' : this . element . scrollLeft ( ) ,
'top' : this . element . scrollTop ( )
@ -3377,6 +3453,9 @@
for ( i in this . _model . data ) {
if ( this . _model . data . hasOwnProperty ( i ) ) {
if ( i !== $ . jstree . root ) {
if ( this . _model . data [ i ] . state . loaded && this . settings . core . loaded_state ) {
state . core . loaded . push ( i ) ;
}
if ( this . _model . data [ i ] . state . opened ) {
state . core . open . push ( i ) ;
}
@ -3403,6 +3482,19 @@
}
if ( state . core ) {
var res , n , t , _this , i ;
if ( state . core . loaded ) {
if ( ! this . settings . core . loaded_state || ! $ . isArray ( state . core . loaded ) || ! state . core . loaded . length ) {
delete state . core . loaded ;
this . set_state ( state , callback ) ;
}
else {
this . _load_nodes ( state . core . loaded , function ( nodes ) {
delete state . core . loaded ;
this . set_state ( state , callback ) ;
} ) ;
}
return false ;
}
if ( state . core . open ) {
if ( ! $ . isArray ( state . core . open ) || ! state . core . open . length ) {
delete state . core . open ;
@ -4405,7 +4497,7 @@
w2 = ai . width ( ) * ai . length ,
* /
t = default_text ;
h1 = $ ( "<" + "div />" , { css : { "position" : "absolute" , "top" : "-200px" , "left" : ( rtl ? "0px" : "-1000px" ) , "visibility" : "hidden" } } ) . appendTo ( "body" ) ;
h1 = $ ( "<" + "div />" , { css : { "position" : "absolute" , "top" : "-200px" , "left" : ( rtl ? "0px" : "-1000px" ) , "visibility" : "hidden" } } ) . appendTo ( document . body ) ;
h2 = $ ( "<" + "input />" , {
"value" : t ,
"class" : "jstree-rename-input" ,
@ -4431,6 +4523,7 @@
s . replaceWith ( a ) ;
s . remove ( ) ;
t = f ? t : $ ( '<div></div>' ) . append ( $ . parseHTML ( t ) ) . html ( ) ;
obj = this . get_node ( obj ) ;
this . set_text ( obj , t ) ;
nv = ! ! this . rename_node ( obj , f ? $ ( '<div></div>' ) . text ( v ) . text ( ) : $ ( '<div></div>' ) . append ( $ . parseHTML ( v ) ) . html ( ) ) ;
if ( ! nv ) {
@ -4705,6 +4798,7 @@
obj . icon = icon === true || icon === null || icon === undefined || icon === '' ? true : icon ;
dom = this . get_node ( obj , true ) . children ( ".jstree-anchor" ) . children ( ".jstree-themeicon" ) ;
if ( icon === false ) {
dom . removeClass ( 'jstree-themeicon-custom ' + old ) . css ( "background" , "" ) . removeAttr ( "rel" ) ;
this . hide_icon ( obj ) ;
}
else if ( icon === true || icon === null || icon === undefined || icon === '' ) {
@ -5077,14 +5171,15 @@
if ( s . indexOf ( 'down' ) !== - 1 ) {
//this._data[ t ? 'core' : 'checkbox' ].selected = $.vakata.array_unique(this._data[ t ? 'core' : 'checkbox' ].selected.concat(obj.children_d));
var selectedIds = this . _cascade_new_checked_state ( obj . id , true ) ;
obj . children_d . concat ( obj . id ) . forEach ( function ( id ) {
if ( selectedIds . indexOf ( id ) > - 1 ) {
sel [ id ] = true ;
}
else {
delete sel [ id ] ;
}
} ) ;
var temp = obj . children_d . concat ( obj . id ) ;
for ( i = 0 , j = temp . length ; i < j ; i ++ ) {
if ( selectedIds . indexOf ( temp [ i ] ) > - 1 ) {
sel [ temp [ i ] ] = true ;
}
else {
delete sel [ temp [ i ] ] ;
}
}
}
// apply up
@ -5258,16 +5353,18 @@
} , this ) ) ;
}
} ;
/ * *
* set the undetermined state where and if necessary . Used internally .
* @ private
* @ name _undetermined ( )
* get an array of all nodes whose state is "undetermined"
* @ name get_undetermined ( [ full ] )
* @ param { boolean } full : if set to ` true ` the returned array will consist of the full node objects , otherwise - only IDs will be returned
* @ return { Array }
* @ plugin checkbox
* /
this . _undetermined = function ( ) {
if ( this . element === null ) { return ; }
var i , j , k , l , o = { } , m = this . _model . data , t = this . settings . checkbox . tie_selection , s = this . _data [ t ? 'core' : 'checkbox' ] . selected , p = [ ] , tt = this ;
this . get_undetermined = function ( full ) {
if ( this . settings . checkbox . cascade . indexOf ( 'undetermined' ) === - 1 ) {
return [ ] ;
}
var i , j , k , l , o = { } , m = this . _model . data , t = this . settings . checkbox . tie_selection , s = this . _data [ t ? 'core' : 'checkbox' ] . selected , p = [ ] , tt = this , r = [ ] ;
for ( i = 0 , j = s . length ; i < j ; i ++ ) {
if ( m [ s [ i ] ] && m [ s [ i ] ] . parents ) {
for ( k = 0 , l = m [ s [ i ] ] . parents . length ; k < l ; k ++ ) {
@ -5320,14 +5417,28 @@
}
}
} ) ;
for ( i = 0 , j = p . length ; i < j ; i ++ ) {
if ( ! m [ p [ i ] ] . state [ t ? 'selected' : 'checked' ] ) {
r . push ( full ? m [ p [ i ] ] : p [ i ] ) ;
}
}
return r ;
} ;
/ * *
* set the undetermined state where and if necessary . Used internally .
* @ private
* @ name _undetermined ( )
* @ plugin checkbox
* /
this . _undetermined = function ( ) {
if ( this . element === null ) { return ; }
var p = this . get_undetermined ( false ) , i , j , s ;
this . element . find ( '.jstree-undetermined' ) . removeClass ( 'jstree-undetermined' ) ;
for ( i = 0 , j = p . length ; i < j ; i ++ ) {
if ( ! m [ p [ i ] ] . state [ t ? 'selected' : 'checked' ] ) {
s = this . get_node ( p [ i ] , true ) ;
if ( s && s . length ) {
s . children ( '.jstree-anchor' ) . children ( '.jstree-checkbox' ) . addClass ( 'jstree-undetermined' ) ;
}
for ( i = 0 , j = p . length ; i < j ; i ++ ) {
s = this . get_node ( p [ i ] , true ) ;
if ( s && s . length ) {
s . children ( '.jstree-anchor' ) . children ( '.jstree-checkbox' ) . addClass ( 'jstree-undetermined' ) ;
}
}
} ;
@ -5490,63 +5601,65 @@
} ;
/ * *
* Unchecks a node and all its descendants . This function does NOT affect hidden and disabled nodes ( or their descendants ) .
* Cascades checked state to a node and all its descendants . This function does NOT affect hidden and disabled nodes ( or their descendants ) .
* However if these unaffected nodes are already selected their ids will be included in the returned array .
* @ param id
* @ param checkedState
* @ private
* @ param { string } id the node ID
* @ param { bool } checkedState should the nodes be checked or not
* @ returns { Array } Array of all node id ' s ( in this tree branch ) that are checked .
* /
this . _cascade_new_checked_state = function ( id , checkedState ) {
this . _cascade_new_checked_state = function ( id , checkedState ) {
var self = this ;
var t = this . settings . checkbox . tie_selection ;
var node = this . _model . data [ id ] ;
var selectedNodeIds = [ ] ;
var selectedChildrenIds = [ ] ;
var selectedChildrenIds = [ ] , i , j , selectedChildIds ;
if (
( this . settings . checkbox . cascade_to_disabled || ! node . state . disabled ) &&
( this . settings . checkbox . cascade_to_hidden || ! node . state . hidden )
) {
//First try and check/uncheck the children
if ( node . children ) {
node . children . forEach ( function ( childId ) {
var selectedChildIds = self . _cascade_new_checked_state ( childId , checkedState ) ;
//First try and check/uncheck the children
if ( node . children ) {
for ( i = 0 , j = node . children . length ; i < j ; i ++ ) {
var childId = node . children [ i ] ;
selectedChildIds = self . _cascade_new_checked_state ( childId , checkedState ) ;
selectedNodeIds = selectedNodeIds . concat ( selectedChildIds ) ;
if ( selectedChildIds . indexOf ( childId ) > - 1 ) {
selectedChildrenIds . push ( childId ) ;
}
} ) ;
}
}
var dom = self . get_node ( node , true ) ;
//A node's state is undetermined if some but not all of it's children are checked/selected .
//A node's state is undetermined if some but not all of it's children are checked/selected .
var undetermined = selectedChildrenIds . length > 0 && selectedChildrenIds . length < node . children . length ;
if ( node . original && node . original . state && node . original . state . undetermined ) {
node . original . state . undetermined = undetermined ;
}
//If a node is undetermined then remove selected class
//If a node is undetermined then remove selected class
if ( undetermined ) {
node . state [ t ? 'selected' : 'checked' ] = false ;
dom . attr ( 'aria-selected' , false ) . children ( '.jstree-anchor' ) . removeClass ( t ? 'jstree-clicked' : 'jstree-checked' ) ;
node . state [ t ? 'selected' : 'checked' ] = false ;
dom . attr ( 'aria-selected' , false ) . children ( '.jstree-anchor' ) . removeClass ( t ? 'jstree-clicked' : 'jstree-checked' ) ;
}
//Otherwise, if the checkedState === true (i.e. the node is being checked now) and all of the node's children are checked (if it has any children),
//check the node and style it correctly.
//Otherwise, if the checkedState === true (i.e. the node is being checked now) and all of the node's children are checked (if it has any children),
//check the node and style it correctly.
else if ( checkedState && selectedChildrenIds . length === node . children . length ) {
node . state [ t ? 'selected' : 'checked' ] = checkedState ;
node . state [ t ? 'selected' : 'checked' ] = checkedState ;
selectedNodeIds . push ( node . id ) ;
dom . attr ( 'aria-selected' , true ) . children ( '.jstree-anchor' ) . addClass ( t ? 'jstree-clicked' : 'jstree-checked' ) ;
}
else {
node . state [ t ? 'selected' : 'checked' ] = false ;
node . state [ t ? 'selected' : 'checked' ] = false ;
dom . attr ( 'aria-selected' , false ) . children ( '.jstree-anchor' ) . removeClass ( t ? 'jstree-clicked' : 'jstree-checked' ) ;
}
}
else {
var selectedChildIds = this . get_checked_descendants ( id ) ;
selectedChildIds = this . get_checked_descendants ( id ) ;
if ( node . state [ t ? 'selected' : 'checked' ] ) {
selectedChildIds . push ( node . id ) ;
@ -5560,9 +5673,12 @@
/ * *
* Gets ids of nodes selected in branch ( of tree ) specified by id ( does not include the node specified by id )
* @ param id
* @ name get_checked_descendants ( obj )
* @ param { string } id the node ID
* @ return { Array } array of IDs
* @ plugin checkbox
* /
this . get_checked_descendants = function ( id ) {
this . get_checked_descendants = function ( id ) {
var self = this ;
var t = self . settings . checkbox . tie_selection ;
var node = self . _model . data [ id ] ;
@ -5813,7 +5929,7 @@
return res ;
} ;
this . refresh = function ( skip_loading , forget_state ) {
if ( ! this . settings . checkbox . tie_selection ) {
if ( this . settings . checkbox . tie_selection ) {
this . _data . checkbox . selected = [ ] ;
}
return parent . refresh . apply ( this , arguments ) ;
@ -5840,7 +5956,7 @@
// own function
this . activate_node = function ( obj , e ) {
if ( this . settings . conditionalselect . call ( this , this . get_node ( obj ) , e ) ) {
parent . activate_node . call ( this , obj , e ) ;
return parent . activate_node . call ( this , obj , e ) ;
}
} ;
} ;
@ -6041,8 +6157,9 @@
} , 750 ) ;
} )
. on ( 'touchmove.vakata.jstree' , function ( e ) {
if ( cto && e . originalEvent && e . originalEvent . changedTouches && e . originalEvent . changedTouches [ 0 ] && ( Math . abs ( ex - e . originalEvent . changedTouches [ 0 ] . clientX ) > 5 0 || Math . abs ( ey - e . originalEvent . changedTouches [ 0 ] . clientY ) > 5 0) ) {
if ( cto && e . originalEvent && e . originalEvent . changedTouches && e . originalEvent . changedTouches [ 0 ] && ( Math . abs ( ex - e . originalEvent . changedTouches [ 0 ] . clientX ) > 1 0 || Math . abs ( ey - e . originalEvent . changedTouches [ 0 ] . clientY ) > 1 0) ) {
clearTimeout ( cto ) ;
$ . vakata . context . hide ( ) ;
}
} )
. on ( 'touchend.vakata.jstree' , function ( e ) {
@ -6314,7 +6431,7 @@
vakata_context . element . html ( vakata_context . html ) ;
}
if ( vakata_context . items . length ) {
vakata_context . element . appendTo ( "body" ) ;
vakata_context . element . appendTo ( document . body ) ;
e = vakata_context . element ;
x = vakata_context . position_x ;
y = vakata_context . position_y ;
@ -6370,7 +6487,7 @@
}
} ;
$ ( function ( ) {
right_to_left = $ ( "body" ) . css ( "direction" ) === "rtl" ;
right_to_left = $ ( document . body ) . css ( "direction" ) === "rtl" ;
var to = false ;
vakata_context . element = $ ( "<ul class='vakata-context'></ul>" ) ;
@ -6658,11 +6775,23 @@
marker = $ ( '<div id="jstree-marker"> </div>' ) . hide ( ) ; //.appendTo('body');
$ ( document )
. on ( 'dragover.vakata.jstree' , function ( e ) {
if ( elm ) {
$ . vakata . dnd . _trigger ( 'move' , e , { 'helper' : $ ( ) , 'element' : elm , 'data' : drg } ) ;
}
} )
. on ( 'drop.vakata.jstree' , function ( e ) {
if ( elm ) {
$ . vakata . dnd . _trigger ( 'stop' , e , { 'helper' : $ ( ) , 'element' : elm , 'data' : drg } ) ;
elm = null ;
drg = null ;
}
} )
. on ( 'dnd_start.vakata.jstree' , function ( e , data ) {
lastmv = false ;
lastev = false ;
if ( ! data || ! data . data || ! data . data . jstree ) { return ; }
marker . appendTo ( 'body' ) ; //.show();
marker . appendTo ( document . body ) ; //.show();
} )
. on ( 'dnd_move.vakata.jstree' , function ( e , data ) {
var isDifferentNode = data . event . target !== lastev . target ;
@ -6796,7 +6925,7 @@
lastmv = false ;
data . helper . find ( '.jstree-icon' ) . removeClass ( 'jstree-ok' ) . addClass ( 'jstree-er' ) ;
if ( data . event . originalEvent && data . event . originalEvent . dataTransfer ) {
data . event . originalEvent . dataTransfer . dropEffect = 'none' ;
//data.event.originalEvent.dataTransfer.dropEffect = 'none';
}
marker . hide ( ) ;
} )
@ -6889,7 +7018,7 @@
helper_left : 5 ,
helper_top : 10 ,
threshold : 5 ,
threshold_touch : 5 0
threshold_touch : 1 0
} ,
_trigger : function ( event_name , e , data ) {
if ( data === undefined ) {
@ -7007,7 +7136,7 @@
Math . abs ( e . pageY - vakata_dnd . init_y ) > ( vakata_dnd . is_touch ? $ . vakata . dnd . settings . threshold_touch : $ . vakata . dnd . settings . threshold )
) {
if ( vakata_dnd . helper ) {
vakata_dnd . helper . appendTo ( "body" ) ;
vakata_dnd . helper . appendTo ( document . body ) ;
vakata_dnd . helper_w = vakata_dnd . helper . outerWidth ( ) ;
}
vakata_dnd . is_drag = true ;
@ -7399,7 +7528,7 @@
}
if ( ! skip_async && a !== false ) {
if ( $ . isFunction ( a ) ) {
return a . call ( this , str , inside , $ . proxy ( function ( d ) { // CHANGE: added "inside" as argument
return a . call ( this , str , $ . proxy ( function ( d ) {
if ( d && d . d ) { d = d . d ; }
this . _load_nodes ( ! $ . isArray ( d ) ? [ ] : $ . vakata . array_unique ( d ) , function ( ) {
this . search ( str , true , show_only_matches , inside , append , show_only_matches_children ) ;
@ -7754,7 +7883,13 @@
* @ name $ . jstree . defaults . state . filter
* @ plugin state
* /
filter : false
filter : false ,
/ * *
* Should loaded nodes be restored ( setting this to true means that it is possible that the whole tree will be loaded for some users - use with caution ) . Defaults to ` false `
* @ name $ . jstree . defaults . state . preserve_loaded
* @ plugin state
* /
preserve_loaded : false
} ;
$ . jstree . plugins . state = function ( options , parent ) {
this . bind = function ( ) {
@ -7784,7 +7919,11 @@
* @ plugin state
* /
this . save_state = function ( ) {
var st = { 'state' : this . get_state ( ) , 'ttl' : this . settings . state . ttl , 'sec' : + ( new Date ( ) ) } ;
var tm = this . get_state ( ) ;
if ( ! this . settings . state . preserve_loaded ) {
delete tm . core . loaded ;
}
var st = { 'state' : tm , 'ttl' : this . settings . state . ttl , 'sec' : + ( new Date ( ) ) } ;
$ . vakata . storage . set ( this . settings . state . key , JSON . stringify ( st ) ) ;
} ;
/ * *
@ -7799,6 +7938,9 @@
if ( ! ! k && k . state ) { k = k . state ; }
if ( ! ! k && $ . isFunction ( this . settings . state . filter ) ) { k = this . settings . state . filter . call ( this , k ) ; }
if ( ! ! k ) {
if ( ! this . settings . state . preserve_loaded ) {
delete k . core . loaded ;
}
this . element . one ( "set_state.jstree" , function ( e , data ) { data . instance . trigger ( 'restore_state' , { 'state' : $ . extend ( true , { } , k ) } ) ; } ) ;
this . set_state ( k ) ;
return true ;
@ -8202,6 +8344,12 @@
* @ plugin unique
* /
case_sensitive : false ,
/ * *
* Indicates if white space should be trimmed before the comparison . Default is ` false ` .
* @ name $ . jstree . defaults . unique . trim_whitespace
* @ plugin unique
* /
trim_whitespace : false ,
/ * *
* A callback executed in the instance ' s scope when a new node is created and the name is already taken , the two arguments are the conflicting name and the counter . The default will produce results like ` New node (2) ` .
* @ name $ . jstree . defaults . unique . duplicate
@ -8221,16 +8369,32 @@
var n = chk === "rename_node" ? pos : obj . text ,
c = [ ] ,
s = this . settings . unique . case_sensitive ,
m = this . _model . data , i , j ;
w = this . settings . unique . trim_whitespace ,
m = this . _model . data , i , j , t ;
for ( i = 0 , j = par . children . length ; i < j ; i ++ ) {
c . push ( s ? m [ par . children [ i ] ] . text : m [ par . children [ i ] ] . text . toLowerCase ( ) ) ;
t = m [ par . children [ i ] ] . text ;
if ( ! s ) {
t = t . toLowerCase ( ) ;
}
if ( w ) {
t = t . replace ( /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g , '' ) ;
}
c . push ( t ) ;
}
if ( ! s ) { n = n . toLowerCase ( ) ; }
if ( w ) { n = n . replace ( /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g , '' ) ; }
switch ( chk ) {
case "delete_node" :
return true ;
case "rename_node" :
i = ( $ . inArray ( n , c ) === - 1 || ( obj . text && obj . text [ s ? 'toString' : 'toLowerCase' ] ( ) === n ) ) ;
t = obj . text || '' ;
if ( ! s ) {
t = t . toLowerCase ( ) ;
}
if ( w ) {
t = t . replace ( /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g , '' ) ;
}
i = ( $ . inArray ( n , c ) === - 1 || ( obj . text && t === n ) ) ;
if ( ! i ) {
this . _data . core . last_error = { 'error' : 'check' , 'plugin' : 'unique' , 'id' : 'unique_01' , 'reason' : 'Child with name ' + n + ' already exists. Preventing: ' + chk , 'data' : JSON . stringify ( { 'chk' : chk , 'pos' : pos , 'obj' : obj && obj . id ? obj . id : false , 'par' : par && par . id ? par . id : false } ) } ;
}
@ -8270,15 +8434,36 @@
return parent . create_node . call ( this , par , node , pos , callback , is_loaded ) ;
}
if ( ! node ) { node = { } ; }
var tmp , n , dpc , i , j , m = this . _model . data , s = this . settings . unique . case_sensitive , cb = this . settings . unique . duplicate ;
var tmp , n , dpc , i , j , m = this . _model . data , s = this . settings . unique . case_sensitive , w = this . settings . unique . trim_whitespace , cb = this . settings . unique . duplicate , t ;
n = tmp = this . get_string ( 'New node' ) ;
dpc = [ ] ;
for ( i = 0 , j = par . children . length ; i < j ; i ++ ) {
dpc . push ( s ? m [ par . children [ i ] ] . text : m [ par . children [ i ] ] . text . toLowerCase ( ) ) ;
t = m [ par . children [ i ] ] . text ;
if ( ! s ) {
t = t . toLowerCase ( ) ;
}
if ( w ) {
t = t . replace ( /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g , '' ) ;
}
dpc . push ( t ) ;
}
i = 1 ;
while ( $ . inArray ( s ? n : n . toLowerCase ( ) , dpc ) !== - 1 ) {
t = n ;
if ( ! s ) {
t = t . toLowerCase ( ) ;
}
if ( w ) {
t = t . replace ( /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g , '' ) ;
}
while ( $ . inArray ( t , dpc ) !== - 1 ) {
n = cb . call ( this , tmp , ( ++ i ) ) . toString ( ) ;
t = n ;
if ( ! s ) {
t = t . toLowerCase ( ) ;
}
if ( w ) {
t = t . replace ( /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g , '' ) ;
}
}
node . text = n ;
}
@ -8395,7 +8580,7 @@
} ;
// include the wholerow plugin by default
// $.jstree.defaults.plugins.push("wholerow");
if ( document . registerElement && Object && Object . create ) {
if ( window . customElements && Object && Object . create ) {
var proto = Object . create ( HTMLElement . prototype ) ;
proto . createdCallback = function ( ) {
var c = { core : { } , plugins : [ ] } , i ;
@ -8416,8 +8601,8 @@
} ;
// proto.attributeChangedCallback = function (name, previous, value) { };
try {
document . registerElement ( "vakata-jstree" , { prototype : proto } ) ;
} catch ( ignore ) { }
window . customElements . define ( "vakata-jstree" , function ( ) { } , { prototype : proto } ) ;
} catch ( ignore ) { }
}
} ) ) ;
} ) ) ;