%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home/opti/workflow/src/public/app-assets/vendors/js-filer/
Upload File :
Create Path :
Current File : /home/opti/workflow/src/public/app-assets/vendors/js-filer/jsfiler.js

/**
 * jsFiler jQuery plugin
 * Dependencies:  jsTree 3.x
 * 
 * @package     Filer
 * @version     1.3.2
 * @author      Vallo Reima <info@vallo.me>
 * @license     GNU LGPL http://opensource.org/licenses/lgpl-3.0.html
 * @copyright   (c) 2014, Hareko
 * 
 * @param {object} $ jQuery
 * @param {object} document
 * @param {object} undefined
 * @returns {object}
 */
(function($, document, undefined) {

  "use strict";

  if ($.jsfiler === undefined) {
    var that = this;
  } else {
    return; /* prevent another load */
  }

  var trees = []; /* tree info objects */
  var tree = '';  /* current tree object */
  var plugins = ['types', 'search', 'dnd'];
  var treeConfig = {/* properties & methods configurable*/
    menuMode: 1, /* 1 - right-click menu, 2 - icon menu, 3 - both */
    iconPath: '', /* path to tree and menu icons */
    checkBox: 0, /* no tree checkboxes 02.2018 */
    canDrag: true, /* allow drag & drop */
    rootSingle: false, /* allow multiple roots */
    rootLeaf: true, /* allow leafs for root node */
    rootParent: -1, /* root parent id */
    saveState: false, /* save opened/selected state */
    selectOpen: 2, /* open the node on: 1 - click, 2 - dblclick, 3 - both 04.2017 */
    knotRemove: 0, /* knots deletion: 0 - empty only, 1 - +copied, 2 - all */
    nameDupl: 0, /* duplicate child names: 2 - allow, 1 - case-sensitive, 0 - no */
    nameTrim: /^\s+|\s+$/g, /* name trim patterm (leading & trailing spaces */
    nameValidate: false, /* don't validate */
//    nameValidate: /^[^\\\/?%*:|'\"<>]+$/, /* Windows-like test pattern */
    userAuth: null, /* user authorization token */
    urlAjax: 'ajax.php' /* ajax request url */
  };
  var change = ['canDrag', 'rootLeaf', 'knotRemove', 'selectOpen', 'userAuth', 'urlAjax']; /* dynamically changeable */
  var txts = {
    searchResult: '# nodes found',
    confirmReplace: 'Are you sure to replace the node',
    confirmDelete: 'Are you sure to delete the node(s)',
    knotExists: 'The node exists already',
    badName: "Invalid name. Don't use \\\/?%*:'|\"<>",
    ajaxFail: 'An error occured',
    loading: 'Loading...'
  };

  var busy = {tck: null, dts: '', txt: ''}; /* ajax call in progress status */
  var treeClass = 'js-filer-tree';
  var menuSuffix = '-menu';
  var menuClass = 'js-filer' + menuSuffix;
  var meterClass = 'js-filer-meter'; /* command meter div */
  var pasteClass = 'js-filer-';
  var suffix = '-no'; /* disabled command */
  var copied = 'copied'; /* copied node attribute */

  var treeCommands = {/* core set */
    opn: {label: 'Open', menu: false},
    sch: {label: 'Search', icon: ['c_sch.png', 'c_sch-no.png']},
    cpy: {label: 'Copy', icon: ['c_cpy.png', 'c_cpy-no.png']},
    cut: {label: 'Cut', icon: ['c_cut.png', 'c_cut-no.png']},
    pst: {label: 'Paste', icon: ['c_pst.png', 'c_pst-no.png']},
    mve: {label: 'Move', menu: false},
    cre: {label: 'Create', submenu: {
        'new': {label: 'New knot', icon: ['c_new.png', 'c_new-no.png']},
        'add': {label: 'New leaf', icon: ['c_add.png', 'c_add-no.png']}
      }
    },
    ren: {label: 'Rename', icon: ['c_ren.png', 'c_ren-no.png']},
    del: {label: 'Delete', icon: ['c_del.png', 'c_del-no.png']}
  };

  $.jsfiler = {
    /** 
     *  the jsfiler version in use
     */
    version: '1.3.2',
    /**
     * commander
     * @param {string} cmd -- command token
     * @param {object|array} obj -- node(s)
     * @param {mixed} prm -- parameters
     */
    Command: function(cmd, obj, prm) {
      if (prm.args) {
        tree.args = $.extend({}, prm.args);
        delete prm.args;
      } else {
        tree.args = {};
      }
      if (cmd === 'sch') {
        Search(prm, obj);
      } else if (cmd === 'cpy') {
        CheckAllowed(cmd, obj);
      } else if (cmd === 'cut') {
        CheckAllowed(cmd, obj);
      } else if (cmd === 'pst') {
        var pst = $(tree.Id).jstree('get_buffer');
        if (pst.mode && pst.node) {
          Remit(cmd, pst.node, $(tree.Id).jstree('get_node', obj));
        }
      } else if (cmd === 'new' || cmd === 'add') {
        Create(cmd, obj, prm);
      } else if (cmd === 'ren') {
        if (prm.text === undefined) {
          prm.text = tree.cmdInfo.name;
        }
        $(tree.Id).jstree('rename_node', obj, prm.text);
      } else if (cmd === 'del') {
        CheckAllowed(cmd, obj);
      } else if (!$.jsfiler.Engaged()) {
        prm.node = $(tree.Id).jstree('get_node', obj);
        Request(cmd, {
          id: prm.node.id,
          idt: prm.node.text,
          pid: prm.node.parent}, prm);
      }
    },
    /**
     * refresh the node/tree
     * @param {array} nodes
     */
    Refresh: function(nodes) {
      for (var i = 0; i < nodes.length; i++) {
        var n = nodes[i];
        for (var t in trees) {
          if (n.indexOf(t) + 1) {
            tree = trees[t];
            if (n === t) {
              $(tree.Id).jstree('refresh');
            } else if ($('#' + n).length) {
              $(tree.Id).jstree('refresh_node', '#' + n);
            }
          }
        }
      }
    },
    /**
     * check if action allowed
     * @param {string} id 
     * @return {bool}
     */
    TreeInfo: function(id) {
      var t = false;
      if (isNaN(id)) {
        var Id = id ? ('#' + id) : tree.Id;
        for (var i in trees) {
          if (Id.indexOf(trees[i].Id) + 1) {
            t = i;
            break;
          }
        }
      } else {
        var k = 0;
        for (var i in trees) {
          if (k === id) {
            t = i;
            break;
          } else {
            k++;
          }
        }
      }
      return t === false ? {} : $.extend({}, trees[t]);
    },
    /**
     * check if action allowed
     * @return {bool}
     */
    Engaged: function() {
      return (busy.tck !== null);
    },
    /**
     * indicate the command name in action
     * @param {string} txt -- text to show
     * @param {object} obj -- user meter 
     */
    Busy: function(txt, obj) {
      if (txt) {
        if (obj) {
          busy.obj = GetObj(obj);
          busy.obj.addClass(meterClass);
        } else {
          NodeOpts(tree.cmdInfo.Id, txt, false);
        }
        busy.txt = txt;
        busy.tck = setInterval(function() {
          busy.dts += '.';
          if (busy.dts.length > 3) {
            busy.dts = '';
          }
          var d = busy.dts;
          for (var i = busy.dts.length; i < 3; i++) {
            d += '&nbsp;';
          }
          $('.' + meterClass).html(busy.txt + d);
        }, 200);
      } else if (busy.tck !== null) {
        clearInterval(busy.tck);
        busy.tck = null;
        if (busy.obj) {
          busy.obj.removeClass(meterClass);
          busy.obj.html('');
          delete busy.obj;
        } else {
          $('.' + meterClass).remove();
        }
      }
    },
    /**
     * set node type & icon and refresh
     * @param {str} id
     * @param {int} type
     * @param {int} icon
     * @param {bool} frsh refresh
     */
    SetNode: function(id, type, icon, frsh) {
      var obj = GetObj(id);
      $(tree.Id).jstree('deselect_all', true);
      $(tree.Id).jstree('select_node', obj);
      if (type) {
        $(tree.Id).jstree('set_type', obj, type);
      }
      if (icon) {
        var t = type ? type : $(tree.Id).jstree('get_type', obj);
        if (tree.treeIcons[t]) {
          var i = icon - 1;
          if (tree.icons[tree.treeIcons[t][0]]) {
            var a = tree.icons[tree.treeIcons[t][0]];
            var ico = i < a.length ? a[i].src : '';
          } else {
            a = tree.treeIcons[t][1];
            ico = i < a.length ? a[i] : '';
            ;
          }
          $(tree.Id).jstree('set_icon', obj, ico);
        }
      }
      if (frsh) {
        $(tree.Id).jstree('refresh_node', obj);
      }
    },
    /**
     * destroy an instance
     * @param {string} Id
     */
    Destroy: function(Id) {
      var id = Id.replace('#', '');
      GetObj(id).jstree('destroy');
      trees[id] = null;
      delete trees[id];
      id = '';
      for (var t in trees) {
        if (trees.hasOwnProperty(t)) {
          id = t;
          break;
        }
      }
      tree = id ? trees[id] : null;
    }
  };

  /* core callbacks */
  var callBacks = {
    encode: function(dat) { /* encode request data */
      return encodeURI(dat);
    },
    check: null, /* dnd check */
    allow: null, /* commands accesssible */
    action: null, /* action processor */
    request: null, /* request processor */
    response: null, /*response processor */
    dialog: null  /* user dialog */
  };

  var treeParm = {
    plugins: [],
    core: {
      dblclick_toggle: true, //04.2017
      animation: 100,
      strings: {'Loading ...': ''},
      data: function(node, callback) {
        var prm = {cmd: 'opn', id: (node.id === '#' ? tree.rootParent : node.id)};
        GetData(prm, function(nodes) {
          if (nodes.length) {
            Open(nodes, callback);
          } else {
            callback(nodes);
          }
        });
      }
    },
    search: {
      fuzzy: false,
      close_opened_onclear: false,
      ajax: function(str, callback) {
        tree.search.str = tree.callBacks.encode(str);
        var prm = {cmd: 'sch', id: tree.cmdInfo.Id.replace('#', ''), fnd: tree.search};
        GetData(prm, callback);
      },
      search_callback: function(str, node) {
        var s = tree.search.csi ? str : str.toLowerCase();  /* needle */
        var t = tree.search.csi ? node.text : node.text.toLowerCase();  /* haystack */
        if (tree.search.pos === 0) {
          var f = (t === s);
        } else if (tree.search.pos === 1) {
          f = (t.indexOf(s) === 0);
        } else if (tree.search.pos === 2) {
          f = (t.lastIndexOf(s) === t.length - s.length);
        } else if (tree.search.pos === 3) {
          f = (t.indexOf(s) !== -1);
        } else {
          f = null;
        }
        return f;
      }
    },
    state: {
      key: '',
      filter: function(obj) {
        return obj;
      }
    },
    dnd: {
      copy: true,
      always_copy: false,
      check_while_dragging: true,
      is_draggable: function(n) {
        TreeSelect(n[0].id);
        return (tree.canDrag !== false && !$.jsfiler.Engaged() && CheckDnd(n));
      }
    },
    checkbox: {
      three_state: true, //cascading
      whole_node: false, //not clicking anywhere
      tie_selection: false
    },
    contextmenu: {
      select_node: true,
      items: function(obj) {
        ClearOpts(obj);
        ContextMenu(tree.cmdMenu, AllowCommands(GetObj(obj)));
        return tree.cmdMenu;
      }
    },
    types: {}
  };
  var types = {
    '#': {
      max_children: -1,
      valid_children: [0]
    },
    0: {
      valid_children: [1, 2],
      icon: 'root'
    },
    1: {
      valid_children: [1, 2, 3],
      icon: 'knot_leaf'
    },
    2: {
      valid_children: [1, 2, 3],
      icon: 'knot'
    },
    3: {
      valid_children: [],
      icon: 'leaf'
    }
  };

  /**
   * open/search
   * @param {object} args -- request arguments
   * @param {function} clb -- callback
   */
  var GetData = function(args, clb) {
    TreeSelect(args.id);
    if (args.id === tree.rootParent) {
      args.idt = '';
      args.ckd = null;
    } else {
      args.idt = NodeName(args.id);
      args.ckd = tree.checkBox ? ($(tree.Id).jstree('is_checked', args.id) === true) : null;
    }
    args.cmt = tree.cmdList[args.cmd].label;
    Ajax(args, {busy: $.jsfiler.Engaged()}, function(args, rslt) {
      var dat = rslt.status ? rslt.factor : [];
      clb.call(this, dat);
      if (rslt.prompt) {
        Dialog(rslt.prompt);
      }
    });
  };

  /**
   * open subtree
   * @param {array} nodes
   * @param {function} clbk
   */
  var Open = function(nodes, clbk) {
    if (nodes[0].type === 0) {
      if (nodes.length > 1 && tree.rootSingle) {
        nodes = [nodes.shift()];  /* reject other roots */
      }
      if (nodes.length === 1) {
        nodes[0].state.opened = true; /* open single root */
      }
      for (var id in trees) {
        if (nodes[0].id.indexOf(id) + 1) {
          trees[id].cmdInfo.Id = '#' + nodes[0].id;
          trees[id].cmdInfo.name = nodes[0].text;
          trees[id].cmdInfo.type = 0;
        }
      }
    }
    clbk(nodes);
    Opening(nodes);
  };
  /**
   * fill subtree
   * @param {array} nodes
   */
  var Opening = function(nodes) {
    if ($('#' + nodes[0].id).length > 0) {
      if (tree.callBacks.metadata) {
        tree.callBacks.metadata(nodes);
      }
      if (!$.isEmptyObject(tree.pending)) { /* waiting for a load */
        var opr = tree.pending.shift();
        opr.apply(that, tree.pending);
        tree.pending = [];
      }
    } else {
      /* wait for the populating */
      setTimeout(function() {
        Opening(nodes);
      }, 100);
    }
  };

  /**
   * create a node
   * @param {string} cmd -- new/add
   * @param {object|array} obj -- node(s)
   * @param {mixed} prm -- parameters
   */
  var Create = function(cmd, obj, prm) {
    var parm = typeof prm === 'object' ? prm : {};
    parm.type = cmd === 'new' ? 2 : 3;
    if (parm.icon === undefined) {
      parm.icon = $(tree.Id).jstree(true).settings.types[parm.type].icon;
    }
    if (parm.text === undefined) {
      parm.text = tree.cmdList[cmd].label;
    }
    if (parm.pos === undefined) {
      var pos = 'last';
    } else {
      pos = parm.pos;
      delete parm.pos;
    }
    $(tree.Id).jstree('create_node', obj, parm, pos, function(node) {
      if ($(tree.Id).jstree('is_closed', '#' + node.parent)) {
        $(tree.Id).jstree('open_node', '#' + node.parent, null, false);
      }
    });
  };

  /**
   * form command list and attach event
   * @param {bool} flg -- true - include disabled
   */
  var CommandList = function(flg) {
    var cmds = '';
    for (var cmd in tree.cmdList) {
      if (tree.cmdList[cmd].menu !== false) {
        cmds += CommandItem(cmd, cmd);
        if (flg) {
          cmds += CommandItem(cmd + suffix, cmd);
        }
      }
    }
    return cmds;
  };
  /**
   * form command list and attach event
   * @param {string} cmd
   * @param {string} key -- list key
   */
  var CommandItem = function(cmd, key) {
    var cmds = '<a href="#' + cmd + '"' + ' title="' + tree.cmdList[key].label + '"';
    if (!tree.iconPath) {
      cmds += ' class="_' + cmd + '">';
    } else if (tree.iconPath === '_') {
      var s = cmd.indexOf(suffix) + 1 ? 'none' : 'underline';
      cmds += ' style="text-decoration:' + s + ';">' + tree.cmdList[key].label;
    } else {
      cmds += '><img src="' + tree.icons[cmd].src + '" alt="" />';
    }
    cmds += '</a>';
    return cmds;
  };
  /**
   * correct right-click menu
   * @param {object} coms
   * @param {array} cms -- alowed
   * @return {bool} true -- all disabled
   */
  var ContextMenu = function(coms, cms) {
    var f = true; /* disable parent */
    for (var cmd in coms) {
      if (coms[cmd].submenu) {
        coms[cmd]._disabled = ContextMenu(coms[cmd].submenu, cms);
      } else if ($.inArray(cmd, cms) + 1) {
        f = false;
        coms[cmd].icon = tree.icons[cmd] ? tree.icons[cmd].src : '_' + cmd + ' _cmd';
        coms[cmd]._disabled = false;
      } else {
        coms[cmd].icon = tree.icons[cmd + suffix] ? tree.icons[cmd + suffix].src : '_' + cmd + suffix + ' _cmd';
        var f = tree.cmdList[cmd].icon && tree.cmdList[cmd].icon.length > 1 && tree.cmdList[cmd].icon[0] === tree.cmdList[cmd].icon[1];
        coms[cmd]._disabled = !f;
      }
    }
    return f;
  };
  /**
   * dynamic menu action
   * @param {string} cmd 
   */
  var ContextMenu0 = function(cmd) {
    /**
     * dynamic menu action
     * @param {object} obj node
     */
    this.act = function(obj) {
      Action(obj, cmd);
    };
  };
  /**
   * process a command
   * @param {object} com -- selected command or node
   * @param {bool|string} flg -- true - main menu
   *                             false - node menu
   *                             string - contextmenu command
   */
  var Action = function(com, flg) {
    if ($.jsfiler.Engaged()) {
      return;
    } else if (flg === true) {
      var a = com.parents('.' + menuClass);
      tree = trees[$(a[0]).attr('id').replace(menuSuffix, '')];
    } else {
      TreeSelect(com);
    }
    tree.cmdInfo.cmd = typeof flg === 'string' ? flg : com.attr('href').substr(1).replace(suffix, '');
    if (tree.menuType === 2 && $(tree.menuId).length) {
      $(tree.menuId).children().hide();
    }
    var obj = $(tree.cmdInfo.Id);
    if ($(tree.Id).jstree('can_paste') && tree.cmdInfo.cmd !== 'pst') {
      $(tree.Id).jstree('clear_buffer');  /* cancel pending paste */
      CopyCut('clr', []);
    }
    var act = tree.callBacks.action ? tree.callBacks.action(obj) : tree.cmdInfo.cmd;
    if (act === 'sch') {
      var str = Dialog(tree.cmdList.sch.label, {pmt: ''});
      if (str) {
        $.jsfiler.Command(act, obj, str);
      } else {
        $(tree.Id).jstree('deselect_node', obj);
        $(tree.Id).jstree('select_node', obj);
      }
    } else if (act !== false) {
      var prm = typeof act === 'object' ? act : {};
      $.jsfiler.Command(tree.cmdInfo.cmd, obj, prm);
    }
  };
  /**
   * get node title
   * @param {array} cms
   */
  var ShowIcons = function(cms) {
    $(tree.menuId).children().hide();
    for (var cmd in tree.cmdList) {
      var c = '';
      if ($.inArray(cmd, cms) + 1) {
        c = 'a[href="#' + cmd + '"]';
      } else if (tree.menuType === 1) {
        var f = (tree.cmdList[cmd].icon && tree.cmdList[cmd].icon.length > 1);
        if (!tree.iconPath || f) {
          var s = f && tree.cmdList[cmd].icon[0] === tree.cmdList[cmd].icon[1] ? '' : suffix;
          c = 'a[href="#' + cmd + s + '"]';
        }
      }
      if (c !== '') {
        $(tree.menuId).children(c).css('display', 'inline-block');
      }
    }
  };
  /**
   * form node options htm
   * @param {object} node
   * @param {string} htm -- html to insert
   * @param {bool} flg -- true - menu (else meter)
   */
  var NodeOpts = function(node, htm, flg) {
    if (tree.menuType !== 1) {
      ClearOpts(node);
    }
    var h = '<span class="';
    if (flg) {
      h += menuClass + '" id="' + tree.menuId.substr(1) + '">';
    } else {
      h += meterClass + '">';
    }
    h += htm + '</span>';
    var obj = GetObj(node);
    if ($(obj).children('a').length) {
      $(obj).children('a:first').after(h);
    } else {
      $(obj).append(h);
    }
  };
  /**
   * remove node options
   * @param {object} node
   */
  var ClearOpts = function(node) {
    var id = TreeSelect(node, true);
    if (id && trees[id].menuType === 2 && $(trees[id].menuId).length) {
      if ($(trees[id].menuId).children('a').length) {
        $(trees[id].menuId).children('a').off('click');
      }
      $(trees[id].menuId).remove();
    }
  };

  /**
   * save current node info
   * @param {object} obj -- node
   * @param {string} cmd -- token
   */
  var NodeInfo = function(obj, cmd) {
    var id = TreeSelect(obj, true);
    var o = GetObj(obj);
    var c = cmd ? cmd : trees[id].cmdInfo.cmd;
    trees[id].cmdInfo = {
      cmd: c,
      Id: '#' + o.attr('id'),
      name: $(trees[id].Id).jstree('get_node', o).text,
      type: $(trees[id].Id).jstree('get_type', o),
      flag: false
    };
  };

  /**
   * get tree info
   * @param {mixed} node
   * @param {bool} mode -- true - get id
   * @return {object} 
   */
  var TreeSelect = function(node, mode) {
    var id = null;
    var a = GetObj(node).parents('.' + treeClass);
    if (a.length === 1) {
      id = $(a[0]).attr('id');
      if (!trees[id]) {
        id = false;
      } else if (!mode) {
        tree = trees[id];
      }
    }
    return id;
  };

  /**
   * get jQuery object
   * @param {string|object} obj
   * @return {object} 
   */
  var GetObj = function(obj) {
    var o;
    if (typeof obj === 'string') {
      o = $('#' + obj.replace('#', ''));
    } else if (obj.id) {
      o = $('#' + obj.id);
    } else if (obj.attr) {
      o = obj;
    } else {
      o = $(obj);
    }
    return o;
  };

  /**
   * tree instances
   * @param {object} options
   * @returns {object}
   */
  $.fn.jsfiler = function(options) {

    var config = {
      Id: '#', /* tree id */
      menuId: '#', /* commands block */
      menuType: 0, /* 0 - no icon menu, 1 - common, 2 - node */
      mainMenu: '',
      callBacks: {},
      cmdList: {},
      cmdMenu: {},
      treeIcons: {},
      icons: {},
      txts: {},
      cmdInfo: {Id: '', cmd: '', flag: false, name: '', type: null},
      args: {}, /* request arguments */
      search: false,
      nodes: [], /* multiple delete or paste id's */
      nodez: {}, /* move/copy replacement ids */
      pending: {} /* revoke command after node load */
    };
    var parm = {}; /* tree parameters */

    var that = this;

    /**
     * extract/merge the options
     */
    var Options = function() {
      if (opts.styles) {
        var c = (typeof opts.styles === 'string' ? [opts.styles] : opts.styles.join("\n"));
        Style(c);
        delete opts.styles;
      }
      $.extend(config.txts, txts);
      if (opts.txts) {
        $.extend(config.txts, opts.txts);
        delete opts.txts;
      }
      $.extend(config.callBacks, callBacks);
      if (opts.callBacks) {
        for (c in opts.callBacks) {
          if (opts.callBacks[c] !== null) {
            config.callBacks[c] = opts.callBacks[c];
          }
        }
        delete opts.callBacks;
      }
      if (opts.cmdList === undefined) {
        var coms = $.extend({}, treeCommands);
        CmdList(coms);
      } else {
        coms = $.extend(true, {}, opts.cmdList);
        CmdList(coms);
        for (c in treeCommands) {
          if (treeCommands[c].menu === false) {
            if (config.cmdList[c] === undefined) {
              config.cmdList[c] = treeCommands[c];
            } else {
              config.cmdList[c].menu = false;
            }
          }
        }
        delete opts.cmdList;
      }
      if (typeof opts.selectOpen != 'undefined') {
        opts.selectOpen = Number(opts.selectOpen); //for a backward compatibility 04.2017
      }
      TreeIcons();
      $.extend(config, treeConfig, opts);
      if (config.iconPath) {
        Icons();
      }
      $.extend(parm, treeParm);
      $.extend(parm.types, types);
      Types();
      parm.plugins = $.merge([], plugins);
      if (config.saveState !== false) {
        parm.plugins.push('state');
      }
      if (config.checkBox) {
        parm.plugins.push('checkbox');
        parm.checkbox.three_state = (config.checkBox > 1);
      }
      if (config.menuMode && config.menuMode !== 2) {//04.2017
        parm.plugins.push('contextmenu');
        config.cmdMenu = $.extend(true, {}, coms);
        CmdMenu(config.cmdMenu);
      }
      parm.core.dblclick_toggle = (config.selectOpen > 1);//04.2017
      parm.core.strings['Loading ...'] = config.loading;
    };
    /**
     * build command list
     * @param {object} coms
     */
    var CmdList = function(coms) {
      for (var com in coms) {
        if (coms[com].submenu) {
          CmdList(coms[com].submenu);
        } else {
          config.cmdList[com] = coms[com];
        }
      }
    };
    /**
     * correct right-click menu
     * @param {object} coms
     */
    var CmdMenu = function(coms) {
      for (var com in coms) {
        if (coms[com].submenu) {
          CmdMenu(coms[com].submenu);
        } else if (coms[com].menu !== false) {
          var f = new ContextMenu0(com);
          coms[com].action = f.act;
          delete coms[com].flag;
        } else {
          delete coms[com];
        }
      }
    };
    /**
     * create caller's style tag
     * @param {string} css
     */
    var Style = function(css) {
      var obj = document.createElement('style');
      obj.setAttribute('type', 'text/css');
      if (obj.styleSheet) {                          /* IE */
        obj.styleSheet.cssText = css;
      } else {
        obj.appendChild(document.createTextNode(css));
      }
      var div = document.getElementsByTagName('head')[0];
      div.appendChild(obj);
    };
    /**
     * set tree icons
     */
    var TreeIcons = function() {
      if (opts.treeIcons === undefined) {
        config.treeIcons = {};
        for (var c in types) {
          if (types[c].icon) {
            config.treeIcons[c] = [types[c].icon, [types[c].icon]];
          }
        }
      } else {
        for (c in opts.treeIcons) {
          if (!$.isArray(opts.treeIcons[c][1])) {
            opts.treeIcons[c][1] = [opts.treeIcons[c][1]];
          }
        }
        config.treeIcons = opts.treeIcons;
        delete opts.treeIcons;
      }
    };
    /**
     * icon loader
     */
    var Icons = function() {
      for (var c in config.treeIcons) {  /* preload tree images */
        if ($.isArray(config.treeIcons[c]) && config.treeIcons[c].length > 1) {
          var i = config.treeIcons[c];
          config.icons[i[0]] = [];
          for (var j = 0; j < i[1].length; j++) {
            config.icons[i[0]][j] = new Image();
            config.icons[i[0]][j].src = config.iconPath + i[1][j];
          }
        }
      }
      for (c in config.cmdList) {  /* preload command images */
        if (config.cmdList[c].icon) {
          if (typeof config.cmdList[c].icon === 'string') {
            config.cmdList[c].icon = [config.cmdList[c].icon];
          }
          config.icons[c] = new Image();
          config.icons[c].src = config.iconPath + config.cmdList[c].icon[0];
          if (config.cmdList[c].icon.length > 1) {
            config.icons[c + suffix] = new Image();
            config.icons[c + suffix].src = config.iconPath + config.cmdList[c].icon[1];
          }
        }
      }
    };
    /**
     * types plugin types
     */
    var Types = function() {
      for (var c in parm.types) {  /* normalize */
        if (config.treeIcons[c]) {
          var i = config.treeIcons[c][0];
          if (config.icons[i]) {
            parm.types[c].icon = config.icons[i][0].src;
          } else {
            parm.types[c].icon = config.treeIcons[c][1][0];
          }
        }
      }
      if (config.rootSingle) {
        parm.types['#'].max_children = 1; /* single top node */
      }
      if (config.rootLeaf) {
        parm.types[0].valid_children.push(3);
      }
    };

    /**
     * create a tree
     * @param {string} id -- tree id
     */
    var Init = function(id) {
      tree = $.extend({}, config);
      tree.Id = '#' + id;
      tree.menuId = '#' + id + menuSuffix; /* commands block */
      if (tree.menuMode > 1) {
        tree.menuType = $(tree.mainMenu).length ? 1 : 2;
      }
      trees[id] = tree;
      $(tree.Id).addClass(treeClass);
      if (tree.menuType === 1) {
        NodeOpts($(tree.mainMenu), CommandList(true), true);
        ShowIcons([]);
        $(tree.menuId).children('a').click(function() {
          var c = $(this).attr('href').replace(suffix, '').substr(1);
          if ($(this).attr('href').indexOf(suffix) === -1) {
            Action($(this), true);
          }
          return false;
        });
      }
      parm.state.key = id;
      Operations(id);
      $('#' + id).jstree(parm);
      $('#' + id).jstree(true).settings.core.check_callback = CheckBefore;
    };

    /**
     * tree operations
     * @param {string} id -- tree id
     */
    var Operations = function(id) {
      var i, j, r;
      $('#' + id).on({
        'loaded.jstree': function(e, data) {
//          i = $(e.target).jstree(true).settings.types[0].icon;
//          var r = $(e.target).find('li');
          r = $($(e.target).children('ul')[0]).children('li');//04.2017
          for (j = 0; j < r.length; j++) {  /* icon/type adjustment */
            $(e.target).jstree('set_type', r[j], 0); // replace default root type
//            $(e.target).jstree('set_icon', r[j], i); // replace default root icon
          }
        }, 'select_node.jstree': function(e, data) {
          if (data.node && $(tree.Id).find('.jstree-clicked').length === 1) {
            if ($.jsfiler.Engaged()) {  /* prevent selection */
              if (tree.cmdInfo.Id.substr(1) !== data.node.id) {
                $(tree.Id).jstree('deselect_node', data.node, true);
                $(tree.Id).jstree('select_node', tree.cmdInfo.Id, true);
              }
            } else if (!tree.cmdInfo.flag) {
              if (tree.selectOpen) {
                $(tree.Id).jstree('open_node', data.node);
              }
              NodeCommands(data.node.id);
            }
          }
        }, 'check_node.jstree': function(e, data) {
          if (tree.checkBox > 1 && !tree.cmdInfo.flag) {
            $(tree.Id).jstree('open_node', data.node); //display checked subs
          }
        }, 'uncheck_node.jstree': function(e, data) {
          debugger;
        }, 'before_open.jstree': function(e, data) {
          if (true) {
            return false;
          }
        }, 'search.jstree': function(e, data) {
          $(tree.Id).jstree('deselect_node', tree.cmdInfo.Id);
          if (data.nodes.length === 0) {
            tree.search = false;
            $(tree.Id).jstree('select_node', tree.cmdInfo.Id);
          }
        }, 'create_node.jstree': function(e, data) {
          tree.cmdInfo.flag = 2;
          $(tree.Id).jstree('edit', data.node);
        }, 'rename_node.jstree': function(e, data) {
          r = $('#' + data.node.id);
          var flg = tree.cmdInfo.flag;
          if (flg) {
            var title = CheckName(data.node.text, data.old, data.node.parent, r);
            tree.cmdInfo.flag = false;
          } else {
            title = null;
            tree.cmdInfo.flag = 1;
            $(tree.Id).jstree('edit', r);
          }
          if (typeof title === 'string') {  /* name is correct */
            Request(tree.cmdInfo.cmd, {id: data.node.id, idt: title, pid: data.node.parent}, data);
          } else if (title === true) {  /* incorrect name, retry */
            tree.cmdInfo.flag = flg;
            $(tree.Id).jstree('edit', r);
          } else if (flg === 1 && title === false) {
            $(tree.Id).jstree('set_text', r, data.old);
          } else if (flg === 2) {
//            $(tree.Id).jstree('delete_node', '#' + data.node.id);
            $(tree.Id).jstree('refresh_node', '#' + data.node.parent);
          }
        }, 'copy.jstree': function(e, data) {
          CopyCut('cpy', data.node);
        }, 'cut.jstree': function(e, data) {
          CopyCut('cut', data.node);
        }, 'paste.jstree': function(e, data) {
          CopyCut('pst', []);
        }, 'copy_node.jstree': function(e, data) {
          r = 'cpy';
          if (tree.cmdInfo.cmd === 'mve') {
            r = 'MVE';      /* multi tree move */
          } else if (tree.cmdInfo.cmd === 'pst') {
            i = $(tree.Id).jstree('get_buffer');
            if (i && i.mode === 'move_node') {
              r = 'MVE';    /* multi tree cut/paste */
            }
          }
          CopyMove(r, data);
        }, 'move_node.jstree': function(e, data) {
          CopyMove('mve', data);
        }, 'delete_node.jstree': function(e, data) {
        }, 'after_open.jstree': function(e, data) { /* check copy/cut */
          var pst = $(tree.Id).jstree('get_buffer');
          if (pst.mode) {
            var cmd = pst.mode === 'copy_node' ? 'cpy' : 'cut';
            var nds = $(tree.Id).jstree('get_children_dom', '#' + data.node.id);
            nds.push({id: data.node.id});
            for (i = 0; i < nds.length; i++) {
              for (j = 0; j < pst.node.length; j++) {
                if (nds[i].id === pst.node[j].id) {
                  $('#' + nds[i].id).addClass(pasteClass + cmd);
                  break;
                }
              }
            }
          }
        }, 'refresh_node.jstree': function(e, data) { /* new selection */
          $(tree.Id).jstree('open_node', data.node);
        }, 'changed.jstree': function(e, data) { /* new selection */
        }
      });
      /*      $(document).on('dnd_stop.vakata', function (e, data) {
       console.log(data);
       }); */
    };

    /**
     * constructor
     */
    var opts = options ? $.extend({}, options) : {};
    Options(); /* override defaults */
    return that.each(function() {
      var id = $(this).attr('id');
      if (trees[id] === undefined) {
        Init(id); /* create a tree */
      } else {
        for (var opt in opts) { /* modify config */
          if ($.inArray(opt, change) + 1) {
            trees[id][opt] = config[opt]; /* allowed change */
          }
        }
      }
    });
  };

  /**
   * form command list and attach event
   * @param {object} node
   */
  var NodeCommands = function(node) {
    TreeSelect(node);
    if (tree.search) {
      $(tree.Id).jstree('clear_search');
      tree.search = false;
    }
    var obj = GetObj(node);
    if (tree.menuType === 2) {
      NodeOpts(obj, CommandList(), true);
    }
    ShowIcons(AllowCommands(obj));
    NodeInfo(obj);
    if (tree.menuType === 2) {
      $(tree.menuId).children('a').click(function() {
        Action($(this), false);
        return false;
      });
    }
    return true;
  };

  /**
   * check operation allowance
   * @param {string} oper
   * @param {object} node
   * @param {object} parent
   * @param {int} pos
   * @param {object} misc -- move - new parent
   * @return {bool} 
   */
  var CheckBefore = function(oper, node, parent, pos, misc) {
    if ($.jsfiler.Engaged()) {
      var chk = false;
    } else if ((oper === 'move_node' || oper === 'copy_node') && tree.cmdInfo.flag === false) {
      if (misc && misc.core) {
        var id = TreeSelect(node, true);
        Remit(trees[id].cmdInfo.cmd, node, parent);
        chk = false;
      } else if (misc && misc.dnd) {
        chk = CheckDnd(node, misc.ref);
        tree.cmdInfo.cmd = oper === 'copy_node' ? 'cpy' : 'mve';
      }
    } else {
      chk = true;
    }
    return chk;
  };
  /**
   *  drag/drop allowance
   *  @param {object} obj -- node(s) - jstree
   *  @param {object} parent -- Drop - jstree
   * @return {bool} 
   */
  var CheckDnd = function(obj, parent) {
    if (parent === undefined) {
      var f = obj.length === 1 && obj[0].type !== 0; /* don't drag multiple nodes and/or root node */
    } else {
      f = parent.type && parent.type !== 3 && /* don't drop to a leaf node */
              (obj.parent && obj.parent !== parent.id); /* don't drop to parent */
    }
    if (tree.callBacks.check) {
      f = tree.callBacks.check(f, obj, parent);
    }
    return f;
  };
  /**
   * search command
   * @param {mixed} cnd -- search condition
   * @param {object} obj -- selected node
   */
  var Search = function(cnd, obj) {
    $(tree.Id).jstree('deselect_node', obj);
    if (tree.menuType === 1) {
      ShowIcons([]);
    } else if (tree.menuType === 2) {
      ClearOpts(obj);
    }
    if (typeof cnd !== 'object') {
      cnd = {str: cnd, csi: 0, pos: 0};
    }
    tree.search = cnd;
    $(tree.Id).jstree('search', cnd.str);
  };
  /**
   * trim and validate name, check for duplicates
   * @param {string} nme -- new name
   * @param {string} old -- old name
   * @param {string} pid -- parent id
   * @param {object} rlt -- result node
   * @return {mixed} -- null - no changes
   *                    false - cancel
   *                    true - retry 
   *                    string - trimmed new name
   */
  var CheckName = function(nme, old, pid, rlt) {
    var err = '';
    var trm = new RegExp(tree.nameTrim);
    var name = nme.replace(trm, ''); /* trim spaces and periods */
    var nam = name;
    if (name !== nme) {
      $(tree.Id).jstree('set_text', rlt, name); /* replace with trimmed name */
    }
    if (name === '' || name === old) {
      var flg = null; /* empty or not changed */
    } else if (tree.nameValidate) {
      var ptr = new RegExp(tree.nameValidate);
      flg = ptr.test(name); /* check for denied symbols */
    } else {
      flg = true;
    }
    if (flg && tree.nameDupl < 2) {
      var nid = rlt.attr('id');
      var nodes = $(tree.Id).jstree('get_children_dom', '#' + pid);
      for (var i = 0; i < nodes.length; i++) {  /* check for duplicate names */
        var id = $(nodes[i]).attr('id');
        var nn = NodeName(id);
        if (id && id !== nid && ((tree.nameDupl === 1 && nn === name) ||
                (tree.nameDupl === 0 && nn.toLowerCase() === name.toLowerCase()))) {
          nam = nn;
          flg = false;
          break;
        }
      }
      if (!flg) {
        err = tree.txts.knotExists;
      }
    } else if (flg === false) {
      err = tree.txts.badName;
    }
    if (err !== '') {
      flg = Dialog([err, nam], {pmt: true});
    } else if (flg) {
      flg = name;
    }
    return flg;
  };

  /**
   * exclude non-delete nodes, ask for delete confirmation
   * @param {string} cmd
   * @param {object} node -- command node
   * @return {bool}
   */
  var CheckAllowed = function(cmd, node) {
    var ids = $(tree.Id).jstree('get_selected');
    var id = GetObj(node).attr('id');
    var a = [id];
    for (var i in ids) {
      var obj = $('#' + ids[i]);
      if ($.inArray(cmd, AllowCommands(obj)) === -1) {
        $(tree.Id).jstree('deselect_node', obj, true);
      } else if (ids[i] !== id) {
        a.push(ids[i]);
      }
    }
    var txt = [tree.txts.confirmDelete];
    var b = [];
    for (i = 0; i < a.length; i++) {
      obj = '#' + a[i];
      if (ClickedParent(a[i]).length) {
        $(tree.Id).jstree('deselect_node', obj, true);
      } else {
        b.push(obj);
//        txt.push(NodeName(obj));
        txt.push($(tree.Id).jstree('get_path', obj, '/'));
      }
    }
    if (b.length > 0) {
      if (cmd === 'del') {
        Dialog(txt, {cmd: 'del', fnc: ConfirmDelete, dat: b});
      } else {
        $(tree.Id).jstree(cmd === 'cpy' ? 'copy' : 'cut', b);
      }
    }
    return b;
  };

  /**
   * find clicked parent nodes
   * @param {string} id -- node to check
   * @return {array}
   */
  var ClickedParent = function(id) {
    var rlt = [];
    var ids = $(tree.Id).jstree('get_path', '#' + id, false, true);
    ids.shift();
    ids.pop();
    for (var i in ids) {
      if ($(tree.Id).jstree('is_selected', '#' + ids[i])) {
        rlt.push(ids[i]);
      }
    }
    return rlt;
  };

  /**
   * dialog box answer
   * @param {bool} cfm -- true - remove
   * @param {array} nodes
   */
  var ConfirmDelete = function(cfm, nodes) {
    /**
     * check if action allowed
     * @param {object} data -- before object
     * @return {bool}
     */
    if (cfm) {
      tree.nodes = [];
      tree.nodez = {};
      for (var i = 0; i < nodes.length; i++) {
        var id = nodes[i].substr(1);
        tree.nodes.push(id);
        tree.nodez[id] = $(tree.Id).jstree('get_parent', nodes[i]);
      }
      Request('del', {id: tree.nodes, pid: tree.nodez});
    } else {
      $(tree.Id).jstree('deselect_all', true);
      $(tree.Id).jstree('select_node', tree.cmdInfo.Id);
    }
  };

  /**
   * copy/move/paste when new parent's children are loaded
   * @param {string} cmd
   * @param {object|array} node
   * @param {object} parent - new one
   * @param {bool} flg -- true - load was made
   */
  var Remit = function(cmd, node, parent, flg) {
    TreeSelect(parent);
    NodeInfo(parent, cmd);
    if (parent.type === 2 || $(tree.Id).jstree('is_loaded', '#' + parent.id)) {
      if (parent.state.opened) {
        CheckReplace(cmd, node, parent);
      } else {
        $(tree.Id).jstree('open_node', parent, function() {
          CheckReplace(cmd, node, parent);
        });
      }
    } else if (!flg) {
      tree.pending = [Remit, cmd, node, parent, true];
      $(tree.Id).jstree('load_node', parent, function() {
        $(tree.Id).jstree('open_node', parent);
      });
    }
  };

  /**
   * check if destination subnode exists
   * @param {string} cmd -- move/copy_node
   * @param {object} node -- to move
   * @param {object} parent -- new parent
   */
  var CheckReplace = function(cmd, node, parent) {
    var nodes = $.isArray(node) ? node : [node];
    NodeInfo(nodes[0], cmd);
    var pos = 0;
    tree.nodez = {};
    var txt = [tree.txts.confirmReplace];
    var child = $(tree.Id).jstree('get_children_dom', '#' + parent.id);
    for (var i = 0; i < child.length; i++) {
      var nme = NodeName(child[i].id);
      for (var j = 0; j < nodes.length; j++) {
        if (child[i].id !== nodes[j].id && ((tree.nameDupl === 1 && nme === nodes[j].text) ||
                (tree.nameDupl === 0 && nme.toLowerCase() === nodes[j].text.toLowerCase()))) {
          tree.nodez[nodes[j].id] = child[i].id;
          txt.push($(tree.Id).jstree('get_path', child[i].id, '/'));
          break;
        }
      }
      if (nme < nodes[0].text) {
        pos = i + 1;
      }
    }
    tree.nodes = {};
    tree.cmdInfo.flag = nodes.length;
    var data = [cmd, nodes, parent, pos];
    if ($.isEmptyObject(tree.nodez)) {
      ConfirmReplace(true, data);
    } else {
      Dialog(txt, {cmd: 'rpl', fnc: ConfirmReplace, dat: data});
    }
  };

  /**
   * dialog box answer
   * @param {bool} cfm
   * @param {object} data -- copy/move object
   * @return {bool}
   */
  var ConfirmReplace = function(cfm, data) {
    if (!cfm) {
      tree.cmdInfo.flag = false;
      if (data[0] === 'pst') {
        $(tree.Id).jstree('clear_buffer');  /* cancel paste */
        CopyCut('clr', []);
        NodeCommands(data[2].id);
      }
    } else if (data[0] === 'pst') {
      $(tree.Id).jstree('paste', data[2], data[3]);
    } else if (data[0] === 'cpy') {
      $(tree.Id).jstree('copy_node', data[1], data[2], data[3]);
    } else {
      $(tree.Id).jstree('move_node', data[1], data[2], data[3]);
    }
  };
  /**
   * copy/move server-side
   * @param {string} cmd -- cpy/mve; MVE - move as copy
   * @param {object} data
   */
  var CopyMove = function(cmd, data) {
    tree.nodes[data.node.id] = [cmd === 'mve' ? data.node.id : data.original.id, data.old_parent];
    tree.cmdInfo.flag--;
    if (tree.cmdInfo.flag === 0) {
      if (!$.isEmptyObject(tree.nodez)) {  /* replacement */
        tree.args.rpl = tree.nodez;
      }
      var fid = tree.Id.replace('#', '');
      if (data.old_parent.indexOf(fid) === -1) {
        fid = TreeSelect(data.old_parent, true);
      } else if (data.parent.indexOf(fid) === -1) {
        fid = TreeSelect(data.parent, true);
      } else {
        fid = null;
      }
      if (fid) {
        tree.args.fid = fid;
      }
      tree.cmdInfo.flag = false;
      Request(cmd.toLowerCase(), {
        id: tree.nodes,
        idt: data.node.text,
        pid: data.parent
      }, data);
    }
  };

  /**
   * mark the nodes
   * @param {string} cmd -- cpy/cut
   * @param {array} nodes
   */
  var CopyCut = function(cmd, nodes) {
    for (var t in trees) {
      $(trees[t].Id).find('.' + pasteClass + 'cpy' + ',' + '.' + pasteClass + 'cut').removeClass(pasteClass + 'cpy' + ' ' + pasteClass + 'cut');
    }
    for (var i = 0; i < nodes.length; i++) {
      GetObj(nodes[i]).addClass(pasteClass + cmd);
    }
  };

  /**
   * get valid commands
   * @param {object} obj node
   * @return {array} 
   */
  var AllowCommands = function(obj) {
    var node = $(tree.Id).jstree('get_node', obj);
    var cms = [];
    for (var cmd in tree.cmdList) {
      if ((cmd === 'sch' && node.type < 2) ||
              (cmd === 'new' && node.type !== 3) ||
              (cmd === 'add' && node.type !== 3 && (node.type !== 0 || tree.rootLeaf)) ||
              (cmd === 'cpy' && node.type !== 0) ||
              (cmd === 'cut' && node.type !== 0 && RemoveAllowed(node)) ||
              (cmd === 'pst' && PasteAllowed(node)) ||
              (cmd === 'ren' && (node.type !== 0 || !tree.rootSingle)) ||
              (cmd === 'del' && RemoveAllowed(node))) {
        cms.push(cmd);
      }
    }
    return tree.callBacks.allow ? tree.callBacks.allow(node, cms) : cms;
  };
  /**
   * check remove allowance
   * @param {object} node jstree
   * @returns {bool}
   */
  var RemoveAllowed = function(node) {
    return (tree.knotRemove > 1 || node.type > 1 ||
            (tree.knotRemove === 1 && node.li_attr[copied]));
  };
  /**
   * check paste allowance
   * @param {object} node jstree
   * @returns {bool}
   */
  var PasteAllowed = function(node) {
    var pst = $(tree.Id).jstree('get_buffer');
    if (pst.mode && node.type !== 3) {
      var f = 0;
      for (var i = 0; i < pst.node.length; i++) {
        if (pst.node[i].id === node.id || pst.node[i].parent === node.id) {
          f = 2;
        } else if (pst.node[i].type === 3) {
          f = 1;
          break;
        }
      }
      var r = (f === 0 || (f === 1 && (node.type !== 0 || tree.rootLeaf)));
    } else {
      r = false;
    }
    return r;
  };
  /**
   * get node title
   * @param {object} obj
   * @return {string} 
   */
  var NodeName = function(obj) {
    var c = $(tree.Id).jstree('get_node', obj).text;
    return c;
  };
  /**
   * server request
   * @param {string} cmd -- command token
   * @param {object} parm -- command params
   * @param {array} data -- jstree data
   *                          args - additional params
   * @return {object} 
   */
  var Request = function(cmd, parm, data) {
    var args = $.extend({}, tree.args, parm);
    tree.args = {};
    args.cmd = cmd;
    args.cmt = tree.callBacks.encode(tree.cmdList[cmd].label);
    args.idt = parm.idt ? tree.callBacks.encode(parm.idt) : '';
    args.ckd = null;
    if (data === undefined) {
      data = {};
    } else if (data.node && tree.checkBox) {
      args.ckd = ($(tree.Id).jstree('is_checked', data.node) === true);
    }
    if (tree.cmdList[cmd].menu !== false) {
      if (data.busy) {
        $.jsfiler.Busy(data.busy.txt, data.busy.obj);
      } else {
        $.jsfiler.Busy(tree.cmdList[cmd].label);
      }
    }
    Ajax(args, data, Response);
  };

  /**
   * command response
   * @param {object} arg -- request params
   * @param {object} rsp -- response 
   * @param {object} dat
   */
  var Response = function(arg, rsp, dat) {
    var i;
    var sid = null;
    if (!rsp.status) {
      sid = RollBack(arg, rsp, dat);
    } else if (arg.cmd === 'new' || arg.cmd === 'add') {
      sid = rsp.factor.id;
      $(tree.Id).jstree('set_id', dat.node, sid);
      if (rsp.factor.li_attr) {
        for (i in rsp.factor.li_attr) {
          dat.node.li_attr[i] = rsp.factor.li_attr[i];
          $('#' + sid).attr(i, rsp.factor.li_attr[i]);
        }
      }
      if (rsp.factor.a_attr) {
        for (i in rsp.factor.a_attr) {
          dat.node.a_attr[i] = rsp.factor.a_attr[i];
          $('#' + sid).find('a').attr(i, rsp.factor.a_attr[i]);
        }
      }
      if (tree.callBacks.metadata) {
        tree.callBacks.metadata([rsp.factor]);
      }
      if ($(tree.Id).jstree('get_type', dat.node.parent) === 2) {
        $(tree.Id).jstree('set_type', dat.node.parent, 1);
        $(tree.Id).jstree('set_icon', dat.node.parent, $(tree.Id).jstree(true).settings.types[1].icon);
      }
    } else if (arg.cmd === 'cpy' || arg.cmd === 'mve') {
      ResponseRemit(arg, rsp.factor, dat);
    } else if (arg.cmd === 'del') {
      for (i in arg.pid) {
        $(tree.Id).jstree('delete_node', i);
        if (arg.pid[i] !== '#') {
          sid = arg.pid[i];
          if ($(tree.Id).jstree('get_type', sid) !== 0 && !$(tree.Id).jstree('get_children_dom', sid).length) {
            $(tree.Id).jstree('set_type', sid, 2);
            $(tree.Id).jstree('set_icon', sid, $(tree.Id).jstree(true).settings.types[2].icon);
          }
        }
      }
    }
    if (!sid) {
      var a = $(tree.Id).jstree('get_selected');
      if (a.length) {
        sid = a[0];
      }
    }
    $(tree.Id).jstree('deselect_all');
    if (sid) {
      $(tree.Id).jstree('select_node', sid);
    } else {
      ShowIcons([]);
    }
    if (rsp.status && tree.callBacks.response) {
      tree.callBacks.response(arg, rsp, dat);
    }
    if (rsp.prompt) {
      Dialog(rsp.prompt);
    }
  };

  /**
   * undo the changes
   * @param {object} arg -- request params
   * @param {object} rsp -- response 
   * @param {object} dat
   * @return {string}
   */
  var RollBack = function(arg, rsp, dat) {
    var i, a;
    var sid = null;
    if (arg.cmd === 'new' || arg.cmd === 'add') {
      sid = dat.node.parent;
      $(tree.Id).jstree('delete_node', dat.node);
    } else if (arg.cmd === 'ren') {
      sid = dat.node.id;
      $(tree.Id).jstree('set_text', dat.node, dat.old);
    } else if (arg.cmd === 'cpy' || arg.cmd === 'mve') {
      a = rsp.factor ? rsp.factor : {};
      for (i in arg.id) {
        if (a[i] === undefined) {
          $(tree.Id).jstree('delete_node', '#' + i);
          if (arg.cmd === 'mve') {
            TreeSelect(arg.id[i][1]);
            $(tree.Id).jstree('refresh_node', '#' + arg.id[i][1]);
            TreeSelect(i);
          }
        }
      }
    }
    return sid;
  };

  /**
   * copy/move response
   * @param {object} arg -- request args
   * @param {object} ids -- ids to change 
   * @param {object} dat -- tree data
   */

  var ResponseRemit = function(arg, ids, dat) {
    var i;
    if (!$.isEmptyObject(ids) && $(tree.Id).jstree('get_type', '#' + dat.parent) === 2) {
      $(tree.Id).jstree('open_node', dat.parent);
      $(tree.Id).jstree('set_type', '#' + dat.parent, 1);
//      $(tree.Id).jstree('set_icon', '#' + dat.parent, $(tree.Id).jstree(true).settings.types[1].icon);
    }
    if (arg.rpl) {
      for (i in arg.rpl) {
        $(tree.Id).jstree('delete_node', arg.rpl[i]);
      }
    }
    if (ids) {
      for (i in ids) {
        var n = $(tree.Id).jstree('get_node', i);
        if (arg.cmd === 'cpy') {
          n.li_attr[copied] = i;
        }
        if (i !== ids[i]) {
          $(tree.Id).jstree('set_id', '#' + i, ids[i]);
        }
        if (n.parent !== arg.pid) {
          n.parent = arg.pid;
        }
      }
    }
    for (i in arg.id) {
      var id = arg.id[i][1];
      if (!$(tree.Id).jstree('get_children_dom', '#' + id).length) {
        $(tree.Id).jstree('set_type', '#' + id, 2);
      }
    }
    if (arg.cmd === 'mve' && arg.fid !== arg.tid) {
      TreeSelect(id);
      $(tree.Id).jstree('deselect_all', true);
      $(tree.Id).jstree('select_node', '#' + id);
      TreeSelect(arg.pid);
    }
  };
  /**
   * make ajax request
   * @param {object} args -- request params
   * @param {object} data -- misc. caller data
   *                    meth - request method (default POST)
   * @param {function} clbk callback
   */
  var Ajax = function(args, data, clbk) {
    args.tid = tree.Id.replace('#', '');
    args.tzo = (new Date()).getTimezoneOffset();
    args.ver = $.jsfiler.version;
    if (tree.callBacks.request) {
      var dat = tree.callBacks.request(args, data);
      args = dat.args;
      data = dat.data;
    }
    var rslt = '';
    $.ajax({
      async: true,
      type: 'POST',
      url: tree.urlAjax,
      dataType: 'json',
      beforeSend: function(xhr) {
        if (tree.jsonSend) {
          xhr.setRequestHeader('Content-Type', 'application/json');
        }
        if (tree.userAuth) {
          xhr.setRequestHeader('Authorization', tree.userAuth);
        }
      },
      data: (tree.jsonSend ? JSON.stringify(args) : args),
      success: function(result) {
        rslt = result;
      },
      complete: function(obj, sts) {
        if (sts !== 'success') {
          var pmt = [tree.txts.ajaxFail + ': ', sts + ' (' + obj.status + ' ' + obj.statusText + ')'];
          rslt = {status: false, prompt: pmt, factor: null};
        }
        if (data.busy === true) {
          delete data.busy;
        } else {
          $.jsfiler.Busy();
        }
        clbk(args, rslt, data);
      }
    });
  };
  /**
   * customized/default messenger
   * @param {string|array} msg -- message text
   * @param {object} obj -- caller info
   * @return {bool|null} 
   */
  var Dialog = function(msg, obj) {
    if (tree.callBacks.dialog) {  /* caller dialoger */
      var rtn = tree.callBacks.dialog(msg, obj);
    } else {
      var txt = (typeof msg === 'string') ? msg : msg.join("\n");
      if (obj) {
        if (typeof obj.pmt === 'string') {
          rtn = prompt(txt, obj.pmt);
        } else {
          rtn = confirm(txt);
        }
        if (obj.fnc) {
          obj.fnc(rtn, obj.dat);
        }
      } else {
        alert(txt);
        var rtn = null;
      }
    }
    return rtn;
  };

})(jQuery, document);

Zerion Mini Shell 1.0