123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- /*
- * Fuel UX Tree
- * https://github.com/ExactTarget/fuelux
- *
- * Copyright (c) 2014 ExactTarget
- * Licensed under the BSD New license.
- */
- // -- BEGIN UMD WRAPPER PREFACE --
- // For more information on UMD visit:
- // https://github.com/umdjs/umd/blob/master/jqueryPlugin.js
- (function (factory) {
- if (typeof define === 'function' && define.amd) {
- // if AMD loader is available, register as an anonymous module.
- define(['jquery'], factory);
- } else {
- // OR use browser globals if AMD is not present
- factory(jQuery);
- }
- }(function ($) {
- // -- END UMD WRAPPER PREFACE --
-
- // -- BEGIN MODULE CODE HERE --
- var old = $.fn.tree;
- // TREE CONSTRUCTOR AND PROTOTYPE
- var Tree = function (element, options) {
- this.$element = $(element);
- this.options = $.extend({}, $.fn.tree.defaults, options);
- this.$element.on('click.fu.tree', '.tree-item', $.proxy( function(ev) { this.selectItem(ev.currentTarget); } ,this));
- //this.$element.on('click.fu.tree', '.tree-branch-name', $.proxy( function(ev) { this.openFolder(ev.currentTarget); }, this));
- this.$element.on('click.fu.tree', '.tree-branch-header', $.proxy( function(ev) { this.openFolder(ev.currentTarget); }, this));
- //ACE
-
- //ACE
- /**
- if( this.options.folderSelect ){
- this.$element.off('click.fu.tree', '.tree-branch-header');
- this.$element.on('click.fu.tree', '.icon-caret', $.proxy( function(ev) { this.openFolder($(ev.currentTarget).parent()); }, this));
- this.$element.on('click.fu.tree', '.tree-branch-header', $.proxy( function(ev) { this.selectFolder($(ev.currentTarget)); }, this));
- }
- */
- this.render();
- };
- Tree.prototype = {
- constructor: Tree,
- destroy: function() {
- // any external bindings [none]
- // empty elements to return to original markup
- this.$element.find("li:not([data-template])").remove();
- this.$element.remove();
- // returns string of markup
- return this.$element[0].outerHTML;
- },
- render: function () {
- this.populate(this.$element);
- },
- populate: function ($el) {
- var self = this;
- var $parent = ($el.hasClass('tree')) ? $el : $el.parent();
- var loader = $parent.find('.tree-loader:eq(0)');
- var treeData = $parent.data();
- loader.removeClass('hide');
- this.options.dataSource( treeData ? treeData : {} , function (items) {
- loader.addClass('hide');
- $.each( items.data, function(index, value) {
- var $entity;
- if(value.type === 'folder') {
- $entity = self.$element.find('[data-template=treebranch]:eq(0)').clone().removeClass('hide').removeAttr('data-template');
- $entity.data(value);
- $entity.find('.tree-branch-name > .tree-label').html(value.text || value.name);
-
- //ACE
- var header = $entity.find('.tree-branch-header');
- if('icon-class' in value)
- header.find('i').addClass(value['icon-class']);
-
- if('additionalParameters' in value
- && 'item-selected' in value.additionalParameters
- && value.additionalParameters['item-selected'] == true) {
- setTimeout(function(){header.trigger('click')}, 0);
- }
-
- } else if (value.type === 'item') {
- $entity = self.$element.find('[data-template=treeitem]:eq(0)').clone().removeClass('hide').removeAttr('data-template');
- $entity.find('.tree-item-name > .tree-label').html(value.text || value.name);
- $entity.data(value);
-
- //ACE
- if('additionalParameters' in value
- && 'item-selected' in value.additionalParameters
- && value.additionalParameters['item-selected'] == true) {
- $entity.addClass ('tree-selected');
- $entity.find('i').removeClass(self.options['unselected-icon']).addClass(self.options['selected-icon']);
- //$entity.closest('.tree-folder-content').show();
- }
- }
- // Decorate $entity with data or other attributes making the
- // element easily accessable with libraries like jQuery.
- //
- // Values are contained within the object returned
- // for folders and items as attr:
- //
- // {
- // name: "An Item",
- // type: 'item',
- // attr = {
- // 'classes': 'required-item red-text',
- // 'data-parent': parentId,
- // 'guid': guid,
- // 'id': guid
- // }
- // };
- //
- // the "name" attribute is also supported but is deprecated for "text"
- // add attributes to tree-branch or tree-item
- var attr = value['attr'] || value.dataAttributes || [];
- $.each(attr, function(key, value) {
- switch (key) {
- case 'cssClass':
- case 'class':
- case 'className':
- $entity.addClass(value);
- break;
-
- // allow custom icons
- case 'data-icon':
- $entity.find('.icon-item').removeClass().addClass('icon-item ' + value);
- $entity.attr(key, value);
- break;
- // ARIA support
- case 'id':
- $entity.attr(key, value);
- $entity.attr('aria-labelledby', value + '-label');
- $entity.find('.tree-branch-name > .tree-label').attr('id', value + '-label');
- break;
- // id, style, data-*
- default:
- $entity.attr(key, value);
- break;
- }
- });
- // add child nodes
- if($el.hasClass('tree-branch-header')) {
- $parent.find('.tree-branch-children:eq(0)').append($entity);
- } else {
- $el.append($entity);
- }
- });
- // return newly populated folder
- self.$element.trigger('loaded.fu.tree', $parent);
- });
- },
- selectItem: function (el) {
- if(this.options['selectable'] == false) return;//ACE
-
- var $el = $(el);
- var selData = $el.data();
- var $all = this.$element.find('.tree-selected');
- var data = [];
- var $icon = $el.find('.icon-item');
- if (this.options.multiSelect) {
- $.each($all, function(index, value) {
- var $val = $(value);
- if($val[0] !== $el[0]) {
- data.push( $(value).data() );
- }
- });
- } else if ($all[0] !== $el[0]) {
- //
- $all.removeClass('tree-selected')
- .find('i').removeClass(this.options['selected-icon']).addClass(this.options['unselected-icon']);//ACE
- data.push(selData);
- }
- var eventType = 'selected';
- if($el.hasClass('tree-selected')) {
- eventType = 'deselected';
- $el.removeClass('tree-selected');
- if($icon.hasClass(this.options['selected-icon']) || $icon.hasClass(this.options['unselected-icon']) ) {
- $icon.removeClass(this.options['selected-icon']).addClass(this.options['unselected-icon']);//ACE
- }
- } else {
- $el.addClass ('tree-selected');
- // add tree dot back in
- if($icon.hasClass(this.options['selected-icon']) || $icon.hasClass(this.options['unselected-icon']) ) {
- $icon.removeClass(this.options['unselected-icon']).addClass(this.options['selected-icon']);//ACE
- }
- if (this.options.multiSelect) {
- data.push( selData );
- }
- }
- this.$element.trigger(eventType + '.fu.tree', {target: selData, selected: data});
- // Return new list of selected items, the item
- // clicked, and the type of event:
- $el.trigger('updated.fu.tree', {
- selected: data,
- item: $el,
- eventType: eventType
- });
- },
- openFolder: function (el) {
- var $el = $(el); // tree-branch-name
- var $branch;
- var $treeFolderContent;
- var $treeFolderContentFirstChild;
- // if item select only
- //ACE
- /**
- if (!this.options.folderSelect) {
- $el = $(el).parent(); // tree-branch, if tree-branch-name clicked
- }
- */
- $branch = $el.closest('.tree-branch'); // tree branch
- $treeFolderContent = $branch.find('.tree-branch-children');
- $treeFolderContentFirstChild = $treeFolderContent.eq(0);
- // manipulate branch/folder
- var eventType, classToTarget, classToAdd;
- if ($el.find('.'+$.trim(this.options['close-icon'].replace(/(\s+)/g, '.'))).length) {//ACE
- eventType = 'opened';
- classToTarget = this.options['close-icon'];//ACE
- classToAdd = this.options['open-icon'];//ACE
- $branch.addClass('tree-open');
- $branch.attr('aria-expanded', 'true');
- $treeFolderContentFirstChild.removeClass('hide');
- if (!$treeFolderContent.children().length) {
- this.populate($treeFolderContent);
- }
- } else if($el.find('.'+$.trim(this.options['open-icon'].replace(/(\s+)/g, '.')))) {
- eventType = 'closed';
- classToTarget = this.options['open-icon'];//ACE
- classToAdd = this.options['close-icon'];//ACE
- $branch.removeClass('tree-open');
- $branch.attr('aria-expanded', 'false');
- $treeFolderContentFirstChild.addClass('hide');
- // remove if no cache
- if (!this.options.cacheItems) {
- $treeFolderContentFirstChild.empty();
- }
- }
-
- $branch.find('> .tree-branch-header .icon-folder').eq(0)
- //.removeClass(this.options['close-icon'] + ' ' + this.options['open-icon'])
- .removeClass(classToTarget)//ACE
- .addClass(classToAdd);
- this.$element.trigger(eventType + '.fu.tree', $branch.data());
- },
- selectFolder: function (clickedElement) {
- var $clickedElement = $(clickedElement);
- var $clickedBranch = $clickedElement.closest('.tree-branch');
- var $selectedBranch = this.$element.find('.tree-branch.tree-selected');
- var clickedData = $clickedBranch.data();
- var selectedData = [];
- var eventType = 'selected';
- // select clicked item
- if($clickedBranch.hasClass('tree-selected')) {
- eventType = 'deselected';
- $clickedBranch.removeClass('tree-selected');
- } else {
- $clickedBranch.addClass('tree-selected');
- }
- if (this.options.multiSelect) {
- // get currently selected
- $selectedBranch = this.$element.find('.tree-branch.tree-selected');
- $.each($selectedBranch, function(index, value) {
- var $value = $(value);
- if($value[0] !== $clickedElement[0]) {
- selectedData.push( $(value).data() );
- }
- });
- } else if ($selectedBranch[0] !== $clickedElement[0]) {
- $selectedBranch.removeClass('tree-selected');
- selectedData.push(clickedData);
- }
- this.$element.trigger(eventType + '.fu.tree', {target: clickedData, selected: selectedData});
- // Return new list of selected items, the item
- // clicked, and the type of event:
- $clickedElement.trigger('updated.fu.tree', {
- selected: selectedData,
- item: $clickedElement,
- eventType: eventType
- });
- },
- selectedItems: function () {
- var $sel = this.$element.find('.tree-selected');
- var data = [];
- $.each($sel, function (index, value) {
- data.push($(value).data());
- });
- return data;
- },
- // collapses open folders
- collapse: function () {
- var cacheItems = this.options.cacheItems;
- // find open folders
- this.$element.find('.'+$.trim(this.options['open-icon'].replace(/(\s+)/g, '.'))).each(function () {//ACE
- // update icon class
- var $this = $(this)
- .removeClass(this.options['open-icon'] + ' ' + this.options['close-icon'])
- .addClass(this.options['close-icon']);
- // "close" or empty folder contents
- var $parent = $this.parent().parent();
- var $folder = $parent.children('.tree-branch-children');
- $folder.addClass('hide');
- if (!cacheItems) {
- $folder.empty();
- }
- });
- }
- };
- // TREE PLUGIN DEFINITION
- $.fn.tree = function (option) {
- var args = Array.prototype.slice.call( arguments, 1 );
- var methodReturn;
- var $set = this.each(function () {
- var $this = $( this );
- var data = $this.data( 'fu.tree' );
- var options = typeof option === 'object' && option;
- if( !data ) $this.data('fu.tree', (data = new Tree( this, options ) ) );
- if( typeof option === 'string' ) methodReturn = data[ option ].apply( data, args );
- });
- return ( methodReturn === undefined ) ? $set : methodReturn;
- };
- $.fn.tree.defaults = {
- dataSource: function(options, callback){},
- multiSelect: false,
- cacheItems: true,
- folderSelect: false//ACE
- };
- $.fn.tree.Constructor = Tree;
- $.fn.tree.noConflict = function () {
- $.fn.tree = old;
- return this;
- };
- // NO DATA-API DUE TO NEED OF DATA-SOURCE
- // -- BEGIN UMD WRAPPER AFTERWORD --
- }));
- // -- END UMD WRAPPER AFTERWORD --
|