(function (root, factory) { if (typeof define == 'function' && define.amd) { define( factory ); } else if (typeof module === 'object' && module.exports) { module.exports = factory(); } else { root.VanillaTree = factory(); } }(this, function () { "use strict"; // Look at the Balalaika https://github.com/finom/balalaika var $=function(n,e,k,h,p,m,l,b,d,g,f,c){c=function(a,b){return new c.i(a,b)};c.i=function(a,d){k.push.apply(this,a?a.nodeType||a==n?[a]:""+a===a?/</.test(a)?((b=e.createElement(d||"q")).innerHTML=a,b.children):(d&&c(d)[0]||e).querySelectorAll(a):/f/.test(typeof a)?/c/.test(e.readyState)?a():c(e).on("DOMContentLoaded",a):a:k)};c.i[f="prototype"]=(c.extend=function(a){g=arguments;for(b=1;b<g.length;b++)if(f=g[b])for(d in f)a[d]=f[d];return a})(c.fn=c[f]=k,{on:function(a,d){a=a.split(h);this.map(function(c){(h[b=a[0]+(c.b$=c.b$||++p)]=h[b]||[]).push([d,a[1]]);c["add"+m](a[0],d)});return this},off:function(a,c){a=a.split(h);f="remove"+m;this.map(function(e){if(b=(g=h[a[0]+e.b$])&&g.length)for(;d=g[--b];)c&&c!=d[0]||a[1]&&a[1]!=d[1]||(e[f](a[0],d[0]),g.splice(b,1));else!a[1]&&e[f](a[0],c)});return this},is:function(a){d=(b=this[0])&&(b.matches||b["webkit"+l]||b["moz"+l]||b["ms"+l]);return!!d&&d.call(b,a)}});return c}(window,document,[],/\.(.+)/,0,"EventListener","MatchesSelector"); var create = function( tagName, props ) { return $.extend( document.createElement( tagName ), props ); }, Tree = function( s, options ) { var _this = this, container = _this.container = $( s )[ 0 ], tree = _this.tree = container.appendChild( create( 'ul', { className: 'vtree' }) ); _this.placeholder = options && options.placeholder; _this._placeholder(); _this.leafs = {}; tree.addEventListener( 'click', function( evt ) { if( $( evt.target ).is( '.vtree-leaf-label' ) ) { _this.select( evt.target.parentNode.getAttribute('data-vtree-id') ); } else if( $( evt.target ).is( '.vtree-toggle' ) ) { _this.toggle( evt.target.parentNode.getAttribute('data-vtree-id') ); } }); if( options && options.contextmenu ) { tree.addEventListener( 'contextmenu', function( evt ) { var menu; $( '.vtree-contextmenu' ).forEach( function( menu ) { menu.parentNode.removeChild( menu ); }); if( $( evt.target ).is( '.vtree-leaf-label' ) ) { evt.preventDefault(); evt.stopPropagation(); menu = create( 'menu', { className: 'vtree-contextmenu' }); var rect = evt.target.getBoundingClientRect(); $.extend(menu.style, { top: (evt.target.offsetTop + rect.height).toString() + "px", left: evt.target.offsetLeft.toString() + "px", display: 'block' }); options.contextmenu.forEach( function( item ) { menu.appendChild( create( 'li', { className: 'vtree-contextmenu-item', innerHTML: item.label }) ).addEventListener( 'click', item.action.bind( item, evt.target.parentNode.getAttribute('data-vtree-id') ) ); }); evt.target.parentNode.appendChild( menu ); } }); document.addEventListener( 'click', function( evt ) { if(evt.button === 2) return; $( '.vtree-contextmenu' ).forEach( function( menu ) { menu.parentNode.removeChild( menu ); }); }); } }; Tree.prototype = { constructor: Tree, _dispatch: function( name, id ) { var event; try { event = new CustomEvent( 'vtree-' + name, { bubbles: true, cancelable: true, detail: { id: id } }); } catch(e) { event = document.createEvent( 'CustomEvent' ); event.initCustomEvent( 'vtree-' + name, true, true, { id: id }); } ( this.getLeaf( id, true ) || this.tree ) .dispatchEvent( event ); return this; }, _placeholder: function() { var p; if( !this.tree.children.length && this.placeholder ) { this.tree.innerHTML = '<li class="vtree-placeholder">' + this.placeholder + '</li>' } else if( p = this.tree.querySelector( '.vtree-placeholder' ) ) { this.tree.removeChild( p ); } return this; }, getLeaf: function( id, notThrow ) { var leaf = $( '[data-vtree-id="' + id + '"]', this.tree )[ 0 ]; if( !notThrow && !leaf ) throw Error( 'No VanillaTree leaf with id "' + id + '"' ) return leaf; }, getChildList: function( id ) { var list, parent; if( id ) { parent = this.getLeaf( id ); if( !( list = $( 'ul', parent )[ 0 ] ) ) { list = parent.appendChild( create( 'ul', { className: 'vtree-subtree' }) ); } } else { list = this.tree; } return list; }, add: function( options ) { // see https://github.com/finom/vanillatree/issues/8 if(this.getLeaf( options.id,true )){return;}// don't add leaves that already exist var id, leaf = create( 'li', { className: 'vtree-leaf' }), parentList = this.getChildList( options.parent ); leaf.setAttribute( 'data-vtree-id', id = options.id || Math.random() ); leaf.appendChild( create( 'span', { className: 'vtree-toggle' }) ); leaf.appendChild( create( 'a', { className: 'vtree-leaf-label', innerHTML: options.label }) ); parentList.appendChild( leaf ); if( parentList !== this.tree ) { parentList.parentNode.classList.add( 'vtree-has-children' ); } this.leafs[ id ] = options; if( !options.opened ) { this.close( id ); } if( options.selected ) { this.select( id ); } return this._placeholder()._dispatch( 'add', id ); }, move: function( id, parentId ) { var leaf = this.getLeaf( id ), oldParent = leaf.parentNode, newParent = this.getLeaf( parentId, true ); if( newParent ) { newParent.classList.add( 'vtree-has-children' ); } this.getChildList( parentId ).appendChild( leaf ); oldParent.parentNode.classList.toggle( 'vtree-has-children', !!oldParent.children.length ); return this._dispatch( 'move', id ); }, remove: function( id ) { var leaf = this.getLeaf( id ), oldParent = leaf.parentNode; oldParent.removeChild( leaf ); oldParent.parentNode.classList.toggle( 'vtree-has-children', !!oldParent.children.length ); return this._placeholder()._dispatch( 'remove', id ); }, open: function( id ) { this.getLeaf( id ).classList.remove( 'closed' ); return this._dispatch( 'open', id ); }, close: function( id ) { this.getLeaf( id ).classList.add( 'closed' ); return this._dispatch( 'close', id ); }, toggle: function( id ) { return this[ this.getLeaf( id ).classList.contains( 'closed' ) ? 'open' : 'close' ]( id ); }, select: function( id ) { var leaf = this.getLeaf( id ); if( !leaf.classList.contains( 'vtree-selected' ) ) { $( 'li.vtree-leaf', this.tree ).forEach( function( leaf ) { leaf.classList.remove( 'vtree-selected' ); }); leaf.classList.add( 'vtree-selected' ); this._dispatch( 'select', id ); } return this; } }; return Tree; // Look at the Balalaika https://github.com/finom/balalaika }));