From 9ee1be2ecea62b991a8bffd1736ed0f80ee06a21 Mon Sep 17 00:00:00 2001 From: juanf <juanf> Date: Mon, 14 Dec 2015 14:31:23 +0000 Subject: [PATCH] SSDM-2960 : ELN: Layout Improvements - Side Menu as tree SVN: 35305 --- .../1/as/webapps/eln-lims/html/index.html | 4 + .../SideMenu/SideMenuWidgetController.js | 111 +- .../js/views/SideMenu/SideMenuWidgetView.js | 71 +- .../html/lib/jquery-fancytree/LICENSE.txt | 9 + .../html/lib/jquery-fancytree/VERSION.txt | 1 + .../js/jquery.fancytree-all.js | 7678 +++++++ .../js/jquery.fancytree-all.min.js | 47 + .../jquery-fancytree/js/jquery.fancytree.js | 4515 +++++ .../js/jquery.fancytree.min.js | 14 + .../js/skin-awesome/ui.fancytree.css | 361 + .../js/skin-awesome/ui.fancytree.less | 53 + .../js/skin-awesome/ui.fancytree.min.css | 6 + .../js/skin-bootstrap-n/ui.fancytree.css | 441 + .../js/skin-bootstrap-n/ui.fancytree.less | 173 + .../js/skin-bootstrap-n/ui.fancytree.min.css | 6 + .../js/skin-bootstrap/ui.fancytree.css | 492 + .../js/skin-bootstrap/ui.fancytree.less | 333 + .../js/skin-bootstrap/ui.fancytree.min.css | 6 + .../lib/jquery-fancytree/js/skin-common.less | 685 + .../js/skin-custom-1/README.md | 14 + .../jquery-fancytree/js/skin-lion/icons.gif | Bin 0 -> 5906 bytes .../jquery-fancytree/js/skin-lion/loading.gif | Bin 0 -> 1849 bytes .../js/skin-lion/ui.fancytree.css | 565 + .../js/skin-lion/ui.fancytree.less | 95 + .../js/skin-lion/ui.fancytree.min.css | 6 + .../js/skin-themeroller/icons.gif | Bin 0 -> 5492 bytes .../js/skin-themeroller/loading.gif | Bin 0 -> 3234 bytes .../js/skin-themeroller/ui.fancytree.css | 505 + .../js/skin-themeroller/ui.fancytree.min.css | 1 + .../jquery-fancytree/js/skin-vista/icons.gif | Bin 0 -> 5492 bytes .../js/skin-vista/loading.gif | Bin 0 -> 3234 bytes .../js/skin-vista/ui.fancytree.css | 571 + .../js/skin-vista/ui.fancytree.less | 112 + .../js/skin-vista/ui.fancytree.min.css | 6 + .../jquery-fancytree/js/skin-win7/icons.gif | Bin 0 -> 5492 bytes .../jquery-fancytree/js/skin-win7/loading.gif | Bin 0 -> 3234 bytes .../js/skin-win7/ui.fancytree.css | 630 + .../js/skin-win7/ui.fancytree.less | 152 + .../js/skin-win7/ui.fancytree.min.css | 6 + .../jquery-fancytree/js/skin-win8-n/icons.gif | Bin 0 -> 5492 bytes .../js/skin-win8-n/loading.gif | Bin 0 -> 3234 bytes .../js/skin-win8-n/ui.fancytree.css | 575 + .../js/skin-win8-n/ui.fancytree.less | 143 + .../js/skin-win8-n/ui.fancytree.min.css | 6 + .../js/skin-win8-xxl/icons.gif | Bin 0 -> 20860 bytes .../js/skin-win8-xxl/loading.gif | Bin 0 -> 6243 bytes .../js/skin-win8-xxl/ui.fancytree.css | 583 + .../js/skin-win8-xxl/ui.fancytree.less | 37 + .../js/skin-win8-xxl/ui.fancytree.min.css | 11 + .../jquery-fancytree/js/skin-win8/icons.gif | Bin 0 -> 5492 bytes .../jquery-fancytree/js/skin-win8/loading.gif | Bin 0 -> 3234 bytes .../js/skin-win8/ui.fancytree.css | 573 + .../js/skin-win8/ui.fancytree.less | 153 + .../js/skin-win8/ui.fancytree.min.css | 6 + .../jquery-fancytree/js/skin-xp/icons-rtl.gif | Bin 0 -> 4046 bytes .../lib/jquery-fancytree/js/skin-xp/icons.gif | Bin 0 -> 4041 bytes .../jquery-fancytree/js/skin-xp/loading.gif | Bin 0 -> 570 bytes .../js/skin-xp/ui.fancytree.css | 562 + .../js/skin-xp/ui.fancytree.less | 96 + .../js/skin-xp/ui.fancytree.min.css | 6 + .../jquery-fancytree/js/skin-xp/vline-rtl.gif | Bin 0 -> 842 bytes .../lib/jquery-fancytree/js/skin-xp/vline.gif | Bin 0 -> 844 bytes .../js/src/jquery.fancytree.childcounter.js | 208 + .../js/src/jquery.fancytree.clones.js | 451 + .../js/src/jquery.fancytree.columnview.js | 150 + .../js/src/jquery.fancytree.debug.js | 142 + .../js/src/jquery.fancytree.dnd.js | 553 + .../js/src/jquery.fancytree.edit.js | 309 + .../js/src/jquery.fancytree.filter.js | 283 + .../js/src/jquery.fancytree.glyph.js | 139 + .../js/src/jquery.fancytree.gridnav.js | 199 + .../js/src/jquery.fancytree.js | 4515 +++++ .../js/src/jquery.fancytree.menu.js | 155 + .../js/src/jquery.fancytree.persist.js | 383 + .../js/src/jquery.fancytree.table.js | 366 + .../js/src/jquery.fancytree.themeroller.js | 78 + .../js/src/jquery.fancytree.wide.js | 183 + .../eln-lims/html/lib/jquery-ui/LICENSE.txt | 1 + .../eln-lims/html/lib/jquery-ui/VERSION.txt | 1 + .../html/lib/jquery-ui/js/jquery-ui-custom.js | 16617 ++++++++++++++++ 80 files changed, 45071 insertions(+), 82 deletions(-) create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/LICENSE.txt create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/VERSION.txt create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/jquery.fancytree-all.js create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/jquery.fancytree-all.min.js create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/jquery.fancytree.js create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/jquery.fancytree.min.js create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-awesome/ui.fancytree.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-awesome/ui.fancytree.less create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-awesome/ui.fancytree.min.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap-n/ui.fancytree.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap-n/ui.fancytree.less create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap-n/ui.fancytree.min.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap/ui.fancytree.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap/ui.fancytree.less create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap/ui.fancytree.min.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-common.less create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-custom-1/README.md create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-lion/icons.gif create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-lion/loading.gif create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-lion/ui.fancytree.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-lion/ui.fancytree.less create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-lion/ui.fancytree.min.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-themeroller/icons.gif create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-themeroller/loading.gif create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-themeroller/ui.fancytree.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-themeroller/ui.fancytree.min.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-vista/icons.gif create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-vista/loading.gif create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-vista/ui.fancytree.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-vista/ui.fancytree.less create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-vista/ui.fancytree.min.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win7/icons.gif create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win7/loading.gif create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win7/ui.fancytree.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win7/ui.fancytree.less create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win7/ui.fancytree.min.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-n/icons.gif create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-n/loading.gif create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-n/ui.fancytree.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-n/ui.fancytree.less create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-n/ui.fancytree.min.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-xxl/icons.gif create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-xxl/loading.gif create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-xxl/ui.fancytree.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-xxl/ui.fancytree.less create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-xxl/ui.fancytree.min.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8/icons.gif create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8/loading.gif create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8/ui.fancytree.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8/ui.fancytree.less create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8/ui.fancytree.min.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/icons-rtl.gif create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/icons.gif create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/loading.gif create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/ui.fancytree.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/ui.fancytree.less create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/ui.fancytree.min.css create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/vline-rtl.gif create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/vline.gif create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.childcounter.js create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.clones.js create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.columnview.js create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.debug.js create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.dnd.js create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.edit.js create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.filter.js create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.glyph.js create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.gridnav.js create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.js create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.menu.js create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.persist.js create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.table.js create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.themeroller.js create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.wide.js create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-ui/LICENSE.txt create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-ui/VERSION.txt create mode 100644 plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-ui/js/jquery-ui-custom.js diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/index.html b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/index.html index 9fc1d389765..5f9cc348693 100644 --- a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/index.html +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/index.html @@ -32,12 +32,16 @@ <link type="text/css" rel="stylesheet" href="./lib/jquery-tooltipster/css/tooltipster.css" /> <link type="text/css" rel="stylesheet" href="./lib/fuelux/css/fuelux.min.css" /> <link type="text/css" rel="stylesheet" href="./lib/drawingboard/css/drawingboard.min.css" /> + <link type="text/css" rel="stylesheet" href="./lib/jquery-fancytree/js/skin-lion/ui.fancytree.min.css" /> <!-- ELN UI Stylesheets --> <link type="text/css" rel="stylesheet" href="./css/style.css" /> <!-- Third party libraries --> <script type="text/javascript" src="./lib/jquery/js/jquery-1.11.3.min.js"></script> + <script type="text/javascript" src="./lib/jquery-ui/js/jquery-ui-custom.js"></script> + <script type="text/javascript" src="./lib/jquery-fancytree/js/jquery.fancytree.js"></script> + <script type="text/javascript" src="./lib/bootstrap-datetimepicker/js/moment.js"></script> <script type="text/javascript" src="./lib/bootstrap/js/bootstrap.min.js"></script> <script type="text/javascript" src="./lib/bootstrap-datetimepicker/js/bootstrap-datetimepicker.min.js"></script> diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SideMenu/SideMenuWidgetController.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SideMenu/SideMenuWidgetController.js index 8330a8216f2..e1722786255 100644 --- a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SideMenu/SideMenuWidgetController.js +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SideMenu/SideMenuWidgetController.js @@ -40,8 +40,8 @@ function SideMenuWidgetController(mainController) { if(currentItemChild.uniqueId === uniqueId) { currentItem.newMenuIfSelected.children.splice(i,1); if(!notMoveToParent) { + this._sideMenuWidgetModel.pointerToMenuNode = currentItem; mainController.changeView(currentItem.newViewIfSelected, currentItem.newViewIfSelectedData); - this._sideMenuWidgetModel.pointerToMenuNode = currentItem; } this._sideMenuWidgetView.repaint(); @@ -91,7 +91,7 @@ function SideMenuWidgetController(mainController) { this.refreshProject = function(spaceCode, projectCode) { - var menuItemSpace = this._getSpaceNodeForCode(spaceCode); + var menuItemSpace = this._getUniqueId(spaceCode); var newMenuIfSelectedProject = { children: [] }; @@ -136,7 +136,7 @@ function SideMenuWidgetController(mainController) { this.refreshExperiment = function(experiment, isInventory) { var projectIdentifierEnd = experiment.identifier.lastIndexOf("/"); var projectIdentifier = experiment.identifier.substring(0, projectIdentifierEnd); - var projectNode = this._getProjectNodeForIdentifier(projectIdentifier); + var projectNode = this._getUniqueId(projectIdentifier); var newMenuIfSelectedExperiment = { children: [] @@ -171,7 +171,7 @@ function SideMenuWidgetController(mainController) { for (var i = 0; i < subExperiments.result.length; i++) { var subExperiment = subExperiments.result[i]; if (subExperiment.experimentIdentifierOrNull) { - var experimentNode = _this._getExperimentNodeForIdentifier(subExperiment.experimentIdentifierOrNull); + var experimentNode = _this._getUniqueId(subExperiment.experimentIdentifierOrNull); var displayName = null; if (profile.hideCodes) { displayName = subExperiment.properties[profile.propertyReplacingCode]; @@ -198,10 +198,9 @@ function SideMenuWidgetController(mainController) { this.init = function($container, initCallback) { this._sideMenuWidgetModel.$container = $container; var _this = this; - - this._sideMenuWidgetModel.menuStructure.newMenuIfSelected.children.push( - new SideMenuWidgetComponent(false, true, "LAB NOTEBOOK", "LAB_NOTEBOOK", this._sideMenuWidgetModel.menuStructure, null, null, null, "") - ); + + var labNotebookNode = new SideMenuWidgetComponent(true, true, "LAB NOTEBOOK", "LAB_NOTEBOOK", this._sideMenuWidgetModel.menuStructure, { children: [] }, null, null, ""); + this._sideMenuWidgetModel.menuStructure.newMenuIfSelected.children.push(labNotebookNode); mainController.serverFacade.listSpacesWithProjectsAndRoleAssignments(null, function(dataWithSpacesAndProjects) { //Fill Spaces @@ -217,9 +216,9 @@ function SideMenuWidgetController(mainController) { var newMenuIfSelectedSpace = { children: [] }; - var menuItemSpace = new SideMenuWidgetComponent(true, false, space.code, space.code, _this._sideMenuWidgetModel.menuStructure, newMenuIfSelectedSpace, 'showSpacePage', space.code, "(Space)"); - _this._sideMenuWidgetModel.menuStructure.newMenuIfSelected.children.push(menuItemSpace); - + var menuItemSpace = new SideMenuWidgetComponent(true, false, space.code, space.code, labNotebookNode, newMenuIfSelectedSpace, 'showSpacePage', space.code, "(Space)"); + labNotebookNode.newMenuIfSelected.children.push(menuItemSpace); + //Fill Projects for (var j = 0; j < space.projects.length; j++) { var project = space.projects[j]; @@ -250,7 +249,7 @@ function SideMenuWidgetController(mainController) { experimentsToAskForSamples.push(experiment); var projectIdentifierEnd = experiment.identifier.lastIndexOf("/"); var projectIdentifier = experiment.identifier.substring(0, projectIdentifierEnd); - var projectNode = _this._getProjectNodeForIdentifier(projectIdentifier); + var projectNode = _this._getUniqueId(projectIdentifier); toSortExperiments[projectNode.uniqueId] = projectNode; var newMenuIfSelectedExperiment = { children: [] @@ -280,7 +279,7 @@ function SideMenuWidgetController(mainController) { for (var i = 0; i < subExperiments.result.length; i++) { var subExperiment = subExperiments.result[i]; - var experimentNode = _this._getExperimentNodeForIdentifier(subExperiment.experimentIdentifierOrNull); + var experimentNode = _this._getUniqueId(subExperiment.experimentIdentifierOrNull); toSortSubExperiments[experimentNode.uniqueId] = experimentNode; if (subExperiment.experimentIdentifierOrNull) { var displayName = null; @@ -303,9 +302,8 @@ function SideMenuWidgetController(mainController) { //Fill Inventory - _this._sideMenuWidgetModel.menuStructure.newMenuIfSelected.children.push( - new SideMenuWidgetComponent(false, true, "INVENTORY", "INVENTORY", _this._sideMenuWidgetModel.menuStructure, null, null, null, "") - ); + var inventoryNode = new SideMenuWidgetComponent(true, true, "INVENTORY", "INVENTORY", _this._sideMenuWidgetModel.menuStructure, { children: [] }, null, null, ""); + _this._sideMenuWidgetModel.menuStructure.newMenuIfSelected.children.push(inventoryNode); //Fill Spaces var spaces = dataWithSpacesAndProjects.result; @@ -320,8 +318,8 @@ function SideMenuWidgetController(mainController) { var newMenuIfSelectedSpace = { children: [] }; - var menuItemSpace = new SideMenuWidgetComponent(true, false, space.code, space.code, _this._sideMenuWidgetModel.menuStructure, newMenuIfSelectedSpace, 'showSpacePage', space.code, "(Space)"); - _this._sideMenuWidgetModel.menuStructure.newMenuIfSelected.children.push(menuItemSpace); + var menuItemSpace = new SideMenuWidgetComponent(true, false, space.code, space.code, inventoryNode, newMenuIfSelectedSpace, 'showSpacePage', space.code, "(Space)"); + inventoryNode.newMenuIfSelected.children.push(menuItemSpace); //Fill Projects for (var j = 0; j < space.projects.length; j++) { @@ -349,7 +347,7 @@ function SideMenuWidgetController(mainController) { experimentsToAskForSamples.push(experiment); var projectIdentifierEnd = experiment.identifier.lastIndexOf("/"); var projectIdentifier = experiment.identifier.substring(0, projectIdentifierEnd); - var projectNode = _this._getProjectNodeForIdentifier(projectIdentifier); + var projectNode = _this._getUniqueId(projectIdentifier); var newMenuIfSelectedExperiment = { children: [] @@ -371,31 +369,30 @@ function SideMenuWidgetController(mainController) { //Fill Utils - _this._sideMenuWidgetModel.menuStructure.newMenuIfSelected.children.push( - new SideMenuWidgetComponent(false, true, "UTILITIES", "UTILITIES", _this._sideMenuWidgetModel.menuStructure, null, null, null, "") - ); -// _this._sideMenuWidgetModel.menuStructure.newMenuIfSelected.children.push( -// new SideMenuWidgetComponent(true, false, "DRAWING BOARD", "DRAWING_BOARD", _this._sideMenuWidgetModel.menuStructure, null, "showDrawingBoard", null, "") + var utilities = new SideMenuWidgetComponent(true, true, "UTILITIES", "UTILITIES", _this._sideMenuWidgetModel.menuStructure, { children : [] } , null, null, ""); + _this._sideMenuWidgetModel.menuStructure.newMenuIfSelected.children.push(utilities); +// utilities.newMenuIfSelected.children.push( +// new SideMenuWidgetComponent(true, false, "DRAWING BOARD", "DRAWING_BOARD", utilities, null, "showDrawingBoard", null, "") // ); - _this._sideMenuWidgetModel.menuStructure.newMenuIfSelected.children.push( - new SideMenuWidgetComponent(true, false, "SAMPLE BROWSER", "SAMPLE_BROWSER", _this._sideMenuWidgetModel.menuStructure, null, "showSamplesPage", null, "") + utilities.newMenuIfSelected.children.push( + new SideMenuWidgetComponent(true, false, "SAMPLE BROWSER", "SAMPLE_BROWSER", utilities, null, "showSamplesPage", null, "") ); if (profile.storagesConfiguration["isEnabled"]) { - _this._sideMenuWidgetModel.menuStructure.newMenuIfSelected.children.push( - new SideMenuWidgetComponent(true, false, "STORAGE MANAGER", "STORAGE_MANAGER", _this._sideMenuWidgetModel.menuStructure, null, "showStorageManager", null, "") + utilities.newMenuIfSelected.children.push( + new SideMenuWidgetComponent(true, false, "STORAGE MANAGER", "STORAGE_MANAGER", utilities, null, "showStorageManager", null, "") ); } - _this._sideMenuWidgetModel.menuStructure.newMenuIfSelected.children.push( - new SideMenuWidgetComponent(true, false, "TRASHCAN", "TRASHCAN", _this._sideMenuWidgetModel.menuStructure, null, "showTrashcanPage", null, "") + utilities.newMenuIfSelected.children.push( + new SideMenuWidgetComponent(true, false, "TRASHCAN", "TRASHCAN", utilities, null, "showTrashcanPage", null, "") ); - _this._sideMenuWidgetModel.menuStructure.newMenuIfSelected.children.push( - new SideMenuWidgetComponent(true, false, "VOCABULARY VIEWER", "VOCABULARY_VIEWER", _this._sideMenuWidgetModel.menuStructure, null, "showVocabularyManagerPage", null, "") + utilities.newMenuIfSelected.children.push( + new SideMenuWidgetComponent(true, false, "VOCABULARY VIEWER", "VOCABULARY_VIEWER", utilities, null, "showVocabularyManagerPage", null, "") ); mainController.serverFacade.listPersons(function(data) { if(data.result && data.result.length > 0) { - _this._sideMenuWidgetModel.menuStructure.newMenuIfSelected.children.push( - new SideMenuWidgetComponent(true, false, "USER MANAGER", "USER_MANAGER", _this._sideMenuWidgetModel.menuStructure, null, "showUserManagerPage", null, "") + utilities.newMenuIfSelected.children.push( + new SideMenuWidgetComponent(true, false, "USER MANAGER", "USER_MANAGER", utilities, null, "showUserManagerPage", null, "") ); } @@ -439,53 +436,7 @@ function SideMenuWidgetController(mainController) { $elementBody.css('max-height', (windowHeight - sideMenuHeaderHeight - 17) + "px"); }); }; - - // - // Utility Methods - // - this._getSpaceNodeForCode = function(spaceCode) { - for (var sIdx = 0; sIdx < this._sideMenuWidgetModel.menuStructure.newMenuIfSelected.children.length; sIdx++) { - var spaceNode = this._sideMenuWidgetModel.menuStructure.newMenuIfSelected.children[sIdx]; - if (spaceNode.isTitle && !spaceNode.isSelectable) { - continue; - } - if (spaceNode.uniqueId === spaceCode) { - return spaceNode; - } - } - return null; - }; - - this._getProjectNodeForIdentifier = function(projectIdentifier) { - for (var sIdx = 0; sIdx < this._sideMenuWidgetModel.menuStructure.newMenuIfSelected.children.length; sIdx++) { - var spaceNode = this._sideMenuWidgetModel.menuStructure.newMenuIfSelected.children[sIdx]; - if (spaceNode.isTitle && !spaceNode.isSelectable) { - continue; - } - var projectsFromSpace = spaceNode.newMenuIfSelected.children; - for (var pIdx = 0; pIdx < projectsFromSpace.length; pIdx++) { - var projectNode = projectsFromSpace[pIdx]; - if (projectNode.uniqueId === projectIdentifier) { - return projectNode; - } - } - } - return null; - }; - this._getExperimentNodeForIdentifier = function(experimentIdentifier) { - var projectIdentifierEnd = experimentIdentifier.lastIndexOf("/"); - var projectIdentifier = experimentIdentifier.substring(0, projectIdentifierEnd); - var projectNode = this._getProjectNodeForIdentifier(projectIdentifier); - var experimentsFromProject = projectNode.newMenuIfSelected.children; - for (var eIdx = 0; eIdx < experimentsFromProject.length; eIdx++) { - var experimentNode = experimentsFromProject[eIdx]; - if (experimentNode.uniqueId === experimentIdentifier) { - return experimentNode; - } - } - return null; - }; } function SideMenuWidgetComponent(isSelectable, isTitle, displayName, uniqueId, parent, newMenuIfSelected, newViewIfSelected, newViewIfSelectedData, contextTitle) { diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SideMenu/SideMenuWidgetView.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SideMenu/SideMenuWidgetView.js index 604ae7ef5e9..1bf393cbc7c 100644 --- a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SideMenu/SideMenuWidgetView.js +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SideMenu/SideMenuWidgetView.js @@ -205,8 +205,76 @@ function SideMenuWidgetView(sideMenuWidgetController, sideMenuWidgetModel) { this._sideMenuWidgetModel.menuDOMBody = $body; this.repaint(); }; - + this.repaint = function() { + this.treeMenu(); +// this.repaintSliderMenu(); + } + + this.treeMenu = function() { + var _this = this; + + this._sideMenuWidgetModel.menuDOMBody.empty(); + var tree = $("<div>", { "id" : "tree" }); + + // + // Body + // + var rootNode = { title : "Main Menu", key : "MAIN_MENU", menuData : this._sideMenuWidgetModel.menuStructure }; + var sourceByKey = { "MAIN_MENU" : rootNode }; + var treeModel = [rootNode]; + var todo = [this._sideMenuWidgetModel.menuStructure]; + + while(todo.length > 0) { + var modelNode = todo.shift(); + var treeModelNode = sourceByKey[modelNode.uniqueId]; + if(modelNode.newMenuIfSelected && modelNode.newMenuIfSelected.children.length !== 0) { + treeModelNode.folder = true; + if(!treeModelNode.children) { + treeModelNode.children = []; + } + + for(var cIdx = 0; cIdx < modelNode.newMenuIfSelected.children.length; cIdx++) { + var modelNodeChild = modelNode.newMenuIfSelected.children[cIdx]; + treeModelChild = {title : modelNodeChild.displayName, key : modelNodeChild.uniqueId, menuData : modelNodeChild}; + treeModelNode.children.push(treeModelChild); + todo.push(modelNodeChild); + sourceByKey[treeModelChild.key] = treeModelChild; + } + } + } + tree.fancytree({ + source: treeModel, + activate: function(event, data){ + var menuData = data.node.data.menuData; + data.node.setExpanded(true); + if(menuData.isSelectable) { + _this._sideMenuWidgetModel.pointerToMenuNode = menuData; + if(menuData.newViewIfSelected && menuData.newViewIfSelectedData) { + mainController.changeView(menuData.newViewIfSelected, menuData.newViewIfSelectedData); + } + } + } + }); + this._sideMenuWidgetModel.menuDOMBody.append(tree); + + //Expand Tree Node + var expandToParent = function(tree, menuData, isFirst) { + var node = tree.fancytree("getTree").getNodeByKey(menuData.uniqueId); + node.setExpanded(true); + if(isFirst) { + node.setActive(true); + } + if(menuData.parent) { + expandToParent(tree, menuData.parent, false); + } + } + + var menuToPaint = this._sideMenuWidgetModel.pointerToMenuNode; + expandToParent(tree, menuToPaint, true); + } + + this.repaintSliderMenu = function() { var _this = this; var menuToPaint = this._sideMenuWidgetModel.pointerToMenuNode; // @@ -219,7 +287,6 @@ function SideMenuWidgetView(sideMenuWidgetController, sideMenuWidgetModel) { var titleDisplayName = (menuToPaint.displayName); } // - this._sideMenuWidgetModel.menuDOMTitle.empty(); var isBackButtonShown = menuToPaint.parent !== null; if (isBackButtonShown) { diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/LICENSE.txt b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/LICENSE.txt new file mode 100644 index 00000000000..f8e92fe22e5 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/LICENSE.txt @@ -0,0 +1,9 @@ +Open Source - MIT License : https://github.com/mar10/fancytree/wiki/LicenseInfo + +artin@MBP edited this page on 17 Jan 2014 · 1 revision + +You may use Fancytree under the terms of the MIT License. + +The MIT License is simple and easy to understand and it places almost no restrictions on what you can do with Fancytree. + +You are free to use Fancytree in any other project (even commercial projects) as long as the copyright header is left intact. \ No newline at end of file diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/VERSION.txt b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/VERSION.txt new file mode 100644 index 00000000000..a3ebb9f516e --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/VERSION.txt @@ -0,0 +1 @@ +2.13.0 \ No newline at end of file diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/jquery.fancytree-all.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/jquery.fancytree-all.js new file mode 100644 index 00000000000..2ac1aa18426 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/jquery.fancytree-all.js @@ -0,0 +1,7678 @@ +/*! + * jquery.fancytree.js + * Tree view control with support for lazy loading and much more. + * https://github.com/mar10/fancytree/ + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +/** Core Fancytree module. + */ + + +// Start of local namespace +;(function($, window, document, undefined) { +"use strict"; + +// prevent duplicate loading +if ( $.ui && $.ui.fancytree ) { + $.ui.fancytree.warn("Fancytree: ignored duplicate include"); + return; +} + + +/* ***************************************************************************** + * Private functions and variables + */ + +function _assert(cond, msg){ + // TODO: see qunit.js extractStacktrace() + if(!cond){ + msg = msg ? ": " + msg : ""; + // consoleApply("assert", [!!cond, msg]); + $.error("Fancytree assertion failed" + msg); + } +} + +_assert($.ui, "Fancytree requires jQuery UI (http://jqueryui.com)"); + +function consoleApply(method, args){ + var i, s, + fn = window.console ? window.console[method] : null; + + if(fn){ + try{ + fn.apply(window.console, args); + } catch(e) { + // IE 8? + s = ""; + for( i=0; i<args.length; i++){ + s += args[i]; + } + fn(s); + } + } +} + +/*Return true if x is a FancytreeNode.*/ +function _isNode(x){ + return !!(x.tree && x.statusNodeType !== undefined); +} + +/** Return true if dotted version string is equal or higher than requested version. + * + * See http://jsfiddle.net/mar10/FjSAN/ + */ +function isVersionAtLeast(dottedVersion, major, minor, patch){ + var i, v, t, + verParts = $.map($.trim(dottedVersion).split("."), function(e){ return parseInt(e, 10); }), + testParts = $.map(Array.prototype.slice.call(arguments, 1), function(e){ return parseInt(e, 10); }); + + for( i = 0; i < testParts.length; i++ ){ + v = verParts[i] || 0; + t = testParts[i] || 0; + if( v !== t ){ + return ( v > t ); + } + } + return true; +} + +/** Return a wrapper that calls sub.methodName() and exposes + * this : tree + * this._local : tree.ext.EXTNAME + * this._super : base.methodName() + */ +function _makeVirtualFunction(methodName, tree, base, extension, extName){ + // $.ui.fancytree.debug("_makeVirtualFunction", methodName, tree, base, extension, extName); + // if(rexTestSuper && !rexTestSuper.test(func)){ + // // extension.methodName() doesn't call _super(), so no wrapper required + // return func; + // } + // Use an immediate function as closure + var proxy = (function(){ + var prevFunc = tree[methodName], // org. tree method or prev. proxy + baseFunc = extension[methodName], // + _local = tree.ext[extName], + _super = function(){ + return prevFunc.apply(tree, arguments); + }, + _superApply = function(args){ + return prevFunc.apply(tree, args); + }; + + // Return the wrapper function + return function(){ + var prevLocal = tree._local, + prevSuper = tree._super, + prevSuperApply = tree._superApply; + + try{ + tree._local = _local; + tree._super = _super; + tree._superApply = _superApply; + return baseFunc.apply(tree, arguments); + }finally{ + tree._local = prevLocal; + tree._super = prevSuper; + tree._superApply = prevSuperApply; + } + }; + })(); // end of Immediate Function + return proxy; +} + +/** + * Subclass `base` by creating proxy functions + */ +function _subclassObject(tree, base, extension, extName){ + // $.ui.fancytree.debug("_subclassObject", tree, base, extension, extName); + for(var attrName in extension){ + if(typeof extension[attrName] === "function"){ + if(typeof tree[attrName] === "function"){ + // override existing method + tree[attrName] = _makeVirtualFunction(attrName, tree, base, extension, extName); + }else if(attrName.charAt(0) === "_"){ + // Create private methods in tree.ext.EXTENSION namespace + tree.ext[extName][attrName] = _makeVirtualFunction(attrName, tree, base, extension, extName); + }else{ + $.error("Could not override tree." + attrName + ". Use prefix '_' to create tree." + extName + "._" + attrName); + } + }else{ + // Create member variables in tree.ext.EXTENSION namespace + if(attrName !== "options"){ + tree.ext[extName][attrName] = extension[attrName]; + } + } + } +} + + +function _getResolvedPromise(context, argArray){ + if(context === undefined){ + return $.Deferred(function(){this.resolve();}).promise(); + }else{ + return $.Deferred(function(){this.resolveWith(context, argArray);}).promise(); + } +} + + +function _getRejectedPromise(context, argArray){ + if(context === undefined){ + return $.Deferred(function(){this.reject();}).promise(); + }else{ + return $.Deferred(function(){this.rejectWith(context, argArray);}).promise(); + } +} + + +function _makeResolveFunc(deferred, context){ + return function(){ + deferred.resolveWith(context); + }; +} + + +function _getElementDataAsDict($el){ + // Evaluate 'data-NAME' attributes with special treatment for 'data-json'. + var d = $.extend({}, $el.data()), + json = d.json; + + delete d.fancytree; // added to container by widget factory (old jQuery UI) + delete d.uiFancytree; // added to container by widget factory + + if( json ) { + delete d.json; + // <li data-json='...'> is already returned as object (http://api.jquery.com/data/#data-html5) + d = $.extend(d, json); + } + return d; +} + + +// TODO: use currying +function _makeNodeTitleMatcher(s){ + s = s.toLowerCase(); + return function(node){ + return node.title.toLowerCase().indexOf(s) >= 0; + }; +} + + +function _makeNodeTitleStartMatcher(s){ + var reMatch = new RegExp("^" + s, "i"); + return function(node){ + return reMatch.test(node.title); + }; +} + +var i, attr, + FT = null, // initialized below + ENTITY_MAP = {"&": "&", "<": "<", ">": ">", "\"": """, "'": "'", "/": "/"}, + IGNORE_KEYCODES = { 16: true, 17: true, 18: true }, + SPECIAL_KEYCODES = { + 8: "backspace", 9: "tab", 10: "return", 13: "return", + // 16: null, 17: null, 18: null, // ignore shift, ctrl, alt + 19: "pause", 20: "capslock", 27: "esc", 32: "space", 33: "pageup", + 34: "pagedown", 35: "end", 36: "home", 37: "left", 38: "up", + 39: "right", 40: "down", 45: "insert", 46: "del", 59: ";", 61: "=", + 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", + 103: "7", 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", + 111: "/", 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: "scroll", 173: "-", 186: ";", 187: "=", + 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", + 221: "]", 222: "'"}, + MOUSE_BUTTONS = { 0: "", 1: "left", 2: "middle", 3: "right" }, + //boolean attributes that can be set with equivalent class names in the LI tags + CLASS_ATTRS = "active expanded focus folder hideCheckbox lazy selected unselectable".split(" "), + CLASS_ATTR_MAP = {}, + // Top-level Fancytree node attributes, that can be set by dict + NODE_ATTRS = "expanded extraClasses folder hideCheckbox key lazy refKey selected title tooltip unselectable".split(" "), + NODE_ATTR_MAP = {}, + // Mapping of lowercase -> real name (because HTML5 data-... attribute only supports lowercase) + NODE_ATTR_LOWERCASE_MAP = {}, + // Attribute names that should NOT be added to node.data + NONE_NODE_DATA_MAP = {"active": true, "children": true, "data": true, "focus": true}; + +for(i=0; i<CLASS_ATTRS.length; i++){ CLASS_ATTR_MAP[CLASS_ATTRS[i]] = true; } +for(i=0; i<NODE_ATTRS.length; i++) { + attr = NODE_ATTRS[i]; + NODE_ATTR_MAP[attr] = true; + if( attr !== attr.toLowerCase() ) { + NODE_ATTR_LOWERCASE_MAP[attr.toLowerCase()] = attr; + } +} + + +/* ***************************************************************************** + * FancytreeNode + */ + + +/** + * Creates a new FancytreeNode + * + * @class FancytreeNode + * @classdesc A FancytreeNode represents the hierarchical data model and operations. + * + * @param {FancytreeNode} parent + * @param {NodeData} obj + * + * @property {Fancytree} tree The tree instance + * @property {FancytreeNode} parent The parent node + * @property {string} key Node id (must be unique inside the tree) + * @property {string} title Display name (may contain HTML) + * @property {object} data Contains all extra data that was passed on node creation + * @property {FancytreeNode[] | null | undefined} children Array of child nodes.<br> + * For lazy nodes, null or undefined means 'not yet loaded'. Use an empty array + * to define a node that has no children. + * @property {boolean} expanded Use isExpanded(), setExpanded() to access this property. + * @property {string} extraClasses Addtional CSS classes, added to the node's `<span>` + * @property {boolean} folder Folder nodes have different default icons and click behavior.<br> + * Note: Also non-folders may have children. + * @property {string} statusNodeType null or type of temporarily generated system node like 'loading', or 'error'. + * @property {boolean} lazy True if this node is loaded on demand, i.e. on first expansion. + * @property {boolean} selected Use isSelected(), setSelected() to access this property. + * @property {string} tooltip Alternative description used as hover banner + */ +function FancytreeNode(parent, obj){ + var i, l, name, cl; + + this.parent = parent; + this.tree = parent.tree; + this.ul = null; + this.li = null; // <li id='key' ftnode=this> tag + this.statusNodeType = null; // if this is a temp. node to display the status of its parent + this._isLoading = false; // if this node itself is loading + this._error = null; // {message: '...'} if a load error occurred + this.data = {}; + + // TODO: merge this code with node.toDict() + // copy attributes from obj object + for(i=0, l=NODE_ATTRS.length; i<l; i++){ + name = NODE_ATTRS[i]; + this[name] = obj[name]; + } + // node.data += obj.data + if(obj.data){ + $.extend(this.data, obj.data); + } + // copy all other attributes to this.data.NAME + for(name in obj){ + if(!NODE_ATTR_MAP[name] && !$.isFunction(obj[name]) && !NONE_NODE_DATA_MAP[name]){ + // node.data.NAME = obj.NAME + this.data[name] = obj[name]; + } + } + + // Fix missing key + if( this.key == null ){ // test for null OR undefined + if( this.tree.options.defaultKey ) { + this.key = this.tree.options.defaultKey(this); + _assert(this.key, "defaultKey() must return a unique key"); + } else { + this.key = "_" + (FT._nextNodeKey++); + } + } else { + this.key = "" + this.key; // Convert to string (#217) + } + + // Fix tree.activeNode + // TODO: not elegant: we use obj.active as marker to set tree.activeNode + // when loading from a dictionary. + if(obj.active){ + _assert(this.tree.activeNode === null, "only one active node allowed"); + this.tree.activeNode = this; + } + if( obj.selected ){ // #186 + this.tree.lastSelectedNode = this; + } + // TODO: handle obj.focus = true + // Create child nodes + cl = obj.children; + if( cl ){ + if( cl.length ){ + this._setChildren(cl); + } else { + // if an empty array was passed for a lazy node, keep it, in order to mark it 'loaded' + this.children = this.lazy ? [] : null; + } + } else { + this.children = null; + } + // Add to key/ref map (except for root node) +// if( parent ) { + this.tree._callHook("treeRegisterNode", this.tree, true, this); +// } +} + + +FancytreeNode.prototype = /** @lends FancytreeNode# */{ + /* Return the direct child FancytreeNode with a given key, index. */ + _findDirectChild: function(ptr){ + var i, l, + cl = this.children; + + if(cl){ + if(typeof ptr === "string"){ + for(i=0, l=cl.length; i<l; i++){ + if(cl[i].key === ptr){ + return cl[i]; + } + } + }else if(typeof ptr === "number"){ + return this.children[ptr]; + }else if(ptr.parent === this){ + return ptr; + } + } + return null; + }, + // TODO: activate() + // TODO: activateSilently() + /* Internal helper called in recursive addChildren sequence.*/ + _setChildren: function(children){ + _assert(children && (!this.children || this.children.length === 0), "only init supported"); + this.children = []; + for(var i=0, l=children.length; i<l; i++){ + this.children.push(new FancytreeNode(this, children[i])); + } + }, + /** + * Append (or insert) a list of child nodes. + * + * @param {NodeData[]} children array of child node definitions (also single child accepted) + * @param {FancytreeNode | string | Integer} [insertBefore] child node (or key or index of such). + * If omitted, the new children are appended. + * @returns {FancytreeNode} first child added + * + * @see FancytreeNode#applyPatch + */ + addChildren: function(children, insertBefore){ + var i, l, pos, + firstNode = null, + nodeList = []; + + if($.isPlainObject(children) ){ + children = [children]; + } + if(!this.children){ + this.children = []; + } + for(i=0, l=children.length; i<l; i++){ + nodeList.push(new FancytreeNode(this, children[i])); + } + firstNode = nodeList[0]; + if(insertBefore == null){ + this.children = this.children.concat(nodeList); + }else{ + insertBefore = this._findDirectChild(insertBefore); + pos = $.inArray(insertBefore, this.children); + _assert(pos >= 0, "insertBefore must be an existing child"); + // insert nodeList after children[pos] + this.children.splice.apply(this.children, [pos, 0].concat(nodeList)); + } + if( !this.parent || this.parent.ul || this.tr ){ + // render if the parent was rendered (or this is a root node) + this.render(); + } + if( this.tree.options.selectMode === 3 ){ + this.fixSelection3FromEndNodes(); + } + return firstNode; + }, + /** + * Append or prepend a node, or append a child node. + * + * This a convenience function that calls addChildren() + * + * @param {NodeData} node node definition + * @param {string} [mode=child] 'before', 'after', 'firstChild', or 'child' ('over' is a synonym for 'child') + * @returns {FancytreeNode} new node + */ + addNode: function(node, mode){ + if(mode === undefined || mode === "over"){ + mode = "child"; + } + switch(mode){ + case "after": + return this.getParent().addChildren(node, this.getNextSibling()); + case "before": + return this.getParent().addChildren(node, this); + case "firstChild": + // Insert before the first child if any + var insertBefore = (this.children ? this.children[0] : null); + return this.addChildren(node, insertBefore); + case "child": + case "over": + return this.addChildren(node); + } + _assert(false, "Invalid mode: " + mode); + }, + /** + * Append new node after this. + * + * This a convenience function that calls addNode(node, 'after') + * + * @param {NodeData} node node definition + * @returns {FancytreeNode} new node + */ + appendSibling: function(node){ + return this.addNode(node, "after"); + }, + /** + * Modify existing child nodes. + * + * @param {NodePatch} patch + * @returns {$.Promise} + * @see FancytreeNode#addChildren + */ + applyPatch: function(patch) { + // patch [key, null] means 'remove' + if(patch === null){ + this.remove(); + return _getResolvedPromise(this); + } + // TODO: make sure that root node is not collapsed or modified + // copy (most) attributes to node.ATTR or node.data.ATTR + var name, promise, v, + IGNORE_MAP = { children: true, expanded: true, parent: true }; // TODO: should be global + + for(name in patch){ + v = patch[name]; + if( !IGNORE_MAP[name] && !$.isFunction(v)){ + if(NODE_ATTR_MAP[name]){ + this[name] = v; + }else{ + this.data[name] = v; + } + } + } + // Remove and/or create children + if(patch.hasOwnProperty("children")){ + this.removeChildren(); + if(patch.children){ // only if not null and not empty list + // TODO: addChildren instead? + this._setChildren(patch.children); + } + // TODO: how can we APPEND or INSERT child nodes? + } + if(this.isVisible()){ + this.renderTitle(); + this.renderStatus(); + } + // Expand collapse (final step, since this may be async) + if(patch.hasOwnProperty("expanded")){ + promise = this.setExpanded(patch.expanded); + }else{ + promise = _getResolvedPromise(this); + } + return promise; + }, + /** Collapse all sibling nodes. + * @returns {$.Promise} + */ + collapseSiblings: function() { + return this.tree._callHook("nodeCollapseSiblings", this); + }, + /** Copy this node as sibling or child of `node`. + * + * @param {FancytreeNode} node source node + * @param {string} [mode=child] 'before' | 'after' | 'child' + * @param {Function} [map] callback function(NodeData) that could modify the new node + * @returns {FancytreeNode} new + */ + copyTo: function(node, mode, map) { + return node.addNode(this.toDict(true, map), mode); + }, + /** Count direct and indirect children. + * + * @param {boolean} [deep=true] pass 'false' to only count direct children + * @returns {int} number of child nodes + */ + countChildren: function(deep) { + var cl = this.children, i, l, n; + if( !cl ){ + return 0; + } + n = cl.length; + if(deep !== false){ + for(i=0, l=n; i<l; i++){ + n += cl[i].countChildren(); + } + } + return n; + }, + // TODO: deactivate() + /** Write to browser console if debugLevel >= 2 (prepending node info) + * + * @param {*} msg string or object or array of such + */ + debug: function(msg){ + if( this.tree.options.debugLevel >= 2 ) { + Array.prototype.unshift.call(arguments, this.toString()); + consoleApply("log", arguments); + } + }, + /** Deprecated. + * @deprecated since 2014-02-16. Use resetLazy() instead. + */ + discard: function(){ + this.warn("FancytreeNode.discard() is deprecated since 2014-02-16. Use .resetLazy() instead."); + return this.resetLazy(); + }, + + // TODO: expand(flag) + + /**Find all nodes that match condition (excluding self). + * + * @param {string | function(node)} match title string to search for, or a + * callback function that returns `true` if a node is matched. + * @returns {FancytreeNode[]} array of nodes (may be empty) + */ + findAll: function(match) { + match = $.isFunction(match) ? match : _makeNodeTitleMatcher(match); + var res = []; + this.visit(function(n){ + if(match(n)){ + res.push(n); + } + }); + return res; + }, + /**Find first node that matches condition (excluding self). + * + * @param {string | function(node)} match title string to search for, or a + * callback function that returns `true` if a node is matched. + * @returns {FancytreeNode} matching node or null + * @see FancytreeNode#findAll + */ + findFirst: function(match) { + match = $.isFunction(match) ? match : _makeNodeTitleMatcher(match); + var res = null; + this.visit(function(n){ + if(match(n)){ + res = n; + return false; + } + }); + return res; + }, + /* Apply selection state (internal use only) */ + _changeSelectStatusAttrs: function (state) { + var changed = false; + + switch(state){ + case false: + changed = ( this.selected || this.partsel ); + this.selected = false; + this.partsel = false; + break; + case true: + changed = ( !this.selected || !this.partsel ); + this.selected = true; + this.partsel = true; + break; + case undefined: + changed = ( this.selected || !this.partsel ); + this.selected = false; + this.partsel = true; + break; + default: + _assert(false, "invalid state: " + state); + } + // this.debug("fixSelection3AfterLoad() _changeSelectStatusAttrs()", state, changed); + if( changed ){ + this.renderStatus(); + } + return changed; + }, + /** + * Fix selection status, after this node was (de)selected in multi-hier mode. + * This includes (de)selecting all children. + */ + fixSelection3AfterClick: function() { + var flag = this.isSelected(); + +// this.debug("fixSelection3AfterClick()"); + + this.visit(function(node){ + node._changeSelectStatusAttrs(flag); + }); + this.fixSelection3FromEndNodes(); + }, + /** + * Fix selection status for multi-hier mode. + * Only end-nodes are considered to update the descendants branch and parents. + * Should be called after this node has loaded new children or after + * children have been modified using the API. + */ + fixSelection3FromEndNodes: function() { +// this.debug("fixSelection3FromEndNodes()"); + _assert(this.tree.options.selectMode === 3, "expected selectMode 3"); + + // Visit all end nodes and adjust their parent's `selected` and `partsel` + // attributes. Return selection state true, false, or undefined. + function _walk(node){ + var i, l, child, s, state, allSelected,someSelected, + children = node.children; + + if( children && children.length ){ + // check all children recursively + allSelected = true; + someSelected = false; + + for( i=0, l=children.length; i<l; i++ ){ + child = children[i]; + // the selection state of a node is not relevant; we need the end-nodes + s = _walk(child); + if( s !== false ) { + someSelected = true; + } + if( s !== true ) { + allSelected = false; + } + } + state = allSelected ? true : (someSelected ? undefined : false); + }else{ + // This is an end-node: simply report the status +// state = ( node.unselectable ) ? undefined : !!node.selected; + state = !!node.selected; + } + node._changeSelectStatusAttrs(state); + return state; + } + _walk(this); + + // Update parent's state + this.visitParents(function(node){ + var i, l, child, state, + children = node.children, + allSelected = true, + someSelected = false; + + for( i=0, l=children.length; i<l; i++ ){ + child = children[i]; + // When fixing the parents, we trust the sibling status (i.e. + // we don't recurse) + if( child.selected || child.partsel ) { + someSelected = true; + } + if( !child.unselectable && !child.selected ) { + allSelected = false; + } + } + state = allSelected ? true : (someSelected ? undefined : false); + node._changeSelectStatusAttrs(state); + }); + }, + // TODO: focus() + /** + * Update node data. If dict contains 'children', then also replace + * the hole sub tree. + * @param {NodeData} dict + * + * @see FancytreeNode#addChildren + * @see FancytreeNode#applyPatch + */ + fromDict: function(dict) { + // copy all other attributes to this.data.xxx + for(var name in dict){ + if(NODE_ATTR_MAP[name]){ + // node.NAME = dict.NAME + this[name] = dict[name]; + }else if(name === "data"){ + // node.data += dict.data + $.extend(this.data, dict.data); + }else if(!$.isFunction(dict[name]) && !NONE_NODE_DATA_MAP[name]){ + // node.data.NAME = dict.NAME + this.data[name] = dict[name]; + } + } + if(dict.children){ + // recursively set children and render + this.removeChildren(); + this.addChildren(dict.children); + } + this.renderTitle(); +/* + var children = dict.children; + if(children === undefined){ + this.data = $.extend(this.data, dict); + this.render(); + return; + } + dict = $.extend({}, dict); + dict.children = undefined; + this.data = $.extend(this.data, dict); + this.removeChildren(); + this.addChild(children); +*/ + }, + /** Return the list of child nodes (undefined for unexpanded lazy nodes). + * @returns {FancytreeNode[] | undefined} + */ + getChildren: function() { + if(this.hasChildren() === undefined){ // TODO: only required for lazy nodes? + return undefined; // Lazy node: unloaded, currently loading, or load error + } + return this.children; + }, + /** Return the first child node or null. + * @returns {FancytreeNode | null} + */ + getFirstChild: function() { + return this.children ? this.children[0] : null; + }, + /** Return the 0-based child index. + * @returns {int} + */ + getIndex: function() { +// return this.parent.children.indexOf(this); + return $.inArray(this, this.parent.children); // indexOf doesn't work in IE7 + }, + /** Return the hierarchical child index (1-based, e.g. '3.2.4'). + * @returns {string} + */ + getIndexHier: function(separator) { + separator = separator || "."; + var res = []; + $.each(this.getParentList(false, true), function(i, o){ + res.push(o.getIndex() + 1); + }); + return res.join(separator); + }, + /** Return the parent keys separated by options.keyPathSeparator, e.g. "id_1/id_17/id_32". + * @param {boolean} [excludeSelf=false] + * @returns {string} + */ + getKeyPath: function(excludeSelf) { + var path = [], + sep = this.tree.options.keyPathSeparator; + this.visitParents(function(n){ + if(n.parent){ + path.unshift(n.key); + } + }, !excludeSelf); + return sep + path.join(sep); + }, + /** Return the last child of this node or null. + * @returns {FancytreeNode | null} + */ + getLastChild: function() { + return this.children ? this.children[this.children.length - 1] : null; + }, + /** Return node depth. 0: System root node, 1: visible top-level node, 2: first sub-level, ... . + * @returns {int} + */ + getLevel: function() { + var level = 0, + dtn = this.parent; + while( dtn ) { + level++; + dtn = dtn.parent; + } + return level; + }, + /** Return the successor node (under the same parent) or null. + * @returns {FancytreeNode | null} + */ + getNextSibling: function() { + // TODO: use indexOf, if available: (not in IE6) + if( this.parent ){ + var i, l, + ac = this.parent.children; + + for(i=0, l=ac.length-1; i<l; i++){ // up to length-2, so next(last) = null + if( ac[i] === this ){ + return ac[i+1]; + } + } + } + return null; + }, + /** Return the parent node (null for the system root node). + * @returns {FancytreeNode | null} + */ + getParent: function() { + // TODO: return null for top-level nodes? + return this.parent; + }, + /** Return an array of all parent nodes (top-down). + * @param {boolean} [includeRoot=false] Include the invisible system root node. + * @param {boolean} [includeSelf=false] Include the node itself. + * @returns {FancytreeNode[]} + */ + getParentList: function(includeRoot, includeSelf) { + var l = [], + dtn = includeSelf ? this : this.parent; + while( dtn ) { + if( includeRoot || dtn.parent ){ + l.unshift(dtn); + } + dtn = dtn.parent; + } + return l; + }, + /** Return the predecessor node (under the same parent) or null. + * @returns {FancytreeNode | null} + */ + getPrevSibling: function() { + if( this.parent ){ + var i, l, + ac = this.parent.children; + + for(i=1, l=ac.length; i<l; i++){ // start with 1, so prev(first) = null + if( ac[i] === this ){ + return ac[i-1]; + } + } + } + return null; + }, + /** Return true if node has children. Return undefined if not sure, i.e. the node is lazy and not yet loaded). + * @returns {boolean | undefined} + */ + hasChildren: function() { + if(this.lazy){ + if(this.children == null ){ + // null or undefined: Not yet loaded + return undefined; + }else if(this.children.length === 0){ + // Loaded, but response was empty + return false; + }else if(this.children.length === 1 && this.children[0].isStatusNode() ){ + // Currently loading or load error + return undefined; + } + return true; + } + return !!( this.children && this.children.length ); + }, + /** Return true if node has keyboard focus. + * @returns {boolean} + */ + hasFocus: function() { + return (this.tree.hasFocus() && this.tree.focusNode === this); + }, + /** Write to browser console if debugLevel >= 1 (prepending node info) + * + * @param {*} msg string or object or array of such + */ + info: function(msg){ + if( this.tree.options.debugLevel >= 1 ) { + Array.prototype.unshift.call(arguments, this.toString()); + consoleApply("info", arguments); + } + }, + /** Return true if node is active (see also FancytreeNode#isSelected). + * @returns {boolean} + */ + isActive: function() { + return (this.tree.activeNode === this); + }, + /** Return true if node is a direct child of otherNode. + * @param {FancytreeNode} otherNode + * @returns {boolean} + */ + isChildOf: function(otherNode) { + return (this.parent && this.parent === otherNode); + }, + /** Return true, if node is a direct or indirect sub node of otherNode. + * @param {FancytreeNode} otherNode + * @returns {boolean} + */ + isDescendantOf: function(otherNode) { + if(!otherNode || otherNode.tree !== this.tree){ + return false; + } + var p = this.parent; + while( p ) { + if( p === otherNode ){ + return true; + } + p = p.parent; + } + return false; + }, + /** Return true if node is expanded. + * @returns {boolean} + */ + isExpanded: function() { + return !!this.expanded; + }, + /** Return true if node is the first node of its parent's children. + * @returns {boolean} + */ + isFirstSibling: function() { + var p = this.parent; + return !p || p.children[0] === this; + }, + /** Return true if node is a folder, i.e. has the node.folder attribute set. + * @returns {boolean} + */ + isFolder: function() { + return !!this.folder; + }, + /** Return true if node is the last node of its parent's children. + * @returns {boolean} + */ + isLastSibling: function() { + var p = this.parent; + return !p || p.children[p.children.length-1] === this; + }, + /** Return true if node is lazy (even if data was already loaded) + * @returns {boolean} + */ + isLazy: function() { + return !!this.lazy; + }, + /** Return true if node is lazy and loaded. For non-lazy nodes always return true. + * @returns {boolean} + */ + isLoaded: function() { + return !this.lazy || this.hasChildren() !== undefined; // Also checks if the only child is a status node + }, + /** Return true if children are currently beeing loaded, i.e. a Ajax request is pending. + * @returns {boolean} + */ + isLoading: function() { + return !!this._isLoading; + }, + /* + * @deprecated since v2.4.0: Use isRootNode() instead + */ + isRoot: function() { + return this.isRootNode(); + }, + /** Return true if this is the (invisible) system root node. + * @returns {boolean} + * @since 2.4 + */ + isRootNode: function() { + return (this.tree.rootNode === this); + }, + /** Return true if node is selected, i.e. has a checkmark set (see also FancytreeNode#isActive). + * @returns {boolean} + */ + isSelected: function() { + return !!this.selected; + }, + /** Return true if this node is a temporarily generated system node like + * 'loading', or 'error' (node.statusNodeType contains the type). + * @returns {boolean} + */ + isStatusNode: function() { + return !!this.statusNodeType; + }, + /** Return true if this a top level node, i.e. a direct child of the (invisible) system root node. + * @returns {boolean} + * @since 2.4 + */ + isTopLevel: function() { + return (this.tree.rootNode === this.parent); + }, + /** Return true if node is lazy and not yet loaded. For non-lazy nodes always return false. + * @returns {boolean} + */ + isUndefined: function() { + return this.hasChildren() === undefined; // also checks if the only child is a status node + }, + /** Return true if all parent nodes are expanded. Note: this does not check + * whether the node is scrolled into the visible part of the screen. + * @returns {boolean} + */ + isVisible: function() { + var i, l, + parents = this.getParentList(false, false); + + for(i=0, l=parents.length; i<l; i++){ + if( ! parents[i].expanded ){ return false; } + } + return true; + }, + /** Deprecated. + * @deprecated since 2014-02-16: use load() instead. + */ + lazyLoad: function(discard) { + this.warn("FancytreeNode.lazyLoad() is deprecated since 2014-02-16. Use .load() instead."); + return this.load(discard); + }, + /** + * Load all children of a lazy node if neccessary. The *expanded* state is maintained. + * @param {boolean} [forceReload=false] Pass true to discard any existing nodes before. + * @returns {$.Promise} + */ + load: function(forceReload) { + var res, source, + that = this; + + _assert( this.isLazy(), "load() requires a lazy node" ); + // _assert( forceReload || this.isUndefined(), "Pass forceReload=true to re-load a lazy node" ); + if( !forceReload && !this.isUndefined() ) { + return _getResolvedPromise(this); + } + if( this.isLoaded() ){ + this.resetLazy(); // also collapses + } + // This method is also called by setExpanded() and loadKeyPath(), so we + // have to avoid recursion. + source = this.tree._triggerNodeEvent("lazyLoad", this); + if( source === false ) { // #69 + return _getResolvedPromise(this); + } + _assert(typeof source !== "boolean", "lazyLoad event must return source in data.result"); + res = this.tree._callHook("nodeLoadChildren", this, source); + if( this.expanded ) { + res.always(function(){ + that.render(); + }); + } + return res; + }, + /** Expand all parents and optionally scroll into visible area as neccessary. + * Promise is resolved, when lazy loading and animations are done. + * @param {object} [opts] passed to `setExpanded()`. + * Defaults to {noAnimation: false, noEvents: false, scrollIntoView: true} + * @returns {$.Promise} + */ + makeVisible: function(opts) { + var i, + that = this, + deferreds = [], + dfd = new $.Deferred(), + parents = this.getParentList(false, false), + len = parents.length, + effects = !(opts && opts.noAnimation === true), + scroll = !(opts && opts.scrollIntoView === false); + + // Expand bottom-up, so only the top node is animated + for(i = len - 1; i >= 0; i--){ + // that.debug("pushexpand" + parents[i]); + deferreds.push(parents[i].setExpanded(true, opts)); + } + $.when.apply($, deferreds).done(function(){ + // All expands have finished + // that.debug("expand DONE", scroll); + if( scroll ){ + that.scrollIntoView(effects).done(function(){ + // that.debug("scroll DONE"); + dfd.resolve(); + }); + } else { + dfd.resolve(); + } + }); + return dfd.promise(); + }, + /** Move this node to targetNode. + * @param {FancytreeNode} targetNode + * @param {string} mode <pre> + * 'child': append this node as last child of targetNode. + * This is the default. To be compatble with the D'n'd + * hitMode, we also accept 'over'. + * 'before': add this node as sibling before targetNode. + * 'after': add this node as sibling after targetNode.</pre> + * @param {function} [map] optional callback(FancytreeNode) to allow modifcations + */ + moveTo: function(targetNode, mode, map) { + if(mode === undefined || mode === "over"){ + mode = "child"; + } + var pos, + prevParent = this.parent, + targetParent = (mode === "child") ? targetNode : targetNode.parent; + + if(this === targetNode){ + return; + }else if( !this.parent ){ + throw "Cannot move system root"; + }else if( targetParent.isDescendantOf(this) ){ + throw "Cannot move a node to its own descendant"; + } + // Unlink this node from current parent + if( this.parent.children.length === 1 ) { + if( this.parent === targetParent ){ + return; // #258 + } + this.parent.children = this.parent.lazy ? [] : null; + this.parent.expanded = false; + } else { + pos = $.inArray(this, this.parent.children); + _assert(pos >= 0, "invalid source parent"); + this.parent.children.splice(pos, 1); + } + // Remove from source DOM parent +// if(this.parent.ul){ +// this.parent.ul.removeChild(this.li); +// } + + // Insert this node to target parent's child list + this.parent = targetParent; + if( targetParent.hasChildren() ) { + switch(mode) { + case "child": + // Append to existing target children + targetParent.children.push(this); + break; + case "before": + // Insert this node before target node + pos = $.inArray(targetNode, targetParent.children); + _assert(pos >= 0, "invalid target parent"); + targetParent.children.splice(pos, 0, this); + break; + case "after": + // Insert this node after target node + pos = $.inArray(targetNode, targetParent.children); + _assert(pos >= 0, "invalid target parent"); + targetParent.children.splice(pos+1, 0, this); + break; + default: + throw "Invalid mode " + mode; + } + } else { + targetParent.children = [ this ]; + } + // Parent has no <ul> tag yet: +// if( !targetParent.ul ) { +// // This is the parent's first child: create UL tag +// // (Hidden, because it will be +// targetParent.ul = document.createElement("ul"); +// targetParent.ul.style.display = "none"; +// targetParent.li.appendChild(targetParent.ul); +// } +// // Issue 319: Add to target DOM parent (only if node was already rendered(expanded)) +// if(this.li){ +// targetParent.ul.appendChild(this.li); +// }^ + + // Let caller modify the nodes + if( map ){ + targetNode.visit(map, true); + } + // Handle cross-tree moves + if( this.tree !== targetNode.tree ) { + // Fix node.tree for all source nodes +// _assert(false, "Cross-tree move is not yet implemented."); + this.warn("Cross-tree moveTo is experimantal!"); + this.visit(function(n){ + // TODO: fix selection state and activation, ... + n.tree = targetNode.tree; + }, true); + } + + // A collaposed node won't re-render children, so we have to remove it manually + // if( !targetParent.expanded ){ + // prevParent.ul.removeChild(this.li); + // } + + // Update HTML markup + if( !prevParent.isDescendantOf(targetParent)) { + prevParent.render(); + } + if( !targetParent.isDescendantOf(prevParent) && targetParent !== prevParent) { + targetParent.render(); + } + // TODO: fix selection state + // TODO: fix active state + +/* + var tree = this.tree; + var opts = tree.options; + var pers = tree.persistence; + + + // Always expand, if it's below minExpandLevel +// tree.logDebug ("%s._addChildNode(%o), l=%o", this, ftnode, ftnode.getLevel()); + if ( opts.minExpandLevel >= ftnode.getLevel() ) { +// tree.logDebug ("Force expand for %o", ftnode); + this.bExpanded = true; + } + + // In multi-hier mode, update the parents selection state + // DT issue #82: only if not initializing, because the children may not exist yet +// if( !ftnode.data.isStatusNode() && opts.selectMode==3 && !isInitializing ) +// ftnode._fixSelectionState(); + + // In multi-hier mode, update the parents selection state + if( ftnode.bSelected && opts.selectMode==3 ) { + var p = this; + while( p ) { + if( !p.hasSubSel ) + p._setSubSel(true); + p = p.parent; + } + } + // render this node and the new child + if ( tree.bEnableUpdate ) + this.render(); + + return ftnode; + +*/ + }, + /** Set focus relative to this node and optionally activate. + * + * @param {number} where The keyCode that would normally trigger this move, + * e.g. `$.ui.keyCode.LEFT` would collapse the node if it + * is expanded or move to the parent oterwise. + * @param {boolean} [activate=true] + * @returns {$.Promise} + */ + // navigate: function(where, activate) { + // console.time("navigate") + // this._navigate(where, activate) + // console.timeEnd("navigate") + // }, + navigate: function(where, activate) { + var i, parents, + handled = true, + KC = $.ui.keyCode, + sib = null; + + // Navigate to node + function _goto(n){ + if( n ){ + try { n.makeVisible(); } catch(e) {} // #272 + // Node may still be hidden by a filter + if( ! $(n.span).is(":visible") ) { + n.debug("Navigate: skipping hidden node"); + n.navigate(where, activate); + return; + } + return activate === false ? n.setFocus() : n.setActive(); + } + } + + switch( where ) { + case KC.BACKSPACE: + if( this.parent && this.parent.parent ) { + _goto(this.parent); + } + break; + case KC.LEFT: + if( this.expanded ) { + this.setExpanded(false); + _goto(this); + } else if( this.parent && this.parent.parent ) { + _goto(this.parent); + } + break; + case KC.RIGHT: + if( !this.expanded && (this.children || this.lazy) ) { + this.setExpanded(); + _goto(this); + } else if( this.children && this.children.length ) { + _goto(this.children[0]); + } + break; + case KC.UP: + sib = this.getPrevSibling(); + // #359: skip hidden sibling nodes, preventing a _goto() recursion + while( sib && !$(sib.span).is(":visible") ) { + sib = sib.getPrevSibling(); + } + while( sib && sib.expanded && sib.children && sib.children.length ) { + sib = sib.children[sib.children.length - 1]; + } + if( !sib && this.parent && this.parent.parent ){ + sib = this.parent; + } + _goto(sib); + break; + case KC.DOWN: + if( this.expanded && this.children && this.children.length ) { + sib = this.children[0]; + } else { + parents = this.getParentList(false, true); + for(i=parents.length-1; i>=0; i--) { + sib = parents[i].getNextSibling(); + // #359: skip hidden sibling nodes, preventing a _goto() recursion + while( sib && !$(sib.span).is(":visible") ) { + sib = sib.getNextSibling(); + } + if( sib ){ break; } + } + } + _goto(sib); + break; + default: + handled = false; + } + }, + /** + * Remove this node (not allowed for system root). + */ + remove: function() { + return this.parent.removeChild(this); + }, + /** + * Remove childNode from list of direct children. + * @param {FancytreeNode} childNode + */ + removeChild: function(childNode) { + return this.tree._callHook("nodeRemoveChild", this, childNode); + }, + /** + * Remove all child nodes and descendents. This converts the node into a leaf.<br> + * If this was a lazy node, it is still considered 'loaded'; call node.resetLazy() + * in order to trigger lazyLoad on next expand. + */ + removeChildren: function() { + return this.tree._callHook("nodeRemoveChildren", this); + }, + /** + * This method renders and updates all HTML markup that is required + * to display this node in its current state.<br> + * Note: + * <ul> + * <li>It should only be neccessary to call this method after the node object + * was modified by direct access to its properties, because the common + * API methods (node.setTitle(), moveTo(), addChildren(), remove(), ...) + * already handle this. + * <li> {@link FancytreeNode#renderTitle} and {@link FancytreeNode#renderStatus} + * are implied. If changes are more local, calling only renderTitle() or + * renderStatus() may be sufficient and faster. + * <li>If a node was created/removed, node.render() must be called <i>on the parent</i>. + * </ul> + * + * @param {boolean} [force=false] re-render, even if html markup was already created + * @param {boolean} [deep=false] also render all descendants, even if parent is collapsed + */ + render: function(force, deep) { + return this.tree._callHook("nodeRender", this, force, deep); + }, + /** Create HTML markup for the node's outer <span> (expander, checkbox, icon, and title). + * Implies {@link FancytreeNode#renderStatus}. + * @see Fancytree_Hooks#nodeRenderTitle + */ + renderTitle: function() { + return this.tree._callHook("nodeRenderTitle", this); + }, + /** Update element's CSS classes according to node state. + * @see Fancytree_Hooks#nodeRenderStatus + */ + renderStatus: function() { + return this.tree._callHook("nodeRenderStatus", this); + }, + /** + * Remove all children, collapse, and set the lazy-flag, so that the lazyLoad + * event is triggered on next expand. + */ + resetLazy: function() { + this.removeChildren(); + this.expanded = false; + this.lazy = true; + this.children = undefined; + this.renderStatus(); + }, + /** Schedule activity for delayed execution (cancel any pending request). + * scheduleAction('cancel') will only cancel a pending request (if any). + * @param {string} mode + * @param {number} ms + */ + scheduleAction: function(mode, ms) { + if( this.tree.timer ) { + clearTimeout(this.tree.timer); +// this.tree.debug("clearTimeout(%o)", this.tree.timer); + } + this.tree.timer = null; + var self = this; // required for closures + switch (mode) { + case "cancel": + // Simply made sure that timer was cleared + break; + case "expand": + this.tree.timer = setTimeout(function(){ + self.tree.debug("setTimeout: trigger expand"); + self.setExpanded(true); + }, ms); + break; + case "activate": + this.tree.timer = setTimeout(function(){ + self.tree.debug("setTimeout: trigger activate"); + self.setActive(true); + }, ms); + break; + default: + throw "Invalid mode " + mode; + } +// this.tree.debug("setTimeout(%s, %s): %s", mode, ms, this.tree.timer); + }, + /** + * + * @param {boolean | PlainObject} [effects=false] animation options. + * @param {object} [options=null] {topNode: null, effects: ..., parent: ...} this node will remain visible in + * any case, even if `this` is outside the scroll pane. + * @returns {$.Promise} + */ + scrollIntoView: function(effects, options) { + if( options !== undefined && _isNode(options) ) { + this.warn("scrollIntoView() with 'topNode' option is deprecated since 2014-05-08. Use 'options.topNode' instead."); + options = {topNode: options}; + } + // this.$scrollParent = (this.options.scrollParent === "auto") ? $ul.scrollParent() : $(this.options.scrollParent); + // this.$scrollParent = this.$scrollParent.length ? this.$scrollParent || this.$container; + + var topNodeY, nodeY, horzScrollbarHeight, containerOffsetTop, + opts = $.extend({ + effects: (effects === true) ? {duration: 200, queue: false} : effects, + scrollOfs: this.tree.options.scrollOfs, + scrollParent: this.tree.options.scrollParent || this.tree.$container, + topNode: null + }, options), + dfd = new $.Deferred(), + that = this, + nodeHeight = $(this.span).height(), + $container = $(opts.scrollParent), + topOfs = opts.scrollOfs.top || 0, + bottomOfs = opts.scrollOfs.bottom || 0, + containerHeight = $container.height(),// - topOfs - bottomOfs, + scrollTop = $container.scrollTop(), + $animateTarget = $container, + isParentWindow = $container[0] === window, + topNode = opts.topNode || null, + newScrollTop = null; + + // this.debug("scrollIntoView(), scrollTop=", scrollTop, opts.scrollOfs); +// _assert($(this.span).is(":visible"), "scrollIntoView node is invisible"); // otherwise we cannot calc offsets + if( !$(this.span).is(":visible") ) { + // We cannot calc offsets for hidden elements + this.warn("scrollIntoView(): node is invisible."); + return _getResolvedPromise(); + } + if( isParentWindow ) { + nodeY = $(this.span).offset().top; + topNodeY = (topNode && topNode.span) ? $(topNode.span).offset().top : 0; + $animateTarget = $("html,body"); + + } else { + _assert($container[0] !== document && $container[0] !== document.body, "scrollParent should be an simple element or `window`, not document or body."); + + containerOffsetTop = $container.offset().top, + nodeY = $(this.span).offset().top - containerOffsetTop + scrollTop; // relative to scroll parent + topNodeY = topNode ? $(topNode.span).offset().top - containerOffsetTop + scrollTop : 0; + horzScrollbarHeight = Math.max(0, ($container.innerHeight() - $container[0].clientHeight)); + containerHeight -= horzScrollbarHeight; + } + + // this.debug(" scrollIntoView(), nodeY=", nodeY, "containerHeight=", containerHeight); + if( nodeY < (scrollTop + topOfs) ){ + // Node is above visible container area + newScrollTop = nodeY - topOfs; + // this.debug(" scrollIntoView(), UPPER newScrollTop=", newScrollTop); + + }else if((nodeY + nodeHeight) > (scrollTop + containerHeight - bottomOfs)){ + newScrollTop = nodeY + nodeHeight - containerHeight + bottomOfs; + // this.debug(" scrollIntoView(), LOWER newScrollTop=", newScrollTop); + // If a topNode was passed, make sure that it is never scrolled + // outside the upper border + if(topNode){ + _assert(topNode.isRootNode() || $(topNode.span).is(":visible"), "topNode must be visible"); + if( topNodeY < newScrollTop ){ + newScrollTop = topNodeY - topOfs; + // this.debug(" scrollIntoView(), TOP newScrollTop=", newScrollTop); + } + } + } + + if(newScrollTop !== null){ + // this.debug(" scrollIntoView(), SET newScrollTop=", newScrollTop); + if(opts.effects){ + opts.effects.complete = function(){ + dfd.resolveWith(that); + }; + $animateTarget.stop(true).animate({ + scrollTop: newScrollTop + }, opts.effects); + }else{ + $animateTarget[0].scrollTop = newScrollTop; + dfd.resolveWith(this); + } + }else{ + dfd.resolveWith(this); + } + return dfd.promise(); + }, + + /**Activate this node. + * @param {boolean} [flag=true] pass false to deactivate + * @param {object} [opts] additional options. Defaults to {noEvents: false} + * @returns {$.Promise} + */ + setActive: function(flag, opts){ + return this.tree._callHook("nodeSetActive", this, flag, opts); + }, + /**Expand or collapse this node. Promise is resolved, when lazy loading and animations are done. + * @param {boolean} [flag=true] pass false to collapse + * @param {object} [opts] additional options. Defaults to {noAnimation: false, noEvents: false} + * @returns {$.Promise} + */ + setExpanded: function(flag, opts){ + return this.tree._callHook("nodeSetExpanded", this, flag, opts); + }, + /**Set keyboard focus to this node. + * @param {boolean} [flag=true] pass false to blur + * @see Fancytree#setFocus + */ + setFocus: function(flag){ + return this.tree._callHook("nodeSetFocus", this, flag); + }, + /**Select this node, i.e. check the checkbox. + * @param {boolean} [flag=true] pass false to deselect + */ + setSelected: function(flag){ + return this.tree._callHook("nodeSetSelected", this, flag); + }, + /**Mark a lazy node as 'error', 'loading', or 'ok'. + * @param {string} status 'error', 'ok' + * @param {string} [message] + * @param {string} [details] + */ + setStatus: function(status, message, details){ + return this.tree._callHook("nodeSetStatus", this, status, message, details); + }, + /**Rename this node. + * @param {string} title + */ + setTitle: function(title){ + this.title = title; + this.renderTitle(); + }, + /**Sort child list by title. + * @param {function} [cmp] custom compare function(a, b) that returns -1, 0, or 1 (defaults to sort by title). + * @param {boolean} [deep=false] pass true to sort all descendant nodes + */ + sortChildren: function(cmp, deep) { + var i,l, + cl = this.children; + + if( !cl ){ + return; + } + cmp = cmp || function(a, b) { + var x = a.title.toLowerCase(), + y = b.title.toLowerCase(); + return x === y ? 0 : x > y ? 1 : -1; + }; + cl.sort(cmp); + if( deep ){ + for(i=0, l=cl.length; i<l; i++){ + if( cl[i].children ){ + cl[i].sortChildren(cmp, "$norender$"); + } + } + } + if( deep !== "$norender$" ){ + this.render(); + } + }, + /** Convert node (or whole branch) into a plain object. + * + * The result is compatible with node.addChildren(). + * + * @param {boolean} [recursive=false] include child nodes + * @param {function} [callback] callback(dict, node) is called for every node, in order to allow modifications + * @returns {NodeData} + */ + toDict: function(recursive, callback) { + var i, l, node, + dict = {}, + self = this; + + $.each(NODE_ATTRS, function(i, a){ + if(self[a] || self[a] === false){ + dict[a] = self[a]; + } + }); + if(!$.isEmptyObject(this.data)){ + dict.data = $.extend({}, this.data); + if($.isEmptyObject(dict.data)){ + delete dict.data; + } + } + if( callback ){ + callback(dict, self); + } + if( recursive ) { + if(this.hasChildren()){ + dict.children = []; + for(i=0, l=this.children.length; i<l; i++ ){ + node = this.children[i]; + if( !node.isStatusNode() ){ + dict.children.push(node.toDict(true, callback)); + } + } + }else{ +// dict.children = null; + } + } + return dict; + }, + /** Flip expanded status. */ + toggleExpanded: function(){ + return this.tree._callHook("nodeToggleExpanded", this); + }, + /** Flip selection status. */ + toggleSelected: function(){ + return this.tree._callHook("nodeToggleSelected", this); + }, + toString: function() { + return "<FancytreeNode(#" + this.key + ", '" + this.title + "')>"; + }, + /** Call fn(node) for all child nodes.<br> + * Stop iteration, if fn() returns false. Skip current branch, if fn() returns "skip".<br> + * Return false if iteration was stopped. + * + * @param {function} fn the callback function. + * Return false to stop iteration, return "skip" to skip this node and + * its children only. + * @param {boolean} [includeSelf=false] + * @returns {boolean} + */ + visit: function(fn, includeSelf) { + var i, l, + res = true, + children = this.children; + + if( includeSelf === true ) { + res = fn(this); + if( res === false || res === "skip" ){ + return res; + } + } + if(children){ + for(i=0, l=children.length; i<l; i++){ + res = children[i].visit(fn, true); + if( res === false ){ + break; + } + } + } + return res; + }, + /** Call fn(node) for all child nodes and recursively load lazy children.<br> + * <b>Note:</b> If you need this method, you probably should consider to review + * your architecture! Recursivley loading nodes is a perfect way for lazy + * programmers to flood the server with requests ;-) + * + * @param {function} [fn] optional callback function. + * Return false to stop iteration, return "skip" to skip this node and + * its children only. + * @param {boolean} [includeSelf=false] + * @returns {$.Promise} + * @since 2.4 + */ + visitAndLoad: function(fn, includeSelf, _recursion) { + var dfd, res, loaders, + node = this; + + // node.debug("visitAndLoad"); + if( fn && includeSelf === true ) { + res = fn(node); + if( res === false || res === "skip" ) { + return _recursion ? res : _getResolvedPromise(); + } + } + if( !node.children && !node.lazy ) { + return _getResolvedPromise(); + } + dfd = new $.Deferred(); + loaders = []; + // node.debug("load()..."); + node.load().done(function(){ + // node.debug("load()... done."); + for(var i=0, l=node.children.length; i<l; i++){ + res = node.children[i].visitAndLoad(fn, true, true); + if( res === false ) { + dfd.reject(); + break; + } else if ( res !== "skip" ) { + loaders.push(res); // Add promise to the list + } + } + $.when.apply(this, loaders).then(function(){ + dfd.resolve(); + }); + }); + return dfd.promise(); + }, + /** Call fn(node) for all parent nodes, bottom-up, including invisible system root.<br> + * Stop iteration, if fn() returns false.<br> + * Return false if iteration was stopped. + * + * @param {function} fn the callback function. + * Return false to stop iteration, return "skip" to skip this node and children only. + * @param {boolean} [includeSelf=false] + * @returns {boolean} + */ + visitParents: function(fn, includeSelf) { + // Visit parent nodes (bottom up) + if(includeSelf && fn(this) === false){ + return false; + } + var p = this.parent; + while( p ) { + if(fn(p) === false){ + return false; + } + p = p.parent; + } + return true; + }, + /** Write warning to browser console (prepending node info) + * + * @param {*} msg string or object or array of such + */ + warn: function(msg){ + Array.prototype.unshift.call(arguments, this.toString()); + consoleApply("warn", arguments); + } +}; + + +/* ***************************************************************************** + * Fancytree + */ +/** + * Construct a new tree object. + * + * @class Fancytree + * @classdesc The controller behind a fancytree. + * This class also contains 'hook methods': see {@link Fancytree_Hooks}. + * + * @param {Widget} widget + * + * @property {string} _id Automatically generated unique tree instance ID, e.g. "1". + * @property {string} _ns Automatically generated unique tree namespace, e.g. ".fancytree-1". + * @property {FancytreeNode} activeNode Currently active node or null. + * @property {string} ariaPropName Property name of FancytreeNode that contains the element which will receive the aria attributes. + * Typically "li", but "tr" for table extension. + * @property {jQueryObject} $container Outer <ul> element (or <table> element for ext-table). + * @property {jQueryObject} $div A jQuery object containing the element used to instantiate the tree widget (`widget.element`) + * @property {object} data Metadata, i.e. properties that may be passed to `source` in addition to a children array. + * @property {object} ext Hash of all active plugin instances. + * @property {FancytreeNode} focusNode Currently focused node or null. + * @property {FancytreeNode} lastSelectedNode Used to implement selectMode 1 (single select) + * @property {string} nodeContainerAttrName Property name of FancytreeNode that contains the outer element of single nodes. + * Typically "li", but "tr" for table extension. + * @property {FancytreeOptions} options Current options, i.e. default options + options passed to constructor. + * @property {FancytreeNode} rootNode Invisible system root node. + * @property {string} statusClassPropName Property name of FancytreeNode that contains the element which will receive the status classes. + * Typically "span", but "tr" for table extension. + * @property {object} widget Base widget instance. + */ +function Fancytree(widget) { + this.widget = widget; + this.$div = widget.element; + this.options = widget.options; + if( this.options ) { + if( $.isFunction(this.options.lazyload ) && !$.isFunction(this.options.lazyLoad) ) { + this.options.lazyLoad = function() { + FT.warn("The 'lazyload' event is deprecated since 2014-02-25. Use 'lazyLoad' (with uppercase L) instead."); + return widget.options.lazyload.apply(this, arguments); + }; + } + if( $.isFunction(this.options.loaderror) ) { + $.error("The 'loaderror' event was renamed since 2014-07-03. Use 'loadError' (with uppercase E) instead."); + } + if( this.options.fx !== undefined ) { + FT.warn("The 'fx' options was replaced by 'toggleEffect' since 2014-11-30."); + } + } + this.ext = {}; // Active extension instances + // allow to init tree.data.foo from <div data-foo=''> + this.data = _getElementDataAsDict(this.$div); + // TODO: use widget.uuid instead? + this._id = $.ui.fancytree._nextId++; + // TODO: use widget.eventNamespace instead? + this._ns = ".fancytree-" + this._id; // append for namespaced events + this.activeNode = null; + this.focusNode = null; + this._hasFocus = null; + this.lastSelectedNode = null; + this.systemFocusElement = null; + this.lastQuicksearchTerm = ""; + this.lastQuicksearchTime = 0; + + this.statusClassPropName = "span"; + this.ariaPropName = "li"; + this.nodeContainerAttrName = "li"; + + // Remove previous markup if any + this.$div.find(">ul.fancytree-container").remove(); + + // Create a node without parent. + var fakeParent = { tree: this }, + $ul; + this.rootNode = new FancytreeNode(fakeParent, { + title: "root", + key: "root_" + this._id, + children: null, + expanded: true + }); + this.rootNode.parent = null; + + // Create root markup + $ul = $("<ul>", { + "class": "ui-fancytree fancytree-container fancytree-plain" + }).appendTo(this.$div); + this.$container = $ul; + this.rootNode.ul = $ul[0]; + + if(this.options.debugLevel == null){ + this.options.debugLevel = FT.debugLevel; + } + // Add container to the TAB chain + // See http://www.w3.org/TR/wai-aria-practices/#focus_activedescendant + this.$container.attr("tabindex", this.options.tabbable ? "0" : "-1"); + if(this.options.aria){ + this.$container + .attr("role", "tree") + .attr("aria-multiselectable", true); + } +} + + +Fancytree.prototype = /** @lends Fancytree# */{ + /* Return a context object that can be re-used for _callHook(). + * @param {Fancytree | FancytreeNode | EventData} obj + * @param {Event} originalEvent + * @param {Object} extra + * @returns {EventData} + */ + _makeHookContext: function(obj, originalEvent, extra) { + var ctx, tree; + if(obj.node !== undefined){ + // obj is already a context object + if(originalEvent && obj.originalEvent !== originalEvent){ + $.error("invalid args"); + } + ctx = obj; + }else if(obj.tree){ + // obj is a FancytreeNode + tree = obj.tree; + ctx = { node: obj, tree: tree, widget: tree.widget, options: tree.widget.options, originalEvent: originalEvent }; + }else if(obj.widget){ + // obj is a Fancytree + ctx = { node: null, tree: obj, widget: obj.widget, options: obj.widget.options, originalEvent: originalEvent }; + }else{ + $.error("invalid args"); + } + if(extra){ + $.extend(ctx, extra); + } + return ctx; + }, + /* Trigger a hook function: funcName(ctx, [...]). + * + * @param {string} funcName + * @param {Fancytree|FancytreeNode|EventData} contextObject + * @param {any} [_extraArgs] optional additional arguments + * @returns {any} + */ + _callHook: function(funcName, contextObject, _extraArgs) { + var ctx = this._makeHookContext(contextObject), + fn = this[funcName], + args = Array.prototype.slice.call(arguments, 2); + if(!$.isFunction(fn)){ + $.error("_callHook('" + funcName + "') is not a function"); + } + args.unshift(ctx); +// this.debug("_hook", funcName, ctx.node && ctx.node.toString() || ctx.tree.toString(), args); + return fn.apply(this, args); + }, + /* Check if current extensions dependencies are met and throw an error if not. + * + * This method may be called inside the `treeInit` hook for custom extensions. + * + * @param {string} extension name of the required extension + * @param {boolean} [required=true] pass `false` if the extension is optional, but we want to check for order if it is present + * @param {boolean} [before] `true` if `name` must be included before this, `false` otherwise (use `null` if order doesn't matter) + * @param {string} [message] optional error message (defaults to a descriptve error message) + */ + _requireExtension: function(name, required, before, message) { + before = !!before; + var thisName = this._local.name, + extList = this.options.extensions, + isBefore = $.inArray(name, extList) < $.inArray(thisName, extList), + isMissing = required && this.ext[name] == null, + badOrder = !isMissing && before != null && (before !== isBefore); + + _assert(thisName && thisName !== name, "invalid or same name"); + + if( isMissing || badOrder ){ + if( !message ){ + if( isMissing || required ){ + message = "'" + thisName + "' extension requires '" + name + "'"; + if( badOrder ){ + message += " to be registered " + (before ? "before" : "after") + " itself"; + } + }else{ + message = "If used together, `" + name + "` must be registered " + (before ? "before" : "after") + " `" + thisName + "`"; + } + } + $.error(message); + return false; + } + return true; + }, + /** Activate node with a given key and fire focus and activate events. + * + * A prevously activated node will be deactivated. + * If activeVisible option is set, all parents will be expanded as necessary. + * Pass key = false, to deactivate the current node only. + * @param {string} key + * @returns {FancytreeNode} activated node (null, if not found) + */ + activateKey: function(key) { + var node = this.getNodeByKey(key); + if(node){ + node.setActive(); + }else if(this.activeNode){ + this.activeNode.setActive(false); + } + return node; + }, + /** (experimental) + * + * @param {Array} patchList array of [key, NodePatch] arrays + * @returns {$.Promise} resolved, when all patches have been applied + * @see TreePatch + */ + applyPatch: function(patchList) { + var dfd, i, p2, key, patch, node, + patchCount = patchList.length, + deferredList = []; + + for(i=0; i<patchCount; i++){ + p2 = patchList[i]; + _assert(p2.length === 2, "patchList must be an array of length-2-arrays"); + key = p2[0]; + patch = p2[1]; + node = (key === null) ? this.rootNode : this.getNodeByKey(key); + if(node){ + dfd = new $.Deferred(); + deferredList.push(dfd); + node.applyPatch(patch).always(_makeResolveFunc(dfd, node)); + }else{ + this.warn("could not find node with key '" + key + "'"); + } + } + // Return a promise that is resolved, when ALL patches were applied + return $.when.apply($, deferredList).promise(); + }, + /* TODO: implement in dnd extension + cancelDrag: function() { + var dd = $.ui.ddmanager.current; + if(dd){ + dd.cancel(); + } + }, + */ + /** Return the number of nodes. + * @returns {integer} + */ + count: function() { + return this.rootNode.countChildren(); + }, + /** Write to browser console if debugLevel >= 2 (prepending tree name) + * + * @param {*} msg string or object or array of such + */ + debug: function(msg){ + if( this.options.debugLevel >= 2 ) { + Array.prototype.unshift.call(arguments, this.toString()); + consoleApply("log", arguments); + } + }, + // TODO: disable() + // TODO: enable() + // TODO: enableUpdate() + + /**Find all nodes that matches condition. + * + * @param {string | function(node)} match title string to search for, or a + * callback function that returns `true` if a node is matched. + * @returns {FancytreeNode[]} array of nodes (may be empty) + * @see FancytreeNode#findAll + * @since 2.12 + */ + findAll: function(match) { + return this.rootNode.findAll(match); + }, + /**Find first node that matches condition. + * + * @param {string | function(node)} match title string to search for, or a + * callback function that returns `true` if a node is matched. + * @returns {FancytreeNode} matching node or null + * @see FancytreeNode#findFirst + * @since 2.12 + */ + findFirst: function(match) { + return this.rootNode.findFirst(match); + }, + /** Find the next visible node that starts with `match`, starting at `startNode` + * and wrap-around at the end. + * + * @param {string|function} match + * @param {FancytreeNode} [startNode] defaults to first node + * @returns {FancytreeNode} matching node or null + */ + findNextNode: function(match, startNode, visibleOnly) { + var stopNode = null, + parentChildren = startNode.parent.children, + matchingNode = null, + walkVisible = function(parent, idx, fn) { + var i, grandParent, + parentChildren = parent.children, + siblingCount = parentChildren.length, + node = parentChildren[idx]; + // visit node itself + if( node && fn(node) === false ) { + return false; + } + // visit descendants + if( node && node.children && node.expanded ) { + if( walkVisible(node, 0, fn) === false ) { + return false; + } + } + // visit subsequent siblings + for( i = idx + 1; i < siblingCount; i++ ) { + if( walkVisible(parent, i, fn) === false ) { + return false; + } + } + // visit parent's subsequent siblings + grandParent = parent.parent; + if( grandParent ) { + return walkVisible(grandParent, grandParent.children.indexOf(parent) + 1, fn); + } else { + // wrap-around: restart with first node + return walkVisible(parent, 0, fn); + } + }; + + match = (typeof match === "string") ? _makeNodeTitleStartMatcher(match) : match; + startNode = startNode || this.getFirstChild(); + + walkVisible(startNode.parent, parentChildren.indexOf(startNode), function(node){ + // Stop iteration if we see the start node a second time + if( node === stopNode ) { + return false; + } + stopNode = stopNode || node; + // Ignore nodes hidden by a filter + if( ! $(node.span).is(":visible") ) { + node.debug("quicksearch: skipping hidden node"); + return; + } + // Test if we found a match, but search for a second match if this + // was the currently active node + if( match(node) ) { + // node.debug("quicksearch match " + node.title, startNode); + matchingNode = node; + if( matchingNode !== startNode ) { + return false; + } + } + }); + return matchingNode; + }, + // TODO: fromDict + /** + * Generate INPUT elements that can be submitted with html forms. + * + * In selectMode 3 only the topmost selected nodes are considered, unless + * `opts.stopOnParents: false` is passed. + * + * @param {boolean | string} [selected=true] Pass false to disable, pass a string to overide the field name (default: 'ft_ID[]') + * @param {boolean | string} [active=true] Pass false to disable, pass a string to overide the field name (default: 'ft_ID_active') + * @param {object} [opts] default { stopOnParents: true } + */ + generateFormElements: function(selected, active, opts) { + // TODO: test case + opts = opts || {}; + + var nodeList, + selectedName = (typeof selected === "string") ? selected : "ft_" + this._id + "[]", + activeName = (typeof active === "string") ? active : "ft_" + this._id + "_active", + id = "fancytree_result_" + this._id, + $result = $("#" + id), + stopOnParents = this.options.selectMode === 3 && opts.stopOnParents !== false; + + if($result.length){ + $result.empty(); + }else{ + $result = $("<div>", { + id: id + }).hide().insertAfter(this.$container); + } + if(selected !== false){ + nodeList = this.getSelectedNodes(stopOnParents); + $.each(nodeList, function(idx, node){ + $result.append($("<input>", { + type: "checkbox", + name: selectedName, + value: node.key, + checked: true + })); + }); + } + if(active !== false && this.activeNode){ + $result.append($("<input>", { + type: "radio", + name: activeName, + value: this.activeNode.key, + checked: true + })); + } + }, + /** + * Return the currently active node or null. + * @returns {FancytreeNode} + */ + getActiveNode: function() { + return this.activeNode; + }, + /** Return the first top level node if any (not the invisible root node). + * @returns {FancytreeNode | null} + */ + getFirstChild: function() { + return this.rootNode.getFirstChild(); + }, + /** + * Return node that has keyboard focus or null. + * @returns {FancytreeNode} + */ + getFocusNode: function() { + return this.focusNode; + }, + /** + * Return node with a given key or null if not found. + * @param {string} key + * @param {FancytreeNode} [searchRoot] only search below this node + * @returns {FancytreeNode | null} + */ + getNodeByKey: function(key, searchRoot) { + // Search the DOM by element ID (assuming this is faster than traversing all nodes). + // $("#...") has problems, if the key contains '.', so we use getElementById() + var el, match; + if(!searchRoot){ + el = document.getElementById(this.options.idPrefix + key); + if( el ){ + return el.ftnode ? el.ftnode : null; + } + } + // Not found in the DOM, but still may be in an unrendered part of tree + // TODO: optimize with specialized loop + // TODO: consider keyMap? + searchRoot = searchRoot || this.rootNode; + match = null; + searchRoot.visit(function(node){ +// window.console.log("getNodeByKey(" + key + "): ", node.key); + if(node.key === key) { + match = node; + return false; + } + }, true); + return match; + }, + /** Return the invisible system root node. + * @returns {FancytreeNode} + */ + getRootNode: function() { + return this.rootNode; + }, + /** + * Return an array of selected nodes. + * @param {boolean} [stopOnParents=false] only return the topmost selected + * node (useful with selectMode 3) + * @returns {FancytreeNode[]} + */ + getSelectedNodes: function(stopOnParents) { + var nodeList = []; + this.rootNode.visit(function(node){ + if( node.selected ) { + nodeList.push(node); + if( stopOnParents === true ){ + return "skip"; // stop processing this branch + } + } + }); + return nodeList; + }, + /** Return true if the tree control has keyboard focus + * @returns {boolean} + */ + hasFocus: function(){ + return !!this._hasFocus; + }, + /** Write to browser console if debugLevel >= 1 (prepending tree name) + * @param {*} msg string or object or array of such + */ + info: function(msg){ + if( this.options.debugLevel >= 1 ) { + Array.prototype.unshift.call(arguments, this.toString()); + consoleApply("info", arguments); + } + }, +/* + TODO: isInitializing: function() { + return ( this.phase=="init" || this.phase=="postInit" ); + }, + TODO: isReloading: function() { + return ( this.phase=="init" || this.phase=="postInit" ) && this.options.persist && this.persistence.cookiesFound; + }, + TODO: isUserEvent: function() { + return ( this.phase=="userEvent" ); + }, +*/ + + /** + * Make sure that a node with a given ID is loaded, by traversing - and + * loading - its parents. This method is ment for lazy hierarchies. + * A callback is executed for every node as we go. + * @example + * tree.loadKeyPath("/_3/_23/_26/_27", function(node, status){ + * if(status === "loaded") { + * console.log("loaded intermiediate node " + node); + * }else if(status === "ok") { + * node.activate(); + * } + * }); + * + * @param {string | string[]} keyPathList one or more key paths (e.g. '/3/2_1/7') + * @param {function} callback callback(node, status) is called for every visited node ('loading', 'loaded', 'ok', 'error') + * @returns {$.Promise} + */ + loadKeyPath: function(keyPathList, callback, _rootNode) { + var deferredList, dfd, i, path, key, loadMap, node, root, segList, + sep = this.options.keyPathSeparator, + self = this; + + if(!$.isArray(keyPathList)){ + keyPathList = [keyPathList]; + } + // Pass 1: handle all path segments for nodes that are already loaded + // Collect distinct top-most lazy nodes in a map + loadMap = {}; + + for(i=0; i<keyPathList.length; i++){ + root = _rootNode || this.rootNode; + path = keyPathList[i]; + // strip leading slash + if(path.charAt(0) === sep){ + path = path.substr(1); + } + // traverse and strip keys, until we hit a lazy, unloaded node + segList = path.split(sep); + while(segList.length){ + key = segList.shift(); +// node = _findDirectChild(root, key); + node = root._findDirectChild(key); + if(!node){ + this.warn("loadKeyPath: key not found: " + key + " (parent: " + root + ")"); + callback.call(this, key, "error"); + break; + }else if(segList.length === 0){ + callback.call(this, node, "ok"); + break; + }else if(!node.lazy || (node.hasChildren() !== undefined )){ + callback.call(this, node, "loaded"); + root = node; + }else{ + callback.call(this, node, "loaded"); +// segList.unshift(key); + if(loadMap[key]){ + loadMap[key].push(segList.join(sep)); + }else{ + loadMap[key] = [segList.join(sep)]; + } + break; + } + } + } +// alert("loadKeyPath: loadMap=" + JSON.stringify(loadMap)); + // Now load all lazy nodes and continue itearation for remaining paths + deferredList = []; + // Avoid jshint warning 'Don't make functions within a loop.': + function __lazyload(key, node, dfd){ + callback.call(self, node, "loading"); + node.load().done(function(){ + self.loadKeyPath.call(self, loadMap[key], callback, node).always(_makeResolveFunc(dfd, self)); + }).fail(function(errMsg){ + self.warn("loadKeyPath: error loading: " + key + " (parent: " + root + ")"); + callback.call(self, node, "error"); + dfd.reject(); + }); + } + for(key in loadMap){ + node = root._findDirectChild(key); +// alert("loadKeyPath: lazy node(" + key + ") = " + node); + dfd = new $.Deferred(); + deferredList.push(dfd); + __lazyload(key, node, dfd); + } + // Return a promise that is resolved, when ALL paths were loaded + return $.when.apply($, deferredList).promise(); + }, + /** Re-fire beforeActivate and activate events. */ + reactivate: function(setFocus) { + var res, + node = this.activeNode; + + if( !node ) { + return _getResolvedPromise(); + } + this.activeNode = null; // Force re-activating + res = node.setActive(); + if( setFocus ){ + node.setFocus(); + } + return res; + }, + /** Reload tree from source and return a promise. + * @param [source] optional new source (defaults to initial source data) + * @returns {$.Promise} + */ + reload: function(source) { + this._callHook("treeClear", this); + return this._callHook("treeLoad", this, source); + }, + /**Render tree (i.e. create DOM elements for all top-level nodes). + * @param {boolean} [force=false] create DOM elemnts, even is parent is collapsed + * @param {boolean} [deep=false] + */ + render: function(force, deep) { + return this.rootNode.render(force, deep); + }, + // TODO: selectKey: function(key, select) + // TODO: serializeArray: function(stopOnParents) + /** + * @param {boolean} [flag=true] + */ + setFocus: function(flag) { + return this._callHook("treeSetFocus", this, flag); + }, + /** + * Return all nodes as nested list of {@link NodeData}. + * + * @param {boolean} [includeRoot=false] Returns the hidden system root node (and its children) + * @param {function} [callback] callback(dict, node) is called for every node, in order to allow modifications + * @returns {Array | object} + * @see FancytreeNode#toDict + */ + toDict: function(includeRoot, callback){ + var res = this.rootNode.toDict(true, callback); + return includeRoot ? res : res.children; + }, + /* Implicitly called for string conversions. + * @returns {string} + */ + toString: function(){ + return "<Fancytree(#" + this._id + ")>"; + }, + /* _trigger a widget event with additional node ctx. + * @see EventData + */ + _triggerNodeEvent: function(type, node, originalEvent, extra) { +// this.debug("_trigger(" + type + "): '" + ctx.node.title + "'", ctx); + var ctx = this._makeHookContext(node, originalEvent, extra), + res = this.widget._trigger(type, originalEvent, ctx); + if(res !== false && ctx.result !== undefined){ + return ctx.result; + } + return res; + }, + /* _trigger a widget event with additional tree data. */ + _triggerTreeEvent: function(type, originalEvent, extra) { +// this.debug("_trigger(" + type + ")", ctx); + var ctx = this._makeHookContext(this, originalEvent, extra), + res = this.widget._trigger(type, originalEvent, ctx); + + if(res !== false && ctx.result !== undefined){ + return ctx.result; + } + return res; + }, + /** Call fn(node) for all nodes. + * + * @param {function} fn the callback function. + * Return false to stop iteration, return "skip" to skip this node and children only. + * @returns {boolean} false, if the iterator was stopped. + */ + visit: function(fn) { + return this.rootNode.visit(fn, false); + }, + /** Write warning to browser console (prepending tree info) + * + * @param {*} msg string or object or array of such + */ + warn: function(msg){ + Array.prototype.unshift.call(arguments, this.toString()); + consoleApply("warn", arguments); + } +}; + +/** + * These additional methods of the {@link Fancytree} class are 'hook functions' + * that can be used and overloaded by extensions. + * (See <a href="https://github.com/mar10/fancytree/wiki/TutorialExtensions">writing extensions</a>.) + * @mixin Fancytree_Hooks + */ +$.extend(Fancytree.prototype, + /** @lends Fancytree_Hooks# */ + { + /** Default handling for mouse click events. + * + * @param {EventData} ctx + */ + nodeClick: function(ctx) { + var activate, expand, + // event = ctx.originalEvent, + targetType = ctx.targetType, + node = ctx.node; + +// this.debug("ftnode.onClick(" + event.type + "): ftnode:" + this + ", button:" + event.button + ", which: " + event.which, ctx); + // TODO: use switch + // TODO: make sure clicks on embedded <input> doesn't steal focus (see table sample) + if( targetType === "expander" ) { + if( node.isLoading() ) { + // #495: we probably got a click event while a lazy load is pending. + // The 'expanded' state is not yet set, so 'toggle' would expand + // and trigger lazyLoad again. + // It would be better to allow to collapse/expand the status node + // while loading (instead of ignoring), but that would require some + // more work. + node.debug("Got 2nd click while loading: ignored"); + return; + } + // Clicking the expander icon always expands/collapses + this._callHook("nodeToggleExpanded", ctx); + + } else if( targetType === "checkbox" ) { + // Clicking the checkbox always (de)selects + this._callHook("nodeToggleSelected", ctx); + if( ctx.options.focusOnSelect ) { // #358 + this._callHook("nodeSetFocus", ctx, true); + } + + } else { + // Honor `clickFolderMode` for + expand = false; + activate = true; + if( node.folder ) { + switch( ctx.options.clickFolderMode ) { + case 2: // expand only + expand = true; + activate = false; + break; + case 3: // expand and activate + activate = true; + expand = true; //!node.isExpanded(); + break; + // else 1 or 4: just activate + } + } + if( activate ) { + this.nodeSetFocus(ctx); + this._callHook("nodeSetActive", ctx, true); + } + if( expand ) { + if(!activate){ +// this._callHook("nodeSetFocus", ctx); + } +// this._callHook("nodeSetExpanded", ctx, true); + this._callHook("nodeToggleExpanded", ctx); + } + } + // Make sure that clicks stop, otherwise <a href='#'> jumps to the top + // if(event.target.localName === "a" && event.target.className === "fancytree-title"){ + // event.preventDefault(); + // } + // TODO: return promise? + }, + /** Collapse all other children of same parent. + * + * @param {EventData} ctx + * @param {object} callOpts + */ + nodeCollapseSiblings: function(ctx, callOpts) { + // TODO: return promise? + var ac, i, l, + node = ctx.node; + + if( node.parent ){ + ac = node.parent.children; + for (i=0, l=ac.length; i<l; i++) { + if ( ac[i] !== node && ac[i].expanded ){ + this._callHook("nodeSetExpanded", ac[i], false, callOpts); + } + } + } + }, + /** Default handling for mouse douleclick events. + * @param {EventData} ctx + */ + nodeDblclick: function(ctx) { + // TODO: return promise? + if( ctx.targetType === "title" && ctx.options.clickFolderMode === 4) { +// this.nodeSetFocus(ctx); +// this._callHook("nodeSetActive", ctx, true); + this._callHook("nodeToggleExpanded", ctx); + } + // TODO: prevent text selection on dblclicks + if( ctx.targetType === "title" ) { + ctx.originalEvent.preventDefault(); + } + }, + /** Default handling for mouse keydown events. + * + * NOTE: this may be called with node == null if tree (but no node) has focus. + * @param {EventData} ctx + */ + nodeKeydown: function(ctx) { + // TODO: return promise? + var matchNode, stamp, res, focusNode, + event = ctx.originalEvent, + node = ctx.node, + tree = ctx.tree, + opts = ctx.options, + which = event.which, + whichChar = String.fromCharCode(which), + clean = !(event.altKey || event.ctrlKey || event.metaKey || event.shiftKey), + $target = $(event.target), + handled = true, + activate = !(event.ctrlKey || !opts.autoActivate ); + +// (node || FT).debug("ftnode.nodeKeydown(" + event.type + "): ftnode:" + this + ", charCode:" + event.charCode + ", keyCode: " + event.keyCode + ", which: " + event.which); +// FT.debug("eventToString", which, '"' + String.fromCharCode(which) + '"', '"' + FT.eventToString(event) + '"'); + + // Set focus to active (or first node) if no other node has the focus yet + if( !node ){ + focusNode = (this.getActiveNode() || this.getFirstChild()); + if (focusNode){ + focusNode.setFocus(); + node = ctx.node = this.focusNode; + node.debug("Keydown force focus on active node"); + } + } + + if( opts.quicksearch && clean && /\w/.test(whichChar) && !$target.is(":input:enabled") ) { + // Allow to search for longer streaks if typed in quickly + stamp = new Date().getTime(); + if( stamp - tree.lastQuicksearchTime > 500 ) { + tree.lastQuicksearchTerm = ""; + } + tree.lastQuicksearchTime = stamp; + tree.lastQuicksearchTerm += whichChar; + // tree.debug("quicksearch find", tree.lastQuicksearchTerm); + matchNode = tree.findNextNode(tree.lastQuicksearchTerm, tree.getActiveNode()); + if( matchNode ) { + matchNode.setActive(); + } + event.preventDefault(); + return; + } + switch( FT.eventToString(event) ) { + case "+": + case "=": // 187: '+' @ Chrome, Safari + tree.nodeSetExpanded(ctx, true); + break; + case "-": + tree.nodeSetExpanded(ctx, false); + break; + case "space": + if(opts.checkbox){ + tree.nodeToggleSelected(ctx); + }else{ + tree.nodeSetActive(ctx, true); + } + break; + case "return": + tree.nodeSetActive(ctx, true); + break; + case "backspace": + case "left": + case "right": + case "up": + case "down": + res = node.navigate(event.which, activate); + break; + default: + handled = false; + } + if(handled){ + event.preventDefault(); + } + }, + + + // /** Default handling for mouse keypress events. */ + // nodeKeypress: function(ctx) { + // var event = ctx.originalEvent; + // }, + + // /** Trigger lazyLoad event (async). */ + // nodeLazyLoad: function(ctx) { + // var node = ctx.node; + // if(this._triggerNodeEvent()) + // }, + /** Load child nodes (async). + * + * @param {EventData} ctx + * @param {object[]|object|string|$.Promise|function} source + * @returns {$.Promise} The deferred will be resolved as soon as the (ajax) + * data was rendered. + */ + nodeLoadChildren: function(ctx, source) { + var ajax, delay, dfd, + tree = ctx.tree, + node = ctx.node; + + if($.isFunction(source)){ + source = source(); + } + // TOTHINK: move to 'ajax' extension? + if(source.url){ + // `source` is an Ajax options object + ajax = $.extend({}, ctx.options.ajax, source); + if(ajax.debugDelay){ + // simulate a slow server + delay = ajax.debugDelay; + if($.isArray(delay)){ // random delay range [min..max] + delay = delay[0] + Math.random() * (delay[1] - delay[0]); + } + + node.debug("nodeLoadChildren waiting debug delay " + Math.round(delay) + "ms"); + ajax.debugDelay = false; + dfd = $.Deferred(function (dfd) { + setTimeout(function () { + $.ajax(ajax) + .done(function () { dfd.resolveWith(this, arguments); }) + .fail(function () { dfd.rejectWith(this, arguments); }); + }, delay); + }); + }else{ + dfd = $.ajax(ajax); + } + + // Defer the deferred: we want to be able to reject, even if ajax + // resolved ok. + source = new $.Deferred(); + dfd.done(function (data, textStatus, jqXHR) { + var errorObj, res; + if(this.dataType === "json" && typeof data === "string"){ + $.error("Ajax request returned a string (did you get the JSON dataType wrong?)."); + } + // postProcess is similar to the standard ajax dataFilter hook, + // but it is also called for JSONP + if( ctx.options.postProcess ){ + res = tree._triggerNodeEvent("postProcess", ctx, ctx.originalEvent, {response: data, error: null, dataType: this.dataType}); + if( res.error ) { + errorObj = $.isPlainObject(res.error) ? res.error : {message: res.error}; + errorObj = tree._makeHookContext(node, null, errorObj); + source.rejectWith(this, [errorObj]); + return; + } + data = $.isArray(res) ? res : data; + + } else if (data && data.hasOwnProperty("d") && ctx.options.enableAspx ) { + // Process ASPX WebMethod JSON object inside "d" property + data = (typeof data.d === "string") ? $.parseJSON(data.d) : data.d; + } + source.resolveWith(this, [data]); + }).fail(function (jqXHR, textStatus, errorThrown) { + var errorObj = tree._makeHookContext(node, null, { + error: jqXHR, + args: Array.prototype.slice.call(arguments), + message: errorThrown, + details: jqXHR.status + ": " + errorThrown + }); + source.rejectWith(this, [errorObj]); + }); + } + // #383: accept and convert ECMAScript 6 Promise + if( $.isFunction(source.then) && $.isFunction(source["catch"]) ) { + dfd = source; + source = new $.Deferred(); + dfd.then(function(value){ + source.resolve(value); + }, function(reason){ + source.reject(reason); + }); + } + if($.isFunction(source.promise)){ + // `source` is a deferred, i.e. ajax request + _assert(!node.isLoading(), "recursive load"); + // node._isLoading = true; + tree.nodeSetStatus(ctx, "loading"); + + source.done(function (children) { + tree.nodeSetStatus(ctx, "ok"); + }).fail(function(error){ + var ctxErr; + if (error.node && error.error && error.message) { + // error is already a context object + ctxErr = error; + } else { + ctxErr = tree._makeHookContext(node, null, { + error: error, // it can be jqXHR or any custom error + args: Array.prototype.slice.call(arguments), + message: error ? (error.message || error.toString()) : "" + }); + } + if( tree._triggerNodeEvent("loadError", ctxErr, null) !== false ) { + tree.nodeSetStatus(ctx, "error", ctxErr.message, ctxErr.details); + } + }); + } + // $.when(source) resolves also for non-deferreds + return $.when(source).done(function(children){ + var metaData; + + if( $.isPlainObject(children) ){ + // We got {foo: 'abc', children: [...]} + // Copy extra properties to tree.data.foo + _assert(node.isRootNode(), "source may only be an object for root nodes (expecting an array of child objects otherwise)"); + _assert($.isArray(children.children), "if an object is passed as source, it must contain a 'children' array (all other properties are added to 'tree.data')"); + metaData = children; + children = children.children; + delete metaData.children; + $.extend(tree.data, metaData); + } + _assert($.isArray(children), "expected array of children"); + node._setChildren(children); + // trigger fancytreeloadchildren + tree._triggerNodeEvent("loadChildren", node); + // }).always(function(){ + // node._isLoading = false; + }); + }, + /** [Not Implemented] */ + nodeLoadKeyPath: function(ctx, keyPathList) { + // TODO: implement and improve + // http://code.google.com/p/dynatree/issues/detail?id=222 + }, + /** + * Remove a single direct child of ctx.node. + * @param {EventData} ctx + * @param {FancytreeNode} childNode dircect child of ctx.node + */ + nodeRemoveChild: function(ctx, childNode) { + var idx, + node = ctx.node, + opts = ctx.options, + subCtx = $.extend({}, ctx, {node: childNode}), + children = node.children; + + // FT.debug("nodeRemoveChild()", node.toString(), childNode.toString()); + + if( children.length === 1 ) { + _assert(childNode === children[0], "invalid single child"); + return this.nodeRemoveChildren(ctx); + } + if( this.activeNode && (childNode === this.activeNode || this.activeNode.isDescendantOf(childNode))){ + this.activeNode.setActive(false); // TODO: don't fire events + } + if( this.focusNode && (childNode === this.focusNode || this.focusNode.isDescendantOf(childNode))){ + this.focusNode = null; + } + // TODO: persist must take care to clear select and expand cookies + this.nodeRemoveMarkup(subCtx); + this.nodeRemoveChildren(subCtx); + idx = $.inArray(childNode, children); + _assert(idx >= 0, "invalid child"); + // Unlink to support GC + childNode.visit(function(n){ + n.parent = null; + }, true); + this._callHook("treeRegisterNode", this, false, childNode); + if ( opts.removeNode ){ + opts.removeNode.call(ctx.tree, {type: "removeNode"}, subCtx); + } + // remove from child list + children.splice(idx, 1); + }, + /**Remove HTML markup for all descendents of ctx.node. + * @param {EventData} ctx + */ + nodeRemoveChildMarkup: function(ctx) { + var node = ctx.node; + + // FT.debug("nodeRemoveChildMarkup()", node.toString()); + // TODO: Unlink attr.ftnode to support GC + if(node.ul){ + if( node.isRootNode() ) { + $(node.ul).empty(); + } else { + $(node.ul).remove(); + node.ul = null; + } + node.visit(function(n){ + n.li = n.ul = null; + }); + } + }, + /**Remove all descendants of ctx.node. + * @param {EventData} ctx + */ + nodeRemoveChildren: function(ctx) { + var subCtx, + tree = ctx.tree, + node = ctx.node, + children = node.children, + opts = ctx.options; + + // FT.debug("nodeRemoveChildren()", node.toString()); + if(!children){ + return; + } + if( this.activeNode && this.activeNode.isDescendantOf(node)){ + this.activeNode.setActive(false); // TODO: don't fire events + } + if( this.focusNode && this.focusNode.isDescendantOf(node)){ + this.focusNode = null; + } + // TODO: persist must take care to clear select and expand cookies + this.nodeRemoveChildMarkup(ctx); + // Unlink children to support GC + // TODO: also delete this.children (not possible using visit()) + subCtx = $.extend({}, ctx); + node.visit(function(n){ + n.parent = null; + tree._callHook("treeRegisterNode", tree, false, n); + if ( opts.removeNode ){ + subCtx.node = n; + opts.removeNode.call(ctx.tree, {type: "removeNode"}, subCtx); + } + }); + if( node.lazy ){ + // 'undefined' would be interpreted as 'not yet loaded' for lazy nodes + node.children = []; + } else{ + node.children = null; + } + if( !node.isRootNode() ) { + node.expanded = false; // #449, #459 + } + this.nodeRenderStatus(ctx); + }, + /**Remove HTML markup for ctx.node and all its descendents. + * @param {EventData} ctx + */ + nodeRemoveMarkup: function(ctx) { + var node = ctx.node; + // FT.debug("nodeRemoveMarkup()", node.toString()); + // TODO: Unlink attr.ftnode to support GC + if(node.li){ + $(node.li).remove(); + node.li = null; + } + this.nodeRemoveChildMarkup(ctx); + }, + /** + * Create `<li><span>..</span> .. </li>` tags for this node. + * + * This method takes care that all HTML markup is created that is required + * to display this node in it's current state. + * + * Call this method to create new nodes, or after the strucuture + * was changed (e.g. after moving this node or adding/removing children) + * nodeRenderTitle() and nodeRenderStatus() are implied. + * + * Note: if a node was created/removed, nodeRender() must be called for the + * parent. + * <code> + * <li id='KEY' ftnode=NODE> + * <span class='fancytree-node fancytree-expanded fancytree-has-children fancytree-lastsib fancytree-exp-el fancytree-ico-e'> + * <span class="fancytree-expander"></span> + * <span class="fancytree-checkbox"></span> // only present in checkbox mode + * <span class="fancytree-icon"></span> + * <a href="#" class="fancytree-title"> Node 1 </a> + * </span> + * <ul> // only present if node has children + * <li id='KEY' ftnode=NODE> child1 ... </li> + * <li id='KEY' ftnode=NODE> child2 ... </li> + * </ul> + * </li> + * </code> + * + * @param {EventData} ctx + * @param {boolean} [force=false] re-render, even if html markup was already created + * @param {boolean} [deep=false] also render all descendants, even if parent is collapsed + * @param {boolean} [collapsed=false] force root node to be collapsed, so we can apply animated expand later + */ + nodeRender: function(ctx, force, deep, collapsed, _recursive) { + /* This method must take care of all cases where the current data mode + * (i.e. node hierarchy) does not match the current markup. + * + * - node was not yet rendered: + * create markup + * - node was rendered: exit fast + * - children have been added + * - children have been removed + */ + var childLI, childNode1, childNode2, i, l, next, subCtx, + node = ctx.node, + tree = ctx.tree, + opts = ctx.options, + aria = opts.aria, + firstTime = false, + parent = node.parent, + isRootNode = !parent, + children = node.children, + successorLi = null; + // FT.debug("nodeRender(" + !!force + ", " + !!deep + ")", node.toString()); + + if( ! isRootNode && ! parent.ul ) { + // Calling node.collapse on a deep, unrendered node + return; + } + _assert(isRootNode || parent.ul, "parent UL must exist"); + + // Render the node + if( !isRootNode ){ + // Discard markup on force-mode, or if it is not linked to parent <ul> + if(node.li && (force || (node.li.parentNode !== node.parent.ul) ) ){ + if( node.li.parentNode === node.parent.ul ){ + // #486: store following node, so we can insert the new markup there later + successorLi = node.li.nextSibling; + }else{ + // May happen, when a top-level node was dropped over another + this.debug("Unlinking " + node + " (must be child of " + node.parent + ")"); + } +// this.debug("nodeRemoveMarkup..."); + this.nodeRemoveMarkup(ctx); + } + // Create <li><span /> </li> +// node.debug("render..."); + if( !node.li ) { +// node.debug("render... really"); + firstTime = true; + node.li = document.createElement("li"); + node.li.ftnode = node; + if(aria){ + // TODO: why doesn't this work: +// node.li.role = "treeitem"; +// $(node.li).attr("role", "treeitem") +// .attr("aria-labelledby", "ftal_" + node.key); + } + if( node.key && opts.generateIds ){ + node.li.id = opts.idPrefix + node.key; + } + node.span = document.createElement("span"); + node.span.className = "fancytree-node"; + if(aria){ + $(node.span).attr("aria-labelledby", "ftal_" + node.key); + } + node.li.appendChild(node.span); + + // Create inner HTML for the <span> (expander, checkbox, icon, and title) + this.nodeRenderTitle(ctx); + + // Allow tweaking and binding, after node was created for the first time + if ( opts.createNode ){ + opts.createNode.call(tree, {type: "createNode"}, ctx); + } + }else{ +// this.nodeRenderTitle(ctx); + this.nodeRenderStatus(ctx); + } + // Allow tweaking after node state was rendered + if ( opts.renderNode ){ + opts.renderNode.call(tree, {type: "renderNode"}, ctx); + } + } + + // Visit child nodes + if( children ){ + if( isRootNode || node.expanded || deep === true ) { + // Create a UL to hold the children + if( !node.ul ){ + node.ul = document.createElement("ul"); + if((collapsed === true && !_recursive) || !node.expanded){ + // hide top UL, so we can use an animation to show it later + node.ul.style.display = "none"; + } + if(aria){ + $(node.ul).attr("role", "group"); + } + if ( node.li ) { // issue #67 + node.li.appendChild(node.ul); + } else { + node.tree.$div.append(node.ul); + } + } + // Add child markup + for(i=0, l=children.length; i<l; i++) { + subCtx = $.extend({}, ctx, {node: children[i]}); + this.nodeRender(subCtx, force, deep, false, true); + } + // Remove <li> if nodes have moved to another parent + childLI = node.ul.firstChild; + while( childLI ){ + childNode2 = childLI.ftnode; + if( childNode2 && childNode2.parent !== node ) { + node.debug("_fixParent: remove missing " + childNode2, childLI); + next = childLI.nextSibling; + childLI.parentNode.removeChild(childLI); + childLI = next; + }else{ + childLI = childLI.nextSibling; + } + } + // Make sure, that <li> order matches node.children order. + childLI = node.ul.firstChild; + for(i=0, l=children.length-1; i<l; i++) { + childNode1 = children[i]; + childNode2 = childLI.ftnode; + if( childNode1 !== childNode2 ) { + // node.debug("_fixOrder: mismatch at index " + i + ": " + childNode1 + " != " + childNode2); + node.ul.insertBefore(childNode1.li, childNode2.li); + } else { + childLI = childLI.nextSibling; + } + } + } + }else{ + // No children: remove markup if any + if( node.ul ){ +// alert("remove child markup for " + node); + this.warn("remove child markup for " + node); + this.nodeRemoveChildMarkup(ctx); + } + } + if( !isRootNode ){ + // Update element classes according to node state + // this.nodeRenderStatus(ctx); + // Finally add the whole structure to the DOM, so the browser can render + if( firstTime ){ + // #486: successorLi is set, if we re-rendered (i.e. discarded) + // existing markup, which we want to insert at the same position. + // (null is equivalent to append) +// parent.ul.appendChild(node.li); + parent.ul.insertBefore(node.li, successorLi); + } + } + }, + /** Create HTML inside the node's outer <span> (i.e. expander, checkbox, + * icon, and title). + * + * nodeRenderStatus() is implied. + * @param {EventData} ctx + * @param {string} [title] optinal new title + */ + nodeRenderTitle: function(ctx, title) { + // set node connector images, links and text + var id, iconSpanClass, nodeTitle, role, tabindex, tooltip, + node = ctx.node, + tree = ctx.tree, + opts = ctx.options, + aria = opts.aria, + level = node.getLevel(), + ares = [], + iconSrc = node.data.icon; + + if(title !== undefined){ + node.title = title; + } + if(!node.span){ + // Silently bail out if node was not rendered yet, assuming + // node.render() will be called as the node becomes visible + return; + } + // connector (expanded, expandable or simple) + // TODO: optimize this if clause + if( level < opts.minExpandLevel ) { + if( !node.lazy ) { + node.expanded = true; + } + if(level > 1){ + if(aria){ + ares.push("<span role='button' class='fancytree-expander fancytree-expander-fixed'></span>"); + }else{ + ares.push("<span class='fancytree-expander fancytree-expander-fixed''></span>"); + } + } + // .. else (i.e. for root level) skip expander/connector alltogether + } else { + if(aria){ + ares.push("<span role='button' class='fancytree-expander'></span>"); + }else{ + ares.push("<span class='fancytree-expander'></span>"); + } + } + // Checkbox mode + if( opts.checkbox && node.hideCheckbox !== true && !node.isStatusNode() ) { + if(aria){ + ares.push("<span role='checkbox' class='fancytree-checkbox'></span>"); + }else{ + ares.push("<span class='fancytree-checkbox'></span>"); + } + } + // folder or doctype icon + role = aria ? " role='img'" : ""; + if( iconSrc === true || (iconSrc !== false && opts.icons !== false) ) { + // opts.icons defines the default behavior, node.icon == true/false can override this + if ( iconSrc && typeof iconSrc === "string" ) { + // node.icon is an image url + iconSrc = (iconSrc.charAt(0) === "/") ? iconSrc : ((opts.imagePath || "") + iconSrc); + ares.push("<img src='" + iconSrc + "' class='fancytree-icon' alt='' />"); + } else { + // See if node.iconclass or opts.iconClass() define a class name + iconSpanClass = (opts.iconClass && opts.iconClass.call(tree, {type: "iconClass"}, ctx)) || node.data.iconclass || null; + if( iconSpanClass ) { + ares.push("<span " + role + " class='fancytree-custom-icon " + iconSpanClass + "'></span>"); + } else { + ares.push("<span " + role + " class='fancytree-icon'></span>"); + } + } + } + + // node title + nodeTitle = ""; + if ( opts.renderTitle ){ + nodeTitle = opts.renderTitle.call(tree, {type: "renderTitle"}, ctx) || ""; + } + if(!nodeTitle){ + tooltip = node.tooltip ? " title='" + FT.escapeHtml(node.tooltip) + "'" : ""; + id = aria ? " id='ftal_" + node.key + "'" : ""; + role = aria ? " role='treeitem'" : ""; + tabindex = opts.titlesTabbable ? " tabindex='0'" : ""; + + nodeTitle = "<span " + role + " class='fancytree-title'" + id + tooltip + tabindex + ">" + node.title + "</span>"; + } + ares.push(nodeTitle); + // Note: this will trigger focusout, if node had the focus + //$(node.span).html(ares.join("")); // it will cleanup the jQuery data currently associated with SPAN (if any), but it executes more slowly + node.span.innerHTML = ares.join(""); + // Update CSS classes + this.nodeRenderStatus(ctx); + }, + /** Update element classes according to node state. + * @param {EventData} ctx + */ + nodeRenderStatus: function(ctx) { + // Set classes for current status + var node = ctx.node, + tree = ctx.tree, + opts = ctx.options, +// nodeContainer = node[tree.nodeContainerAttrName], + hasChildren = node.hasChildren(), + isLastSib = node.isLastSibling(), + aria = opts.aria, +// $ariaElem = aria ? $(node[tree.ariaPropName]) : null, + $ariaElem = $(node.span).find(".fancytree-title"), + cn = opts._classNames, + cnList = [], + statusElem = node[tree.statusClassPropName]; + + if( !statusElem ){ + // if this function is called for an unrendered node, ignore it (will be updated on nect render anyway) + return; + } + // Build a list of class names that we will add to the node <span> + cnList.push(cn.node); + if( tree.activeNode === node ){ + cnList.push(cn.active); +// $(">span.fancytree-title", statusElem).attr("tabindex", "0"); +// tree.$container.removeAttr("tabindex"); + // }else{ +// $(">span.fancytree-title", statusElem).removeAttr("tabindex"); +// tree.$container.attr("tabindex", "0"); + } + if( tree.focusNode === node ){ + cnList.push(cn.focused); + if(aria){ +// $(">span.fancytree-title", statusElem).attr("tabindex", "0"); +// $(">span.fancytree-title", statusElem).attr("tabindex", "-1"); + // TODO: is this the right element for this attribute? + $ariaElem + .attr("aria-activedescendant", true); +// .attr("tabindex", "-1"); + } + }else if(aria){ +// $(">span.fancytree-title", statusElem).attr("tabindex", "-1"); + $ariaElem + .removeAttr("aria-activedescendant"); +// .removeAttr("tabindex"); + } + if( node.expanded ){ + cnList.push(cn.expanded); + if(aria){ + $ariaElem.attr("aria-expanded", true); + } + }else if(aria){ + $ariaElem.removeAttr("aria-expanded"); + } + if( node.folder ){ + cnList.push(cn.folder); + } + if( hasChildren !== false ){ + cnList.push(cn.hasChildren); + } + // TODO: required? + if( isLastSib ){ + cnList.push(cn.lastsib); + } + if( node.lazy && node.children == null ){ + cnList.push(cn.lazy); + } + if( node.partsel ){ + cnList.push(cn.partsel); + } + if( node.unselectable ){ + cnList.push(cn.unselectable); + } + if( node._isLoading ){ + cnList.push(cn.loading); + } + if( node._error ){ + cnList.push(cn.error); + } + if( node.selected ){ + cnList.push(cn.selected); + if(aria){ + $ariaElem.attr("aria-selected", true); + } + }else if(aria){ + $ariaElem.attr("aria-selected", false); + } + if( node.extraClasses ){ + cnList.push(node.extraClasses); + } + // IE6 doesn't correctly evaluate multiple class names, + // so we create combined class names that can be used in the CSS + if( hasChildren === false ){ + cnList.push(cn.combinedExpanderPrefix + "n" + + (isLastSib ? "l" : "") + ); + }else{ + cnList.push(cn.combinedExpanderPrefix + + (node.expanded ? "e" : "c") + + (node.lazy && node.children == null ? "d" : "") + + (isLastSib ? "l" : "") + ); + } + cnList.push(cn.combinedIconPrefix + + (node.expanded ? "e" : "c") + + (node.folder ? "f" : "") + ); +// node.span.className = cnList.join(" "); + statusElem.className = cnList.join(" "); + + // TODO: we should not set this in the <span> tag also, if we set it here: + // Maybe most (all) of the classes should be set in LI instead of SPAN? + if(node.li){ + node.li.className = isLastSib ? cn.lastsib : ""; + } + }, + /** Activate node. + * flag defaults to true. + * If flag is true, the node is activated (must be a synchronous operation) + * If flag is false, the node is deactivated (must be a synchronous operation) + * @param {EventData} ctx + * @param {boolean} [flag=true] + * @param {object} [opts] additional options. Defaults to {noEvents: false, noFocus: false} + * @returns {$.Promise} + */ + nodeSetActive: function(ctx, flag, callOpts) { + // Handle user click / [space] / [enter], according to clickFolderMode. + callOpts = callOpts || {}; + var subCtx, + node = ctx.node, + tree = ctx.tree, + opts = ctx.options, + noEvents = (callOpts.noEvents === true), + noFocus = (callOpts.noFocus === true), + isActive = (node === tree.activeNode); + + // flag defaults to true + flag = (flag !== false); + // node.debug("nodeSetActive", flag); + + if(isActive === flag){ + // Nothing to do + return _getResolvedPromise(node); + }else if(flag && !noEvents && this._triggerNodeEvent("beforeActivate", node, ctx.originalEvent) === false ){ + // Callback returned false + return _getRejectedPromise(node, ["rejected"]); + } + if(flag){ + if(tree.activeNode){ + _assert(tree.activeNode !== node, "node was active (inconsistency)"); + subCtx = $.extend({}, ctx, {node: tree.activeNode}); + tree.nodeSetActive(subCtx, false); + _assert(tree.activeNode === null, "deactivate was out of sync?"); + } + if(opts.activeVisible){ + // tree.nodeMakeVisible(ctx); + node.makeVisible({scrollIntoView: false}); // nodeSetFocus will scroll + } + tree.activeNode = node; + tree.nodeRenderStatus(ctx); + if( !noFocus ) { + tree.nodeSetFocus(ctx); + } + if( !noEvents ) { + tree._triggerNodeEvent("activate", node, ctx.originalEvent); + } + }else{ + _assert(tree.activeNode === node, "node was not active (inconsistency)"); + tree.activeNode = null; + this.nodeRenderStatus(ctx); + if( !noEvents ) { + ctx.tree._triggerNodeEvent("deactivate", node, ctx.originalEvent); + } + } + return _getResolvedPromise(node); + }, + /** Expand or collapse node, return Deferred.promise. + * + * @param {EventData} ctx + * @param {boolean} [flag=true] + * @param {object} [opts] additional options. Defaults to {noAnimation: false, noEvents: false} + * @returns {$.Promise} The deferred will be resolved as soon as the (lazy) + * data was retrieved, rendered, and the expand animation finshed. + */ + nodeSetExpanded: function(ctx, flag, callOpts) { + callOpts = callOpts || {}; + var _afterLoad, dfd, i, l, parents, prevAC, + node = ctx.node, + tree = ctx.tree, + opts = ctx.options, + noAnimation = (callOpts.noAnimation === true), + noEvents = (callOpts.noEvents === true); + + // flag defaults to true + flag = (flag !== false); + + // node.debug("nodeSetExpanded(" + flag + ")"); + + if((node.expanded && flag) || (!node.expanded && !flag)){ + // Nothing to do + // node.debug("nodeSetExpanded(" + flag + "): nothing to do"); + return _getResolvedPromise(node); + }else if(flag && !node.lazy && !node.hasChildren() ){ + // Prevent expanding of empty nodes + // return _getRejectedPromise(node, ["empty"]); + return _getResolvedPromise(node); + }else if( !flag && node.getLevel() < opts.minExpandLevel ) { + // Prevent collapsing locked levels + return _getRejectedPromise(node, ["locked"]); + }else if ( !noEvents && this._triggerNodeEvent("beforeExpand", node, ctx.originalEvent) === false ){ + // Callback returned false + return _getRejectedPromise(node, ["rejected"]); + } + // If this node inside a collpased node, no animation and scrolling is needed + if( !noAnimation && !node.isVisible() ) { + noAnimation = callOpts.noAnimation = true; + } + + dfd = new $.Deferred(); + + // Auto-collapse mode: collapse all siblings + if( flag && !node.expanded && opts.autoCollapse ) { + parents = node.getParentList(false, true); + prevAC = opts.autoCollapse; + try{ + opts.autoCollapse = false; + for(i=0, l=parents.length; i<l; i++){ + // TODO: should return promise? + this._callHook("nodeCollapseSiblings", parents[i], callOpts); + } + }finally{ + opts.autoCollapse = prevAC; + } + } + // Trigger expand/collapse after expanding + dfd.done(function(){ + var lastChild = node.getLastChild(); + if( flag && opts.autoScroll && !noAnimation && lastChild ) { + // Scroll down to last child, but keep current node visible + lastChild.scrollIntoView(true, {topNode: node}).always(function(){ + if( !noEvents ) { + ctx.tree._triggerNodeEvent(flag ? "expand" : "collapse", ctx); + } + }); + } else { + if( !noEvents ) { + ctx.tree._triggerNodeEvent(flag ? "expand" : "collapse", ctx); + } + } + }); + // vvv Code below is executed after loading finished: + _afterLoad = function(callback){ + var isVisible, isExpanded, + effect = opts.toggleEffect; + + node.expanded = flag; + // Create required markup, but make sure the top UL is hidden, so we + // can animate later + tree._callHook("nodeRender", ctx, false, false, true); + + // If the currently active node is now hidden, deactivate it + // if( opts.activeVisible && this.activeNode && ! this.activeNode.isVisible() ) { + // this.activeNode.deactivate(); + // } + + // Expanding a lazy node: set 'loading...' and call callback + // if( bExpand && this.data.isLazy && this.childList === null && !this._isLoading ) { + // this._loadContent(); + // return; + // } + // Hide children, if node is collapsed + if( node.ul ) { + isVisible = (node.ul.style.display !== "none"); + isExpanded = !!node.expanded; + if ( isVisible === isExpanded ) { + node.warn("nodeSetExpanded: UL.style.display already set"); + + } else if ( !effect || noAnimation ) { + node.ul.style.display = ( node.expanded || !parent ) ? "" : "none"; + + } else { + // The UI toggle() effect works with the ext-wide extension, + // while jQuery.animate() has problems when the title span + // has positon: absolute + + // duration = opts.fx.duration || 200; + // easing = opts.fx.easing; + // $(node.ul).animate(opts.fx, duration, easing, function(){ + + // node.debug("nodeSetExpanded: animate start..."); + $(node.ul).toggle(effect.effect, effect.options, effect.duration, function(){ + // node.debug("nodeSetExpanded: animate done"); + callback(); + }); + return; + } + } + callback(); + }; + // ^^^ Code above is executed after loading finshed. + + // Load lazy nodes, if any. Then continue with _afterLoad() + if(flag && node.lazy && node.hasChildren() === undefined){ + // node.debug("nodeSetExpanded: load start..."); + node.load().done(function(){ + // node.debug("nodeSetExpanded: load done"); + if(dfd.notifyWith){ // requires jQuery 1.6+ + dfd.notifyWith(node, ["loaded"]); + } + _afterLoad(function () { dfd.resolveWith(node); }); + }).fail(function(errMsg){ + _afterLoad(function () { dfd.rejectWith(node, ["load failed (" + errMsg + ")"]); }); + }); +/* + var source = tree._triggerNodeEvent("lazyLoad", node, ctx.originalEvent); + _assert(typeof source !== "boolean", "lazyLoad event must return source in data.result"); + node.debug("nodeSetExpanded: load start..."); + this._callHook("nodeLoadChildren", ctx, source).done(function(){ + node.debug("nodeSetExpanded: load done"); + if(dfd.notifyWith){ // requires jQuery 1.6+ + dfd.notifyWith(node, ["loaded"]); + } + _afterLoad.call(tree); + }).fail(function(errMsg){ + dfd.rejectWith(node, ["load failed (" + errMsg + ")"]); + }); +*/ + }else{ + _afterLoad(function () { dfd.resolveWith(node); }); + } + // node.debug("nodeSetExpanded: returns"); + return dfd.promise(); + }, + /** Focus or blur this node. + * @param {EventData} ctx + * @param {boolean} [flag=true] + */ + nodeSetFocus: function(ctx, flag) { + // ctx.node.debug("nodeSetFocus(" + flag + ")"); + var ctx2, + tree = ctx.tree, + node = ctx.node; + + flag = (flag !== false); + + // Blur previous node if any + if(tree.focusNode){ + if(tree.focusNode === node && flag){ + // node.debug("nodeSetFocus(" + flag + "): nothing to do"); + return; + } + ctx2 = $.extend({}, ctx, {node: tree.focusNode}); + tree.focusNode = null; + this._triggerNodeEvent("blur", ctx2); + this._callHook("nodeRenderStatus", ctx2); + } + // Set focus to container and node + if(flag){ + if( !this.hasFocus() ){ + node.debug("nodeSetFocus: forcing container focus"); + this._callHook("treeSetFocus", ctx, true, {calledByNode: true}); + } + node.makeVisible({scrollIntoView: false}); + tree.focusNode = node; +// node.debug("FOCUS..."); +// $(node.span).find(".fancytree-title").focus(); + this._triggerNodeEvent("focus", ctx); +// if(ctx.options.autoActivate){ +// tree.nodeSetActive(ctx, true); +// } + if(ctx.options.autoScroll){ + node.scrollIntoView(); + } + this._callHook("nodeRenderStatus", ctx); + } + }, + /** (De)Select node, return new status (sync). + * + * @param {EventData} ctx + * @param {boolean} [flag=true] + */ + nodeSetSelected: function(ctx, flag) { + var node = ctx.node, + tree = ctx.tree, + opts = ctx.options; + // flag defaults to true + flag = (flag !== false); + + node.debug("nodeSetSelected(" + flag + ")", ctx); + if( node.unselectable){ + return; + } + // TODO: !!node.expanded is nicer, but doesn't pass jshint + // https://github.com/jshint/jshint/issues/455 +// if( !!node.expanded === !!flag){ + if((node.selected && flag) || (!node.selected && !flag)){ + return !!node.selected; + }else if ( this._triggerNodeEvent("beforeSelect", node, ctx.originalEvent) === false ){ + return !!node.selected; + } + if(flag && opts.selectMode === 1){ + // single selection mode + if(tree.lastSelectedNode){ + tree.lastSelectedNode.setSelected(false); + } + }else if(opts.selectMode === 3){ + // multi.hier selection mode + node.selected = flag; +// this._fixSelectionState(node); + node.fixSelection3AfterClick(); + } + node.selected = flag; + this.nodeRenderStatus(ctx); + tree.lastSelectedNode = flag ? node : null; + tree._triggerNodeEvent("select", ctx); + }, + /** Show node status (ok, loading, error) using styles and a dummy child node. + * + * @param {EventData} ctx + * @param status + * @param message + * @param details + * @since 2.3 + */ + nodeSetStatus: function(ctx, status, message, details) { + var node = ctx.node, + tree = ctx.tree; + // cn = ctx.options._classNames; + + function _clearStatusNode() { + // Remove dedicated dummy node, if any + var firstChild = ( node.children ? node.children[0] : null ); + if ( firstChild && firstChild.isStatusNode() ) { + try{ + // I've seen exceptions here with loadKeyPath... + if(node.ul){ + node.ul.removeChild(firstChild.li); + firstChild.li = null; // avoid leaks (DT issue 215) + } + }catch(e){} + if( node.children.length === 1 ){ + node.children = []; + }else{ + node.children.shift(); + } + } + } + function _setStatusNode(data, type) { + // Create/modify the dedicated dummy node for 'loading...' or + // 'error!' status. (only called for direct child of the invisible + // system root) + var firstChild = ( node.children ? node.children[0] : null ); + if ( firstChild && firstChild.isStatusNode() ) { + $.extend(firstChild, data); + // tree._callHook("nodeRender", firstChild); + tree._callHook("nodeRenderTitle", firstChild); + } else { + data.key = "_statusNode"; + node._setChildren([data]); + node.children[0].statusNodeType = type; + tree.render(); + } + return node.children[0]; + } + + switch( status ){ + case "ok": + _clearStatusNode(); + // $(node.span).removeClass(cn.loading).removeClass(cn.error); + node._isLoading = false; + node._error = null; + node.renderStatus(); + break; + case "loading": + // $(node.span).removeClass(cn.error).addClass(cn.loading); + if( !node.parent ) { + _setStatusNode({ + title: tree.options.strings.loading + (message ? " (" + message + ") " : ""), + tooltip: details, + extraClasses: "fancytree-statusnode-wait" + }, status); + } + node._isLoading = true; + node._error = null; + node.renderStatus(); + break; + case "error": + // $(node.span).removeClass(cn.loading).addClass(cn.error); + _setStatusNode({ + title: tree.options.strings.loadError + (message ? " (" + message + ") " : ""), + tooltip: details, + extraClasses: "fancytree-statusnode-error" + }, status); + node._isLoading = false; + node._error = { message: message, details: details }; + node.renderStatus(); + break; + default: + $.error("invalid node status " + status); + } + }, + /** + * + * @param {EventData} ctx + */ + nodeToggleExpanded: function(ctx) { + return this.nodeSetExpanded(ctx, !ctx.node.expanded); + }, + /** + * @param {EventData} ctx + */ + nodeToggleSelected: function(ctx) { + return this.nodeSetSelected(ctx, !ctx.node.selected); + }, + /** Remove all nodes. + * @param {EventData} ctx + */ + treeClear: function(ctx) { + var tree = ctx.tree; + tree.activeNode = null; + tree.focusNode = null; + tree.$div.find(">ul.fancytree-container").empty(); + // TODO: call destructors and remove reference loops + tree.rootNode.children = null; + }, + /** Widget was created (called only once, even it re-initialized). + * @param {EventData} ctx + */ + treeCreate: function(ctx) { + }, + /** Widget was destroyed. + * @param {EventData} ctx + */ + treeDestroy: function(ctx) { + this.$div.find(">ul.fancytree-container").remove(); + this.$source && this.$source.removeClass("ui-helper-hidden"); + }, + /** Widget was (re-)initialized. + * @param {EventData} ctx + */ + treeInit: function(ctx) { + //this.debug("Fancytree.treeInit()"); + this.treeLoad(ctx); + }, + /** Parse Fancytree from source, as configured in the options. + * @param {EventData} ctx + * @param {object} [source] optional new source (use last data otherwise) + */ + treeLoad: function(ctx, source) { + var type, $ul, + tree = ctx.tree, + $container = ctx.widget.element, + dfd, + // calling context for root node + rootCtx = $.extend({}, ctx, {node: this.rootNode}); + + if(tree.rootNode.children){ + this.treeClear(ctx); + } + source = source || this.options.source; + + if(!source){ + type = $container.data("type") || "html"; + switch(type){ + case "html": + $ul = $container.find(">ul:first"); + $ul.addClass("ui-fancytree-source ui-helper-hidden"); + source = $.ui.fancytree.parseHtml($ul); + // allow to init tree.data.foo from <ul data-foo=''> + this.data = $.extend(this.data, _getElementDataAsDict($ul)); + break; + case "json": + // $().addClass("ui-helper-hidden"); + source = $.parseJSON($container.text()); + if(source.children){ + if(source.title){tree.title = source.title;} + source = source.children; + } + break; + default: + $.error("Invalid data-type: " + type); + } + }else if(typeof source === "string"){ + // TODO: source is an element ID + $.error("Not implemented"); + } + + // Trigger fancytreeinit after nodes have been loaded + dfd = this.nodeLoadChildren(rootCtx, source).done(function(){ + tree.render(); + if( ctx.options.selectMode === 3 ){ + tree.rootNode.fixSelection3FromEndNodes(); + } + if( tree.activeNode && tree.options.activeVisible ) { + tree.activeNode.makeVisible(); + } + tree._triggerTreeEvent("init", null, { status: true }); + }).fail(function(){ + tree.render(); + tree._triggerTreeEvent("init", null, { status: false }); + }); + return dfd; + }, + /** Node was inserted into or removed from the tree. + * @param {EventData} ctx + * @param {boolean} add + * @param {FancytreeNode} node + */ + treeRegisterNode: function(ctx, add, node) { + }, + /** Widget got focus. + * @param {EventData} ctx + * @param {boolean} [flag=true] + */ + treeSetFocus: function(ctx, flag, callOpts) { + flag = (flag !== false); + + // this.debug("treeSetFocus(" + flag + "), callOpts: " + callOpts, this.hasFocus()); + // this.debug(" focusNode: " + this.focusNode); + // this.debug(" activeNode: " + this.activeNode); + if( flag !== this.hasFocus() ){ + this._hasFocus = flag; + if( !flag && this.focusNode ) { + // Node also looses focus if widget blurs + this.focusNode.setFocus(false); + } + this.$container.toggleClass("fancytree-treefocus", flag); + this._triggerTreeEvent(flag ? "focusTree" : "blurTree"); + } + } +}); + + +/* ****************************************************************************** + * jQuery UI widget boilerplate + */ + +/** + * The plugin (derrived from <a href=" http://api.jqueryui.com/jQuery.widget/">jQuery.Widget</a>).<br> + * This constructor is not called directly. Use `$(selector).fancytree({})` + * to initialize the plugin instead.<br> + * <pre class="sh_javascript sunlight-highlight-javascript">// Access widget methods and members: + * var tree = $("#tree").fancytree("getTree"); + * var node = $("#tree").fancytree("getActiveNode", "1234"); + * </pre> + * + * @mixin Fancytree_Widget + */ + +$.widget("ui.fancytree", + /** @lends Fancytree_Widget# */ + { + /**These options will be used as defaults + * @type {FancytreeOptions} + */ + options: + { + activeVisible: true, + ajax: { + type: "GET", + cache: false, // false: Append random '_' argument to the request url to prevent caching. +// timeout: 0, // >0: Make sure we get an ajax error if server is unreachable + dataType: "json" // Expect json format and pass json object to callbacks. + }, // + aria: false, // TODO: default to true + autoActivate: true, + autoCollapse: false, +// autoFocus: false, + autoScroll: false, + checkbox: false, + /**defines click behavior*/ + clickFolderMode: 4, + debugLevel: null, // 0..2 (null: use global setting $.ui.fancytree.debugInfo) + disabled: false, // TODO: required anymore? + enableAspx: true, // TODO: document + extensions: [], + // fx: { height: "toggle", duration: 200 }, + // toggleEffect: { effect: "drop", options: {direction: "left"}, duration: 200 }, + // toggleEffect: { effect: "slide", options: {direction: "up"}, duration: 200 }, + toggleEffect: { effect: "blind", options: {direction: "vertical", scale: "box"}, duration: 200 }, + generateIds: false, + icons: true, + idPrefix: "ft_", + focusOnSelect: false, + keyboard: true, + keyPathSeparator: "/", + minExpandLevel: 1, + quicksearch: false, + scrollOfs: {top: 0, bottom: 0}, + scrollParent: null, + selectMode: 2, + strings: { + loading: "Loading…", + loadError: "Load error!" + }, + tabbable: true, + titlesTabbable: false, + _classNames: { + node: "fancytree-node", + folder: "fancytree-folder", + combinedExpanderPrefix: "fancytree-exp-", + combinedIconPrefix: "fancytree-ico-", + hasChildren: "fancytree-has-children", + active: "fancytree-active", + selected: "fancytree-selected", + expanded: "fancytree-expanded", + lazy: "fancytree-lazy", + focused: "fancytree-focused", + partsel: "fancytree-partsel", + unselectable: "fancytree-unselectable", + lastsib: "fancytree-lastsib", + loading: "fancytree-loading", + error: "fancytree-error" + }, + // events + lazyLoad: null, + postProcess: null + }, + /* Set up the widget, Called on first $().fancytree() */ + _create: function() { + this.tree = new Fancytree(this); + + this.$source = this.source || this.element.data("type") === "json" ? this.element + : this.element.find(">ul:first"); + // Subclass Fancytree instance with all enabled extensions + var extension, extName, i, + extensions = this.options.extensions, + base = this.tree; + + for(i=0; i<extensions.length; i++){ + extName = extensions[i]; + extension = $.ui.fancytree._extensions[extName]; + if(!extension){ + $.error("Could not apply extension '" + extName + "' (it is not registered, did you forget to include it?)"); + } + // Add extension options as tree.options.EXTENSION +// _assert(!this.tree.options[extName], "Extension name must not exist as option name: " + extName); + this.tree.options[extName] = $.extend(true, {}, extension.options, this.tree.options[extName]); + // Add a namespace tree.ext.EXTENSION, to hold instance data + _assert(this.tree.ext[extName] === undefined, "Extension name must not exist as Fancytree.ext attribute: '" + extName + "'"); +// this.tree[extName] = extension; + this.tree.ext[extName] = {}; + // Subclass Fancytree methods using proxies. + _subclassObject(this.tree, base, extension, extName); + // current extension becomes base for the next extension + base = extension; + } + // + this.tree._callHook("treeCreate", this.tree); + // Note: 'fancytreecreate' event is fired by widget base class +// this.tree._triggerTreeEvent("create"); + }, + + /* Called on every $().fancytree() */ + _init: function() { + this.tree._callHook("treeInit", this.tree); + // TODO: currently we call bind after treeInit, because treeInit + // might change tree.$container. + // It would be better, to move ebent binding into hooks altogether + this._bind(); + }, + + /* Use the _setOption method to respond to changes to options */ + _setOption: function(key, value) { + var callDefault = true, + rerender = false; + switch( key ) { + case "aria": + case "checkbox": + case "icons": + case "minExpandLevel": + case "tabbable": +// case "nolink": + this.tree._callHook("treeCreate", this.tree); + rerender = true; + break; + case "source": + callDefault = false; + this.tree._callHook("treeLoad", this.tree, value); + break; + } + this.tree.debug("set option " + key + "=" + value + " <" + typeof(value) + ">"); + if(callDefault){ + // In jQuery UI 1.8, you have to manually invoke the _setOption method from the base widget + $.Widget.prototype._setOption.apply(this, arguments); + // TODO: In jQuery UI 1.9 and above, you use the _super method instead +// this._super( "_setOption", key, value ); + } + if(rerender){ + this.tree.render(true, false); // force, not-deep + } + }, + + /** Use the destroy method to clean up any modifications your widget has made to the DOM */ + destroy: function() { + this._unbind(); + this.tree._callHook("treeDestroy", this.tree); + // In jQuery UI 1.8, you must invoke the destroy method from the base widget + $.Widget.prototype.destroy.call(this); + // TODO: delete tree and nodes to make garbage collect easier? + // TODO: In jQuery UI 1.9 and above, you would define _destroy instead of destroy and not call the base method + }, + + // ------------------------------------------------------------------------- + + /* Remove all event handlers for our namespace */ + _unbind: function() { + var ns = this.tree._ns; + this.element.unbind(ns); + this.tree.$container.unbind(ns); + $(document).unbind(ns); + }, + /* Add mouse and kyboard handlers to the container */ + _bind: function() { + var that = this, + opts = this.options, + tree = this.tree, + ns = tree._ns + // selstartEvent = ( $.support.selectstart ? "selectstart" : "mousedown" ) + ; + + // Remove all previuous handlers for this tree + this._unbind(); + + //alert("keydown" + ns + "foc=" + tree.hasFocus() + tree.$container); + // tree.debug("bind events; container: ", tree.$container); + tree.$container.on("focusin" + ns + " focusout" + ns, function(event){ + var node = FT.getNode(event), + flag = (event.type === "focusin"); + // tree.debug("Tree container got event " + event.type, node, event); + // tree.treeOnFocusInOut.call(tree, event); + if(node){ + // For example clicking into an <input> that is part of a node + tree._callHook("nodeSetFocus", node, flag); + }else{ + tree._callHook("treeSetFocus", tree, flag); + } + }).on("selectstart" + ns, "span.fancytree-title", function(event){ + // prevent mouse-drags to select text ranges + // tree.debug("<span title> got event " + event.type); + event.preventDefault(); + }).on("keydown" + ns, function(event){ + // TODO: also bind keyup and keypress + // tree.debug("got event " + event.type + ", hasFocus:" + tree.hasFocus()); + // if(opts.disabled || opts.keyboard === false || !tree.hasFocus() ){ + if(opts.disabled || opts.keyboard === false ){ + return true; + } + var res, + node = tree.focusNode, // node may be null + ctx = tree._makeHookContext(node || tree, event), + prevPhase = tree.phase; + + try { + tree.phase = "userEvent"; + // If a 'fancytreekeydown' handler returns false, skip the default + // handling (implemented by tree.nodeKeydown()). + if(node){ + res = tree._triggerNodeEvent("keydown", node, event); + }else{ + res = tree._triggerTreeEvent("keydown", event); + } + if ( res === "preventNav" ){ + res = true; // prevent keyboard navigation, but don't prevent default handling of embedded input controls + } else if ( res !== false ){ + res = tree._callHook("nodeKeydown", ctx); + } + return res; + } finally { + tree.phase = prevPhase; + } + }).on("click" + ns + " dblclick" + ns, function(event){ + // that.tree.debug("event(" + event + "): !"); + if(opts.disabled){ + return true; + } + var ctx, + et = FT.getEventTarget(event), + node = et.node, + tree = that.tree, + prevPhase = tree.phase; + + // that.tree.debug("event(" + event.type + "): node: ", node); + if( !node ){ + return true; // Allow bubbling of other events + } + ctx = tree._makeHookContext(node, event); +// that.tree.debug("event(" + event.type + "): node: ", node); + try { + tree.phase = "userEvent"; + switch(event.type) { + case "click": + ctx.targetType = et.type; + return ( tree._triggerNodeEvent("click", ctx, event) === false ) ? false : tree._callHook("nodeClick", ctx); + case "dblclick": + ctx.targetType = et.type; + return ( tree._triggerNodeEvent("dblclick", ctx, event) === false ) ? false : tree._callHook("nodeDblclick", ctx); + } +// } catch(e) { +// // var _ = null; // DT issue 117 // TODO +// $.error(e); + } finally { + tree.phase = prevPhase; + } + }); + }, + /** Return the active node or null. + * @returns {FancytreeNode} + */ + getActiveNode: function() { + return this.tree.activeNode; + }, + /** Return the matching node or null. + * @param {string} key + * @returns {FancytreeNode} + */ + getNodeByKey: function(key) { + return this.tree.getNodeByKey(key); + }, + /** Return the invisible system root node. + * @returns {FancytreeNode} + */ + getRootNode: function() { + return this.tree.rootNode; + }, + /** Return the current tree instance. + * @returns {Fancytree} + */ + getTree: function() { + return this.tree; + } +}); + +// $.ui.fancytree was created by the widget factory. Create a local shortcut: +FT = $.ui.fancytree; + +/** + * Static members in the `$.ui.fancytree` namespace.<br> + * <br> + * <pre class="sh_javascript sunlight-highlight-javascript">// Access static members: + * var node = $.ui.fancytree.getNode(element); + * alert($.ui.fancytree.version); + * </pre> + * + * @mixin Fancytree_Static + */ +$.extend($.ui.fancytree, + /** @lends Fancytree_Static# */ + { + /** @type {string} */ + version: "2.13.0", // Set to semver by 'grunt release' + /** @type {string} */ + buildType: "production", // Set to 'production' by 'grunt build' + /** @type {int} */ + debugLevel: 1, // Set to 1 by 'grunt build' + // Used by $.ui.fancytree.debug() and as default for tree.options.debugLevel + + _nextId: 1, + _nextNodeKey: 1, + _extensions: {}, + // focusTree: null, + + /** Expose class object as $.ui.fancytree._FancytreeClass */ + _FancytreeClass: Fancytree, + /** Expose class object as $.ui.fancytree._FancytreeNodeClass */ + _FancytreeNodeClass: FancytreeNode, + /* Feature checks to provide backwards compatibility */ + jquerySupports: { + // http://jqueryui.com/upgrade-guide/1.9/#deprecated-offset-option-merged-into-my-and-at + positionMyOfs: isVersionAtLeast($.ui.version, 1, 9) + }, + /** Throw an error if condition fails (debug method). + * @param {boolean} cond + * @param {string} msg + */ + assert: function(cond, msg){ + return _assert(cond, msg); + }, + /** Return a function that executes *fn* at most every *timeout* ms. + * @param {integer} timeout + * @param {function} fn + * @param {boolean} [invokeAsap=false] + * @param {any} [ctx] + */ + debounce: function(timeout, fn, invokeAsap, ctx) { + var timer; + if(arguments.length === 3 && typeof invokeAsap !== "boolean") { + ctx = invokeAsap; + invokeAsap = false; + } + return function() { + var args = arguments; + ctx = ctx || this; + invokeAsap && !timer && fn.apply(ctx, args); + clearTimeout(timer); + timer = setTimeout(function() { + invokeAsap || fn.apply(ctx, args); + timer = null; + }, timeout); + }; + }, + /** Write message to console if debugLevel >= 2 + * @param {string} msg + */ + debug: function(msg){ + /*jshint expr:true */ + ($.ui.fancytree.debugLevel >= 2) && consoleApply("log", arguments); + }, + /** Write error message to console. + * @param {string} msg + */ + error: function(msg){ + consoleApply("error", arguments); + }, + /** Convert <, >, &, ", ', / to the equivalent entities. + * + * @param {string} s + * @returns {string} + */ + escapeHtml: function(s){ + return ("" + s).replace(/[&<>"'\/]/g, function (s) { + return ENTITY_MAP[s]; + }); + }, + /** Make jQuery.position() arguments backwards compatible, i.e. if + * jQuery UI version <= 1.8, convert + * { my: "left+3 center", at: "left bottom", of: $target } + * to + * { my: "left center", at: "left bottom", of: $target, offset: "3 0" } + * + * See http://jqueryui.com/upgrade-guide/1.9/#deprecated-offset-option-merged-into-my-and-at + * and http://jsfiddle.net/mar10/6xtu9a4e/ + */ + fixPositionOptions: function(opts) { + if( opts.offset || ("" + opts.my + opts.at ).indexOf("%") >= 0 ) { + $.error("expected new position syntax (but '%' is not supported)"); + } + if( ! $.ui.fancytree.jquerySupports.positionMyOfs ) { + var // parse 'left+3 center' into ['left+3 center', 'left', '+3', 'center', undefined] + myParts = /(\w+)([+-]?\d+)?\s+(\w+)([+-]?\d+)?/.exec(opts.my), + atParts = /(\w+)([+-]?\d+)?\s+(\w+)([+-]?\d+)?/.exec(opts.at), + // convert to numbers + dx = (myParts[2] ? (+myParts[2]) : 0) + (atParts[2] ? (+atParts[2]) : 0), + dy = (myParts[4] ? (+myParts[4]) : 0) + (atParts[4] ? (+atParts[4]) : 0); + + opts = $.extend({}, opts, { // make a copy and overwrite + my: myParts[1] + " " + myParts[3], + at: atParts[1] + " " + atParts[3] + }); + if( dx || dy ) { + opts.offset = "" + dx + " " + dy; + } + } + return opts; + }, + /** Return a {node: FancytreeNode, type: TYPE} object for a mouse event. + * + * @param {Event} event Mouse event, e.g. click, ... + * @returns {string} 'title' | 'prefix' | 'expander' | 'checkbox' | 'icon' | undefined + */ + getEventTargetType: function(event){ + return this.getEventTarget(event).type; + }, + /** Return a {node: FancytreeNode, type: TYPE} object for a mouse event. + * + * @param {Event} event Mouse event, e.g. click, ... + * @returns {object} Return a {node: FancytreeNode, type: TYPE} object + * TYPE: 'title' | 'prefix' | 'expander' | 'checkbox' | 'icon' | undefined + */ + getEventTarget: function(event){ + var tcn = event && event.target ? event.target.className : "", + res = {node: this.getNode(event.target), type: undefined}; + // We use a fast version of $(res.node).hasClass() + // See http://jsperf.com/test-for-classname/2 + if( /\bfancytree-title\b/.test(tcn) ){ + res.type = "title"; + }else if( /\bfancytree-expander\b/.test(tcn) ){ + res.type = (res.node.hasChildren() === false ? "prefix" : "expander"); + }else if( /\bfancytree-checkbox\b/.test(tcn) || /\bfancytree-radio\b/.test(tcn) ){ + res.type = "checkbox"; + }else if( /\bfancytree-icon\b/.test(tcn) ){ + res.type = "icon"; + }else if( /\bfancytree-node\b/.test(tcn) ){ + // Somewhere near the title + res.type = "title"; + }else if( event && event.target && $(event.target).closest(".fancytree-title").length ) { + // #228: clicking an embedded element inside a title + res.type = "title"; + } + return res; + }, + /** Return a FancytreeNode instance from element, event, or jQuery object. + * + * @param {Element | jQueryObject | Event} el + * @returns {FancytreeNode} matching node or null + */ + getNode: function(el){ + if(el instanceof FancytreeNode){ + return el; // el already was a FancytreeNode + }else if(el.selector !== undefined){ + el = el[0]; // el was a jQuery object: use the DOM element + }else if(el.originalEvent !== undefined){ + el = el.target; // el was an Event + } + while( el ) { + if(el.ftnode) { + return el.ftnode; + } + el = el.parentNode; + } + return null; + }, + /** Return a Fancytree instance, from element, index, event, or jQueryObject. + * + * @param {Element | jQueryObject | Event | integer | string} [el] + * @returns {Fancytree} matching tree or null + * @example + * $.ui.fancytree.getTree(); // Get first Fancytree instance on page + * $.ui.fancytree.getTree(1); // Get second Fancytree instance on page + * $.ui.fancytree.getTree("#tree"); // Get tree for this matching element + * + * @since 2.13 + */ + getTree: function(el){ + var widget; + + if( el instanceof Fancytree ) { + return el; // el already was a Fancytree + } + if( el === undefined ) { + el = 0; // get first tree + } + if( typeof el === "number" ) { + el = $(".fancytree-container").eq(el); // el was an integer: return nth instance + } else if( typeof el === "string" ) { + el = $(el).eq(0); // el was a selector: use first match + } else if( el.selector !== undefined ) { + el = el.eq(0); // el was a jQuery object: use the first DOM element + } else if( el.originalEvent !== undefined ) { + el = $(el.target); // el was an Event + } + el = el.closest(":ui-fancytree"); + widget = el.data("ui-fancytree") || el.data("fancytree"); // the latter is required by jQuery <= 1.8 + return widget ? widget.tree : null; + }, + /** Write message to console if debugLevel >= 1 + * @param {string} msg + */ + info: function(msg){ + /*jshint expr:true */ + ($.ui.fancytree.debugLevel >= 1) && consoleApply("info", arguments); + }, + /** Convert a keydown or mouse event to a canonical string like 'ctrl+a', 'ctrl+shift+f2', 'shift+leftdblclick'. + * This is especially handy for switch-statements in event handlers. + * @param {event} + * @returns {string} + */ + eventToString: function(event) { + // Poor-man's hotkeys. See here for a complete implementation: + // https://github.com/jeresig/jquery.hotkeys + var which = event.which, + et = event.type, + s = []; + + if( event.altKey ) { s.push("alt"); } + if( event.ctrlKey ) { s.push("ctrl"); } + if( event.metaKey ) { s.push("meta"); } + if( event.shiftKey ) { s.push("shift"); } + + if( et === "click" || et === "dblclick" ) { + s.push(MOUSE_BUTTONS[event.button] + et); + } else { + if( !IGNORE_KEYCODES[which] ) { + s.push( SPECIAL_KEYCODES[which] || String.fromCharCode(which).toLowerCase() ); + } + } + return s.join("+"); + }, + /* @deprecated: use eventToString(event) instead. + */ + keyEventToString: function(event) { + this.warn("keyEventToString() is deprecated: use eventToString()"); + return this.eventToString(event); + }, + /** + * Parse tree data from HTML <ul> markup + * + * @param {jQueryObject} $ul + * @returns {NodeData[]} + */ + parseHtml: function($ul) { + // TODO: understand this: + /*jshint validthis:true */ + var classes, className, extraClasses, i, iPos, l, tmp, tmp2, + $children = $ul.find(">li"), + children = []; + + $children.each(function() { + var allData, lowerCaseAttr, + $li = $(this), + $liSpan = $li.find(">span:first", this), + $liA = $liSpan.length ? null : $li.find(">a:first"), + d = { tooltip: null, data: {} }; + + if( $liSpan.length ) { + d.title = $liSpan.html(); + + } else if( $liA && $liA.length ) { + // If a <li><a> tag is specified, use it literally and extract href/target. + d.title = $liA.html(); + d.data.href = $liA.attr("href"); + d.data.target = $liA.attr("target"); + d.tooltip = $liA.attr("title"); + + } else { + // If only a <li> tag is specified, use the trimmed string up to + // the next child <ul> tag. + d.title = $li.html(); + iPos = d.title.search(/<ul/i); + if( iPos >= 0 ){ + d.title = d.title.substring(0, iPos); + } + } + d.title = $.trim(d.title); + + // Make sure all fields exist + for(i=0, l=CLASS_ATTRS.length; i<l; i++){ + d[CLASS_ATTRS[i]] = undefined; + } + // Initialize to `true`, if class is set and collect extraClasses + classes = this.className.split(" "); + extraClasses = []; + for(i=0, l=classes.length; i<l; i++){ + className = classes[i]; + if(CLASS_ATTR_MAP[className]){ + d[className] = true; + }else{ + extraClasses.push(className); + } + } + d.extraClasses = extraClasses.join(" "); + + // Parse node options from ID, title and class attributes + tmp = $li.attr("title"); + if( tmp ){ + d.tooltip = tmp; // overrides <a title='...'> + } + tmp = $li.attr("id"); + if( tmp ){ + d.key = tmp; + } + // Add <li data-NAME='...'> as node.data.NAME + allData = _getElementDataAsDict($li); + if( allData && !$.isEmptyObject(allData) ) { + // #507: convert data-hidecheckbox (lower case) to hideCheckbox + for( lowerCaseAttr in NODE_ATTR_LOWERCASE_MAP ) { + if( allData.hasOwnProperty(lowerCaseAttr) ) { + allData[NODE_ATTR_LOWERCASE_MAP[lowerCaseAttr]] = allData[lowerCaseAttr]; + delete allData[lowerCaseAttr]; + } + } + // #56: Allow to set special node.attributes from data-... + for(i=0, l=NODE_ATTRS.length; i<l; i++){ + tmp = NODE_ATTRS[i]; + tmp2 = allData[tmp]; + if( tmp2 != null ) { + delete allData[tmp]; + d[tmp] = tmp2; + } + } + // All other data-... goes to node.data... + $.extend(d.data, allData); + } + // Recursive reading of child nodes, if LI tag contains an UL tag + $ul = $li.find(">ul:first"); + if( $ul.length ) { + d.children = $.ui.fancytree.parseHtml($ul); + }else{ + d.children = d.lazy ? undefined : null; + } + children.push(d); +// FT.debug("parse ", d, children); + }); + return children; + }, + /** Add Fancytree extension definition to the list of globally available extensions. + * + * @param {object} definition + */ + registerExtension: function(definition){ + _assert(definition.name != null, "extensions must have a `name` property."); + _assert(definition.version != null, "extensions must have a `version` property."); + $.ui.fancytree._extensions[definition.name] = definition; + }, + /** Inverse of escapeHtml(). + * + * @param {string} s + * @returns {string} + */ + unescapeHtml: function(s){ + var e = document.createElement("div"); + e.innerHTML = s; + return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue; + }, + /** Write warning message to console. + * @param {string} msg + */ + warn: function(msg){ + consoleApply("warn", arguments); + } +}); + +}(jQuery, window, document)); + +// Extending Fancytree +// =================== +// +// See also the [live demo](http://wwwendt.de/tech/fancytree/demo/sample-ext-childcounter.html) of this code. +// +// Every extension should have a comment header containing some information +// about the author, copyright and licensing. Also a pointer to the latest +// source code. +// Prefix with `/*!` so the comment is not removed by the minifier. + +/*! + * jquery.fancytree.childcounter.js + * + * Add a child counter bubble to tree nodes. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +// To keep the global namespace clean, we wrap everything in a closure + +;(function($, undefined) { + +// Consider to use [strict mode](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) +"use strict"; + +// The [coding guidelines](http://contribute.jquery.org/style-guide/js/) +// require jshint compliance. +// But for this sample, we want to allow unused variables for demonstration purpose. + +/*jshint unused:false */ + + +// Adding methods +// -------------- + +// New member functions can be added to the `Fancytree` class. +// This function will be available for every tree instance: +// +// var tree = $("#tree").fancytree("getTree"); +// tree.countSelected(false); + +$.ui.fancytree._FancytreeClass.prototype.countSelected = function(topOnly){ + var tree = this, + treeOptions = tree.options; + + return tree.getSelectedNodes(topOnly).length; +}; + + +// The `FancytreeNode` class can also be easily extended. This would be called +// like +// node.updateCounters(); +// +// It is also good practice to add a docstring comment. +/** + * [ext-childcounter] Update counter badges for `node` and its parents. + * May be called in the `loadChildren` event, to update parents of lazy loaded + * nodes. + * @alias FancytreeNode#updateCounters + * @requires jquery.fancytree.childcounters.js + */ +$.ui.fancytree._FancytreeNodeClass.prototype.updateCounters = function(){ + var node = this, + $badge = $("span.fancytree-childcounter", node.span), + extOpts = node.tree.options.childcounter, + count = node.countChildren(extOpts.deep); + + node.data.childCounter = count; + if( (count || !extOpts.hideZeros) && (!node.isExpanded() || !extOpts.hideExpanded) ) { + if( !$badge.length ) { + $badge = $("<span class='fancytree-childcounter'/>").appendTo($("span.fancytree-icon", node.span)); + } + $badge.text(count); + } else { + $badge.remove(); + } + if( extOpts.deep && !node.isTopLevel() && !node.isRoot() ) { + node.parent.updateCounters(); + } +}; + + +// Finally, we can extend the widget API and create functions that are called +// like so: +// +// $("#tree").fancytree("widgetMethod1", "abc"); + +$.ui.fancytree.prototype.widgetMethod1 = function(arg1){ + var tree = this.tree; + return arg1; +}; + + +// Register a Fancytree extension +// ------------------------------ +// A full blown extension, extension is available for all trees and can be +// enabled like so (see also the [live demo](http://wwwendt.de/tech/fancytree/demo/sample-ext-childcounter.html)): +// +// <script src="../src/jquery.fancytree.js" type="text/javascript"></script> +// <script src="../src/jquery.fancytree.childcounter.js" type="text/javascript"></script> +// ... +// +// $("#tree").fancytree({ +// extensions: ["childcounter"], +// childcounter: { +// hideExpanded: true +// }, +// ... +// }); +// + + +/* 'childcounter' extension */ +$.ui.fancytree.registerExtension({ +// Every extension must be registered by a unique name. + name: "childcounter", +// Version information should be compliant with [semver](http://semver.org) + version: "1.0.0", + +// Extension specific options and their defaults. +// This options will be available as `tree.options.childcounter.hideExpanded` + + options: { + deep: true, + hideZeros: true, + hideExpanded: false + }, + +// Attributes other than `options` (or functions) can be defined here, and +// will be added to the tree.ext.EXTNAME namespace, in this case `tree.ext.childcounter.foo`. +// They can also be accessed as `this._local.foo` from within the extension +// methods. + foo: 42, + +// Local functions are prefixed with an underscore '_'. +// Callable as `this._local._appendCounter()`. + + _appendCounter: function(bar){ + var tree = this; + }, + +// **Override virtual methods for this extension.** +// +// Fancytree implements a number of 'hook methods', prefixed by 'node...' or 'tree...'. +// with a `ctx` argument (see [EventData](http://www.wwwendt.de/tech/fancytree/doc/jsdoc/global.html#EventData) +// for details) and an extended calling context:<br> +// `this` : the Fancytree instance<br> +// `this._local`: the namespace that contains extension attributes and private methods (same as this.ext.EXTNAME)<br> +// `this._super`: the virtual function that was overridden (member of previous extension or Fancytree) +// +// See also the [complete list of available hook functions](http://www.wwwendt.de/tech/fancytree/doc/jsdoc/Fancytree_Hooks.html). + + /* Init */ +// `treeInit` is triggered when a tree is initalized. We can set up classes or +// bind event handlers here... + treeInit: function(ctx){ + var tree = this, // same as ctx.tree, + opts = ctx.options, + extOpts = ctx.options.childcounter; +// Optionally check for dependencies with other extensions + /* this._requireExtension("glyph", false, false); */ +// Call the base implementation + this._superApply(arguments); +// Add a class to the tree container + this.$container.addClass("fancytree-ext-childcounter"); + }, + +// Destroy this tree instance (we only call the default implementation, so +// this method could as well be omitted). + + treeDestroy: function(ctx){ + this._superApply(arguments); + }, + +// Overload the `renderTitle` hook, to append a counter badge + nodeRenderTitle: function(ctx, title) { + var node = ctx.node, + extOpts = ctx.options.childcounter, + count = (node.data.childCounter == null) ? node.countChildren(extOpts.deep) : +node.data.childCounter; +// Let the base implementation render the title + this._superApply(arguments); +// Append a counter badge + if( (count || ! extOpts.hideZeros) && (!node.isExpanded() || !extOpts.hideExpanded) ){ + $("span.fancytree-icon", node.span).append($("<span class='fancytree-childcounter'/>").text(count)); + } + }, +// Overload the `setExpanded` hook, so the counters are updated + nodeSetExpanded: function(ctx, flag, opts) { + var tree = ctx.tree, + node = ctx.node; +// Let the base implementation expand/collapse the node, then redraw the title +// after the animation has finished + return this._superApply(arguments).always(function(){ + tree.nodeRenderTitle(ctx); + }); + } + +// End of extension definition +}); +// End of namespace closure +}(jQuery)); + +/*! + * + * jquery.fancytree.clones.js + * Support faster lookup of nodes by key and shared ref-ids. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + +/******************************************************************************* + * Private functions and variables + */ +function _assert(cond, msg){ + // TODO: see qunit.js extractStacktrace() + if(!cond){ + msg = msg ? ": " + msg : ""; + $.error("Assertion failed" + msg); + } +} + + +/* Return first occurrence of member from array. */ +function _removeArrayMember(arr, elem) { + // TODO: use Array.indexOf for IE >= 9 + var i; + for (i = arr.length - 1; i >= 0; i--) { + if (arr[i] === elem) { + arr.splice(i, 1); + return true; + } + } + return false; +} + + +// /** +// * Calculate a 32 bit FNV-1a hash +// * Found here: https://gist.github.com/vaiorabbit/5657561 +// * Ref.: http://isthe.com/chongo/tech/comp/fnv/ +// * +// * @param {string} str the input value +// * @param {boolean} [asString=false] set to true to return the hash value as +// * 8-digit hex string instead of an integer +// * @param {integer} [seed] optionally pass the hash of the previous chunk +// * @returns {integer | string} +// */ +// function hashFnv32a(str, asString, seed) { +// /*jshint bitwise:false */ +// var i, l, +// hval = (seed === undefined) ? 0x811c9dc5 : seed; + +// for (i = 0, l = str.length; i < l; i++) { +// hval ^= str.charCodeAt(i); +// hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24); +// } +// if( asString ){ +// // Convert to 8 digit hex string +// return ("0000000" + (hval >>> 0).toString(16)).substr(-8); +// } +// return hval >>> 0; +// } + + +/** + * JS Implementation of MurmurHash3 (r136) (as of May 20, 2011) + * + * @author <a href="mailto:gary.court@gmail.com">Gary Court</a> + * @see http://github.com/garycourt/murmurhash-js + * @author <a href="mailto:aappleby@gmail.com">Austin Appleby</a> + * @see http://sites.google.com/site/murmurhash/ + * + * @param {string} key ASCII only + * @param {boolean} [asString=false] + * @param {number} seed Positive integer only + * @return {number} 32-bit positive integer hash + */ +function hashMurmur3(key, asString, seed) { + /*jshint bitwise:false */ + var h1b, k1, + remainder = key.length & 3, + bytes = key.length - remainder, + h1 = seed, + c1 = 0xcc9e2d51, + c2 = 0x1b873593, + i = 0; + + while (i < bytes) { + k1 = + ((key.charCodeAt(i) & 0xff)) | + ((key.charCodeAt(++i) & 0xff) << 8) | + ((key.charCodeAt(++i) & 0xff) << 16) | + ((key.charCodeAt(++i) & 0xff) << 24); + ++i; + + k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff; + k1 = (k1 << 15) | (k1 >>> 17); + k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff; + + h1 ^= k1; + h1 = (h1 << 13) | (h1 >>> 19); + h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff; + h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16)); + } + + k1 = 0; + + switch (remainder) { + /*jshint -W086:true */ + case 3: k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16; + case 2: k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8; + case 1: k1 ^= (key.charCodeAt(i) & 0xff); + + k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff; + k1 = (k1 << 15) | (k1 >>> 17); + k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff; + h1 ^= k1; + } + + h1 ^= key.length; + + h1 ^= h1 >>> 16; + h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff; + h1 ^= h1 >>> 13; + h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff; + h1 ^= h1 >>> 16; + + if( asString ){ + // Convert to 8 digit hex string + return ("0000000" + (h1 >>> 0).toString(16)).substr(-8); + } + return h1 >>> 0; +} + +// console.info(hashMurmur3("costarring")); +// console.info(hashMurmur3("costarring", true)); +// console.info(hashMurmur3("liquid")); +// console.info(hashMurmur3("liquid", true)); + + +/* + * Return a unique key for node by calculationg the hash of the parents refKey-list + */ +function calcUniqueKey(node) { + var key, + path = $.map(node.getParentList(false, true), function(e){ return e.refKey || e.key; }); + path = path.join("/"); + key = "id_" + hashMurmur3(path, true); + // node.debug(path + " -> " + key); + return key; +} + + +/** + * [ext-clones] Return a list of clone-nodes or null. + * @param {boolean} [includeSelf=false] + * @returns {FancytreeNode[] | null} + * + * @alias FancytreeNode#getCloneList + * @requires jquery.fancytree.clones.js + */ +$.ui.fancytree._FancytreeNodeClass.prototype.getCloneList = function(includeSelf){ + var key, + tree = this.tree, + refList = tree.refMap[this.refKey] || null, + keyMap = tree.keyMap; + + if( refList ) { + key = this.key; + // Convert key list to node list + if( includeSelf ) { + refList = $.map(refList, function(val){ return keyMap[val]; }); + } else { + refList = $.map(refList, function(val){ return val === key ? null : keyMap[val]; }); + if( refList.length < 1 ) { + refList = null; + } + } + } + return refList; +}; + + +/** + * [ext-clones] Return true if this node has at least another clone with same refKey. + * @returns {boolean} + * + * @alias FancytreeNode#isClone + * @requires jquery.fancytree.clones.js + */ +$.ui.fancytree._FancytreeNodeClass.prototype.isClone = function(){ + var refKey = this.refKey || null, + refList = refKey && this.tree.refMap[refKey] || null; + return !!(refList && refList.length > 1); +}; + + +/** + * [ext-clones] Update key and/or refKey for an existing node. + * @param {string} key + * @param {string} refKey + * @returns {boolean} + * + * @alias FancytreeNode#reRegister + * @requires jquery.fancytree.clones.js + */ +$.ui.fancytree._FancytreeNodeClass.prototype.reRegister = function(key, refKey){ + key = (key == null) ? null : "" + key; + refKey = (refKey == null) ? null : "" + refKey; + // this.debug("reRegister", key, refKey); + + var tree = this.tree, + prevKey = this.key, + prevRefKey = this.refKey, + keyMap = tree.keyMap, + refMap = tree.refMap, + refList = refMap[prevRefKey] || null, +// curCloneKeys = refList ? node.getCloneList(true), + modified = false; + + // Key has changed: update all references + if( key != null && key !== this.key ) { + if( keyMap[key] ) { + $.error("[ext-clones] reRegister(" + key + "): already exists: " + this); + } + // Update keyMap + delete keyMap[prevKey]; + keyMap[key] = this; + // Update refMap + if( refList ) { + refMap[prevRefKey] = $.map(refList, function(e){ + return e === prevKey ? key : e; + }); + } + this.key = key; + modified = true; + } + + // refKey has changed + if( refKey != null && refKey !== this.refKey ) { + // Remove previous refKeys + if( refList ){ + if( refList.length === 1 ){ + delete refMap[prevRefKey]; + }else{ + refMap[prevRefKey] = $.map(refList, function(e){ + return e === prevKey ? null : e; + }); + } + } + // Add refKey + if( refMap[refKey] ) { + refMap[refKey].append(key); + }else{ + refMap[refKey] = [ this.key ]; + } + this.refKey = refKey; + modified = true; + } + return modified; +}; + + +/** + * [ext-clones] Return all nodes with a given refKey (null if not found). + * @param {string} refKey + * @param {FancytreeNode} [rootNode] optionally restrict results to descendants of this node + * @returns {FancytreeNode[] | null} + * @alias Fancytree#getNodesByRef + * @requires jquery.fancytree.clones.js + */ +$.ui.fancytree._FancytreeClass.prototype.getNodesByRef = function(refKey, rootNode){ + var keyMap = this.keyMap, + refList = this.refMap[refKey] || null; + + if( refList ) { + // Convert key list to node list + if( rootNode ) { + refList = $.map(refList, function(val){ + var node = keyMap[val]; + return node.isDescendantOf(rootNode) ? node : null; + }); + }else{ + refList = $.map(refList, function(val){ return keyMap[val]; }); + } + if( refList.length < 1 ) { + refList = null; + } + } + return refList; +}; + + +/** + * [ext-clones] Replace a refKey with a new one. + * @param {string} oldRefKey + * @param {string} newRefKey + * @alias Fancytree#changeRefKey + * @requires jquery.fancytree.clones.js + */ +$.ui.fancytree._FancytreeClass.prototype.changeRefKey = function(oldRefKey, newRefKey) { + var i, node, + keyMap = this.keyMap, + refList = this.refMap[oldRefKey] || null; + + if (refList) { + for (i = 0; i < refList.length; i++) { + node = keyMap[refList[i]]; + node.refKey = newRefKey; + } + delete this.refMap[oldRefKey]; + this.refMap[newRefKey] = refList; + } +}; + + +/******************************************************************************* + * Extension code + */ +$.ui.fancytree.registerExtension({ + name: "clones", + version: "0.0.3", + // Default options for this extension. + options: { + highlightActiveClones: true, // set 'fancytree-active-clone' on active clones and all peers + highlightClones: false // set 'fancytree-clone' class on any node that has at least one clone + }, + + treeCreate: function(ctx){ + this._superApply(arguments); + ctx.tree.refMap = {}; + ctx.tree.keyMap = {}; + }, + treeInit: function(ctx){ + this.$container.addClass("fancytree-ext-clones"); + _assert(ctx.options.defaultKey == null); + // Generate unique / reproducible default keys + ctx.options.defaultKey = function(node){ + return calcUniqueKey(node); + }; + // The default implementation loads initial data + this._superApply(arguments); + }, + treeClear: function(ctx){ + ctx.tree.refMap = {}; + ctx.tree.keyMap = {}; + return this._superApply(arguments); + }, + treeRegisterNode: function(ctx, add, node) { + var refList, len, + tree = ctx.tree, + keyMap = tree.keyMap, + refMap = tree.refMap, + key = node.key, + refKey = (node && node.refKey != null) ? "" + node.refKey : null; + +// ctx.tree.debug("clones.treeRegisterNode", add, node); + + if( key === "_statusNode" ){ + return this._superApply(arguments); + } + + if( add ) { + if( keyMap[node.key] != null ) { + $.error("clones.treeRegisterNode: node.key already exists: " + node); + } + keyMap[key] = node; + if( refKey ) { + refList = refMap[refKey]; + if( refList ) { + refList.push(key); + if( refList.length === 2 && ctx.options.clones.highlightClones ) { + // Mark peer node, if it just became a clone (no need to + // mark current node, since it will be rendered later anyway) + keyMap[refList[0]].renderStatus(); + } + } else { + refMap[refKey] = [key]; + } + // node.debug("clones.treeRegisterNode: add clone =>", refMap[refKey]); + } + }else { + if( keyMap[key] == null ) { + $.error("clones.treeRegisterNode: node.key not registered: " + node.key); + } + delete keyMap[key]; + if( refKey ) { + refList = refMap[refKey]; + // node.debug("clones.treeRegisterNode: remove clone BEFORE =>", refMap[refKey]); + if( refList ) { + len = refList.length; + if( len <= 1 ){ + _assert(len === 1); + _assert(refList[0] === key); + delete refMap[refKey]; + }else{ + _removeArrayMember(refList, key); + // Unmark peer node, if this was the only clone + if( len === 2 && ctx.options.clones.highlightClones ) { +// node.debug("clones.treeRegisterNode: last =>", node.getCloneList()); + keyMap[refList[0]].renderStatus(); + } + } + // node.debug("clones.treeRegisterNode: remove clone =>", refMap[refKey]); + } + } + } + return this._superApply(arguments); + }, + nodeRenderStatus: function(ctx) { + var $span, res, + node = ctx.node; + + res = this._superApply(arguments); + + if( ctx.options.clones.highlightClones ) { + $span = $(node[ctx.tree.statusClassPropName]); + // Only if span already exists + if( $span.length && node.isClone() ){ +// node.debug("clones.nodeRenderStatus: ", ctx.options.clones.highlightClones); + $span.addClass("fancytree-clone"); + } + } + return res; + }, + nodeSetActive: function(ctx, flag) { + var res, + scpn = ctx.tree.statusClassPropName, + node = ctx.node; + + res = this._superApply(arguments); + + if( ctx.options.clones.highlightActiveClones && node.isClone() ) { + $.each(node.getCloneList(true), function(idx, n){ + // n.debug("clones.nodeSetActive: ", flag !== false); + $(n[scpn]).toggleClass("fancytree-active-clone", flag !== false); + }); + } + return res; + } +}); +}(jQuery, window, document)); + +/*! + * jquery.fancytree.dnd.js + * + * Drag-and-drop support. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + +/* ***************************************************************************** + * Private functions and variables + */ +var didRegisterDnd = false, + classDropAccept = "fancytree-drop-accept", + classDropAfter = "fancytree-drop-after", + classDropBefore = "fancytree-drop-before", + classDropOver = "fancytree-drop-over", + classDropReject = "fancytree-drop-reject", + classDropTarget = "fancytree-drop-target"; + +/* Convert number to string and prepend +/-; return empty string for 0.*/ +function offsetString(n){ + return n === 0 ? "" : (( n > 0 ) ? ("+" + n) : ("" + n)); +} + +/* ***************************************************************************** + * Drag and drop support + */ +function _initDragAndDrop(tree) { + var dnd = tree.options.dnd || null, + glyph = tree.options.glyph || null; + + // Register 'connectToFancytree' option with ui.draggable + if( dnd ) { + _registerDnd(); + } + // Attach ui.draggable to this Fancytree instance + if(dnd && dnd.dragStart ) { + tree.widget.element.draggable($.extend({ + addClasses: false, + // DT issue 244: helper should be child of scrollParent: + appendTo: tree.$container, +// appendTo: "body", + containment: false, +// containment: "parent", + delay: 0, + distance: 4, + revert: false, + scroll: true, // to disable, also set css 'position: inherit' on ul.fancytree-container + scrollSpeed: 7, + scrollSensitivity: 10, + // Delegate draggable.start, drag, and stop events to our handler + connectToFancytree: true, + // Let source tree create the helper element + helper: function(event) { + var $helper, $nodeTag, opts, + sourceNode = $.ui.fancytree.getNode(event.target); + + if(!sourceNode){ + // #405, DT issue 211: might happen, if dragging a table *header* + return "<div>ERROR?: helper requested but sourceNode not found</div>"; + } + opts = sourceNode.tree.options.dnd; + $nodeTag = $(sourceNode.span); + // Only event and node argument is available + $helper = $("<div class='fancytree-drag-helper'><span class='fancytree-drag-helper-img' /></div>") + .css({zIndex: 3, position: "relative"}) // so it appears above ext-wide selection bar + .append($nodeTag.find("span.fancytree-title").clone()); + + // Attach node reference to helper object + $helper.data("ftSourceNode", sourceNode); + + // Support glyph symbols instead of icons + if( glyph ) { + $helper.find(".fancytree-drag-helper-img") + .addClass(glyph.map.dragHelper); + } + // Allow to modify the helper, e.g. to add multi-node-drag feedback + if( opts.initHelper ) { + opts.initHelper.call(sourceNode.tree, sourceNode, { + node: sourceNode, + tree: sourceNode.tree, + originalEvent: event, + ui: { helper: $helper } + }); + } + // We return an unconnected element, so `draggable` will add this + // to the parent specified as `appendTo` option + return $helper; + }, + start: function(event, ui) { + var sourceNode = ui.helper.data("ftSourceNode"); + return !!sourceNode; // Abort dragging if no node could be found + } + }, tree.options.dnd.draggable)); + } + // Attach ui.droppable to this Fancytree instance + if(dnd && dnd.dragDrop) { + tree.widget.element.droppable($.extend({ + addClasses: false, + tolerance: "intersect", + greedy: false +/* + activate: function(event, ui) { + tree.debug("droppable - activate", event, ui, this); + }, + create: function(event, ui) { + tree.debug("droppable - create", event, ui); + }, + deactivate: function(event, ui) { + tree.debug("droppable - deactivate", event, ui); + }, + drop: function(event, ui) { + tree.debug("droppable - drop", event, ui); + }, + out: function(event, ui) { + tree.debug("droppable - out", event, ui); + }, + over: function(event, ui) { + tree.debug("droppable - over", event, ui); + } +*/ + }, tree.options.dnd.droppable)); + } +} + +//--- Extend ui.draggable event handling -------------------------------------- + +function _registerDnd() { + if(didRegisterDnd){ + return; + } + + // Register proxy-functions for draggable.start/drag/stop + + $.ui.plugin.add("draggable", "connectToFancytree", { + start: function(event, ui) { + // 'draggable' was renamed to 'ui-draggable' since jQueryUI 1.10 + var draggable = $(this).data("ui-draggable") || $(this).data("draggable"), + sourceNode = ui.helper.data("ftSourceNode") || null; + + if(sourceNode) { + // Adjust helper offset, so cursor is slightly outside top/left corner + draggable.offset.click.top = -2; + draggable.offset.click.left = + 16; + // Trigger dragStart event + // TODO: when called as connectTo..., the return value is ignored(?) + return sourceNode.tree.ext.dnd._onDragEvent("start", sourceNode, null, event, ui, draggable); + } + }, + drag: function(event, ui) { + var ctx, isHelper, logObject, + // 'draggable' was renamed to 'ui-draggable' since jQueryUI 1.10 + draggable = $(this).data("ui-draggable") || $(this).data("draggable"), + sourceNode = ui.helper.data("ftSourceNode") || null, + prevTargetNode = ui.helper.data("ftTargetNode") || null, + targetNode = $.ui.fancytree.getNode(event.target), + dndOpts = sourceNode && sourceNode.tree.options.dnd; + + // logObject = sourceNode || prevTargetNode || $.ui.fancytree; + // logObject.debug("Drag event:", event, event.shiftKey); + if(event.target && !targetNode){ + // We got a drag event, but the targetNode could not be found + // at the event location. This may happen, + // 1. if the mouse jumped over the drag helper, + // 2. or if a non-fancytree element is dragged + // We ignore it: + isHelper = $(event.target).closest("div.fancytree-drag-helper,#fancytree-drop-marker").length > 0; + if(isHelper){ + logObject = sourceNode || prevTargetNode || $.ui.fancytree; + logObject.debug("Drag event over helper: ignored."); + return; + } + } + ui.helper.data("ftTargetNode", targetNode); + + if( dndOpts && dndOpts.updateHelper ) { + ctx = sourceNode.tree._makeHookContext(sourceNode, event, { + otherNode: targetNode, + ui: ui, + draggable: draggable, + dropMarker: $("#fancytree-drop-marker") + }); + dndOpts.updateHelper.call(sourceNode.tree, sourceNode, ctx); + } + + // Leaving a tree node + if(prevTargetNode && prevTargetNode !== targetNode ) { + prevTargetNode.tree.ext.dnd._onDragEvent("leave", prevTargetNode, sourceNode, event, ui, draggable); + } + if(targetNode){ + if(!targetNode.tree.options.dnd.dragDrop) { + // not enabled as drop target + } else if(targetNode === prevTargetNode) { + // Moving over same node + targetNode.tree.ext.dnd._onDragEvent("over", targetNode, sourceNode, event, ui, draggable); + }else{ + // Entering this node first time + targetNode.tree.ext.dnd._onDragEvent("enter", targetNode, sourceNode, event, ui, draggable); + } + } + // else go ahead with standard event handling + }, + stop: function(event, ui) { + var logObject, + // 'draggable' was renamed to 'ui-draggable' since jQueryUI 1.10: + draggable = $(this).data("ui-draggable") || $(this).data("draggable"), + sourceNode = ui.helper.data("ftSourceNode") || null, + targetNode = ui.helper.data("ftTargetNode") || null, + dropped = (event.type === "mouseup" && event.which === 1); + + if(!dropped){ + logObject = sourceNode || targetNode || $.ui.fancytree; + logObject.debug("Drag was cancelled"); + } + if(targetNode) { + if(dropped){ + targetNode.tree.ext.dnd._onDragEvent("drop", targetNode, sourceNode, event, ui, draggable); + } + targetNode.tree.ext.dnd._onDragEvent("leave", targetNode, sourceNode, event, ui, draggable); + } + if(sourceNode){ + sourceNode.tree.ext.dnd._onDragEvent("stop", sourceNode, null, event, ui, draggable); + } + } + }); + + didRegisterDnd = true; +} + + +/* ***************************************************************************** + * + */ + +$.ui.fancytree.registerExtension({ + name: "dnd", + version: "0.2.0", + // Default options for this extension. + options: { + // Make tree nodes accept draggables + autoExpandMS: 1000, // Expand nodes after n milliseconds of hovering. + draggable: null, // Additional options passed to jQuery draggable + droppable: null, // Additional options passed to jQuery droppable + focusOnClick: false, // Focus, although draggable cancels mousedown event (#270) + preventVoidMoves: true, // Prevent dropping nodes 'before self', etc. + preventRecursiveMoves: true, // Prevent dropping nodes on own descendants + smartRevert: true, // set draggable.revert = true if drop was rejected + // Events (drag support) + dragStart: null, // Callback(sourceNode, data), return true, to enable dnd + dragStop: null, // Callback(sourceNode, data) + initHelper: null, // Callback(sourceNode, data) + updateHelper: null, // Callback(sourceNode, data) + // Events (drop support) + dragEnter: null, // Callback(targetNode, data) + dragOver: null, // Callback(targetNode, data) + dragDrop: null, // Callback(targetNode, data) + dragLeave: null // Callback(targetNode, data) + }, + + treeInit: function(ctx){ + var tree = ctx.tree; + this._superApply(arguments); + // issue #270: draggable eats mousedown events + if( tree.options.dnd.dragStart ){ + tree.$container.on("mousedown", function(event){ +// if( !tree.hasFocus() && ctx.options.dnd.focusOnClick ) { + if( ctx.options.dnd.focusOnClick ) { // #270 + var node = $.ui.fancytree.getNode(event); + if (node){ + node.debug("Re-enable focus that was prevented by jQuery UI draggable."); + // node.setFocus(); + // $(node.span).closest(":tabbable").focus(); + // $(event.target).trigger("focus"); + // $(event.target).closest(":tabbable").trigger("focus"); + } + setTimeout(function() { // #300 + $(event.target).closest(":tabbable").focus(); + }, 10); + } + }); + } + _initDragAndDrop(tree); + }, + /* Display drop marker according to hitMode ('after', 'before', 'over'). */ + _setDndStatus: function(sourceNode, targetNode, helper, hitMode, accept) { + var markerOffsetX = 0, + markerAt = "center", + instData = this._local, + glyph = this.options.glyph || null, + $source = sourceNode ? $(sourceNode.span) : null, + $target = $(targetNode.span); + + if( !instData.$dropMarker ) { + instData.$dropMarker = $("<div id='fancytree-drop-marker'></div>") + .hide() + .css({"z-index": 1000}) + .prependTo($(this.$div).parent()); +// .prependTo("body"); + + if( glyph ) { + // instData.$dropMarker.addClass(glyph.map.dragHelper); + instData.$dropMarker + .addClass(glyph.map.dropMarker); + } + } + if( hitMode === "after" || hitMode === "before" || hitMode === "over" ){ + switch(hitMode){ + case "before": + markerAt = "top"; + break; + case "after": + markerAt = "bottom"; + break; + default: + markerOffsetX = 8; + } + + instData.$dropMarker + .toggleClass(classDropAfter, hitMode === "after") + .toggleClass(classDropOver, hitMode === "over") + .toggleClass(classDropBefore, hitMode === "before") + .show() + .position($.ui.fancytree.fixPositionOptions({ + my: "left" + offsetString(markerOffsetX) + " center", + at: "left " + markerAt, + of: $target + })); + } else { + instData.$dropMarker.hide(); + } + if( $source ){ + $source + .toggleClass(classDropAccept, accept === true) + .toggleClass(classDropReject, accept === false); + } + $target + .toggleClass(classDropTarget, hitMode === "after" || hitMode === "before" || hitMode === "over") + .toggleClass(classDropAfter, hitMode === "after") + .toggleClass(classDropBefore, hitMode === "before") + .toggleClass(classDropAccept, accept === true) + .toggleClass(classDropReject, accept === false); + + helper + .toggleClass(classDropAccept, accept === true) + .toggleClass(classDropReject, accept === false); + }, + + /* + * Handles drag'n'drop functionality. + * + * A standard jQuery drag-and-drop process may generate these calls: + * + * start: + * _onDragEvent("start", sourceNode, null, event, ui, draggable); + * drag: + * _onDragEvent("leave", prevTargetNode, sourceNode, event, ui, draggable); + * _onDragEvent("over", targetNode, sourceNode, event, ui, draggable); + * _onDragEvent("enter", targetNode, sourceNode, event, ui, draggable); + * stop: + * _onDragEvent("drop", targetNode, sourceNode, event, ui, draggable); + * _onDragEvent("leave", targetNode, sourceNode, event, ui, draggable); + * _onDragEvent("stop", sourceNode, null, event, ui, draggable); + */ + _onDragEvent: function(eventName, node, otherNode, event, ui, draggable) { + if(eventName !== "over"){ + this.debug("tree.ext.dnd._onDragEvent(%s, %o, %o) - %o", eventName, node, otherNode, this); + } + var accept, nodeOfs, relPos, relPos2, + enterResponse, hitMode, r, + opts = this.options, + dnd = opts.dnd, + ctx = this._makeHookContext(node, event, {otherNode: otherNode, ui: ui, draggable: draggable}), + res = null, + that = this, + $nodeTag = $(node.span); + + if( dnd.smartRevert ) { + draggable.options.revert = "invalid"; + } + + switch (eventName) { + + case "start": + if( node.isStatusNode() ) { + res = false; + } else if(dnd.dragStart) { + res = dnd.dragStart(node, ctx); + } + if(res === false) { + this.debug("tree.dragStart() cancelled"); + //draggable._clear(); + // NOTE: the return value seems to be ignored (drag is not canceled, when false is returned) + // TODO: call this._cancelDrag()? + ui.helper.trigger("mouseup") + .hide(); + } else { + $nodeTag.addClass("fancytree-drag-source"); + // Register global handlers to allow cancel + $(document) + .on("keydown.fancytree-dnd,mousedown.fancytree-dnd", function(event){ + // node.tree.debug("dnd global event", event.type, event.which); + if( event.type === "keydown" && event.which === $.ui.keyCode.ESCAPE ) { + that.ext.dnd._cancelDrag(); + } else if( event.type === "mousedown" ) { + that.ext.dnd._cancelDrag(); + } + }); + } + break; + + case "enter": + if(dnd.preventRecursiveMoves && node.isDescendantOf(otherNode)){ + r = false; + }else{ + r = dnd.dragEnter ? dnd.dragEnter(node, ctx) : null; + } + if(!r){ + // convert null, undefined, false to false + res = false; + }else if ( $.isArray(r) ) { + // TODO: also accept passing an object of this format directly + res = { + over: ($.inArray("over", r) >= 0), + before: ($.inArray("before", r) >= 0), + after: ($.inArray("after", r) >= 0) + }; + }else{ + res = { + over: ((r === true) || (r === "over")), + before: ((r === true) || (r === "before")), + after: ((r === true) || (r === "after")) + }; + } + ui.helper.data("enterResponse", res); + this.debug("helper.enterResponse: %o", res); + break; + + case "over": + enterResponse = ui.helper.data("enterResponse"); + hitMode = null; + if(enterResponse === false){ + // Don't call dragOver if onEnter returned false. +// break; + } else if(typeof enterResponse === "string") { + // Use hitMode from onEnter if provided. + hitMode = enterResponse; + } else { + // Calculate hitMode from relative cursor position. + nodeOfs = $nodeTag.offset(); + relPos = { x: event.pageX - nodeOfs.left, + y: event.pageY - nodeOfs.top }; + relPos2 = { x: relPos.x / $nodeTag.width(), + y: relPos.y / $nodeTag.height() }; + + if( enterResponse.after && relPos2.y > 0.75 ){ + hitMode = "after"; + } else if(!enterResponse.over && enterResponse.after && relPos2.y > 0.5 ){ + hitMode = "after"; + } else if(enterResponse.before && relPos2.y <= 0.25) { + hitMode = "before"; + } else if(!enterResponse.over && enterResponse.before && relPos2.y <= 0.5) { + hitMode = "before"; + } else if(enterResponse.over) { + hitMode = "over"; + } + // Prevent no-ops like 'before source node' + // TODO: these are no-ops when moving nodes, but not in copy mode + if( dnd.preventVoidMoves ){ + if(node === otherNode){ + this.debug(" drop over source node prevented"); + hitMode = null; + }else if(hitMode === "before" && otherNode && node === otherNode.getNextSibling()){ + this.debug(" drop after source node prevented"); + hitMode = null; + }else if(hitMode === "after" && otherNode && node === otherNode.getPrevSibling()){ + this.debug(" drop before source node prevented"); + hitMode = null; + }else if(hitMode === "over" && otherNode && otherNode.parent === node && otherNode.isLastSibling() ){ + this.debug(" drop last child over own parent prevented"); + hitMode = null; + } + } +// this.debug("hitMode: %s - %s - %s", hitMode, (node.parent === otherNode), node.isLastSibling()); + ui.helper.data("hitMode", hitMode); + } + // Auto-expand node (only when 'over' the node, not 'before', or 'after') + if(hitMode === "over" && dnd.autoExpandMS && node.hasChildren() !== false && !node.expanded) { + node.scheduleAction("expand", dnd.autoExpandMS); + } + if(hitMode && dnd.dragOver){ + // TODO: http://code.google.com/p/dynatree/source/detail?r=625 + ctx.hitMode = hitMode; + res = dnd.dragOver(node, ctx); + } + accept = (res !== false && hitMode !== null); + if( dnd.smartRevert ) { + draggable.options.revert = !accept; + } + this._local._setDndStatus(otherNode, node, ui.helper, hitMode, accept); + break; + + case "drop": + hitMode = ui.helper.data("hitMode"); + if(hitMode && dnd.dragDrop){ + ctx.hitMode = hitMode; + dnd.dragDrop(node, ctx); + } + break; + + case "leave": + // Cancel pending expand request + node.scheduleAction("cancel"); + ui.helper.data("enterResponse", null); + ui.helper.data("hitMode", null); + this._local._setDndStatus(otherNode, node, ui.helper, "out", undefined); + if(dnd.dragLeave){ + dnd.dragLeave(node, ctx); + } + break; + + case "stop": + $nodeTag.removeClass("fancytree-drag-source"); + $(document).off(".fancytree-dnd"); + if(dnd.dragStop){ + dnd.dragStop(node, ctx); + } + break; + + default: + $.error("Unsupported drag event: " + eventName); + } + return res; + }, + + _cancelDrag: function() { + var dd = $.ui.ddmanager.current; + if(dd){ + dd.cancel(); + } + } +}); +}(jQuery, window, document)); + +/*! + * jquery.fancytree.edit.js + * + * Make node titles editable. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + + +/******************************************************************************* + * Private functions and variables + */ + +var isMac = /Mac/.test(navigator.platform), + escapeHtml = $.ui.fancytree.escapeHtml, + unescapeHtml = $.ui.fancytree.unescapeHtml; + +/** + * [ext-edit] Start inline editing of current node title. + * + * @alias FancytreeNode#editStart + * @requires Fancytree + */ +$.ui.fancytree._FancytreeNodeClass.prototype.editStart = function(){ + var $input, + node = this, + tree = this.tree, + local = tree.ext.edit, + instOpts = tree.options.edit, + $title = $(".fancytree-title", node.span), + eventData = { + node: node, + tree: tree, + options: tree.options, + isNew: $(node[tree.statusClassPropName]).hasClass("fancytree-edit-new"), + orgTitle: node.title, + input: null, + dirty: false + }; + + // beforeEdit may want to modify the title before editing + if( instOpts.beforeEdit.call(node, {type: "beforeEdit"}, eventData) === false ) { + return false; + } + $.ui.fancytree.assert(!local.currentNode, "recursive edit"); + local.currentNode = this; + local.eventData = eventData; + + // Disable standard Fancytree mouse- and key handling + tree.widget._unbind(); + // #116: ext-dnd prevents the blur event, so we have to catch outer clicks + $(document).on("mousedown.fancytree-edit", function(event){ + if( ! $(event.target).hasClass("fancytree-edit-input") ){ + node.editEnd(true, event); + } + }); + + // Replace node with <input> + $input = $("<input />", { + "class": "fancytree-edit-input", + type: "text", + value: unescapeHtml(eventData.orgTitle) + }); + local.eventData.input = $input; + if ( instOpts.adjustWidthOfs != null ) { + $input.width($title.width() + instOpts.adjustWidthOfs); + } + if ( instOpts.inputCss != null ) { + $input.css(instOpts.inputCss); + } + + $title.html($input); + + // Focus <input> and bind keyboard handler + $input + .focus() + .change(function(event){ + $input.addClass("fancytree-edit-dirty"); + }).keydown(function(event){ + switch( event.which ) { + case $.ui.keyCode.ESCAPE: + node.editEnd(false, event); + break; + case $.ui.keyCode.ENTER: + node.editEnd(true, event); + return false; // so we don't start editmode on Mac + } + event.stopPropagation(); + }).blur(function(event){ + return node.editEnd(true, event); + }); + + instOpts.edit.call(node, {type: "edit"}, eventData); +}; + + +/** + * [ext-edit] Stop inline editing. + * @param {Boolean} [applyChanges=false] false: cancel edit, true: save (if modified) + * @alias FancytreeNode#editEnd + * @requires jquery.fancytree.edit.js + */ +$.ui.fancytree._FancytreeNodeClass.prototype.editEnd = function(applyChanges, _event){ + var newVal, + node = this, + tree = this.tree, + local = tree.ext.edit, + eventData = local.eventData, + instOpts = tree.options.edit, + $title = $(".fancytree-title", node.span), + $input = $title.find("input.fancytree-edit-input"); + + // eventData.isNew = $(node[tree.statusClassPropName]).hasClass("fancytree-edit-new"); + + if( instOpts.trim ) { + $input.val($.trim($input.val())); + } + newVal = $input.val(); + // eventData.dirty = $input.hasClass("fancytree-edit-dirty") || ; + eventData.dirty = ( newVal !== node.title ); + + // Find out, if saving is required + if( applyChanges === false ) { + // If true/false was passed, honor this (except in rename mode, if unchanged) + eventData.save = false; + } else if( eventData.isNew ) { + // In create mode, we save everyting, except for empty text + eventData.save = (newVal !== ""); + } else { + // In rename mode, we save everyting, except for empty or unchanged text + eventData.save = eventData.dirty && (newVal !== ""); + } + // Allow to break (keep editor open), modify input, or re-define data.save + if( instOpts.beforeClose.call(node, {type: "beforeClose"}, eventData) === false){ + return false; + } + if( eventData.save && instOpts.save.call(node, {type: "save"}, eventData) === false){ + return false; + } + $input + .removeClass("fancytree-edit-dirty") + .unbind(); + // Unbind outer-click handler + $(document).off(".fancytree-edit"); + + if( eventData.save ) { + node.setTitle( escapeHtml(newVal) ); + // $(node[tree.statusClassPropName]).removeClass("fancytree-edit-new"); + node.setFocus(); + }else{ + if( eventData.isNew ) { + node.remove(); + node = eventData.node = null; + local.relatedNode.setFocus(); + } else { + node.renderTitle(); + node.setFocus(); + } + } + local.eventData = null; + local.currentNode = null; + local.relatedNode = null; + // Re-enable mouse and keyboard handling + tree.widget._bind(); + // Set keyboard focus, even if setFocus() claims 'nothing to do' + $(tree.$container).focus(); + eventData.input = null; + instOpts.close.call(node, {type: "close"}, eventData); + return true; +}; + + +/** +* [ext-edit] Create a new child or sibling node and start edit mode. +* +* @param {String} [mode='child'] 'before', 'after', or 'child' +* @param {Object} [init] NodeData (or simple title string) +* @alias FancytreeNode#editCreateNode +* @requires jquery.fancytree.edit.js +* @since 2.4 +*/ +$.ui.fancytree._FancytreeNodeClass.prototype.editCreateNode = function(mode, init){ + var newNode, + tree = this.tree, + self = this; + + mode = mode || "child"; + if( init == null ) { + init = { title: "" }; + } else if( typeof init === "string" ) { + init = { title: init }; + } else { + $.ui.fancytree.assert($.isPlainObject(init)); + } + // Make sure node is expanded (and loaded) in 'child' mode + if( mode === "child" && !this.isExpanded() && this.hasChildren() !== false ) { + this.setExpanded().done(function(){ + self.editCreateNode(mode, init); + }); + return; + } + newNode = this.addNode(init, mode); + newNode.makeVisible(/*{noAnimation: true}*/).done(function(){ + $(newNode[tree.statusClassPropName]).addClass("fancytree-edit-new"); + self.tree.ext.edit.relatedNode = self; + newNode.editStart(); + }); +}; + + +/** + * [ext-edit] Check if any node in this tree in edit mode. + * + * @returns {FancytreeNode | null} + * @alias Fancytree#isEditing + * @requires jquery.fancytree.edit.js + */ +$.ui.fancytree._FancytreeClass.prototype.isEditing = function(){ + return this.ext.edit.currentNode; +}; + + +/** + * [ext-edit] Check if this node is in edit mode. + * @returns {Boolean} true if node is currently beeing edited + * @alias FancytreeNode#isEditing + * @requires jquery.fancytree.edit.js + */ +$.ui.fancytree._FancytreeNodeClass.prototype.isEditing = function(){ + return this.tree.ext.edit.currentNode === this; +}; + + +/******************************************************************************* + * Extension code + */ +$.ui.fancytree.registerExtension({ + name: "edit", + version: "0.2.0", + // Default options for this extension. + options: { + adjustWidthOfs: 4, // null: don't adjust input size to content + allowEmpty: false, // Prevent empty input + inputCss: {minWidth: "3em"}, + triggerCancel: ["esc", "tab", "click"], + // triggerStart: ["f2", "dblclick", "shift+click", "mac+enter"], + triggerStart: ["f2", "shift+click", "mac+enter"], + trim: true, // Trim whitespace before save + // Events: + beforeClose: $.noop, // Return false to prevent cancel/save (data.input is available) + beforeEdit: $.noop, // Return false to prevent edit mode + close: $.noop, // Editor was removed + edit: $.noop, // Editor was opened (available as data.input) +// keypress: $.noop, // Not yet implemented + save: $.noop // Save data.input.val() or return false to keep editor open + }, + // Local attributes + currentNode: null, + + treeInit: function(ctx){ + this._superApply(arguments); + this.$container.addClass("fancytree-ext-edit"); + }, + nodeClick: function(ctx) { + if( $.inArray("shift+click", ctx.options.edit.triggerStart) >= 0 ){ + if( ctx.originalEvent.shiftKey ){ + ctx.node.editStart(); + return false; + } + } + return this._superApply(arguments); + }, + nodeDblclick: function(ctx) { + if( $.inArray("dblclick", ctx.options.edit.triggerStart) >= 0 ){ + ctx.node.editStart(); + return false; + } + return this._superApply(arguments); + }, + nodeKeydown: function(ctx) { + switch( ctx.originalEvent.which ) { + case 113: // [F2] + if( $.inArray("f2", ctx.options.edit.triggerStart) >= 0 ){ + ctx.node.editStart(); + return false; + } + break; + case $.ui.keyCode.ENTER: + if( $.inArray("mac+enter", ctx.options.edit.triggerStart) >= 0 && isMac ){ + ctx.node.editStart(); + return false; + } + break; + } + return this._superApply(arguments); + } +}); +}(jQuery, window, document)); + +/*! + * jquery.fancytree.filter.js + * + * Remove or highlight tree nodes, based on a filter. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + + +/******************************************************************************* + * Private functions and variables + */ + +function _escapeRegex(str){ + /*jshint regexdash:true */ + return (str + "").replace(/([.?*+\^\$\[\]\\(){}|-])/g, "\\$1"); +} + +$.ui.fancytree._FancytreeClass.prototype._applyFilterImpl = function(filter, branchMode, opts){ + var leavesOnly, match, re, re2, + count = 0, + filterOpts = this.options.filter, + hideMode = filterOpts.mode === "hide"; + + opts = opts || {}; + leavesOnly = !!opts.leavesOnly && !branchMode; + + // Default to 'match title substring (not case sensitive)' + if(typeof filter === "string"){ + // console.log("rex", filter.split('').join('\\w*').replace(/\W/, "")) + if( filterOpts.fuzzy ) { + // See https://codereview.stackexchange.com/questions/23899/faster-javascript-fuzzy-string-matching-function/23905#23905 + // and http://www.quora.com/How-is-the-fuzzy-search-algorithm-in-Sublime-Text-designed + // and http://www.dustindiaz.com/autocomplete-fuzzy-matching + match = filter.split("").reduce(function(a, b) { + return a + "[^" + b + "]*" + b; + }); + } else { + match = _escapeRegex(filter); // make sure a '.' is treated literally + } + re = new RegExp(".*" + match + ".*", "i"); + re2 = new RegExp(filter, "gi"); + filter = function(node){ + var res = !!re.test(node.title); + // node.debug("filter res", res, filterOpts.highlight) + if( res && filterOpts.highlight ) { + node.titleWithHighlight = node.title.replace(re2, function(s){ + return "<mark>" + s + "</mark>"; + }); + // } else { + // delete node.titleWithHighlight; + } + return res; + }; + } + + this.enableFilter = true; + this.lastFilterArgs = arguments; + + this.$div.addClass("fancytree-ext-filter"); + if( hideMode ){ + this.$div.addClass("fancytree-ext-filter-hide"); + } else { + this.$div.addClass("fancytree-ext-filter-dimm"); + } + // Reset current filter + this.visit(function(node){ + delete node.match; + delete node.titleWithHighlight; + node.subMatchCount = 0; + }); + // Adjust node.hide, .match, and .subMatchCount properties + this.visit(function(node){ + if ((!leavesOnly || node.children == null) && filter(node)) { + count++; + node.match = true; + node.visitParents(function(p){ + p.subMatchCount += 1; + if( opts.autoExpand && !p.expanded ) { + p.setExpanded(true, {noAnimation: true, noEvents: true, scrollIntoView: false}); + p._filterAutoExpanded = true; + } + }); + if( branchMode ) { + node.visit(function(p){ + p.match = true; + }); + return "skip"; + } + } + }); + // Redraw whole tree + this.render(); + return count; +}; + +/** + * [ext-filter] Dimm or hide nodes. + * + * @param {function | string} filter + * @param {boolean} [opts={autoExpand: false, leavesOnly: false}] + * @returns {integer} count + * @alias Fancytree#filterNodes + * @requires jquery.fancytree.filter.js + */ +$.ui.fancytree._FancytreeClass.prototype.filterNodes = function(filter, opts) { + if( typeof opts === "boolean" ) { + opts = { leavesOnly: opts }; + this.warn("Fancytree.filterNodes() leavesOnly option is deprecated since 2.9.0 / 2015-04-19."); + } + return this._applyFilterImpl(filter, false, opts); +}; + +/** + * @deprecated + */ +$.ui.fancytree._FancytreeClass.prototype.applyFilter = function(filter){ + this.warn("Fancytree.applyFilter() is deprecated since 2.1.0 / 2014-05-29. Use .filterNodes() instead."); + return this.filterNodes.apply(this, arguments); +}; + +/** + * [ext-filter] Dimm or hide whole branches. + * + * @param {function | string} filter + * @param {boolean} [opts={autoExpand: false}] + * @returns {integer} count + * @alias Fancytree#filterBranches + * @requires jquery.fancytree.filter.js + */ +$.ui.fancytree._FancytreeClass.prototype.filterBranches = function(filter, opts){ + return this._applyFilterImpl(filter, true, opts); +}; + + +/** + * [ext-filter] Reset the filter. + * + * @alias Fancytree#clearFilter + * @requires jquery.fancytree.filter.js + */ +$.ui.fancytree._FancytreeClass.prototype.clearFilter = function(){ + this.visit(function(node){ + if( node.match ) { // #491 + $(">span.fancytree-title", node.span).html(node.title); + } + delete node.match; + delete node.subMatchCount; + delete node.titleWithHighlight; + if ( node.$subMatchBadge ) { + node.$subMatchBadge.remove(); + delete node.$subMatchBadge; + } + if( node._filterAutoExpanded && node.expanded ) { + node.setExpanded(false, {noAnimation: true, noEvents: true, scrollIntoView: false}); + } + delete node._filterAutoExpanded; + }); + this.enableFilter = false; + this.lastFilterArgs = null; + this.$div.removeClass("fancytree-ext-filter fancytree-ext-filter-dimm fancytree-ext-filter-hide"); + this.render(); +}; + + +/** + * [ext-filter] Return true if a filter is currently applied. + * + * @returns {Boolean} + * @alias Fancytree#isFilterActive + * @requires jquery.fancytree.filter.js + * @since 2.13 + */ +$.ui.fancytree._FancytreeClass.prototype.isFilterActive = function(){ + return !!this.enableFilter; +}; + + +/** + * [ext-filter] Return true if this node is matched by current filter (or no filter is active). + * + * @returns {Boolean} + * @alias FancytreeNode#isMatched + * @requires jquery.fancytree.filter.js + * @since 2.13 + */ +$.ui.fancytree._FancytreeNodeClass.prototype.isMatched = function(){ + return !(this.tree.enableFilter && !this.match); +}; + + +/******************************************************************************* + * Extension code + */ +$.ui.fancytree.registerExtension({ + name: "filter", + version: "0.7.0", + // Default options for this extension. + options: { + autoApply: true, // Re-apply last filter if lazy data is loaded + counter: true, // Show a badge with number of matching child nodes near parent icons + fuzzy: false, // Match single characters in order, e.g. 'fb' will match 'FooBar' + hideExpandedCounter: true, // Hide counter badge, when parent is expanded + highlight: true, // Highlight matches by wrapping inside <mark> tags + mode: "dimm" // Grayout unmatched nodes (pass "hide" to remove unmatched node instead) + }, + // treeCreate: function(ctx){ + // this._superApply(arguments); + // console.log("create") + // ctx.tree.options.renderTitle = function(event, data) { + // var node = data.node; + // console.log("create n", node.titleWithHighlight, data.tree.enableFilter) + // if( node.titleWithHighlight && node.tree.enableFilter ) { + // return node.titleWithHighlight; + // } + // } + // }, + // treeInit: function(ctx){ + // this._superApply(arguments); + // }, + nodeLoadChildren: function(ctx, source) { + return this._superApply(arguments).done(function() { + if( ctx.tree.enableFilter && ctx.tree.lastFilterArgs && ctx.options.filter.autoApply ) { + ctx.tree._applyFilterImpl.apply(ctx.tree, ctx.tree.lastFilterArgs); + } + }); + }, + nodeSetExpanded: function(ctx, flag, callOpts) { + delete ctx.node._filterAutoExpanded; + // Make sure counter badge is displayed again, when node is beeing collapsed + if( !flag && ctx.options.filter.hideExpandedCounter && ctx.node.$subMatchBadge ) { + ctx.node.$subMatchBadge.show(); + } + return this._superApply(arguments); + }, + nodeRenderStatus: function(ctx) { + // Set classes for current status + var res, + node = ctx.node, + tree = ctx.tree, + opts = ctx.options.filter, + $span = $(node[tree.statusClassPropName]); + + res = this._superApply(arguments); + // nothing to do, if node was not yet rendered + if( !$span.length || !tree.enableFilter ) { + return res; + } + $span + .toggleClass("fancytree-match", !!node.match) + .toggleClass("fancytree-submatch", !!node.subMatchCount) + .toggleClass("fancytree-hide", !(node.match || node.subMatchCount)); + // Add/update counter badge + if( opts.counter && node.subMatchCount && (!node.isExpanded() || !opts.hideExpandedCounter) ) { + if( !node.$subMatchBadge ) { + node.$subMatchBadge = $("<span class='fancytree-childcounter'/>"); + $("span.fancytree-icon", node.span).append(node.$subMatchBadge); + } + node.$subMatchBadge.show().text(node.subMatchCount); + } else if ( node.$subMatchBadge ) { + node.$subMatchBadge.hide(); + } + // node.debug("nodeRenderStatus", node.titleWithHighlight, node.title) + if( node.titleWithHighlight ) { + $("span.fancytree-title", node.span).html(node.titleWithHighlight); + } else { + $("span.fancytree-title", node.span).html(node.title); + } + return res; + } +}); +}(jQuery, window, document)); + +/*! + * jquery.fancytree.glyph.js + * + * Use glyph fonts as instead of icon sprites. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + +/* ***************************************************************************** + * Private functions and variables + */ + +function _getIcon(opts, type){ + return opts.map[type]; +} + +$.ui.fancytree.registerExtension({ + name: "glyph", + version: "0.3.0", + // Default options for this extension. + options: { + map: { + // Samples from Font Awesome 3.2 + // http://fortawesome.github.io/Font-Awesome/3.2.1/icons/ + // See here for alternatives: + // http://fortawesome.github.io/Font-Awesome/icons/ + // http://getbootstrap.com/components/ + checkbox: "icon-check-empty", + checkboxSelected: "icon-check", + checkboxUnknown: "icon-check icon-muted", + error: "icon-exclamation-sign", + expanderClosed: "icon-caret-right", + expanderLazy: "icon-angle-right", + expanderOpen: "icon-caret-down", + noExpander: "", + dragHelper: "icon-caret-right", + dropMarker: "icon-caret-right", + // Default node icons. + // (Use tree.options.iconClass callback to define custom icons + // based on node data) + doc: "icon-file-alt", + docOpen: "icon-file-alt", + loading: "icon-refresh icon-spin", + folder: "icon-folder-close-alt", + folderOpen: "icon-folder-open-alt" + } + }, + + treeInit: function(ctx){ + var tree = ctx.tree; + this._superApply(arguments); + tree.$container.addClass("fancytree-ext-glyph"); + }, + nodeRenderStatus: function(ctx) { + var icon, span, + node = ctx.node, + $span = $(node.span), + opts = ctx.options.glyph, + // callback = opts.icon, + map = opts.map + // $span = $(node.span) + ; + + this._superApply(arguments); + + if( node.isRoot() ){ + return; + } + span = $span.children("span.fancytree-expander").get(0); + if( span ){ + if( node.isLoading() ){ + icon = "loading"; + }else if( node.expanded ){ + icon = "expanderOpen"; + }else if( node.isUndefined() ){ + icon = "expanderLazy"; + }else if( node.hasChildren() ){ + icon = "expanderClosed"; + }else{ + icon = "noExpander"; + } + span.className = "fancytree-expander " + map[icon]; + } + + if( node.tr ){ + span = $("td", node.tr).find("span.fancytree-checkbox").get(0); + }else{ + span = $span.children("span.fancytree-checkbox").get(0); + } + if( span ){ + icon = node.selected ? "checkboxSelected" : (node.partsel ? "checkboxUnknown" : "checkbox"); + span.className = "fancytree-checkbox " + map[icon]; + } + + // Icon (note that this does not match .fancytree-custom-icon, that might + // be set by opts.iconClass) + span = $span.children("span.fancytree-icon").get(0); + if( span ){ + if( node.folder ){ + icon = node.expanded ? _getIcon(opts, "folderOpen") : _getIcon(opts, "folder"); + }else{ + icon = node.expanded ? _getIcon(opts, "docOpen") : _getIcon(opts, "doc"); + } + span.className = "fancytree-icon " + icon; + } + }, + nodeSetStatus: function(ctx, status, message, details) { + var span, + opts = ctx.options.glyph, + node = ctx.node; + + this._superApply(arguments); + + if(node.parent){ + span = $("span.fancytree-expander", node.span).get(0); + }else{ + span = $(".fancytree-statusnode-wait, .fancytree-statusnode-error", node[this.nodeContainerAttrName]) + .find("span.fancytree-expander").get(0); + } + if( status === "loading"){ + // $("span.fancytree-expander", ctx.node.span).addClass(_getIcon(opts, "loading")); + span.className = "fancytree-expander " + _getIcon(opts, "loading"); + }else if( status === "error"){ + span.className = "fancytree-expander " + _getIcon(opts, "error"); + } + } +}); +}(jQuery, window, document)); + +/*! + * jquery.fancytree.gridnav.js + * + * Support keyboard navigation for trees with embedded input controls. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + + +/******************************************************************************* + * Private functions and variables + */ + +// Allow these navigation keys even when input controls are focused + +var KC = $.ui.keyCode, + // which keys are *not* handled by embedded control, but passed to tree + // navigation handler: + NAV_KEYS = { + "text": [KC.UP, KC.DOWN], + "checkbox": [KC.UP, KC.DOWN, KC.LEFT, KC.RIGHT], + "radiobutton": [KC.UP, KC.DOWN, KC.LEFT, KC.RIGHT], + "select-one": [KC.LEFT, KC.RIGHT], + "select-multiple": [KC.LEFT, KC.RIGHT] + }; + + +/* Calculate TD column index (considering colspans).*/ +function getColIdx($tr, $td) { + var colspan, + td = $td.get(0), + idx = 0; + + $tr.children().each(function () { + if( this === td ) { + return false; + } + colspan = $(this).prop("colspan"); + idx += colspan ? colspan : 1; + }); + return idx; +} + + +/* Find TD at given column index (considering colspans).*/ +function findTdAtColIdx($tr, colIdx) { + var colspan, + res = null, + idx = 0; + + $tr.children().each(function () { + if( idx >= colIdx ) { + res = $(this); + return false; + } + colspan = $(this).prop("colspan"); + idx += colspan ? colspan : 1; + }); + return res; +} + + +/* Find adjacent cell for a given direction. Skip empty cells and consider merged cells */ +function findNeighbourTd($target, keyCode){ + var $tr, colIdx, + $td = $target.closest("td"), + $tdNext = null; + + switch( keyCode ){ + case KC.LEFT: + $tdNext = $td.prev(); + break; + case KC.RIGHT: + $tdNext = $td.next(); + break; + case KC.UP: + case KC.DOWN: + $tr = $td.parent(); + colIdx = getColIdx($tr, $td); + while( true ) { + $tr = (keyCode === KC.UP) ? $tr.prev() : $tr.next(); + if( !$tr.length ) { + break; + } + // Skip hidden rows + if( $tr.is(":hidden") ) { + continue; + } + // Find adjacent cell in the same column + $tdNext = findTdAtColIdx($tr, colIdx); + // Skip cells that don't conatain a focusable element + if( $tdNext && $tdNext.find(":input").length ) { + break; + } + } + break; + } + return $tdNext; +} + + +/******************************************************************************* + * Extension code + */ +$.ui.fancytree.registerExtension({ + name: "gridnav", + version: "0.0.1", + // Default options for this extension. + options: { + autofocusInput: false, // Focus first embedded input if node gets activated + handleCursorKeys: true // Allow UP/DOWN in inputs to move to prev/next node + }, + + treeInit: function(ctx){ + // gridnav requires the table extension to be loaded before itself + this._requireExtension("table", true, true); + this._superApply(arguments); + + this.$container.addClass("fancytree-ext-gridnav"); + + // Activate node if embedded input gets focus (due to a click) + this.$container.on("focusin", function(event){ + var ctx2, + node = $.ui.fancytree.getNode(event.target); + + if( node && !node.isActive() ){ + // Call node.setActive(), but also pass the event + ctx2 = ctx.tree._makeHookContext(node, event); + ctx.tree._callHook("nodeSetActive", ctx2, true); + } + }); + }, + nodeSetActive: function(ctx, flag) { + var $outer, + opts = ctx.options.gridnav, + node = ctx.node, + event = ctx.originalEvent || {}, + triggeredByInput = $(event.target).is(":input"); + + flag = (flag !== false); + + this._superApply(arguments); + + if( flag ){ + if( ctx.options.titlesTabbable ){ + if( !triggeredByInput ) { + $(node.span).find("span.fancytree-title").focus(); + node.setFocus(); + } + // If one node is tabbable, the container no longer needs to be + ctx.tree.$container.attr("tabindex", "-1"); + // ctx.tree.$container.removeAttr("tabindex"); + } else if( opts.autofocusInput && !triggeredByInput ){ + // Set focus to input sub input (if node was clicked, but not + // when TAB was pressed ) + $outer = $(node.tr || node.span); + $outer.find(":input:enabled:first").focus(); + } + } + }, + nodeKeydown: function(ctx) { + var inputType, handleKeys, $td, + opts = ctx.options.gridnav, + event = ctx.originalEvent, + $target = $(event.target); + + // jQuery + inputType = $target.is(":input:enabled") ? $target.prop("type") : null; +// ctx.tree.debug("ext-gridnav nodeKeydown", event, inputType); + + if( inputType && opts.handleCursorKeys ){ + handleKeys = NAV_KEYS[inputType]; + if( handleKeys && $.inArray(event.which, handleKeys) >= 0 ){ + $td = findNeighbourTd($target, event.which); + // ctx.node.debug("ignore keydown in input", event.which, handleKeys); + if( $td && $td.length ) { + $td.find(":input:enabled").focus(); + // Prevent Fancytree default navigation + return false; + } + } + return true; + } + // ctx.tree.debug("ext-gridnav NOT HANDLED", event, inputType); + return this._superApply(arguments); + } +}); +}(jQuery, window, document)); + +/*! + * jquery.fancytree.persist.js + * + * Persist tree status in cookiesRemove or highlight tree nodes, based on a filter. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * @depends: js-cookie or jquery-cookie + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; +/* global Cookies:false */ + +/******************************************************************************* + * Private functions and variables + */ +var cookieGetter, cookieRemover, cookieSetter, + _assert = $.ui.fancytree.assert, + ACTIVE = "active", + EXPANDED = "expanded", + FOCUS = "focus", + SELECTED = "selected"; + +if( typeof Cookies === "function" ) { + // Assume https://github.com/js-cookie/js-cookie + cookieSetter = Cookies.set; + cookieGetter = Cookies.get; + cookieRemover = Cookies.remove; +} else { + // Fall back to https://github.com/carhartl/jquery-cookie + cookieSetter = cookieGetter = $.cookie; + cookieRemover = $.removeCookie; +} + +/* Recursively load lazy nodes + * @param {string} mode 'load', 'expand', false + */ +function _loadLazyNodes(tree, local, keyList, mode, dfd) { + var i, key, l, node, + foundOne = false, + deferredList = [], + missingKeyList = []; + + keyList = keyList || []; + dfd = dfd || $.Deferred(); + + for( i=0, l=keyList.length; i<l; i++ ) { + key = keyList[i]; + node = tree.getNodeByKey(key); + if( node ) { + if( mode && node.isUndefined() ) { + foundOne = true; + tree.debug("_loadLazyNodes: " + node + " is lazy: loading..."); + if( mode === "expand" ) { + deferredList.push(node.setExpanded()); + } else { + deferredList.push(node.load()); + } + } else { + tree.debug("_loadLazyNodes: " + node + " already loaded."); + node.setExpanded(); + } + } else { + missingKeyList.push(key); + tree.debug("_loadLazyNodes: " + node + " was not yet found."); + } + } + + $.when.apply($, deferredList).always(function(){ + // All lazy-expands have finished + if( foundOne && missingKeyList.length > 0 ) { + // If we read new nodes from server, try to resolve yet-missing keys + _loadLazyNodes(tree, local, missingKeyList, mode, dfd); + } else { + if( missingKeyList.length ) { + tree.warn("_loadLazyNodes: could not load those keys: ", missingKeyList); + for( i=0, l=missingKeyList.length; i<l; i++ ) { + key = keyList[i]; + local._appendKey(EXPANDED, keyList[i], false); + } + } + dfd.resolve(); + } + }); + return dfd; +} + + +/** + * [ext-persist] Remove persistence cookies of the given type(s). + * Called like + * $("#tree").fancytree("getTree").clearCookies("active expanded focus selected"); + * + * @alias Fancytree#clearCookies + * @requires jquery.fancytree.persist.js + */ +$.ui.fancytree._FancytreeClass.prototype.clearCookies = function(types){ + var local = this.ext.persist, + prefix = local.cookiePrefix; + + types = types || "active expanded focus selected"; + if(types.indexOf(ACTIVE) >= 0){ + local._data(prefix + ACTIVE, null); + } + if(types.indexOf(EXPANDED) >= 0){ + local._data(prefix + EXPANDED, null); + } + if(types.indexOf(FOCUS) >= 0){ + local._data(prefix + FOCUS, null); + } + if(types.indexOf(SELECTED) >= 0){ + local._data(prefix + SELECTED, null); + } +}; + + +/** + * [ext-persist] Return persistence information from cookies + * + * Called like + * $("#tree").fancytree("getTree").getPersistData(); + * + * @alias Fancytree#getPersistData + * @requires jquery.fancytree.persist.js + */ +$.ui.fancytree._FancytreeClass.prototype.getPersistData = function(){ + var local = this.ext.persist, + prefix = local.cookiePrefix, + delim = local.cookieDelimiter, + res = {}; + + res[ACTIVE] = local._data(prefix + ACTIVE); + res[EXPANDED] = (local._data(prefix + EXPANDED) || "").split(delim); + res[SELECTED] = (local._data(prefix + SELECTED) || "").split(delim); + res[FOCUS] = local._data(prefix + FOCUS); + return res; +}; + + +/* ***************************************************************************** + * Extension code + */ +$.ui.fancytree.registerExtension({ + name: "persist", + version: "0.3.0", + // Default options for this extension. + options: { + cookieDelimiter: "~", + cookiePrefix: undefined, // 'fancytree-<treeId>-' by default + cookie: { + raw: false, + expires: "", + path: "", + domain: "", + secure: false + }, + expandLazy: false, // true: recursively expand and load lazy nodes + fireActivate: true, // false: suppress `activate` event after active node was restored + overrideSource: true, // true: cookie takes precedence over `source` data attributes. + store: "auto", // 'cookie': force cookie, 'local': force localStore, 'session': force sessionStore + types: "active expanded focus selected" + }, + + /* Generic read/write string data to cookie, sessionStorage or localStorage. */ + _data: function(key, value){ + var ls = this._local.localStorage; // null, sessionStorage, or localStorage + + if( value === undefined ) { + return ls ? ls.getItem(key) : cookieGetter(key); + } else if ( value === null ) { + if( ls ) { + ls.removeItem(key); + } else { + cookieRemover(key); + } + } else { + if( ls ) { + ls.setItem(key, value); + } else { + cookieSetter(key, value, this.options.persist.cookie); + } + } + }, + + /* Append `key` to a cookie. */ + _appendKey: function(type, key, flag){ + key = "" + key; // #90 + var local = this._local, + instOpts = this.options.persist, + delim = instOpts.cookieDelimiter, + cookieName = local.cookiePrefix + type, + data = local._data(cookieName), + keyList = data ? data.split(delim) : [], + idx = $.inArray(key, keyList); + // Remove, even if we add a key, so the key is always the last entry + if(idx >= 0){ + keyList.splice(idx, 1); + } + // Append key to cookie + if(flag){ + keyList.push(key); + } + local._data(cookieName, keyList.join(delim)); + }, + + treeInit: function(ctx){ + var tree = ctx.tree, + opts = ctx.options, + local = this._local, + instOpts = this.options.persist; + + // For 'auto' or 'cookie' mode, the cookie plugin must be available + _assert((instOpts.store !== "auto" && instOpts.store !== "cookie") || cookieGetter, + "Missing required plugin for 'persist' extension: js.cookie.js or jquery.cookie.js"); + + local.cookiePrefix = instOpts.cookiePrefix || ("fancytree-" + tree._id + "-"); + local.storeActive = instOpts.types.indexOf(ACTIVE) >= 0; + local.storeExpanded = instOpts.types.indexOf(EXPANDED) >= 0; + local.storeSelected = instOpts.types.indexOf(SELECTED) >= 0; + local.storeFocus = instOpts.types.indexOf(FOCUS) >= 0; + if( instOpts.store === "cookie" || !window.localStorage ) { + local.localStorage = null; + } else { + local.localStorage = (instOpts.store === "local") ? window.localStorage : window.sessionStorage; + } + + // Bind init-handler to apply cookie state + tree.$div.bind("fancytreeinit", function(event){ + var cookie, dfd, i, keyList, node, + prevFocus = local._data(local.cookiePrefix + FOCUS), // record this before node.setActive() overrides it; + noEvents = instOpts.fireActivate === false; + + // tree.debug("document.cookie:", document.cookie); + + cookie = local._data(local.cookiePrefix + EXPANDED); + keyList = cookie && cookie.split(instOpts.cookieDelimiter); + + if( local.storeExpanded ) { + // Recursively load nested lazy nodes if expandLazy is 'expand' or 'load' + // Also remove expand-cookies for unmatched nodes + dfd = _loadLazyNodes(tree, local, keyList, instOpts.expandLazy ? "expand" : false , null); + } else { + // nothing to do + dfd = new $.Deferred().resolve(); + } + + dfd.done(function(){ + if(local.storeSelected){ + cookie = local._data(local.cookiePrefix + SELECTED); + if(cookie){ + keyList = cookie.split(instOpts.cookieDelimiter); + for(i=0; i<keyList.length; i++){ + node = tree.getNodeByKey(keyList[i]); + if(node){ + if(node.selected === undefined || instOpts.overrideSource && (node.selected === false)){ +// node.setSelected(); + node.selected = true; + node.renderStatus(); + } + }else{ + // node is no longer member of the tree: remove from cookie also + local._appendKey(SELECTED, keyList[i], false); + } + } + } + // In selectMode 3 we have to fix the child nodes, since we + // only stored the selected *top* nodes + if( tree.options.selectMode === 3 ){ + tree.visit(function(n){ + if( n.selected ) { + n.fixSelection3AfterClick(); + return "skip"; + } + }); + } + } + if(local.storeActive){ + cookie = local._data(local.cookiePrefix + ACTIVE); + if(cookie && (opts.persist.overrideSource || !tree.activeNode)){ + node = tree.getNodeByKey(cookie); + if(node){ + node.debug("persist: set active", cookie); + // We only want to set the focus if the container + // had the keyboard focus before + node.setActive(true, { + noFocus: true, + noEvents: noEvents + }); + } + } + } + if(local.storeFocus && prevFocus){ + node = tree.getNodeByKey(prevFocus); + if(node){ + // node.debug("persist: set focus", cookie); + if( tree.options.titlesTabbable ) { + $(node.span).find(".fancytree-title").focus(); + } else { + $(tree.$container).focus(); + } + // node.setFocus(); + } + } + tree._triggerTreeEvent("restore", null, {}); + }); + }); + // Init the tree + return this._superApply(arguments); + }, + nodeSetActive: function(ctx, flag, opts) { + var res, + local = this._local; + + flag = (flag !== false); + res = this._superApply(arguments); + + if(local.storeActive){ + local._data(local.cookiePrefix + ACTIVE, this.activeNode ? this.activeNode.key : null); + } + return res; + }, + nodeSetExpanded: function(ctx, flag, opts) { + var res, + node = ctx.node, + local = this._local; + + flag = (flag !== false); + res = this._superApply(arguments); + + if(local.storeExpanded){ + local._appendKey(EXPANDED, node.key, flag); + } + return res; + }, + nodeSetFocus: function(ctx, flag) { + var res, + local = this._local; + + flag = (flag !== false); + res = this._superApply(arguments); + + if( local.storeFocus ) { + local._data(local.cookiePrefix + FOCUS, this.focusNode ? this.focusNode.key : null); + } + return res; + }, + nodeSetSelected: function(ctx, flag) { + var res, selNodes, + tree = ctx.tree, + node = ctx.node, + local = this._local; + + flag = (flag !== false); + res = this._superApply(arguments); + + if(local.storeSelected){ + if( tree.options.selectMode === 3 ){ + // In selectMode 3 we only store the the selected *top* nodes. + // De-selecting a node may also de-select some parents, so we + // calculate the current status again + selNodes = $.map(tree.getSelectedNodes(true), function(n){ + return n.key; + }); + selNodes = selNodes.join(ctx.options.persist.cookieDelimiter); + local._data(local.cookiePrefix + SELECTED, selNodes); + } else { + // beforeSelect can prevent the change - flag doesn't reflect the node.selected state + local._appendKey(SELECTED, node.key, node.selected); + } + } + return res; + } +}); +}(jQuery, window, document)); + +/*! + * jquery.fancytree.table.js + * + * Render tree as table (aka 'treegrid', 'tabletree'). + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + +/* ***************************************************************************** + * Private functions and variables + */ +function _assert(cond, msg){ + msg = msg || ""; + if(!cond){ + $.error("Assertion failed " + msg); + } +} + +function insertSiblingAfter(referenceNode, newNode) { + referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); +} + +/* Show/hide all rows that are structural descendants of `parent`. */ +function setChildRowVisibility(parent, flag) { + parent.visit(function(node){ + var tr = node.tr; + // currentFlag = node.hide ? false : flag; // fix for ext-filter + if(tr){ + tr.style.display = (node.hide || !flag) ? "none" : ""; + } + if(!node.expanded){ + return "skip"; + } + }); +} + +/* Find node that is rendered in previous row. */ +function findPrevRowNode(node){ + var i, last, prev, + parent = node.parent, + siblings = parent ? parent.children : null; + + if(siblings && siblings.length > 1 && siblings[0] !== node){ + // use the lowest descendant of the preceeding sibling + i = $.inArray(node, siblings); + prev = siblings[i - 1]; + _assert(prev.tr); + // descend to lowest child (with a <tr> tag) + while(prev.children){ + last = prev.children[prev.children.length - 1]; + if(!last.tr){ + break; + } + prev = last; + } + }else{ + // if there is no preceding sibling, use the direct parent + prev = parent; + } + return prev; +} + + +$.ui.fancytree.registerExtension({ + name: "table", + version: "0.2.1", + // Default options for this extension. + options: { + checkboxColumnIdx: null, // render the checkboxes into the this column index (default: nodeColumnIdx) + customStatus: false, // true: generate renderColumns events for status nodes + indentation: 16, // indent every node level by 16px + nodeColumnIdx: 0 // render node expander, icon, and title to this column (default: #0) + }, + // Overide virtual methods for this extension. + // `this` : is this extension object + // `this._super`: the virtual function that was overriden (member of prev. extension or Fancytree) + treeInit: function(ctx){ + var i, $row, tdRole, + tree = ctx.tree, + $table = tree.widget.element; + + $table.addClass("fancytree-container fancytree-ext-table"); + tree.tbody = $table.find("> tbody")[0]; + tree.columnCount = $("thead >tr >th", $table).length; + $(tree.tbody).empty(); + + tree.rowFragment = document.createDocumentFragment(); + $row = $("<tr />"); + tdRole = ""; + if(ctx.options.aria){ + $row.attr("role", "row"); + tdRole = " role='gridcell'"; + } + for(i=0; i<tree.columnCount; i++) { + if(ctx.options.table.nodeColumnIdx === i){ + $row.append("<td" + tdRole + "><span class='fancytree-node' /></td>"); + }else{ + $row.append("<td" + tdRole + " />"); + } + } + tree.rowFragment.appendChild($row.get(0)); + + // Make sure that status classes are set on the node's <tr> elements + tree.statusClassPropName = "tr"; + tree.ariaPropName = "tr"; + this.nodeContainerAttrName = "tr"; + + // #489: make sure $container is set to <table>, even if ext-dnd is listed before ext-table + tree.$container = $table; + + this._superApply(arguments); + + // standard Fancytree created a root UL + $(tree.rootNode.ul).remove(); + tree.rootNode.ul = null; +// tree.$container = $table; + // Add container to the TAB chain + this.$container.attr("tabindex", this.options.tabbable ? "0" : "-1"); + if(this.options.aria){ + tree.$container + .attr("role", "treegrid") + .attr("aria-readonly", true); + } + }, + /* Called by nodeRender to sync node order with tag order.*/ +// nodeFixOrder: function(ctx) { +// }, + nodeRemoveChildMarkup: function(ctx) { + var node = ctx.node; +// node.debug("nodeRemoveChildMarkup()"); + node.visit(function(n){ + if(n.tr){ + $(n.tr).remove(); + n.tr = null; + } + }); + }, + nodeRemoveMarkup: function(ctx) { + var node = ctx.node; +// node.debug("nodeRemoveMarkup()"); + if(node.tr){ + $(node.tr).remove(); + node.tr = null; + } + this.nodeRemoveChildMarkup(ctx); + }, + /* Override standard render. */ + nodeRender: function(ctx, force, deep, collapsed, _recursive) { + var children, firstTr, i, l, newRow, prevNode, prevTr, subCtx, + tree = ctx.tree, + node = ctx.node, + opts = ctx.options, + isRootNode = !node.parent; + + if( !_recursive ){ + ctx.hasCollapsedParents = node.parent && !node.parent.expanded; + } + // $.ui.fancytree.debug("*** nodeRender " + node + ", isRoot=" + isRootNode, "tr=" + node.tr, "hcp=" + ctx.hasCollapsedParents, "parent.tr=" + (node.parent && node.parent.tr)); + if( !isRootNode ){ + if(!node.tr){ + if( ctx.hasCollapsedParents && !deep ) { + // #166: we assume that the parent will be (recursively) rendered + // later anyway. + node.debug("nodeRender ignored due to unrendered parent"); + return; + } + // Create new <tr> after previous row + newRow = tree.rowFragment.firstChild.cloneNode(true); + prevNode = findPrevRowNode(node); + // $.ui.fancytree.debug("*** nodeRender " + node + ": prev: " + prevNode.key); + _assert(prevNode); + if(collapsed === true && _recursive){ + // hide all child rows, so we can use an animation to show it later + newRow.style.display = "none"; + }else if(deep && ctx.hasCollapsedParents){ + // also hide this row if deep === true but any parent is collapsed + newRow.style.display = "none"; +// newRow.style.color = "red"; + } + if(!prevNode.tr){ + _assert(!prevNode.parent, "prev. row must have a tr, or is system root"); + tree.tbody.appendChild(newRow); + }else{ + insertSiblingAfter(prevNode.tr, newRow); + } + node.tr = newRow; + if( node.key && opts.generateIds ){ + node.tr.id = opts.idPrefix + node.key; + } + node.tr.ftnode = node; + if(opts.aria){ + // TODO: why doesn't this work: +// node.li.role = "treeitem"; + $(node.tr).attr("aria-labelledby", "ftal_" + node.key); + } + node.span = $("span.fancytree-node", node.tr).get(0); + // Set icon, link, and title (normally this is only required on initial render) + this.nodeRenderTitle(ctx); + // Allow tweaking, binding, after node was created for the first time +// tree._triggerNodeEvent("createNode", ctx); + if ( opts.createNode ){ + opts.createNode.call(tree, {type: "createNode"}, ctx); + } + } else { + if( force ) { + // Set icon, link, and title (normally this is only required on initial render) + this.nodeRenderTitle(ctx); // triggers renderColumns() + } else { + // Update element classes according to node state + this.nodeRenderStatus(ctx); + } + } + } + // Allow tweaking after node state was rendered +// tree._triggerNodeEvent("renderNode", ctx); + if ( opts.renderNode ){ + opts.renderNode.call(tree, {type: "renderNode"}, ctx); + } + // Visit child nodes + // Add child markup + children = node.children; + if(children && (isRootNode || deep || node.expanded)){ + for(i=0, l=children.length; i<l; i++) { + subCtx = $.extend({}, ctx, {node: children[i]}); + subCtx.hasCollapsedParents = subCtx.hasCollapsedParents || !node.expanded; + this.nodeRender(subCtx, force, deep, collapsed, true); + } + } + // Make sure, that <tr> order matches node.children order. + if(children && !_recursive){ // we only have to do it once, for the root branch + prevTr = node.tr || null; + firstTr = tree.tbody.firstChild; + // Iterate over all descendants + node.visit(function(n){ + if(n.tr){ + if(!n.parent.expanded && n.tr.style.display !== "none"){ + // fix after a node was dropped over a collapsed + n.tr.style.display = "none"; + setChildRowVisibility(n, false); + } + if(n.tr.previousSibling !== prevTr){ + node.debug("_fixOrder: mismatch at node: " + n); + var nextTr = prevTr ? prevTr.nextSibling : firstTr; + tree.tbody.insertBefore(n.tr, nextTr); + } + prevTr = n.tr; + } + }); + } + // Update element classes according to node state + // if(!isRootNode){ + // this.nodeRenderStatus(ctx); + // } + }, + nodeRenderTitle: function(ctx, title) { + var $cb, + node = ctx.node, + opts = ctx.options; + + this._superApply(arguments); + // Move checkbox to custom column + if(opts.checkbox && opts.table.checkboxColumnIdx != null ){ + $cb = $("span.fancytree-checkbox", node.span).detach(); + $(node.tr).find("td").eq(+opts.table.checkboxColumnIdx).html($cb); + } + // Update element classes according to node state + if( ! node.isRoot() ){ + this.nodeRenderStatus(ctx); + } + if( !opts.table.customStatus && node.isStatusNode() ) { + // default rendering for status node: leave other cells empty + } else if ( opts.renderColumns ) { + // Let user code write column content + opts.renderColumns.call(ctx.tree, {type: "renderColumns"}, ctx); + } + }, + nodeRenderStatus: function(ctx) { + var indent, + node = ctx.node, + opts = ctx.options; + + this._superApply(arguments); + + $(node.tr).removeClass("fancytree-node"); + // indent + indent = (node.getLevel() - 1) * opts.table.indentation; + $(node.span).css({paddingLeft: indent + "px"}); // #460 + // $(node.span).css({marginLeft: indent + "px"}); + }, + /* Expand node, return Deferred.promise. */ + nodeSetExpanded: function(ctx, flag, opts) { + var dfd = new $.Deferred(), + subOpts = $.extend({}, opts, {noEvents: true, noAnimation: true}); + + opts = opts || {}; + + function _afterExpand(ok) { + flag = (flag !== false); + setChildRowVisibility(ctx.node, flag); + if( ok ) { + if( flag && ctx.options.autoScroll && !opts.noAnimation && ctx.node.hasChildren() ) { + // Scroll down to last child, but keep current node visible + ctx.node.getLastChild().scrollIntoView(true, {topNode: ctx.node}).always(function(){ + if( !opts.noEvents ) { + ctx.tree._triggerNodeEvent(flag ? "expand" : "collapse", ctx); + } + dfd.resolveWith(ctx.node); + }); + } else { + if( !opts.noEvents ) { + ctx.tree._triggerNodeEvent(flag ? "expand" : "collapse", ctx); + } + dfd.resolveWith(ctx.node); + } + } else { + if( !opts.noEvents ) { + ctx.tree._triggerNodeEvent(flag ? "expand" : "collapse", ctx); + } + dfd.rejectWith(ctx.node); + } + } + // Call base-expand with disabled events and animation + this._super(ctx, flag, subOpts).done(function () { + _afterExpand(true); + }).fail(function () { + _afterExpand(false); + }); + return dfd.promise(); + }, + nodeSetStatus: function(ctx, status, message, details) { + if(status === "ok"){ + var node = ctx.node, + firstChild = ( node.children ? node.children[0] : null ); + if ( firstChild && firstChild.isStatusNode() ) { + $(firstChild.tr).remove(); + } + } + return this._superApply(arguments); + }, + treeClear: function(ctx) { + this.nodeRemoveChildMarkup(this._makeHookContext(this.rootNode)); + return this._superApply(arguments); + }, + treeDestroy: function(ctx) { + this.$container.find("tbody").empty(); + this.$source && this.$source.removeClass("ui-helper-hidden"); + } + /*, + treeSetFocus: function(ctx, flag) { +// alert("treeSetFocus" + ctx.tree.$container); + ctx.tree.$container.focus(); + $.ui.fancytree.focusTree = ctx.tree; + }*/ +}); +}(jQuery, window, document)); + +/*! + * jquery.fancytree.themeroller.js + * + * Enable jQuery UI ThemeRoller styles. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * @see http://jqueryui.com/themeroller/ + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + +/******************************************************************************* + * Extension code + */ +$.ui.fancytree.registerExtension({ + name: "themeroller", + version: "0.0.1", + // Default options for this extension. + options: { + activeClass: "ui-state-active", + foccusClass: "ui-state-focus", + hoverClass: "ui-state-hover", + selectedClass: "ui-state-highlight" + }, + + treeInit: function(ctx){ + this._superApply(arguments); + var $el = ctx.widget.element; + + if($el[0].nodeName === "TABLE"){ + $el.addClass("ui-widget ui-corner-all"); + $el.find(">thead tr").addClass("ui-widget-header"); + $el.find(">tbody").addClass("ui-widget-conent"); + }else{ + $el.addClass("ui-widget ui-widget-content ui-corner-all"); + } + + $el.delegate(".fancytree-node", "mouseenter mouseleave", function(event){ + var node = $.ui.fancytree.getNode(event.target), + flag = (event.type === "mouseenter"); + node.debug("hover: " + flag); + $(node.tr ? node.tr : node.span).toggleClass("ui-state-hover ui-corner-all", flag); + }); + }, + treeDestroy: function(ctx){ + this._superApply(arguments); + ctx.widget.element.removeClass("ui-widget ui-widget-content ui-corner-all"); + }, + nodeRenderStatus: function(ctx){ + var node = ctx.node, + $el = $(node.tr ? node.tr : node.span); + this._superApply(arguments); +/* + .ui-state-highlight: Class to be applied to highlighted or selected elements. Applies "highlight" container styles to an element and its child text, links, and icons. + .ui-state-error: Class to be applied to error messaging container elements. Applies "error" container styles to an element and its child text, links, and icons. + .ui-state-error-text: An additional class that applies just the error text color without background. Can be used on form labels for instance. Also applies error icon color to child icons. + + .ui-state-default: Class to be applied to clickable button-like elements. Applies "clickable default" container styles to an element and its child text, links, and icons. + .ui-state-hover: Class to be applied on mouseover to clickable button-like elements. Applies "clickable hover" container styles to an element and its child text, links, and icons. + .ui-state-focus: Class to be applied on keyboard focus to clickable button-like elements. Applies "clickable hover" container styles to an element and its child text, links, and icons. + .ui-state-active: Class to be applied on mousedown to clickable button-like elements. Applies "clickable active" container styles to an element and its child text, links, and icons. +*/ + $el.toggleClass("ui-state-active", node.isActive()); + $el.toggleClass("ui-state-focus", node.hasFocus()); + $el.toggleClass("ui-state-highlight", node.isSelected()); + } +}); +}(jQuery, window, document)); + +/*! + * jquery.fancytree.wide.js + * Support for 100% wide selection bars. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + +var reNumUnit = /^([+-]?(?:\d+|\d*\.\d+))([a-z]*|%)$/; // split "1.5em" to ["1.5", "em"] + +/******************************************************************************* + * Private functions and variables + */ +// var _assert = $.ui.fancytree.assert; + +/* Calculate inner width without scrollbar */ +// function realInnerWidth($el) { +// // http://blog.jquery.com/2012/08/16/jquery-1-8-box-sizing-width-csswidth-and-outerwidth/ +// // inst.contWidth = parseFloat(this.$container.css("width"), 10); +// // 'Client width without scrollbar' - 'padding' +// return $el[0].clientWidth - ($el.innerWidth() - parseFloat($el.css("width"), 10)); +// } + +/* Create a global embedded CSS style for the tree. */ +function defineHeadStyleElement(id, cssText) { + id = "fancytree-style-" + id; + var $headStyle = $("#" + id); + + if( !cssText ) { + $headStyle.remove(); + return null; + } + if( !$headStyle.length ) { + $headStyle = $("<style />") + .attr("id", id) + .addClass("fancytree-style") + .prop("type", "text/css") + .appendTo("head"); + } + try { + $headStyle.html(cssText); + } catch ( e ) { + // fix for IE 6-8 + $headStyle[0].styleSheet.cssText = cssText; + } + return $headStyle; +} + +/* Calculate the CSS rules that indent title spans. */ +function renderLevelCss(containerId, depth, levelOfs, lineOfs, measureUnit) { + var i, + prefix = "#" + containerId + " span.fancytree-level-", + rules = []; + + for(i = 0; i < depth; i++) { + rules.push(prefix + (i + 1) + " span.fancytree-title { padding-left: " + + (i * levelOfs + lineOfs) + measureUnit + "; }"); + } + // Some UI animations wrap the UL inside a DIV and set position:relative on both. + // This breaks the left:0 and padding-left:nn settings of the title + rules.push("#" + containerId + + " div.ui-effects-wrapper ul li span.fancytree-title " + + "{ padding-left: 3px; position: static; width: auto; }"); + return rules.join("\n"); +} + + +// /** +// * [ext-wide] Recalculate the width of the selection bar after the tree container +// * was resized.<br> +// * May be called explicitly on container resize, since there is no resize event +// * for DIV tags. +// * +// * @alias Fancytree#wideUpdate +// * @requires jquery.fancytree.wide.js +// */ +// $.ui.fancytree._FancytreeClass.prototype.wideUpdate = function(){ +// var inst = this.ext.wide, +// prevCw = inst.contWidth, +// prevLo = inst.lineOfs; + +// inst.contWidth = realInnerWidth(this.$container); +// // Each title is precceeded by 2 or 3 icons (16px + 3 margin) +// // + 1px title border and 3px title padding +// // TODO: use code from treeInit() below +// inst.lineOfs = (this.options.checkbox ? 3 : 2) * 19; +// if( prevCw !== inst.contWidth || prevLo !== inst.lineOfs ) { +// this.debug("wideUpdate: " + inst.contWidth); +// this.visit(function(node){ +// node.tree._callHook("nodeRenderTitle", node); +// }); +// } +// }; + +/******************************************************************************* + * Extension code + */ +$.ui.fancytree.registerExtension({ + name: "wide", + version: "0.0.3", + // Default options for this extension. + options: { + iconWidth: null, // Adjust this if @fancy-icon-width != "16px" + iconSpacing: null, // Adjust this if @fancy-icon-spacing != "3px" + levelOfs: null // Adjust this if ul padding != "16px" + }, + + treeCreate: function(ctx){ + this._superApply(arguments); + this.$container.addClass("fancytree-ext-wide"); + + var containerId, cssText, iconSpacingUnit, iconWidthUnit, levelOfsUnit, + instOpts = ctx.options.wide, + // css sniffing + $dummyLI = $("<li id='fancytreeTemp'><span class='fancytree-node'><span class='fancytree-icon' /><span class='fancytree-title' /></span><ul />") + .appendTo(ctx.tree.$container), + $dummyIcon = $dummyLI.find(".fancytree-icon"), + $dummyUL = $dummyLI.find("ul"), + // $dummyTitle = $dummyLI.find(".fancytree-title"), + iconSpacing = instOpts.iconSpacing || $dummyIcon.css("margin-left"), + iconWidth = instOpts.iconWidth || $dummyIcon.css("width"), + levelOfs = instOpts.levelOfs || $dummyUL.css("padding-left"); + + $dummyLI.remove(); + + iconSpacingUnit = iconSpacing.match(reNumUnit)[2]; + iconSpacing = parseFloat(iconSpacing, 10); + iconWidthUnit = iconWidth.match(reNumUnit)[2]; + iconWidth = parseFloat(iconWidth, 10); + levelOfsUnit = levelOfs.match(reNumUnit)[2]; + if( iconSpacingUnit !== iconWidthUnit || levelOfsUnit !== iconWidthUnit ) { + $.error("iconWidth, iconSpacing, and levelOfs must have the same css measure unit"); + } + this._local.measureUnit = iconWidthUnit; + this._local.levelOfs = parseFloat(levelOfs); + this._local.lineOfs = (1 + (ctx.options.checkbox ? 1 : 0) + (ctx.options.icons ? 1 : 0)) * (iconWidth + iconSpacing) + iconSpacing; + this._local.maxDepth = 10; + + // Get/Set a unique Id on the container (if not already exists) + containerId = this.$container.uniqueId().attr("id"); + // Generated css rules for some levels (extended on demand) + cssText = renderLevelCss(containerId, this._local.maxDepth, + this._local.levelOfs, this._local.lineOfs, this._local.measureUnit); + defineHeadStyleElement(containerId, cssText); + }, + treeDestroy: function(ctx){ + // Remove generated css rules + defineHeadStyleElement(this.$container.attr("id"), null); + return this._superApply(arguments); + }, + nodeRenderStatus: function(ctx) { + var containerId, cssText, res, + node = ctx.node, + level = node.getLevel(); + + res = this._superApply(arguments); + // Generate some more level-n rules if required + if( level > this._local.maxDepth ) { + containerId = this.$container.attr("id"); + this._local.maxDepth *= 2; + node.debug("Define global ext-wide css up to level " + this._local.maxDepth); + cssText = renderLevelCss(containerId, this._local.maxDepth, + this._local.levelOfs, this._local.lineOfs, this._local.measureUnit); + defineHeadStyleElement(containerId, cssText); + } + // Add level-n class to apply indentation padding. + // (Setting element style would not work, since it cannot easily be + // overriden while animations run) + $(node.span).addClass("fancytree-level-" + level); + return res; + } +}); +}(jQuery, window, document)); diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/jquery.fancytree-all.min.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/jquery.fancytree-all.min.js new file mode 100644 index 00000000000..efb518cd71e --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/jquery.fancytree-all.min.js @@ -0,0 +1,47 @@ +/*! jQuery Fancytree Plugin - 2.13.0 - 2015-11-16T07:33 + * https://github.com/mar10/fancytree + * Copyright (c) 2015 Martin Wendt; Licensed MIT */ +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + define( [ "jquery" ], factory ); + } else { + factory( jQuery ); + } +}(function( $ ) { + +!function(a,b,c,d){"use strict";function e(b,c){b||(c=c?": "+c:"",a.error("Fancytree assertion failed"+c))}function f(a,c){var d,e,f=b.console?b.console[a]:null;if(f)try{f.apply(b.console,c)}catch(g){for(e="",d=0;d<c.length;d++)e+=c[d];f(e)}}function g(a){return!(!a.tree||a.statusNodeType===d)}function h(b){var c,d,e,f=a.map(a.trim(b).split("."),function(a){return parseInt(a,10)}),g=a.map(Array.prototype.slice.call(arguments,1),function(a){return parseInt(a,10)});for(c=0;c<g.length;c++)if(d=f[c]||0,e=g[c]||0,d!==e)return d>e;return!0}function i(a,b,c,d,e){var f=function(){var c=b[a],f=d[a],g=b.ext[e],h=function(){return c.apply(b,arguments)},i=function(a){return c.apply(b,a)};return function(){var a=b._local,c=b._super,d=b._superApply;try{return b._local=g,b._super=h,b._superApply=i,f.apply(b,arguments)}finally{b._local=a,b._super=c,b._superApply=d}}}();return f}function j(b,c,d,e){for(var f in d)"function"==typeof d[f]?"function"==typeof b[f]?b[f]=i(f,b,c,d,e):"_"===f.charAt(0)?b.ext[e][f]=i(f,b,c,d,e):a.error("Could not override tree."+f+". Use prefix '_' to create tree."+e+"._"+f):"options"!==f&&(b.ext[e][f]=d[f])}function k(b,c){return b===d?a.Deferred(function(){this.resolve()}).promise():a.Deferred(function(){this.resolveWith(b,c)}).promise()}function l(b,c){return b===d?a.Deferred(function(){this.reject()}).promise():a.Deferred(function(){this.rejectWith(b,c)}).promise()}function m(a,b){return function(){a.resolveWith(b)}}function n(b){var c=a.extend({},b.data()),d=c.json;return delete c.fancytree,delete c.uiFancytree,d&&(delete c.json,c=a.extend(c,d)),c}function o(a){return a=a.toLowerCase(),function(b){return b.title.toLowerCase().indexOf(a)>=0}}function p(a){var b=new RegExp("^"+a,"i");return function(a){return b.test(a.title)}}function q(b,c){var d,f,g,h;for(this.parent=b,this.tree=b.tree,this.ul=null,this.li=null,this.statusNodeType=null,this._isLoading=!1,this._error=null,this.data={},d=0,f=B.length;f>d;d++)g=B[d],this[g]=c[g];c.data&&a.extend(this.data,c.data);for(g in c)C[g]||a.isFunction(c[g])||E[g]||(this.data[g]=c[g]);null==this.key?this.tree.options.defaultKey?(this.key=this.tree.options.defaultKey(this),e(this.key,"defaultKey() must return a unique key")):this.key="_"+u._nextNodeKey++:this.key=""+this.key,c.active&&(e(null===this.tree.activeNode,"only one active node allowed"),this.tree.activeNode=this),c.selected&&(this.tree.lastSelectedNode=this),h=c.children,h?h.length?this._setChildren(h):this.children=this.lazy?[]:null:this.children=null,this.tree._callHook("treeRegisterNode",this.tree,!0,this)}function r(b){this.widget=b,this.$div=b.element,this.options=b.options,this.options&&(a.isFunction(this.options.lazyload)&&!a.isFunction(this.options.lazyLoad)&&(this.options.lazyLoad=function(){return u.warn("The 'lazyload' event is deprecated since 2014-02-25. Use 'lazyLoad' (with uppercase L) instead."),b.options.lazyload.apply(this,arguments)}),a.isFunction(this.options.loaderror)&&a.error("The 'loaderror' event was renamed since 2014-07-03. Use 'loadError' (with uppercase E) instead."),this.options.fx!==d&&u.warn("The 'fx' options was replaced by 'toggleEffect' since 2014-11-30.")),this.ext={},this.data=n(this.$div),this._id=a.ui.fancytree._nextId++,this._ns=".fancytree-"+this._id,this.activeNode=null,this.focusNode=null,this._hasFocus=null,this.lastSelectedNode=null,this.systemFocusElement=null,this.lastQuicksearchTerm="",this.lastQuicksearchTime=0,this.statusClassPropName="span",this.ariaPropName="li",this.nodeContainerAttrName="li",this.$div.find(">ul.fancytree-container").remove();var c,e={tree:this};this.rootNode=new q(e,{title:"root",key:"root_"+this._id,children:null,expanded:!0}),this.rootNode.parent=null,c=a("<ul>",{"class":"ui-fancytree fancytree-container fancytree-plain"}).appendTo(this.$div),this.$container=c,this.rootNode.ul=c[0],null==this.options.debugLevel&&(this.options.debugLevel=u.debugLevel),this.$container.attr("tabindex",this.options.tabbable?"0":"-1"),this.options.aria&&this.$container.attr("role","tree").attr("aria-multiselectable",!0)}if(a.ui&&a.ui.fancytree)return void a.ui.fancytree.warn("Fancytree: ignored duplicate include");e(a.ui,"Fancytree requires jQuery UI (http://jqueryui.com)");var s,t,u=null,v={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"},w={16:!0,17:!0,18:!0},x={8:"backspace",9:"tab",10:"return",13:"return",19:"pause",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"insert",46:"del",59:";",61:"=",96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9",106:"*",107:"+",109:"-",110:".",111:"/",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:"scroll",173:"-",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},y={0:"",1:"left",2:"middle",3:"right"},z="active expanded focus folder hideCheckbox lazy selected unselectable".split(" "),A={},B="expanded extraClasses folder hideCheckbox key lazy refKey selected title tooltip unselectable".split(" "),C={},D={},E={active:!0,children:!0,data:!0,focus:!0};for(s=0;s<z.length;s++)A[z[s]]=!0;for(s=0;s<B.length;s++)t=B[s],C[t]=!0,t!==t.toLowerCase()&&(D[t.toLowerCase()]=t);q.prototype={_findDirectChild:function(a){var b,c,d=this.children;if(d)if("string"==typeof a){for(b=0,c=d.length;c>b;b++)if(d[b].key===a)return d[b]}else{if("number"==typeof a)return this.children[a];if(a.parent===this)return a}return null},_setChildren:function(a){e(a&&(!this.children||0===this.children.length),"only init supported"),this.children=[];for(var b=0,c=a.length;c>b;b++)this.children.push(new q(this,a[b]))},addChildren:function(b,c){var d,f,g,h=null,i=[];for(a.isPlainObject(b)&&(b=[b]),this.children||(this.children=[]),d=0,f=b.length;f>d;d++)i.push(new q(this,b[d]));return h=i[0],null==c?this.children=this.children.concat(i):(c=this._findDirectChild(c),g=a.inArray(c,this.children),e(g>=0,"insertBefore must be an existing child"),this.children.splice.apply(this.children,[g,0].concat(i))),(!this.parent||this.parent.ul||this.tr)&&this.render(),3===this.tree.options.selectMode&&this.fixSelection3FromEndNodes(),h},addNode:function(a,b){switch((b===d||"over"===b)&&(b="child"),b){case"after":return this.getParent().addChildren(a,this.getNextSibling());case"before":return this.getParent().addChildren(a,this);case"firstChild":var c=this.children?this.children[0]:null;return this.addChildren(a,c);case"child":case"over":return this.addChildren(a)}e(!1,"Invalid mode: "+b)},appendSibling:function(a){return this.addNode(a,"after")},applyPatch:function(b){if(null===b)return this.remove(),k(this);var c,d,e,f={children:!0,expanded:!0,parent:!0};for(c in b)e=b[c],f[c]||a.isFunction(e)||(C[c]?this[c]=e:this.data[c]=e);return b.hasOwnProperty("children")&&(this.removeChildren(),b.children&&this._setChildren(b.children)),this.isVisible()&&(this.renderTitle(),this.renderStatus()),d=b.hasOwnProperty("expanded")?this.setExpanded(b.expanded):k(this)},collapseSiblings:function(){return this.tree._callHook("nodeCollapseSiblings",this)},copyTo:function(a,b,c){return a.addNode(this.toDict(!0,c),b)},countChildren:function(a){var b,c,d,e=this.children;if(!e)return 0;if(d=e.length,a!==!1)for(b=0,c=d;c>b;b++)d+=e[b].countChildren();return d},debug:function(){this.tree.options.debugLevel>=2&&(Array.prototype.unshift.call(arguments,this.toString()),f("log",arguments))},discard:function(){return this.warn("FancytreeNode.discard() is deprecated since 2014-02-16. Use .resetLazy() instead."),this.resetLazy()},findAll:function(b){b=a.isFunction(b)?b:o(b);var c=[];return this.visit(function(a){b(a)&&c.push(a)}),c},findFirst:function(b){b=a.isFunction(b)?b:o(b);var c=null;return this.visit(function(a){return b(a)?(c=a,!1):void 0}),c},_changeSelectStatusAttrs:function(a){var b=!1;switch(a){case!1:b=this.selected||this.partsel,this.selected=!1,this.partsel=!1;break;case!0:b=!this.selected||!this.partsel,this.selected=!0,this.partsel=!0;break;case d:b=this.selected||!this.partsel,this.selected=!1,this.partsel=!0;break;default:e(!1,"invalid state: "+a)}return b&&this.renderStatus(),b},fixSelection3AfterClick:function(){var a=this.isSelected();this.visit(function(b){b._changeSelectStatusAttrs(a)}),this.fixSelection3FromEndNodes()},fixSelection3FromEndNodes:function(){function a(b){var c,e,f,g,h,i,j,k=b.children;if(k&&k.length){for(i=!0,j=!1,c=0,e=k.length;e>c;c++)f=k[c],g=a(f),g!==!1&&(j=!0),g!==!0&&(i=!1);h=i?!0:j?d:!1}else h=!!b.selected;return b._changeSelectStatusAttrs(h),h}e(3===this.tree.options.selectMode,"expected selectMode 3"),a(this),this.visitParents(function(a){var b,c,e,f,g=a.children,h=!0,i=!1;for(b=0,c=g.length;c>b;b++)e=g[b],(e.selected||e.partsel)&&(i=!0),e.unselectable||e.selected||(h=!1);f=h?!0:i?d:!1,a._changeSelectStatusAttrs(f)})},fromDict:function(b){for(var c in b)C[c]?this[c]=b[c]:"data"===c?a.extend(this.data,b.data):a.isFunction(b[c])||E[c]||(this.data[c]=b[c]);b.children&&(this.removeChildren(),this.addChildren(b.children)),this.renderTitle()},getChildren:function(){return this.hasChildren()===d?d:this.children},getFirstChild:function(){return this.children?this.children[0]:null},getIndex:function(){return a.inArray(this,this.parent.children)},getIndexHier:function(b){b=b||".";var c=[];return a.each(this.getParentList(!1,!0),function(a,b){c.push(b.getIndex()+1)}),c.join(b)},getKeyPath:function(a){var b=[],c=this.tree.options.keyPathSeparator;return this.visitParents(function(a){a.parent&&b.unshift(a.key)},!a),c+b.join(c)},getLastChild:function(){return this.children?this.children[this.children.length-1]:null},getLevel:function(){for(var a=0,b=this.parent;b;)a++,b=b.parent;return a},getNextSibling:function(){if(this.parent){var a,b,c=this.parent.children;for(a=0,b=c.length-1;b>a;a++)if(c[a]===this)return c[a+1]}return null},getParent:function(){return this.parent},getParentList:function(a,b){for(var c=[],d=b?this:this.parent;d;)(a||d.parent)&&c.unshift(d),d=d.parent;return c},getPrevSibling:function(){if(this.parent){var a,b,c=this.parent.children;for(a=1,b=c.length;b>a;a++)if(c[a]===this)return c[a-1]}return null},hasChildren:function(){return this.lazy?null==this.children?d:0===this.children.length?!1:1===this.children.length&&this.children[0].isStatusNode()?d:!0:!(!this.children||!this.children.length)},hasFocus:function(){return this.tree.hasFocus()&&this.tree.focusNode===this},info:function(){this.tree.options.debugLevel>=1&&(Array.prototype.unshift.call(arguments,this.toString()),f("info",arguments))},isActive:function(){return this.tree.activeNode===this},isChildOf:function(a){return this.parent&&this.parent===a},isDescendantOf:function(a){if(!a||a.tree!==this.tree)return!1;for(var b=this.parent;b;){if(b===a)return!0;b=b.parent}return!1},isExpanded:function(){return!!this.expanded},isFirstSibling:function(){var a=this.parent;return!a||a.children[0]===this},isFolder:function(){return!!this.folder},isLastSibling:function(){var a=this.parent;return!a||a.children[a.children.length-1]===this},isLazy:function(){return!!this.lazy},isLoaded:function(){return!this.lazy||this.hasChildren()!==d},isLoading:function(){return!!this._isLoading},isRoot:function(){return this.isRootNode()},isRootNode:function(){return this.tree.rootNode===this},isSelected:function(){return!!this.selected},isStatusNode:function(){return!!this.statusNodeType},isTopLevel:function(){return this.tree.rootNode===this.parent},isUndefined:function(){return this.hasChildren()===d},isVisible:function(){var a,b,c=this.getParentList(!1,!1);for(a=0,b=c.length;b>a;a++)if(!c[a].expanded)return!1;return!0},lazyLoad:function(a){return this.warn("FancytreeNode.lazyLoad() is deprecated since 2014-02-16. Use .load() instead."),this.load(a)},load:function(a){var b,c,d=this;return e(this.isLazy(),"load() requires a lazy node"),a||this.isUndefined()?(this.isLoaded()&&this.resetLazy(),c=this.tree._triggerNodeEvent("lazyLoad",this),c===!1?k(this):(e("boolean"!=typeof c,"lazyLoad event must return source in data.result"),b=this.tree._callHook("nodeLoadChildren",this,c),this.expanded&&b.always(function(){d.render()}),b)):k(this)},makeVisible:function(b){var c,d=this,e=[],f=new a.Deferred,g=this.getParentList(!1,!1),h=g.length,i=!(b&&b.noAnimation===!0),j=!(b&&b.scrollIntoView===!1);for(c=h-1;c>=0;c--)e.push(g[c].setExpanded(!0,b));return a.when.apply(a,e).done(function(){j?d.scrollIntoView(i).done(function(){f.resolve()}):f.resolve()}),f.promise()},moveTo:function(b,c,f){(c===d||"over"===c)&&(c="child");var g,h=this.parent,i="child"===c?b:b.parent;if(this!==b){if(!this.parent)throw"Cannot move system root";if(i.isDescendantOf(this))throw"Cannot move a node to its own descendant";if(1===this.parent.children.length){if(this.parent===i)return;this.parent.children=this.parent.lazy?[]:null,this.parent.expanded=!1}else g=a.inArray(this,this.parent.children),e(g>=0,"invalid source parent"),this.parent.children.splice(g,1);if(this.parent=i,i.hasChildren())switch(c){case"child":i.children.push(this);break;case"before":g=a.inArray(b,i.children),e(g>=0,"invalid target parent"),i.children.splice(g,0,this);break;case"after":g=a.inArray(b,i.children),e(g>=0,"invalid target parent"),i.children.splice(g+1,0,this);break;default:throw"Invalid mode "+c}else i.children=[this];f&&b.visit(f,!0),this.tree!==b.tree&&(this.warn("Cross-tree moveTo is experimantal!"),this.visit(function(a){a.tree=b.tree},!0)),h.isDescendantOf(i)||h.render(),i.isDescendantOf(h)||i===h||i.render()}},navigate:function(b,c){function d(d){if(d){try{d.makeVisible()}catch(e){}return a(d.span).is(":visible")?c===!1?d.setFocus():d.setActive():(d.debug("Navigate: skipping hidden node"),void d.navigate(b,c))}}var e,f,g=!0,h=a.ui.keyCode,i=null;switch(b){case h.BACKSPACE:this.parent&&this.parent.parent&&d(this.parent);break;case h.LEFT:this.expanded?(this.setExpanded(!1),d(this)):this.parent&&this.parent.parent&&d(this.parent);break;case h.RIGHT:this.expanded||!this.children&&!this.lazy?this.children&&this.children.length&&d(this.children[0]):(this.setExpanded(),d(this));break;case h.UP:for(i=this.getPrevSibling();i&&!a(i.span).is(":visible");)i=i.getPrevSibling();for(;i&&i.expanded&&i.children&&i.children.length;)i=i.children[i.children.length-1];!i&&this.parent&&this.parent.parent&&(i=this.parent),d(i);break;case h.DOWN:if(this.expanded&&this.children&&this.children.length)i=this.children[0];else for(f=this.getParentList(!1,!0),e=f.length-1;e>=0;e--){for(i=f[e].getNextSibling();i&&!a(i.span).is(":visible");)i=i.getNextSibling();if(i)break}d(i);break;default:g=!1}},remove:function(){return this.parent.removeChild(this)},removeChild:function(a){return this.tree._callHook("nodeRemoveChild",this,a)},removeChildren:function(){return this.tree._callHook("nodeRemoveChildren",this)},render:function(a,b){return this.tree._callHook("nodeRender",this,a,b)},renderTitle:function(){return this.tree._callHook("nodeRenderTitle",this)},renderStatus:function(){return this.tree._callHook("nodeRenderStatus",this)},resetLazy:function(){this.removeChildren(),this.expanded=!1,this.lazy=!0,this.children=d,this.renderStatus()},scheduleAction:function(a,b){this.tree.timer&&clearTimeout(this.tree.timer),this.tree.timer=null;var c=this;switch(a){case"cancel":break;case"expand":this.tree.timer=setTimeout(function(){c.tree.debug("setTimeout: trigger expand"),c.setExpanded(!0)},b);break;case"activate":this.tree.timer=setTimeout(function(){c.tree.debug("setTimeout: trigger activate"),c.setActive(!0)},b);break;default:throw"Invalid mode "+a}},scrollIntoView:function(f,h){h!==d&&g(h)&&(this.warn("scrollIntoView() with 'topNode' option is deprecated since 2014-05-08. Use 'options.topNode' instead."),h={topNode:h});var i,j,l,m,n=a.extend({effects:f===!0?{duration:200,queue:!1}:f,scrollOfs:this.tree.options.scrollOfs,scrollParent:this.tree.options.scrollParent||this.tree.$container,topNode:null},h),o=new a.Deferred,p=this,q=a(this.span).height(),r=a(n.scrollParent),s=n.scrollOfs.top||0,t=n.scrollOfs.bottom||0,u=r.height(),v=r.scrollTop(),w=r,x=r[0]===b,y=n.topNode||null,z=null;return a(this.span).is(":visible")?(x?(j=a(this.span).offset().top,i=y&&y.span?a(y.span).offset().top:0,w=a("html,body")):(e(r[0]!==c&&r[0]!==c.body,"scrollParent should be an simple element or `window`, not document or body."),m=r.offset().top,j=a(this.span).offset().top-m+v,i=y?a(y.span).offset().top-m+v:0,l=Math.max(0,r.innerHeight()-r[0].clientHeight),u-=l),v+s>j?z=j-s:j+q>v+u-t&&(z=j+q-u+t,y&&(e(y.isRootNode()||a(y.span).is(":visible"),"topNode must be visible"),z>i&&(z=i-s))),null!==z?n.effects?(n.effects.complete=function(){o.resolveWith(p)},w.stop(!0).animate({scrollTop:z},n.effects)):(w[0].scrollTop=z,o.resolveWith(this)):o.resolveWith(this),o.promise()):(this.warn("scrollIntoView(): node is invisible."),k())},setActive:function(a,b){return this.tree._callHook("nodeSetActive",this,a,b)},setExpanded:function(a,b){return this.tree._callHook("nodeSetExpanded",this,a,b)},setFocus:function(a){return this.tree._callHook("nodeSetFocus",this,a)},setSelected:function(a){return this.tree._callHook("nodeSetSelected",this,a)},setStatus:function(a,b,c){return this.tree._callHook("nodeSetStatus",this,a,b,c)},setTitle:function(a){this.title=a,this.renderTitle()},sortChildren:function(a,b){var c,d,e=this.children;if(e){if(a=a||function(a,b){var c=a.title.toLowerCase(),d=b.title.toLowerCase();return c===d?0:c>d?1:-1},e.sort(a),b)for(c=0,d=e.length;d>c;c++)e[c].children&&e[c].sortChildren(a,"$norender$");"$norender$"!==b&&this.render()}},toDict:function(b,c){var d,e,f,g={},h=this;if(a.each(B,function(a,b){(h[b]||h[b]===!1)&&(g[b]=h[b])}),a.isEmptyObject(this.data)||(g.data=a.extend({},this.data),a.isEmptyObject(g.data)&&delete g.data),c&&c(g,h),b&&this.hasChildren())for(g.children=[],d=0,e=this.children.length;e>d;d++)f=this.children[d],f.isStatusNode()||g.children.push(f.toDict(!0,c));return g},toggleExpanded:function(){return this.tree._callHook("nodeToggleExpanded",this)},toggleSelected:function(){return this.tree._callHook("nodeToggleSelected",this)},toString:function(){return"<FancytreeNode(#"+this.key+", '"+this.title+"')>"},visit:function(a,b){var c,d,e=!0,f=this.children;if(b===!0&&(e=a(this),e===!1||"skip"===e))return e;if(f)for(c=0,d=f.length;d>c&&(e=f[c].visit(a,!0),e!==!1);c++);return e},visitAndLoad:function(b,c,d){var e,f,g,h=this;return b&&c===!0&&(f=b(h),f===!1||"skip"===f)?d?f:k():h.children||h.lazy?(e=new a.Deferred,g=[],h.load().done(function(){for(var c=0,d=h.children.length;d>c;c++){if(f=h.children[c].visitAndLoad(b,!0,!0),f===!1){e.reject();break}"skip"!==f&&g.push(f)}a.when.apply(this,g).then(function(){e.resolve()})}),e.promise()):k()},visitParents:function(a,b){if(b&&a(this)===!1)return!1;for(var c=this.parent;c;){if(a(c)===!1)return!1;c=c.parent}return!0},warn:function(){Array.prototype.unshift.call(arguments,this.toString()),f("warn",arguments)}},r.prototype={_makeHookContext:function(b,c,e){var f,g;return b.node!==d?(c&&b.originalEvent!==c&&a.error("invalid args"),f=b):b.tree?(g=b.tree,f={node:b,tree:g,widget:g.widget,options:g.widget.options,originalEvent:c}):b.widget?f={node:null,tree:b,widget:b.widget,options:b.widget.options,originalEvent:c}:a.error("invalid args"),e&&a.extend(f,e),f},_callHook:function(b,c){var d=this._makeHookContext(c),e=this[b],f=Array.prototype.slice.call(arguments,2);return a.isFunction(e)||a.error("_callHook('"+b+"') is not a function"),f.unshift(d),e.apply(this,f)},_requireExtension:function(b,c,d,f){d=!!d;var g=this._local.name,h=this.options.extensions,i=a.inArray(b,h)<a.inArray(g,h),j=c&&null==this.ext[b],k=!j&&null!=d&&d!==i;return e(g&&g!==b,"invalid or same name"),j||k?(f||(j||c?(f="'"+g+"' extension requires '"+b+"'",k&&(f+=" to be registered "+(d?"before":"after")+" itself")):f="If used together, `"+b+"` must be registered "+(d?"before":"after")+" `"+g+"`"),a.error(f),!1):!0},activateKey:function(a){var b=this.getNodeByKey(a);return b?b.setActive():this.activeNode&&this.activeNode.setActive(!1),b},applyPatch:function(b){var c,d,f,g,h,i,j=b.length,k=[];for(d=0;j>d;d++)f=b[d],e(2===f.length,"patchList must be an array of length-2-arrays"),g=f[0],h=f[1],i=null===g?this.rootNode:this.getNodeByKey(g),i?(c=new a.Deferred,k.push(c),i.applyPatch(h).always(m(c,i))):this.warn("could not find node with key '"+g+"'");return a.when.apply(a,k).promise()},count:function(){return this.rootNode.countChildren()},debug:function(){this.options.debugLevel>=2&&(Array.prototype.unshift.call(arguments,this.toString()),f("log",arguments))},findAll:function(a){return this.rootNode.findAll(a)},findFirst:function(a){return this.rootNode.findFirst(a)},findNextNode:function(b,c){var d=null,e=c.parent.children,f=null,g=function(a,b,c){var d,e,f=a.children,h=f.length,i=f[b];if(i&&c(i)===!1)return!1;if(i&&i.children&&i.expanded&&g(i,0,c)===!1)return!1;for(d=b+1;h>d;d++)if(g(a,d,c)===!1)return!1;return e=a.parent,e?g(e,e.children.indexOf(a)+1,c):g(a,0,c)};return b="string"==typeof b?p(b):b,c=c||this.getFirstChild(),g(c.parent,e.indexOf(c),function(e){return e===d?!1:(d=d||e,a(e.span).is(":visible")?b(e)&&(f=e,f!==c)?!1:void 0:void e.debug("quicksearch: skipping hidden node"))}),f},generateFormElements:function(b,c,d){d=d||{};var e,f="string"==typeof b?b:"ft_"+this._id+"[]",g="string"==typeof c?c:"ft_"+this._id+"_active",h="fancytree_result_"+this._id,i=a("#"+h),j=3===this.options.selectMode&&d.stopOnParents!==!1;i.length?i.empty():i=a("<div>",{id:h}).hide().insertAfter(this.$container),b!==!1&&(e=this.getSelectedNodes(j),a.each(e,function(b,c){i.append(a("<input>",{type:"checkbox",name:f,value:c.key,checked:!0}))})),c!==!1&&this.activeNode&&i.append(a("<input>",{type:"radio",name:g,value:this.activeNode.key,checked:!0}))},getActiveNode:function(){return this.activeNode},getFirstChild:function(){return this.rootNode.getFirstChild()},getFocusNode:function(){return this.focusNode},getNodeByKey:function(a,b){var d,e;return!b&&(d=c.getElementById(this.options.idPrefix+a))?d.ftnode?d.ftnode:null:(b=b||this.rootNode,e=null,b.visit(function(b){return b.key===a?(e=b,!1):void 0},!0),e)},getRootNode:function(){return this.rootNode},getSelectedNodes:function(a){var b=[];return this.rootNode.visit(function(c){return c.selected&&(b.push(c),a===!0)?"skip":void 0}),b},hasFocus:function(){return!!this._hasFocus},info:function(){this.options.debugLevel>=1&&(Array.prototype.unshift.call(arguments,this.toString()),f("info",arguments))},loadKeyPath:function(b,c,e){function f(a,b,d){c.call(r,b,"loading"),b.load().done(function(){r.loadKeyPath.call(r,l[a],c,b).always(m(d,r))}).fail(function(){r.warn("loadKeyPath: error loading: "+a+" (parent: "+o+")"),c.call(r,b,"error"),d.reject()})}var g,h,i,j,k,l,n,o,p,q=this.options.keyPathSeparator,r=this;for(a.isArray(b)||(b=[b]),l={},i=0;i<b.length;i++)for(o=e||this.rootNode,j=b[i],j.charAt(0)===q&&(j=j.substr(1)),p=j.split(q);p.length;){if(k=p.shift(),n=o._findDirectChild(k),!n){this.warn("loadKeyPath: key not found: "+k+" (parent: "+o+")"),c.call(this,k,"error");break}if(0===p.length){c.call(this,n,"ok");break}if(n.lazy&&n.hasChildren()===d){c.call(this,n,"loaded"),l[k]?l[k].push(p.join(q)):l[k]=[p.join(q)];break}c.call(this,n,"loaded"),o=n}g=[];for(k in l)n=o._findDirectChild(k),h=new a.Deferred,g.push(h),f(k,n,h);return a.when.apply(a,g).promise()},reactivate:function(a){var b,c=this.activeNode;return c?(this.activeNode=null,b=c.setActive(),a&&c.setFocus(),b):k()},reload:function(a){return this._callHook("treeClear",this),this._callHook("treeLoad",this,a)},render:function(a,b){return this.rootNode.render(a,b)},setFocus:function(a){return this._callHook("treeSetFocus",this,a)},toDict:function(a,b){var c=this.rootNode.toDict(!0,b);return a?c:c.children},toString:function(){return"<Fancytree(#"+this._id+")>"},_triggerNodeEvent:function(a,b,c,e){var f=this._makeHookContext(b,c,e),g=this.widget._trigger(a,c,f);return g!==!1&&f.result!==d?f.result:g},_triggerTreeEvent:function(a,b,c){var e=this._makeHookContext(this,b,c),f=this.widget._trigger(a,b,e);return f!==!1&&e.result!==d?e.result:f},visit:function(a){return this.rootNode.visit(a,!1)},warn:function(){Array.prototype.unshift.call(arguments,this.toString()),f("warn",arguments)}},a.extend(r.prototype,{nodeClick:function(a){var b,c,d=a.targetType,e=a.node;if("expander"===d){if(e.isLoading())return void e.debug("Got 2nd click while loading: ignored");this._callHook("nodeToggleExpanded",a)}else if("checkbox"===d)this._callHook("nodeToggleSelected",a),a.options.focusOnSelect&&this._callHook("nodeSetFocus",a,!0);else{if(c=!1,b=!0,e.folder)switch(a.options.clickFolderMode){case 2:c=!0,b=!1;break;case 3:b=!0,c=!0}b&&(this.nodeSetFocus(a),this._callHook("nodeSetActive",a,!0)),c&&this._callHook("nodeToggleExpanded",a)}},nodeCollapseSiblings:function(a,b){var c,d,e,f=a.node;if(f.parent)for(c=f.parent.children,d=0,e=c.length;e>d;d++)c[d]!==f&&c[d].expanded&&this._callHook("nodeSetExpanded",c[d],!1,b)},nodeDblclick:function(a){"title"===a.targetType&&4===a.options.clickFolderMode&&this._callHook("nodeToggleExpanded",a),"title"===a.targetType&&a.originalEvent.preventDefault()},nodeKeydown:function(b){var c,d,e,f,g=b.originalEvent,h=b.node,i=b.tree,j=b.options,k=g.which,l=String.fromCharCode(k),m=!(g.altKey||g.ctrlKey||g.metaKey||g.shiftKey),n=a(g.target),o=!0,p=!(g.ctrlKey||!j.autoActivate);if(h||(f=this.getActiveNode()||this.getFirstChild(),f&&(f.setFocus(),h=b.node=this.focusNode,h.debug("Keydown force focus on active node"))),j.quicksearch&&m&&/\w/.test(l)&&!n.is(":input:enabled"))return d=(new Date).getTime(),d-i.lastQuicksearchTime>500&&(i.lastQuicksearchTerm=""),i.lastQuicksearchTime=d,i.lastQuicksearchTerm+=l,c=i.findNextNode(i.lastQuicksearchTerm,i.getActiveNode()),c&&c.setActive(),void g.preventDefault();switch(u.eventToString(g)){case"+":case"=":i.nodeSetExpanded(b,!0);break;case"-":i.nodeSetExpanded(b,!1);break;case"space":j.checkbox?i.nodeToggleSelected(b):i.nodeSetActive(b,!0);break;case"return":i.nodeSetActive(b,!0);break;case"backspace":case"left":case"right":case"up":case"down":e=h.navigate(g.which,p);break;default:o=!1}o&&g.preventDefault()},nodeLoadChildren:function(b,c){var d,f,g,h=b.tree,i=b.node;return a.isFunction(c)&&(c=c()),c.url&&(d=a.extend({},b.options.ajax,c),d.debugDelay?(f=d.debugDelay,a.isArray(f)&&(f=f[0]+Math.random()*(f[1]-f[0])),i.debug("nodeLoadChildren waiting debug delay "+Math.round(f)+"ms"),d.debugDelay=!1,g=a.Deferred(function(b){setTimeout(function(){a.ajax(d).done(function(){b.resolveWith(this,arguments)}).fail(function(){b.rejectWith(this,arguments)})},f)})):g=a.ajax(d),c=new a.Deferred,g.done(function(d){var e,f;if("json"===this.dataType&&"string"==typeof d&&a.error("Ajax request returned a string (did you get the JSON dataType wrong?)."),b.options.postProcess){if(f=h._triggerNodeEvent("postProcess",b,b.originalEvent,{response:d,error:null,dataType:this.dataType}),f.error)return e=a.isPlainObject(f.error)?f.error:{message:f.error},e=h._makeHookContext(i,null,e),void c.rejectWith(this,[e]);d=a.isArray(f)?f:d}else d&&d.hasOwnProperty("d")&&b.options.enableAspx&&(d="string"==typeof d.d?a.parseJSON(d.d):d.d);c.resolveWith(this,[d])}).fail(function(a,b,d){var e=h._makeHookContext(i,null,{error:a,args:Array.prototype.slice.call(arguments),message:d,details:a.status+": "+d});c.rejectWith(this,[e])})),a.isFunction(c.then)&&a.isFunction(c["catch"])&&(g=c,c=new a.Deferred,g.then(function(a){c.resolve(a)},function(a){c.reject(a)})),a.isFunction(c.promise)&&(e(!i.isLoading(),"recursive load"),h.nodeSetStatus(b,"loading"),c.done(function(){h.nodeSetStatus(b,"ok")}).fail(function(a){var c;c=a.node&&a.error&&a.message?a:h._makeHookContext(i,null,{error:a,args:Array.prototype.slice.call(arguments),message:a?a.message||a.toString():""}),h._triggerNodeEvent("loadError",c,null)!==!1&&h.nodeSetStatus(b,"error",c.message,c.details)})),a.when(c).done(function(b){var c;a.isPlainObject(b)&&(e(i.isRootNode(),"source may only be an object for root nodes (expecting an array of child objects otherwise)"),e(a.isArray(b.children),"if an object is passed as source, it must contain a 'children' array (all other properties are added to 'tree.data')"),c=b,b=b.children,delete c.children,a.extend(h.data,c)),e(a.isArray(b),"expected array of children"),i._setChildren(b),h._triggerNodeEvent("loadChildren",i)})},nodeLoadKeyPath:function(){},nodeRemoveChild:function(b,c){var d,f=b.node,g=b.options,h=a.extend({},b,{node:c}),i=f.children;return 1===i.length?(e(c===i[0],"invalid single child"),this.nodeRemoveChildren(b)):(this.activeNode&&(c===this.activeNode||this.activeNode.isDescendantOf(c))&&this.activeNode.setActive(!1),this.focusNode&&(c===this.focusNode||this.focusNode.isDescendantOf(c))&&(this.focusNode=null),this.nodeRemoveMarkup(h),this.nodeRemoveChildren(h),d=a.inArray(c,i),e(d>=0,"invalid child"),c.visit(function(a){a.parent=null},!0),this._callHook("treeRegisterNode",this,!1,c),g.removeNode&&g.removeNode.call(b.tree,{type:"removeNode"},h),void i.splice(d,1))},nodeRemoveChildMarkup:function(b){var c=b.node;c.ul&&(c.isRootNode()?a(c.ul).empty():(a(c.ul).remove(),c.ul=null),c.visit(function(a){a.li=a.ul=null}))},nodeRemoveChildren:function(b){var c,d=b.tree,e=b.node,f=e.children,g=b.options;f&&(this.activeNode&&this.activeNode.isDescendantOf(e)&&this.activeNode.setActive(!1),this.focusNode&&this.focusNode.isDescendantOf(e)&&(this.focusNode=null),this.nodeRemoveChildMarkup(b),c=a.extend({},b),e.visit(function(a){a.parent=null,d._callHook("treeRegisterNode",d,!1,a),g.removeNode&&(c.node=a,g.removeNode.call(b.tree,{type:"removeNode"},c))}),e.children=e.lazy?[]:null,e.isRootNode()||(e.expanded=!1),this.nodeRenderStatus(b))},nodeRemoveMarkup:function(b){var c=b.node;c.li&&(a(c.li).remove(),c.li=null),this.nodeRemoveChildMarkup(b)},nodeRender:function(b,d,f,g,h){var i,j,k,l,m,n,o,p=b.node,q=b.tree,r=b.options,s=r.aria,t=!1,u=p.parent,v=!u,w=p.children,x=null;if(v||u.ul){if(e(v||u.ul,"parent UL must exist"),v||(p.li&&(d||p.li.parentNode!==p.parent.ul)&&(p.li.parentNode===p.parent.ul?x=p.li.nextSibling:this.debug("Unlinking "+p+" (must be child of "+p.parent+")"),this.nodeRemoveMarkup(b)),p.li?this.nodeRenderStatus(b):(t=!0,p.li=c.createElement("li"),p.li.ftnode=p,p.key&&r.generateIds&&(p.li.id=r.idPrefix+p.key),p.span=c.createElement("span"),p.span.className="fancytree-node",s&&a(p.span).attr("aria-labelledby","ftal_"+p.key),p.li.appendChild(p.span),this.nodeRenderTitle(b),r.createNode&&r.createNode.call(q,{type:"createNode"},b)),r.renderNode&&r.renderNode.call(q,{type:"renderNode"},b)),w){if(v||p.expanded||f===!0){for(p.ul||(p.ul=c.createElement("ul"),(g===!0&&!h||!p.expanded)&&(p.ul.style.display="none"),s&&a(p.ul).attr("role","group"),p.li?p.li.appendChild(p.ul):p.tree.$div.append(p.ul)),l=0,m=w.length;m>l;l++)o=a.extend({},b,{node:w[l]}),this.nodeRender(o,d,f,!1,!0);for(i=p.ul.firstChild;i;)k=i.ftnode,k&&k.parent!==p?(p.debug("_fixParent: remove missing "+k,i),n=i.nextSibling,i.parentNode.removeChild(i),i=n):i=i.nextSibling;for(i=p.ul.firstChild,l=0,m=w.length-1;m>l;l++)j=w[l],k=i.ftnode,j!==k?p.ul.insertBefore(j.li,k.li):i=i.nextSibling}}else p.ul&&(this.warn("remove child markup for "+p),this.nodeRemoveChildMarkup(b));v||t&&u.ul.insertBefore(p.li,x)}},nodeRenderTitle:function(a,b){var c,e,f,g,h,i,j=a.node,k=a.tree,l=a.options,m=l.aria,n=j.getLevel(),o=[],p=j.data.icon;b!==d&&(j.title=b),j.span&&(n<l.minExpandLevel?(j.lazy||(j.expanded=!0),n>1&&o.push(m?"<span role='button' class='fancytree-expander fancytree-expander-fixed'></span>":"<span class='fancytree-expander fancytree-expander-fixed''></span>")):o.push(m?"<span role='button' class='fancytree-expander'></span>":"<span class='fancytree-expander'></span>"),l.checkbox&&j.hideCheckbox!==!0&&!j.isStatusNode()&&o.push(m?"<span role='checkbox' class='fancytree-checkbox'></span>":"<span class='fancytree-checkbox'></span>"),g=m?" role='img'":"",(p===!0||p!==!1&&l.icons!==!1)&&(p&&"string"==typeof p?(p="/"===p.charAt(0)?p:(l.imagePath||"")+p,o.push("<img src='"+p+"' class='fancytree-icon' alt='' />")):(e=l.iconClass&&l.iconClass.call(k,{type:"iconClass"},a)||j.data.iconclass||null,o.push(e?"<span "+g+" class='fancytree-custom-icon "+e+"'></span>":"<span "+g+" class='fancytree-icon'></span>"))),f="",l.renderTitle&&(f=l.renderTitle.call(k,{type:"renderTitle"},a)||""),f||(i=j.tooltip?" title='"+u.escapeHtml(j.tooltip)+"'":"",c=m?" id='ftal_"+j.key+"'":"",g=m?" role='treeitem'":"",h=l.titlesTabbable?" tabindex='0'":"",f="<span "+g+" class='fancytree-title'"+c+i+h+">"+j.title+"</span>"),o.push(f),j.span.innerHTML=o.join(""),this.nodeRenderStatus(a)) +},nodeRenderStatus:function(b){var c=b.node,d=b.tree,e=b.options,f=c.hasChildren(),g=c.isLastSibling(),h=e.aria,i=a(c.span).find(".fancytree-title"),j=e._classNames,k=[],l=c[d.statusClassPropName];l&&(k.push(j.node),d.activeNode===c&&k.push(j.active),d.focusNode===c?(k.push(j.focused),h&&i.attr("aria-activedescendant",!0)):h&&i.removeAttr("aria-activedescendant"),c.expanded?(k.push(j.expanded),h&&i.attr("aria-expanded",!0)):h&&i.removeAttr("aria-expanded"),c.folder&&k.push(j.folder),f!==!1&&k.push(j.hasChildren),g&&k.push(j.lastsib),c.lazy&&null==c.children&&k.push(j.lazy),c.partsel&&k.push(j.partsel),c.unselectable&&k.push(j.unselectable),c._isLoading&&k.push(j.loading),c._error&&k.push(j.error),c.selected?(k.push(j.selected),h&&i.attr("aria-selected",!0)):h&&i.attr("aria-selected",!1),c.extraClasses&&k.push(c.extraClasses),k.push(f===!1?j.combinedExpanderPrefix+"n"+(g?"l":""):j.combinedExpanderPrefix+(c.expanded?"e":"c")+(c.lazy&&null==c.children?"d":"")+(g?"l":"")),k.push(j.combinedIconPrefix+(c.expanded?"e":"c")+(c.folder?"f":"")),l.className=k.join(" "),c.li&&(c.li.className=g?j.lastsib:""))},nodeSetActive:function(b,c,d){d=d||{};var f,g=b.node,h=b.tree,i=b.options,j=d.noEvents===!0,m=d.noFocus===!0,n=g===h.activeNode;return c=c!==!1,n===c?k(g):c&&!j&&this._triggerNodeEvent("beforeActivate",g,b.originalEvent)===!1?l(g,["rejected"]):(c?(h.activeNode&&(e(h.activeNode!==g,"node was active (inconsistency)"),f=a.extend({},b,{node:h.activeNode}),h.nodeSetActive(f,!1),e(null===h.activeNode,"deactivate was out of sync?")),i.activeVisible&&g.makeVisible({scrollIntoView:!1}),h.activeNode=g,h.nodeRenderStatus(b),m||h.nodeSetFocus(b),j||h._triggerNodeEvent("activate",g,b.originalEvent)):(e(h.activeNode===g,"node was not active (inconsistency)"),h.activeNode=null,this.nodeRenderStatus(b),j||b.tree._triggerNodeEvent("deactivate",g,b.originalEvent)),k(g))},nodeSetExpanded:function(b,c,e){e=e||{};var f,g,h,i,j,m,n=b.node,o=b.tree,p=b.options,q=e.noAnimation===!0,r=e.noEvents===!0;if(c=c!==!1,n.expanded&&c||!n.expanded&&!c)return k(n);if(c&&!n.lazy&&!n.hasChildren())return k(n);if(!c&&n.getLevel()<p.minExpandLevel)return l(n,["locked"]);if(!r&&this._triggerNodeEvent("beforeExpand",n,b.originalEvent)===!1)return l(n,["rejected"]);if(q||n.isVisible()||(q=e.noAnimation=!0),g=new a.Deferred,c&&!n.expanded&&p.autoCollapse){j=n.getParentList(!1,!0),m=p.autoCollapse;try{for(p.autoCollapse=!1,h=0,i=j.length;i>h;h++)this._callHook("nodeCollapseSiblings",j[h],e)}finally{p.autoCollapse=m}}return g.done(function(){var a=n.getLastChild();c&&p.autoScroll&&!q&&a?a.scrollIntoView(!0,{topNode:n}).always(function(){r||b.tree._triggerNodeEvent(c?"expand":"collapse",b)}):r||b.tree._triggerNodeEvent(c?"expand":"collapse",b)}),f=function(d){var e,f,g=p.toggleEffect;if(n.expanded=c,o._callHook("nodeRender",b,!1,!1,!0),n.ul)if(e="none"!==n.ul.style.display,f=!!n.expanded,e===f)n.warn("nodeSetExpanded: UL.style.display already set");else{if(g&&!q)return void a(n.ul).toggle(g.effect,g.options,g.duration,function(){d()});n.ul.style.display=n.expanded||!parent?"":"none"}d()},c&&n.lazy&&n.hasChildren()===d?n.load().done(function(){g.notifyWith&&g.notifyWith(n,["loaded"]),f(function(){g.resolveWith(n)})}).fail(function(a){f(function(){g.rejectWith(n,["load failed ("+a+")"])})}):f(function(){g.resolveWith(n)}),g.promise()},nodeSetFocus:function(b,c){var d,e=b.tree,f=b.node;if(c=c!==!1,e.focusNode){if(e.focusNode===f&&c)return;d=a.extend({},b,{node:e.focusNode}),e.focusNode=null,this._triggerNodeEvent("blur",d),this._callHook("nodeRenderStatus",d)}c&&(this.hasFocus()||(f.debug("nodeSetFocus: forcing container focus"),this._callHook("treeSetFocus",b,!0,{calledByNode:!0})),f.makeVisible({scrollIntoView:!1}),e.focusNode=f,this._triggerNodeEvent("focus",b),b.options.autoScroll&&f.scrollIntoView(),this._callHook("nodeRenderStatus",b))},nodeSetSelected:function(a,b){var c=a.node,d=a.tree,e=a.options;if(b=b!==!1,c.debug("nodeSetSelected("+b+")",a),!c.unselectable){if(c.selected&&b||!c.selected&&!b)return!!c.selected;if(this._triggerNodeEvent("beforeSelect",c,a.originalEvent)===!1)return!!c.selected;b&&1===e.selectMode?d.lastSelectedNode&&d.lastSelectedNode.setSelected(!1):3===e.selectMode&&(c.selected=b,c.fixSelection3AfterClick()),c.selected=b,this.nodeRenderStatus(a),d.lastSelectedNode=b?c:null,d._triggerNodeEvent("select",a)}},nodeSetStatus:function(b,c,d,e){function f(){var a=h.children?h.children[0]:null;if(a&&a.isStatusNode()){try{h.ul&&(h.ul.removeChild(a.li),a.li=null)}catch(b){}1===h.children.length?h.children=[]:h.children.shift()}}function g(b,c){var d=h.children?h.children[0]:null;return d&&d.isStatusNode()?(a.extend(d,b),i._callHook("nodeRenderTitle",d)):(b.key="_statusNode",h._setChildren([b]),h.children[0].statusNodeType=c,i.render()),h.children[0]}var h=b.node,i=b.tree;switch(c){case"ok":f(),h._isLoading=!1,h._error=null,h.renderStatus();break;case"loading":h.parent||g({title:i.options.strings.loading+(d?" ("+d+") ":""),tooltip:e,extraClasses:"fancytree-statusnode-wait"},c),h._isLoading=!0,h._error=null,h.renderStatus();break;case"error":g({title:i.options.strings.loadError+(d?" ("+d+") ":""),tooltip:e,extraClasses:"fancytree-statusnode-error"},c),h._isLoading=!1,h._error={message:d,details:e},h.renderStatus();break;default:a.error("invalid node status "+c)}},nodeToggleExpanded:function(a){return this.nodeSetExpanded(a,!a.node.expanded)},nodeToggleSelected:function(a){return this.nodeSetSelected(a,!a.node.selected)},treeClear:function(a){var b=a.tree;b.activeNode=null,b.focusNode=null,b.$div.find(">ul.fancytree-container").empty(),b.rootNode.children=null},treeCreate:function(){},treeDestroy:function(){this.$div.find(">ul.fancytree-container").remove(),this.$source&&this.$source.removeClass("ui-helper-hidden")},treeInit:function(a){this.treeLoad(a)},treeLoad:function(b,c){var d,e,f,g=b.tree,h=b.widget.element,i=a.extend({},b,{node:this.rootNode});if(g.rootNode.children&&this.treeClear(b),c=c||this.options.source)"string"==typeof c&&a.error("Not implemented");else switch(d=h.data("type")||"html"){case"html":e=h.find(">ul:first"),e.addClass("ui-fancytree-source ui-helper-hidden"),c=a.ui.fancytree.parseHtml(e),this.data=a.extend(this.data,n(e));break;case"json":c=a.parseJSON(h.text()),c.children&&(c.title&&(g.title=c.title),c=c.children);break;default:a.error("Invalid data-type: "+d)}return f=this.nodeLoadChildren(i,c).done(function(){g.render(),3===b.options.selectMode&&g.rootNode.fixSelection3FromEndNodes(),g.activeNode&&g.options.activeVisible&&g.activeNode.makeVisible(),g._triggerTreeEvent("init",null,{status:!0})}).fail(function(){g.render(),g._triggerTreeEvent("init",null,{status:!1})})},treeRegisterNode:function(){},treeSetFocus:function(a,b){b=b!==!1,b!==this.hasFocus()&&(this._hasFocus=b,!b&&this.focusNode&&this.focusNode.setFocus(!1),this.$container.toggleClass("fancytree-treefocus",b),this._triggerTreeEvent(b?"focusTree":"blurTree"))}}),a.widget("ui.fancytree",{options:{activeVisible:!0,ajax:{type:"GET",cache:!1,dataType:"json"},aria:!1,autoActivate:!0,autoCollapse:!1,autoScroll:!1,checkbox:!1,clickFolderMode:4,debugLevel:null,disabled:!1,enableAspx:!0,extensions:[],toggleEffect:{effect:"blind",options:{direction:"vertical",scale:"box"},duration:200},generateIds:!1,icons:!0,idPrefix:"ft_",focusOnSelect:!1,keyboard:!0,keyPathSeparator:"/",minExpandLevel:1,quicksearch:!1,scrollOfs:{top:0,bottom:0},scrollParent:null,selectMode:2,strings:{loading:"Loading…",loadError:"Load error!"},tabbable:!0,titlesTabbable:!1,_classNames:{node:"fancytree-node",folder:"fancytree-folder",combinedExpanderPrefix:"fancytree-exp-",combinedIconPrefix:"fancytree-ico-",hasChildren:"fancytree-has-children",active:"fancytree-active",selected:"fancytree-selected",expanded:"fancytree-expanded",lazy:"fancytree-lazy",focused:"fancytree-focused",partsel:"fancytree-partsel",unselectable:"fancytree-unselectable",lastsib:"fancytree-lastsib",loading:"fancytree-loading",error:"fancytree-error"},lazyLoad:null,postProcess:null},_create:function(){this.tree=new r(this),this.$source=this.source||"json"===this.element.data("type")?this.element:this.element.find(">ul:first");var b,c,f,g=this.options.extensions,h=this.tree;for(f=0;f<g.length;f++)c=g[f],b=a.ui.fancytree._extensions[c],b||a.error("Could not apply extension '"+c+"' (it is not registered, did you forget to include it?)"),this.tree.options[c]=a.extend(!0,{},b.options,this.tree.options[c]),e(this.tree.ext[c]===d,"Extension name must not exist as Fancytree.ext attribute: '"+c+"'"),this.tree.ext[c]={},j(this.tree,h,b,c),h=b;this.tree._callHook("treeCreate",this.tree)},_init:function(){this.tree._callHook("treeInit",this.tree),this._bind()},_setOption:function(b,c){var d=!0,e=!1;switch(b){case"aria":case"checkbox":case"icons":case"minExpandLevel":case"tabbable":this.tree._callHook("treeCreate",this.tree),e=!0;break;case"source":d=!1,this.tree._callHook("treeLoad",this.tree,c)}this.tree.debug("set option "+b+"="+c+" <"+typeof c+">"),d&&a.Widget.prototype._setOption.apply(this,arguments),e&&this.tree.render(!0,!1)},destroy:function(){this._unbind(),this.tree._callHook("treeDestroy",this.tree),a.Widget.prototype.destroy.call(this)},_unbind:function(){var b=this.tree._ns;this.element.unbind(b),this.tree.$container.unbind(b),a(c).unbind(b)},_bind:function(){var a=this,b=this.options,c=this.tree,d=c._ns;this._unbind(),c.$container.on("focusin"+d+" focusout"+d,function(a){var b=u.getNode(a),d="focusin"===a.type;b?c._callHook("nodeSetFocus",b,d):c._callHook("treeSetFocus",c,d)}).on("selectstart"+d,"span.fancytree-title",function(a){a.preventDefault()}).on("keydown"+d,function(a){if(b.disabled||b.keyboard===!1)return!0;var d,e=c.focusNode,f=c._makeHookContext(e||c,a),g=c.phase;try{return c.phase="userEvent",d=e?c._triggerNodeEvent("keydown",e,a):c._triggerTreeEvent("keydown",a),"preventNav"===d?d=!0:d!==!1&&(d=c._callHook("nodeKeydown",f)),d}finally{c.phase=g}}).on("click"+d+" dblclick"+d,function(c){if(b.disabled)return!0;var d,e=u.getEventTarget(c),f=e.node,g=a.tree,h=g.phase;if(!f)return!0;d=g._makeHookContext(f,c);try{switch(g.phase="userEvent",c.type){case"click":return d.targetType=e.type,g._triggerNodeEvent("click",d,c)===!1?!1:g._callHook("nodeClick",d);case"dblclick":return d.targetType=e.type,g._triggerNodeEvent("dblclick",d,c)===!1?!1:g._callHook("nodeDblclick",d)}}finally{g.phase=h}})},getActiveNode:function(){return this.tree.activeNode},getNodeByKey:function(a){return this.tree.getNodeByKey(a)},getRootNode:function(){return this.tree.rootNode},getTree:function(){return this.tree}}),u=a.ui.fancytree,a.extend(a.ui.fancytree,{version:"2.13.0",buildType: "production",debugLevel: 1,_nextId:1,_nextNodeKey:1,_extensions:{},_FancytreeClass:r,_FancytreeNodeClass:q,jquerySupports:{positionMyOfs:h(a.ui.version,1,9)},assert:function(a,b){return e(a,b)},debounce:function(a,b,c,d){var e;return 3===arguments.length&&"boolean"!=typeof c&&(d=c,c=!1),function(){var f=arguments;d=d||this,c&&!e&&b.apply(d,f),clearTimeout(e),e=setTimeout(function(){c||b.apply(d,f),e=null},a)}},debug:function(){a.ui.fancytree.debugLevel>=2&&f("log",arguments)},error:function(){f("error",arguments)},escapeHtml:function(a){return(""+a).replace(/[&<>"'\/]/g,function(a){return v[a]})},fixPositionOptions:function(b){if((b.offset||(""+b.my+b.at).indexOf("%")>=0)&&a.error("expected new position syntax (but '%' is not supported)"),!a.ui.fancytree.jquerySupports.positionMyOfs){var c=/(\w+)([+-]?\d+)?\s+(\w+)([+-]?\d+)?/.exec(b.my),d=/(\w+)([+-]?\d+)?\s+(\w+)([+-]?\d+)?/.exec(b.at),e=(c[2]?+c[2]:0)+(d[2]?+d[2]:0),f=(c[4]?+c[4]:0)+(d[4]?+d[4]:0);b=a.extend({},b,{my:c[1]+" "+c[3],at:d[1]+" "+d[3]}),(e||f)&&(b.offset=""+e+" "+f)}return b},getEventTargetType:function(a){return this.getEventTarget(a).type},getEventTarget:function(b){var c=b&&b.target?b.target.className:"",e={node:this.getNode(b.target),type:d};return/\bfancytree-title\b/.test(c)?e.type="title":/\bfancytree-expander\b/.test(c)?e.type=e.node.hasChildren()===!1?"prefix":"expander":/\bfancytree-checkbox\b/.test(c)||/\bfancytree-radio\b/.test(c)?e.type="checkbox":/\bfancytree-icon\b/.test(c)?e.type="icon":/\bfancytree-node\b/.test(c)?e.type="title":b&&b.target&&a(b.target).closest(".fancytree-title").length&&(e.type="title"),e},getNode:function(a){if(a instanceof q)return a;for(a.selector!==d?a=a[0]:a.originalEvent!==d&&(a=a.target);a;){if(a.ftnode)return a.ftnode;a=a.parentNode}return null},getTree:function(b){var c;return b instanceof r?b:(b===d&&(b=0),"number"==typeof b?b=a(".fancytree-container").eq(b):"string"==typeof b?b=a(b).eq(0):b.selector!==d?b=b.eq(0):b.originalEvent!==d&&(b=a(b.target)),b=b.closest(":ui-fancytree"),c=b.data("ui-fancytree")||b.data("fancytree"),c?c.tree:null)},info:function(){a.ui.fancytree.debugLevel>=1&&f("info",arguments)},eventToString:function(a){var b=a.which,c=a.type,d=[];return a.altKey&&d.push("alt"),a.ctrlKey&&d.push("ctrl"),a.metaKey&&d.push("meta"),a.shiftKey&&d.push("shift"),"click"===c||"dblclick"===c?d.push(y[a.button]+c):w[b]||d.push(x[b]||String.fromCharCode(b).toLowerCase()),d.join("+")},keyEventToString:function(a){return this.warn("keyEventToString() is deprecated: use eventToString()"),this.eventToString(a)},parseHtml:function(b){var c,e,f,g,h,i,j,k,l=b.find(">li"),m=[];return l.each(function(){var l,o,p=a(this),q=p.find(">span:first",this),r=q.length?null:p.find(">a:first"),s={tooltip:null,data:{}};for(q.length?s.title=q.html():r&&r.length?(s.title=r.html(),s.data.href=r.attr("href"),s.data.target=r.attr("target"),s.tooltip=r.attr("title")):(s.title=p.html(),h=s.title.search(/<ul/i),h>=0&&(s.title=s.title.substring(0,h))),s.title=a.trim(s.title),g=0,i=z.length;i>g;g++)s[z[g]]=d;for(c=this.className.split(" "),f=[],g=0,i=c.length;i>g;g++)e=c[g],A[e]?s[e]=!0:f.push(e);if(s.extraClasses=f.join(" "),j=p.attr("title"),j&&(s.tooltip=j),j=p.attr("id"),j&&(s.key=j),l=n(p),l&&!a.isEmptyObject(l)){for(o in D)l.hasOwnProperty(o)&&(l[D[o]]=l[o],delete l[o]);for(g=0,i=B.length;i>g;g++)j=B[g],k=l[j],null!=k&&(delete l[j],s[j]=k);a.extend(s.data,l)}b=p.find(">ul:first"),s.children=b.length?a.ui.fancytree.parseHtml(b):s.lazy?d:null,m.push(s)}),m},registerExtension:function(b){e(null!=b.name,"extensions must have a `name` property."),e(null!=b.version,"extensions must have a `version` property."),a.ui.fancytree._extensions[b.name]=b},unescapeHtml:function(a){var b=c.createElement("div");return b.innerHTML=a,0===b.childNodes.length?"":b.childNodes[0].nodeValue},warn:function(){f("warn",arguments)}})}(jQuery,window,document); + +/*! Extension 'jquery.fancytree.childcounter.min.js' */ +!function(a){"use strict";a.ui.fancytree._FancytreeClass.prototype.countSelected=function(a){{var b=this;b.options}return b.getSelectedNodes(a).length},a.ui.fancytree._FancytreeNodeClass.prototype.updateCounters=function(){var b=this,c=a("span.fancytree-childcounter",b.span),d=b.tree.options.childcounter,e=b.countChildren(d.deep);b.data.childCounter=e,!e&&d.hideZeros||b.isExpanded()&&d.hideExpanded?c.remove():(c.length||(c=a("<span class='fancytree-childcounter'/>").appendTo(a("span.fancytree-icon",b.span))),c.text(e)),!d.deep||b.isTopLevel()||b.isRoot()||b.parent.updateCounters()},a.ui.fancytree.prototype.widgetMethod1=function(a){this.tree;return a},a.ui.fancytree.registerExtension({name:"childcounter",version:"1.0.0",options:{deep:!0,hideZeros:!0,hideExpanded:!1},foo:42,_appendCounter:function(){},treeInit:function(a){a.options,a.options.childcounter;this._superApply(arguments),this.$container.addClass("fancytree-ext-childcounter")},treeDestroy:function(){this._superApply(arguments)},nodeRenderTitle:function(b){var c=b.node,d=b.options.childcounter,e=null==c.data.childCounter?c.countChildren(d.deep):+c.data.childCounter;this._superApply(arguments),!e&&d.hideZeros||c.isExpanded()&&d.hideExpanded||a("span.fancytree-icon",c.span).append(a("<span class='fancytree-childcounter'/>").text(e))},nodeSetExpanded:function(a){{var b=a.tree;a.node}return this._superApply(arguments).always(function(){b.nodeRenderTitle(a)})}})}(jQuery); + +/*! Extension 'jquery.fancytree.clones.min.js' */ +!function(a){"use strict";function b(b,c){b||(c=c?": "+c:"",a.error("Assertion failed"+c))}function c(a,b){var c;for(c=a.length-1;c>=0;c--)if(a[c]===b)return a.splice(c,1),!0;return!1}function d(a,b,c){for(var d,e,f=3&a.length,g=a.length-f,h=c,i=3432918353,j=461845907,k=0;g>k;)e=255&a.charCodeAt(k)|(255&a.charCodeAt(++k))<<8|(255&a.charCodeAt(++k))<<16|(255&a.charCodeAt(++k))<<24,++k,e=(65535&e)*i+(((e>>>16)*i&65535)<<16)&4294967295,e=e<<15|e>>>17,e=(65535&e)*j+(((e>>>16)*j&65535)<<16)&4294967295,h^=e,h=h<<13|h>>>19,d=5*(65535&h)+((5*(h>>>16)&65535)<<16)&4294967295,h=(65535&d)+27492+(((d>>>16)+58964&65535)<<16);switch(e=0,f){case 3:e^=(255&a.charCodeAt(k+2))<<16;case 2:e^=(255&a.charCodeAt(k+1))<<8;case 1:e^=255&a.charCodeAt(k),e=(65535&e)*i+(((e>>>16)*i&65535)<<16)&4294967295,e=e<<15|e>>>17,e=(65535&e)*j+(((e>>>16)*j&65535)<<16)&4294967295,h^=e}return h^=a.length,h^=h>>>16,h=2246822507*(65535&h)+((2246822507*(h>>>16)&65535)<<16)&4294967295,h^=h>>>13,h=3266489909*(65535&h)+((3266489909*(h>>>16)&65535)<<16)&4294967295,h^=h>>>16,b?("0000000"+(h>>>0).toString(16)).substr(-8):h>>>0}function e(b){var c,e=a.map(b.getParentList(!1,!0),function(a){return a.refKey||a.key});return e=e.join("/"),c="id_"+d(e,!0)}a.ui.fancytree._FancytreeNodeClass.prototype.getCloneList=function(b){var c,d=this.tree,e=d.refMap[this.refKey]||null,f=d.keyMap;return e&&(c=this.key,b?e=a.map(e,function(a){return f[a]}):(e=a.map(e,function(a){return a===c?null:f[a]}),e.length<1&&(e=null))),e},a.ui.fancytree._FancytreeNodeClass.prototype.isClone=function(){var a=this.refKey||null,b=a&&this.tree.refMap[a]||null;return!!(b&&b.length>1)},a.ui.fancytree._FancytreeNodeClass.prototype.reRegister=function(b,c){b=null==b?null:""+b,c=null==c?null:""+c;var d=this.tree,e=this.key,f=this.refKey,g=d.keyMap,h=d.refMap,i=h[f]||null,j=!1;return null!=b&&b!==this.key&&(g[b]&&a.error("[ext-clones] reRegister("+b+"): already exists: "+this),delete g[e],g[b]=this,i&&(h[f]=a.map(i,function(a){return a===e?b:a})),this.key=b,j=!0),null!=c&&c!==this.refKey&&(i&&(1===i.length?delete h[f]:h[f]=a.map(i,function(a){return a===e?null:a})),h[c]?h[c].append(b):h[c]=[this.key],this.refKey=c,j=!0),j},a.ui.fancytree._FancytreeClass.prototype.getNodesByRef=function(b,c){var d=this.keyMap,e=this.refMap[b]||null;return e&&(e=c?a.map(e,function(a){var b=d[a];return b.isDescendantOf(c)?b:null}):a.map(e,function(a){return d[a]}),e.length<1&&(e=null)),e},a.ui.fancytree._FancytreeClass.prototype.changeRefKey=function(a,b){var c,d,e=this.keyMap,f=this.refMap[a]||null;if(f){for(c=0;c<f.length;c++)d=e[f[c]],d.refKey=b;delete this.refMap[a],this.refMap[b]=f}},a.ui.fancytree.registerExtension({name:"clones",version:"0.0.3",options:{highlightActiveClones:!0,highlightClones:!1},treeCreate:function(a){this._superApply(arguments),a.tree.refMap={},a.tree.keyMap={}},treeInit:function(a){this.$container.addClass("fancytree-ext-clones"),b(null==a.options.defaultKey),a.options.defaultKey=function(a){return e(a)},this._superApply(arguments)},treeClear:function(a){return a.tree.refMap={},a.tree.keyMap={},this._superApply(arguments)},treeRegisterNode:function(d,e,f){var g,h,i=d.tree,j=i.keyMap,k=i.refMap,l=f.key,m=f&&null!=f.refKey?""+f.refKey:null;return"_statusNode"===l?this._superApply(arguments):(e?(null!=j[f.key]&&a.error("clones.treeRegisterNode: node.key already exists: "+f),j[l]=f,m&&(g=k[m],g?(g.push(l),2===g.length&&d.options.clones.highlightClones&&j[g[0]].renderStatus()):k[m]=[l])):(null==j[l]&&a.error("clones.treeRegisterNode: node.key not registered: "+f.key),delete j[l],m&&(g=k[m],g&&(h=g.length,1>=h?(b(1===h),b(g[0]===l),delete k[m]):(c(g,l),2===h&&d.options.clones.highlightClones&&j[g[0]].renderStatus())))),this._superApply(arguments))},nodeRenderStatus:function(b){var c,d,e=b.node;return d=this._superApply(arguments),b.options.clones.highlightClones&&(c=a(e[b.tree.statusClassPropName]),c.length&&e.isClone()&&c.addClass("fancytree-clone")),d},nodeSetActive:function(b,c){var d,e=b.tree.statusClassPropName,f=b.node;return d=this._superApply(arguments),b.options.clones.highlightActiveClones&&f.isClone()&&a.each(f.getCloneList(!0),function(b,d){a(d[e]).toggleClass("fancytree-active-clone",c!==!1)}),d}})}(jQuery,window,document); + +/*! Extension 'jquery.fancytree.dnd.min.js' */ +!function(a,b,c,d){"use strict";function e(a){return 0===a?"":a>0?"+"+a:""+a}function f(b){var c=b.options.dnd||null,d=b.options.glyph||null;c&&g(),c&&c.dragStart&&b.widget.element.draggable(a.extend({addClasses:!1,appendTo:b.$container,containment:!1,delay:0,distance:4,revert:!1,scroll:!0,scrollSpeed:7,scrollSensitivity:10,connectToFancytree:!0,helper:function(b){var c,e,f,g=a.ui.fancytree.getNode(b.target);return g?(f=g.tree.options.dnd,e=a(g.span),c=a("<div class='fancytree-drag-helper'><span class='fancytree-drag-helper-img' /></div>").css({zIndex:3,position:"relative"}).append(e.find("span.fancytree-title").clone()),c.data("ftSourceNode",g),d&&c.find(".fancytree-drag-helper-img").addClass(d.map.dragHelper),f.initHelper&&f.initHelper.call(g.tree,g,{node:g,tree:g.tree,originalEvent:b,ui:{helper:c}}),c):"<div>ERROR?: helper requested but sourceNode not found</div>"},start:function(a,b){var c=b.helper.data("ftSourceNode");return!!c}},b.options.dnd.draggable)),c&&c.dragDrop&&b.widget.element.droppable(a.extend({addClasses:!1,tolerance:"intersect",greedy:!1},b.options.dnd.droppable))}function g(){h||(a.ui.plugin.add("draggable","connectToFancytree",{start:function(b,c){var d=a(this).data("ui-draggable")||a(this).data("draggable"),e=c.helper.data("ftSourceNode")||null;return e?(d.offset.click.top=-2,d.offset.click.left=16,e.tree.ext.dnd._onDragEvent("start",e,null,b,c,d)):void 0},drag:function(b,c){var d,e,f,g=a(this).data("ui-draggable")||a(this).data("draggable"),h=c.helper.data("ftSourceNode")||null,i=c.helper.data("ftTargetNode")||null,j=a.ui.fancytree.getNode(b.target),k=h&&h.tree.options.dnd;return b.target&&!j&&(e=a(b.target).closest("div.fancytree-drag-helper,#fancytree-drop-marker").length>0)?(f=h||i||a.ui.fancytree,void f.debug("Drag event over helper: ignored.")):(c.helper.data("ftTargetNode",j),k&&k.updateHelper&&(d=h.tree._makeHookContext(h,b,{otherNode:j,ui:c,draggable:g,dropMarker:a("#fancytree-drop-marker")}),k.updateHelper.call(h.tree,h,d)),i&&i!==j&&i.tree.ext.dnd._onDragEvent("leave",i,h,b,c,g),void(j&&j.tree.options.dnd.dragDrop&&(j===i?j.tree.ext.dnd._onDragEvent("over",j,h,b,c,g):j.tree.ext.dnd._onDragEvent("enter",j,h,b,c,g))))},stop:function(b,c){var d,e=a(this).data("ui-draggable")||a(this).data("draggable"),f=c.helper.data("ftSourceNode")||null,g=c.helper.data("ftTargetNode")||null,h="mouseup"===b.type&&1===b.which;h||(d=f||g||a.ui.fancytree,d.debug("Drag was cancelled")),g&&(h&&g.tree.ext.dnd._onDragEvent("drop",g,f,b,c,e),g.tree.ext.dnd._onDragEvent("leave",g,f,b,c,e)),f&&f.tree.ext.dnd._onDragEvent("stop",f,null,b,c,e)}}),h=!0)}var h=!1,i="fancytree-drop-accept",j="fancytree-drop-after",k="fancytree-drop-before",l="fancytree-drop-over",m="fancytree-drop-reject",n="fancytree-drop-target";a.ui.fancytree.registerExtension({name:"dnd",version:"0.2.0",options:{autoExpandMS:1e3,draggable:null,droppable:null,focusOnClick:!1,preventVoidMoves:!0,preventRecursiveMoves:!0,smartRevert:!0,dragStart:null,dragStop:null,initHelper:null,updateHelper:null,dragEnter:null,dragOver:null,dragDrop:null,dragLeave:null},treeInit:function(b){var c=b.tree;this._superApply(arguments),c.options.dnd.dragStart&&c.$container.on("mousedown",function(c){if(b.options.dnd.focusOnClick){var d=a.ui.fancytree.getNode(c);d&&d.debug("Re-enable focus that was prevented by jQuery UI draggable."),setTimeout(function(){a(c.target).closest(":tabbable").focus()},10)}}),f(c)},_setDndStatus:function(b,c,d,f,g){var h=0,o="center",p=this._local,q=this.options.glyph||null,r=b?a(b.span):null,s=a(c.span);if(p.$dropMarker||(p.$dropMarker=a("<div id='fancytree-drop-marker'></div>").hide().css({"z-index":1e3}).prependTo(a(this.$div).parent()),q&&p.$dropMarker.addClass(q.map.dropMarker)),"after"===f||"before"===f||"over"===f){switch(f){case"before":o="top";break;case"after":o="bottom";break;default:h=8}p.$dropMarker.toggleClass(j,"after"===f).toggleClass(l,"over"===f).toggleClass(k,"before"===f).show().position(a.ui.fancytree.fixPositionOptions({my:"left"+e(h)+" center",at:"left "+o,of:s}))}else p.$dropMarker.hide();r&&r.toggleClass(i,g===!0).toggleClass(m,g===!1),s.toggleClass(n,"after"===f||"before"===f||"over"===f).toggleClass(j,"after"===f).toggleClass(k,"before"===f).toggleClass(i,g===!0).toggleClass(m,g===!1),d.toggleClass(i,g===!0).toggleClass(m,g===!1)},_onDragEvent:function(b,e,f,g,h,i){"over"!==b&&this.debug("tree.ext.dnd._onDragEvent(%s, %o, %o) - %o",b,e,f,this);var j,k,l,m,n,o,p,q=this.options,r=q.dnd,s=this._makeHookContext(e,g,{otherNode:f,ui:h,draggable:i}),t=null,u=this,v=a(e.span);switch(r.smartRevert&&(i.options.revert="invalid"),b){case"start":e.isStatusNode()?t=!1:r.dragStart&&(t=r.dragStart(e,s)),t===!1?(this.debug("tree.dragStart() cancelled"),h.helper.trigger("mouseup").hide()):(v.addClass("fancytree-drag-source"),a(c).on("keydown.fancytree-dnd,mousedown.fancytree-dnd",function(b){"keydown"===b.type&&b.which===a.ui.keyCode.ESCAPE?u.ext.dnd._cancelDrag():"mousedown"===b.type&&u.ext.dnd._cancelDrag()}));break;case"enter":p=r.preventRecursiveMoves&&e.isDescendantOf(f)?!1:r.dragEnter?r.dragEnter(e,s):null,t=p?a.isArray(p)?{over:a.inArray("over",p)>=0,before:a.inArray("before",p)>=0,after:a.inArray("after",p)>=0}:{over:p===!0||"over"===p,before:p===!0||"before"===p,after:p===!0||"after"===p}:!1,h.helper.data("enterResponse",t),this.debug("helper.enterResponse: %o",t);break;case"over":n=h.helper.data("enterResponse"),o=null,n===!1||("string"==typeof n?o=n:(k=v.offset(),l={x:g.pageX-k.left,y:g.pageY-k.top},m={x:l.x/v.width(),y:l.y/v.height()},n.after&&m.y>.75?o="after":!n.over&&n.after&&m.y>.5?o="after":n.before&&m.y<=.25?o="before":!n.over&&n.before&&m.y<=.5?o="before":n.over&&(o="over"),r.preventVoidMoves&&(e===f?(this.debug(" drop over source node prevented"),o=null):"before"===o&&f&&e===f.getNextSibling()?(this.debug(" drop after source node prevented"),o=null):"after"===o&&f&&e===f.getPrevSibling()?(this.debug(" drop before source node prevented"),o=null):"over"===o&&f&&f.parent===e&&f.isLastSibling()&&(this.debug(" drop last child over own parent prevented"),o=null)),h.helper.data("hitMode",o))),"over"===o&&r.autoExpandMS&&e.hasChildren()!==!1&&!e.expanded&&e.scheduleAction("expand",r.autoExpandMS),o&&r.dragOver&&(s.hitMode=o,t=r.dragOver(e,s)),j=t!==!1&&null!==o,r.smartRevert&&(i.options.revert=!j),this._local._setDndStatus(f,e,h.helper,o,j);break;case"drop":o=h.helper.data("hitMode"),o&&r.dragDrop&&(s.hitMode=o,r.dragDrop(e,s));break;case"leave":e.scheduleAction("cancel"),h.helper.data("enterResponse",null),h.helper.data("hitMode",null),this._local._setDndStatus(f,e,h.helper,"out",d),r.dragLeave&&r.dragLeave(e,s);break;case"stop":v.removeClass("fancytree-drag-source"),a(c).off(".fancytree-dnd"),r.dragStop&&r.dragStop(e,s);break;default:a.error("Unsupported drag event: "+b)}return t},_cancelDrag:function(){var b=a.ui.ddmanager.current;b&&b.cancel()}})}(jQuery,window,document); + +/*! Extension 'jquery.fancytree.edit.min.js' */ +!function(a,b,c){"use strict";var d=/Mac/.test(navigator.platform),e=a.ui.fancytree.escapeHtml,f=a.ui.fancytree.unescapeHtml;a.ui.fancytree._FancytreeNodeClass.prototype.editStart=function(){var b,d=this,e=this.tree,g=e.ext.edit,h=e.options.edit,i=a(".fancytree-title",d.span),j={node:d,tree:e,options:e.options,isNew:a(d[e.statusClassPropName]).hasClass("fancytree-edit-new"),orgTitle:d.title,input:null,dirty:!1};return h.beforeEdit.call(d,{type:"beforeEdit"},j)===!1?!1:(a.ui.fancytree.assert(!g.currentNode,"recursive edit"),g.currentNode=this,g.eventData=j,e.widget._unbind(),a(c).on("mousedown.fancytree-edit",function(b){a(b.target).hasClass("fancytree-edit-input")||d.editEnd(!0,b)}),b=a("<input />",{"class":"fancytree-edit-input",type:"text",value:f(j.orgTitle)}),g.eventData.input=b,null!=h.adjustWidthOfs&&b.width(i.width()+h.adjustWidthOfs),null!=h.inputCss&&b.css(h.inputCss),i.html(b),b.focus().change(function(){b.addClass("fancytree-edit-dirty")}).keydown(function(b){switch(b.which){case a.ui.keyCode.ESCAPE:d.editEnd(!1,b);break;case a.ui.keyCode.ENTER:return d.editEnd(!0,b),!1}b.stopPropagation()}).blur(function(a){return d.editEnd(!0,a)}),void h.edit.call(d,{type:"edit"},j))},a.ui.fancytree._FancytreeNodeClass.prototype.editEnd=function(b){var d,f=this,g=this.tree,h=g.ext.edit,i=h.eventData,j=g.options.edit,k=a(".fancytree-title",f.span),l=k.find("input.fancytree-edit-input");return j.trim&&l.val(a.trim(l.val())),d=l.val(),i.dirty=d!==f.title,i.save=b===!1?!1:i.isNew?""!==d:i.dirty&&""!==d,j.beforeClose.call(f,{type:"beforeClose"},i)===!1?!1:i.save&&j.save.call(f,{type:"save"},i)===!1?!1:(l.removeClass("fancytree-edit-dirty").unbind(),a(c).off(".fancytree-edit"),i.save?(f.setTitle(e(d)),f.setFocus()):i.isNew?(f.remove(),f=i.node=null,h.relatedNode.setFocus()):(f.renderTitle(),f.setFocus()),h.eventData=null,h.currentNode=null,h.relatedNode=null,g.widget._bind(),a(g.$container).focus(),i.input=null,j.close.call(f,{type:"close"},i),!0)},a.ui.fancytree._FancytreeNodeClass.prototype.editCreateNode=function(b,c){var d,e=this.tree,f=this;return b=b||"child",null==c?c={title:""}:"string"==typeof c?c={title:c}:a.ui.fancytree.assert(a.isPlainObject(c)),"child"!==b||this.isExpanded()||this.hasChildren()===!1?(d=this.addNode(c,b),void d.makeVisible().done(function(){a(d[e.statusClassPropName]).addClass("fancytree-edit-new"),f.tree.ext.edit.relatedNode=f,d.editStart()})):void this.setExpanded().done(function(){f.editCreateNode(b,c)})},a.ui.fancytree._FancytreeClass.prototype.isEditing=function(){return this.ext.edit.currentNode},a.ui.fancytree._FancytreeNodeClass.prototype.isEditing=function(){return this.tree.ext.edit.currentNode===this},a.ui.fancytree.registerExtension({name:"edit",version:"0.2.0",options:{adjustWidthOfs:4,allowEmpty:!1,inputCss:{minWidth:"3em"},triggerCancel:["esc","tab","click"],triggerStart:["f2","shift+click","mac+enter"],trim:!0,beforeClose:a.noop,beforeEdit:a.noop,close:a.noop,edit:a.noop,save:a.noop},currentNode:null,treeInit:function(){this._superApply(arguments),this.$container.addClass("fancytree-ext-edit")},nodeClick:function(b){return a.inArray("shift+click",b.options.edit.triggerStart)>=0&&b.originalEvent.shiftKey?(b.node.editStart(),!1):this._superApply(arguments)},nodeDblclick:function(b){return a.inArray("dblclick",b.options.edit.triggerStart)>=0?(b.node.editStart(),!1):this._superApply(arguments)},nodeKeydown:function(b){switch(b.originalEvent.which){case 113:if(a.inArray("f2",b.options.edit.triggerStart)>=0)return b.node.editStart(),!1;break;case a.ui.keyCode.ENTER:if(a.inArray("mac+enter",b.options.edit.triggerStart)>=0&&d)return b.node.editStart(),!1}return this._superApply(arguments)}})}(jQuery,window,document); + +/*! Extension 'jquery.fancytree.filter.min.js' */ +!function(a){"use strict";function b(a){return(a+"").replace(/([.?*+\^\$\[\]\\(){}|-])/g,"\\$1")}a.ui.fancytree._FancytreeClass.prototype._applyFilterImpl=function(a,c,d){var e,f,g,h,i=0,j=this.options.filter,k="hide"===j.mode;return d=d||{},e=!!d.leavesOnly&&!c,"string"==typeof a&&(f=j.fuzzy?a.split("").reduce(function(a,b){return a+"[^"+b+"]*"+b}):b(a),g=new RegExp(".*"+f+".*","i"),h=new RegExp(a,"gi"),a=function(a){var b=!!g.test(a.title);return b&&j.highlight&&(a.titleWithHighlight=a.title.replace(h,function(a){return"<mark>"+a+"</mark>"})),b}),this.enableFilter=!0,this.lastFilterArgs=arguments,this.$div.addClass("fancytree-ext-filter"),this.$div.addClass(k?"fancytree-ext-filter-hide":"fancytree-ext-filter-dimm"),this.visit(function(a){delete a.match,delete a.titleWithHighlight,a.subMatchCount=0}),this.visit(function(b){return e&&null!=b.children||!a(b)||(i++,b.match=!0,b.visitParents(function(a){a.subMatchCount+=1,d.autoExpand&&!a.expanded&&(a.setExpanded(!0,{noAnimation:!0,noEvents:!0,scrollIntoView:!1}),a._filterAutoExpanded=!0)}),!c)?void 0:(b.visit(function(a){a.match=!0}),"skip")}),this.render(),i},a.ui.fancytree._FancytreeClass.prototype.filterNodes=function(a,b){return"boolean"==typeof b&&(b={leavesOnly:b},this.warn("Fancytree.filterNodes() leavesOnly option is deprecated since 2.9.0 / 2015-04-19.")),this._applyFilterImpl(a,!1,b)},a.ui.fancytree._FancytreeClass.prototype.applyFilter=function(){return this.warn("Fancytree.applyFilter() is deprecated since 2.1.0 / 2014-05-29. Use .filterNodes() instead."),this.filterNodes.apply(this,arguments)},a.ui.fancytree._FancytreeClass.prototype.filterBranches=function(a,b){return this._applyFilterImpl(a,!0,b)},a.ui.fancytree._FancytreeClass.prototype.clearFilter=function(){this.visit(function(b){b.match&&a(">span.fancytree-title",b.span).html(b.title),delete b.match,delete b.subMatchCount,delete b.titleWithHighlight,b.$subMatchBadge&&(b.$subMatchBadge.remove(),delete b.$subMatchBadge),b._filterAutoExpanded&&b.expanded&&b.setExpanded(!1,{noAnimation:!0,noEvents:!0,scrollIntoView:!1}),delete b._filterAutoExpanded}),this.enableFilter=!1,this.lastFilterArgs=null,this.$div.removeClass("fancytree-ext-filter fancytree-ext-filter-dimm fancytree-ext-filter-hide"),this.render()},a.ui.fancytree._FancytreeClass.prototype.isFilterActive=function(){return!!this.enableFilter},a.ui.fancytree._FancytreeNodeClass.prototype.isMatched=function(){return!(this.tree.enableFilter&&!this.match)},a.ui.fancytree.registerExtension({name:"filter",version:"0.7.0",options:{autoApply:!0,counter:!0,fuzzy:!1,hideExpandedCounter:!0,highlight:!0,mode:"dimm"},nodeLoadChildren:function(a){return this._superApply(arguments).done(function(){a.tree.enableFilter&&a.tree.lastFilterArgs&&a.options.filter.autoApply&&a.tree._applyFilterImpl.apply(a.tree,a.tree.lastFilterArgs)})},nodeSetExpanded:function(a,b){return delete a.node._filterAutoExpanded,!b&&a.options.filter.hideExpandedCounter&&a.node.$subMatchBadge&&a.node.$subMatchBadge.show(),this._superApply(arguments)},nodeRenderStatus:function(b){var c,d=b.node,e=b.tree,f=b.options.filter,g=a(d[e.statusClassPropName]);return c=this._superApply(arguments),g.length&&e.enableFilter?(g.toggleClass("fancytree-match",!!d.match).toggleClass("fancytree-submatch",!!d.subMatchCount).toggleClass("fancytree-hide",!(d.match||d.subMatchCount)),!f.counter||!d.subMatchCount||d.isExpanded()&&f.hideExpandedCounter?d.$subMatchBadge&&d.$subMatchBadge.hide():(d.$subMatchBadge||(d.$subMatchBadge=a("<span class='fancytree-childcounter'/>"),a("span.fancytree-icon",d.span).append(d.$subMatchBadge)),d.$subMatchBadge.show().text(d.subMatchCount)),a("span.fancytree-title",d.span).html(d.titleWithHighlight?d.titleWithHighlight:d.title),c):c}})}(jQuery,window,document); + +/*! Extension 'jquery.fancytree.glyph.min.js' */ +!function(a){"use strict";function b(a,b){return a.map[b]}a.ui.fancytree.registerExtension({name:"glyph",version:"0.3.0",options:{map:{checkbox:"icon-check-empty",checkboxSelected:"icon-check",checkboxUnknown:"icon-check icon-muted",error:"icon-exclamation-sign",expanderClosed:"icon-caret-right",expanderLazy:"icon-angle-right",expanderOpen:"icon-caret-down",noExpander:"",dragHelper:"icon-caret-right",dropMarker:"icon-caret-right",doc:"icon-file-alt",docOpen:"icon-file-alt",loading:"icon-refresh icon-spin",folder:"icon-folder-close-alt",folderOpen:"icon-folder-open-alt"}},treeInit:function(a){var b=a.tree;this._superApply(arguments),b.$container.addClass("fancytree-ext-glyph")},nodeRenderStatus:function(c){var d,e,f=c.node,g=a(f.span),h=c.options.glyph,i=h.map;this._superApply(arguments),f.isRoot()||(e=g.children("span.fancytree-expander").get(0),e&&(d=f.isLoading()?"loading":f.expanded?"expanderOpen":f.isUndefined()?"expanderLazy":f.hasChildren()?"expanderClosed":"noExpander",e.className="fancytree-expander "+i[d]),e=f.tr?a("td",f.tr).find("span.fancytree-checkbox").get(0):g.children("span.fancytree-checkbox").get(0),e&&(d=f.selected?"checkboxSelected":f.partsel?"checkboxUnknown":"checkbox",e.className="fancytree-checkbox "+i[d]),e=g.children("span.fancytree-icon").get(0),e&&(d=f.folder?f.expanded?b(h,"folderOpen"):b(h,"folder"):f.expanded?b(h,"docOpen"):b(h,"doc"),e.className="fancytree-icon "+d))},nodeSetStatus:function(c,d){var e,f=c.options.glyph,g=c.node;this._superApply(arguments),e=g.parent?a("span.fancytree-expander",g.span).get(0):a(".fancytree-statusnode-wait, .fancytree-statusnode-error",g[this.nodeContainerAttrName]).find("span.fancytree-expander").get(0),"loading"===d?e.className="fancytree-expander "+b(f,"loading"):"error"===d&&(e.className="fancytree-expander "+b(f,"error"))}})}(jQuery,window,document); + +/*! Extension 'jquery.fancytree.gridnav.min.js' */ +!function(a){"use strict";function b(b,c){var d,e=c.get(0),f=0;return b.children().each(function(){return this===e?!1:(d=a(this).prop("colspan"),void(f+=d?d:1))}),f}function c(b,c){var d,e=null,f=0;return b.children().each(function(){return f>=c?(e=a(this),!1):(d=a(this).prop("colspan"),void(f+=d?d:1))}),e}function d(a,d){var f,g,h=a.closest("td"),i=null;switch(d){case e.LEFT:i=h.prev();break;case e.RIGHT:i=h.next();break;case e.UP:case e.DOWN:for(f=h.parent(),g=b(f,h);;){if(f=d===e.UP?f.prev():f.next(),!f.length)break;if(!f.is(":hidden")&&(i=c(f,g),i&&i.find(":input").length))break}}return i}var e=a.ui.keyCode,f={text:[e.UP,e.DOWN],checkbox:[e.UP,e.DOWN,e.LEFT,e.RIGHT],radiobutton:[e.UP,e.DOWN,e.LEFT,e.RIGHT],"select-one":[e.LEFT,e.RIGHT],"select-multiple":[e.LEFT,e.RIGHT]};a.ui.fancytree.registerExtension({name:"gridnav",version:"0.0.1",options:{autofocusInput:!1,handleCursorKeys:!0},treeInit:function(b){this._requireExtension("table",!0,!0),this._superApply(arguments),this.$container.addClass("fancytree-ext-gridnav"),this.$container.on("focusin",function(c){var d,e=a.ui.fancytree.getNode(c.target);e&&!e.isActive()&&(d=b.tree._makeHookContext(e,c),b.tree._callHook("nodeSetActive",d,!0))})},nodeSetActive:function(b,c){var d,e=b.options.gridnav,f=b.node,g=b.originalEvent||{},h=a(g.target).is(":input");c=c!==!1,this._superApply(arguments),c&&(b.options.titlesTabbable?(h||(a(f.span).find("span.fancytree-title").focus(),f.setFocus()),b.tree.$container.attr("tabindex","-1")):e.autofocusInput&&!h&&(d=a(f.tr||f.span),d.find(":input:enabled:first").focus()))},nodeKeydown:function(b){var c,e,g,h=b.options.gridnav,i=b.originalEvent,j=a(i.target);return c=j.is(":input:enabled")?j.prop("type"):null,c&&h.handleCursorKeys?(e=f[c],e&&a.inArray(i.which,e)>=0&&(g=d(j,i.which),g&&g.length)?(g.find(":input:enabled").focus(),!1):!0):this._superApply(arguments)}})}(jQuery,window,document); + +/*! Extension 'jquery.fancytree.persist.min.js' */ +!function(a,b,c,d){"use strict";function e(b,c,d,f,g){var h,i,j,l,m=!1,n=[],o=[];for(d=d||[],g=g||a.Deferred(),h=0,j=d.length;j>h;h++)i=d[h],l=b.getNodeByKey(i),l?f&&l.isUndefined()?(m=!0,b.debug("_loadLazyNodes: "+l+" is lazy: loading..."),n.push("expand"===f?l.setExpanded():l.load())):(b.debug("_loadLazyNodes: "+l+" already loaded."),l.setExpanded()):(o.push(i),b.debug("_loadLazyNodes: "+l+" was not yet found."));return a.when.apply(a,n).always(function(){if(m&&o.length>0)e(b,c,o,f,g);else{if(o.length)for(b.warn("_loadLazyNodes: could not load those keys: ",o),h=0,j=o.length;j>h;h++)i=d[h],c._appendKey(k,d[h],!1);g.resolve()}}),g}var f,g,h,i=a.ui.fancytree.assert,j="active",k="expanded",l="focus",m="selected";"function"==typeof Cookies?(h=Cookies.set,f=Cookies.get,g=Cookies.remove):(h=f=a.cookie,g=a.removeCookie),a.ui.fancytree._FancytreeClass.prototype.clearCookies=function(a){var b=this.ext.persist,c=b.cookiePrefix;a=a||"active expanded focus selected",a.indexOf(j)>=0&&b._data(c+j,null),a.indexOf(k)>=0&&b._data(c+k,null),a.indexOf(l)>=0&&b._data(c+l,null),a.indexOf(m)>=0&&b._data(c+m,null)},a.ui.fancytree._FancytreeClass.prototype.getPersistData=function(){var a=this.ext.persist,b=a.cookiePrefix,c=a.cookieDelimiter,d={};return d[j]=a._data(b+j),d[k]=(a._data(b+k)||"").split(c),d[m]=(a._data(b+m)||"").split(c),d[l]=a._data(b+l),d},a.ui.fancytree.registerExtension({name:"persist",version:"0.3.0",options:{cookieDelimiter:"~",cookiePrefix:d,cookie:{raw:!1,expires:"",path:"",domain:"",secure:!1},expandLazy:!1,fireActivate:!0,overrideSource:!0,store:"auto",types:"active expanded focus selected"},_data:function(a,b){var c=this._local.localStorage;return b===d?c?c.getItem(a):f(a):void(null===b?c?c.removeItem(a):g(a):c?c.setItem(a,b):h(a,b,this.options.persist.cookie))},_appendKey:function(b,c,d){c=""+c;var e=this._local,f=this.options.persist,g=f.cookieDelimiter,h=e.cookiePrefix+b,i=e._data(h),j=i?i.split(g):[],k=a.inArray(c,j);k>=0&&j.splice(k,1),d&&j.push(c),e._data(h,j.join(g))},treeInit:function(c){var g=c.tree,h=c.options,n=this._local,o=this.options.persist;return i("auto"!==o.store&&"cookie"!==o.store||f,"Missing required plugin for 'persist' extension: js.cookie.js or jquery.cookie.js"),n.cookiePrefix=o.cookiePrefix||"fancytree-"+g._id+"-",n.storeActive=o.types.indexOf(j)>=0,n.storeExpanded=o.types.indexOf(k)>=0,n.storeSelected=o.types.indexOf(m)>=0,n.storeFocus=o.types.indexOf(l)>=0,n.localStorage="cookie"!==o.store&&b.localStorage?"local"===o.store?b.localStorage:b.sessionStorage:null,g.$div.bind("fancytreeinit",function(){var b,c,f,i,p,q=n._data(n.cookiePrefix+l),r=o.fireActivate===!1;b=n._data(n.cookiePrefix+k),i=b&&b.split(o.cookieDelimiter),c=n.storeExpanded?e(g,n,i,o.expandLazy?"expand":!1,null):(new a.Deferred).resolve(),c.done(function(){if(n.storeSelected){if(b=n._data(n.cookiePrefix+m))for(i=b.split(o.cookieDelimiter),f=0;f<i.length;f++)p=g.getNodeByKey(i[f]),p?(p.selected===d||o.overrideSource&&p.selected===!1)&&(p.selected=!0,p.renderStatus()):n._appendKey(m,i[f],!1);3===g.options.selectMode&&g.visit(function(a){return a.selected?(a.fixSelection3AfterClick(),"skip"):void 0})}n.storeActive&&(b=n._data(n.cookiePrefix+j),!b||!h.persist.overrideSource&&g.activeNode||(p=g.getNodeByKey(b),p&&(p.debug("persist: set active",b),p.setActive(!0,{noFocus:!0,noEvents:r})))),n.storeFocus&&q&&(p=g.getNodeByKey(q),p&&(g.options.titlesTabbable?a(p.span).find(".fancytree-title").focus():a(g.$container).focus())),g._triggerTreeEvent("restore",null,{})})}),this._superApply(arguments)},nodeSetActive:function(a,b){var c,d=this._local;return b=b!==!1,c=this._superApply(arguments),d.storeActive&&d._data(d.cookiePrefix+j,this.activeNode?this.activeNode.key:null),c},nodeSetExpanded:function(a,b){var c,d=a.node,e=this._local;return b=b!==!1,c=this._superApply(arguments),e.storeExpanded&&e._appendKey(k,d.key,b),c},nodeSetFocus:function(a,b){var c,d=this._local;return b=b!==!1,c=this._superApply(arguments),d.storeFocus&&d._data(d.cookiePrefix+l,this.focusNode?this.focusNode.key:null),c},nodeSetSelected:function(b,c){var d,e,f=b.tree,g=b.node,h=this._local;return c=c!==!1,d=this._superApply(arguments),h.storeSelected&&(3===f.options.selectMode?(e=a.map(f.getSelectedNodes(!0),function(a){return a.key}),e=e.join(b.options.persist.cookieDelimiter),h._data(h.cookiePrefix+m,e)):h._appendKey(m,g.key,g.selected)),d}})}(jQuery,window,document); + +/*! Extension 'jquery.fancytree.table.min.js' */ +!function(a,b,c){"use strict";function d(b,c){c=c||"",b||a.error("Assertion failed "+c)}function e(a,b){a.parentNode.insertBefore(b,a.nextSibling)}function f(a,b){a.visit(function(a){var c=a.tr;return c&&(c.style.display=a.hide||!b?"none":""),a.expanded?void 0:"skip"})}function g(b){var c,e,f,g=b.parent,h=g?g.children:null;if(h&&h.length>1&&h[0]!==b)for(c=a.inArray(b,h),f=h[c-1],d(f.tr);f.children&&(e=f.children[f.children.length-1],e.tr);)f=e;else f=g;return f}a.ui.fancytree.registerExtension({name:"table",version:"0.2.1",options:{checkboxColumnIdx:null,customStatus:!1,indentation:16,nodeColumnIdx:0},treeInit:function(b){var d,e,f,g=b.tree,h=g.widget.element;for(h.addClass("fancytree-container fancytree-ext-table"),g.tbody=h.find("> tbody")[0],g.columnCount=a("thead >tr >th",h).length,a(g.tbody).empty(),g.rowFragment=c.createDocumentFragment(),e=a("<tr />"),f="",b.options.aria&&(e.attr("role","row"),f=" role='gridcell'"),d=0;d<g.columnCount;d++)e.append(b.options.table.nodeColumnIdx===d?"<td"+f+"><span class='fancytree-node' /></td>":"<td"+f+" />");g.rowFragment.appendChild(e.get(0)),g.statusClassPropName="tr",g.ariaPropName="tr",this.nodeContainerAttrName="tr",g.$container=h,this._superApply(arguments),a(g.rootNode.ul).remove(),g.rootNode.ul=null,this.$container.attr("tabindex",this.options.tabbable?"0":"-1"),this.options.aria&&g.$container.attr("role","treegrid").attr("aria-readonly",!0)},nodeRemoveChildMarkup:function(b){var c=b.node;c.visit(function(b){b.tr&&(a(b.tr).remove(),b.tr=null)})},nodeRemoveMarkup:function(b){var c=b.node;c.tr&&(a(c.tr).remove(),c.tr=null),this.nodeRemoveChildMarkup(b)},nodeRender:function(b,c,h,i,j){var k,l,m,n,o,p,q,r,s=b.tree,t=b.node,u=b.options,v=!t.parent;if(j||(b.hasCollapsedParents=t.parent&&!t.parent.expanded),!v)if(t.tr)c?this.nodeRenderTitle(b):this.nodeRenderStatus(b);else{if(b.hasCollapsedParents&&!h)return void t.debug("nodeRender ignored due to unrendered parent");o=s.rowFragment.firstChild.cloneNode(!0),p=g(t),d(p),i===!0&&j?o.style.display="none":h&&b.hasCollapsedParents&&(o.style.display="none"),p.tr?e(p.tr,o):(d(!p.parent,"prev. row must have a tr, or is system root"),s.tbody.appendChild(o)),t.tr=o,t.key&&u.generateIds&&(t.tr.id=u.idPrefix+t.key),t.tr.ftnode=t,u.aria&&a(t.tr).attr("aria-labelledby","ftal_"+t.key),t.span=a("span.fancytree-node",t.tr).get(0),this.nodeRenderTitle(b),u.createNode&&u.createNode.call(s,{type:"createNode"},b)}if(u.renderNode&&u.renderNode.call(s,{type:"renderNode"},b),k=t.children,k&&(v||h||t.expanded))for(m=0,n=k.length;n>m;m++)r=a.extend({},b,{node:k[m]}),r.hasCollapsedParents=r.hasCollapsedParents||!t.expanded,this.nodeRender(r,c,h,i,!0);k&&!j&&(q=t.tr||null,l=s.tbody.firstChild,t.visit(function(a){if(a.tr){if(a.parent.expanded||"none"===a.tr.style.display||(a.tr.style.display="none",f(a,!1)),a.tr.previousSibling!==q){t.debug("_fixOrder: mismatch at node: "+a);var b=q?q.nextSibling:l;s.tbody.insertBefore(a.tr,b)}q=a.tr}}))},nodeRenderTitle:function(b){var c,d=b.node,e=b.options;this._superApply(arguments),e.checkbox&&null!=e.table.checkboxColumnIdx&&(c=a("span.fancytree-checkbox",d.span).detach(),a(d.tr).find("td").eq(+e.table.checkboxColumnIdx).html(c)),d.isRoot()||this.nodeRenderStatus(b),!e.table.customStatus&&d.isStatusNode()||e.renderColumns&&e.renderColumns.call(b.tree,{type:"renderColumns"},b)},nodeRenderStatus:function(b){var c,d=b.node,e=b.options;this._superApply(arguments),a(d.tr).removeClass("fancytree-node"),c=(d.getLevel()-1)*e.table.indentation,a(d.span).css({paddingLeft:c+"px"})},nodeSetExpanded:function(b,c,d){function e(a){c=c!==!1,f(b.node,c),a?c&&b.options.autoScroll&&!d.noAnimation&&b.node.hasChildren()?b.node.getLastChild().scrollIntoView(!0,{topNode:b.node}).always(function(){d.noEvents||b.tree._triggerNodeEvent(c?"expand":"collapse",b),g.resolveWith(b.node)}):(d.noEvents||b.tree._triggerNodeEvent(c?"expand":"collapse",b),g.resolveWith(b.node)):(d.noEvents||b.tree._triggerNodeEvent(c?"expand":"collapse",b),g.rejectWith(b.node))}var g=new a.Deferred,h=a.extend({},d,{noEvents:!0,noAnimation:!0});return d=d||{},this._super(b,c,h).done(function(){e(!0)}).fail(function(){e(!1)}),g.promise()},nodeSetStatus:function(b,c){if("ok"===c){var d=b.node,e=d.children?d.children[0]:null;e&&e.isStatusNode()&&a(e.tr).remove()}return this._superApply(arguments)},treeClear:function(){return this.nodeRemoveChildMarkup(this._makeHookContext(this.rootNode)),this._superApply(arguments)},treeDestroy:function(){this.$container.find("tbody").empty(),this.$source&&this.$source.removeClass("ui-helper-hidden")}})}(jQuery,window,document); + +/*! Extension 'jquery.fancytree.themeroller.min.js' */ +!function(a){"use strict";a.ui.fancytree.registerExtension({name:"themeroller",version:"0.0.1",options:{activeClass:"ui-state-active",foccusClass:"ui-state-focus",hoverClass:"ui-state-hover",selectedClass:"ui-state-highlight"},treeInit:function(b){this._superApply(arguments);var c=b.widget.element;"TABLE"===c[0].nodeName?(c.addClass("ui-widget ui-corner-all"),c.find(">thead tr").addClass("ui-widget-header"),c.find(">tbody").addClass("ui-widget-conent")):c.addClass("ui-widget ui-widget-content ui-corner-all"),c.delegate(".fancytree-node","mouseenter mouseleave",function(b){var c=a.ui.fancytree.getNode(b.target),d="mouseenter"===b.type;c.debug("hover: "+d),a(c.tr?c.tr:c.span).toggleClass("ui-state-hover ui-corner-all",d)})},treeDestroy:function(a){this._superApply(arguments),a.widget.element.removeClass("ui-widget ui-widget-content ui-corner-all")},nodeRenderStatus:function(b){var c=b.node,d=a(c.tr?c.tr:c.span);this._superApply(arguments),d.toggleClass("ui-state-active",c.isActive()),d.toggleClass("ui-state-focus",c.hasFocus()),d.toggleClass("ui-state-highlight",c.isSelected())}})}(jQuery,window,document); + +/*! Extension 'jquery.fancytree.wide.min.js' */ +!function(a){"use strict";function b(b,c){b="fancytree-style-"+b;var d=a("#"+b);if(!c)return d.remove(),null;d.length||(d=a("<style />").attr("id",b).addClass("fancytree-style").prop("type","text/css").appendTo("head"));try{d.html(c)}catch(e){d[0].styleSheet.cssText=c}return d}function c(a,b,c,d,e){var f,g="#"+a+" span.fancytree-level-",h=[];for(f=0;b>f;f++)h.push(g+(f+1)+" span.fancytree-title { padding-left: "+(f*c+d)+e+"; }");return h.push("#"+a+" div.ui-effects-wrapper ul li span.fancytree-title { padding-left: 3px; position: static; width: auto; }"),h.join("\n")}var d=/^([+-]?(?:\d+|\d*\.\d+))([a-z]*|%)$/;a.ui.fancytree.registerExtension({name:"wide",version:"0.0.3",options:{iconWidth:null,iconSpacing:null,levelOfs:null},treeCreate:function(e){this._superApply(arguments),this.$container.addClass("fancytree-ext-wide");var f,g,h,i,j,k=e.options.wide,l=a("<li id='fancytreeTemp'><span class='fancytree-node'><span class='fancytree-icon' /><span class='fancytree-title' /></span><ul />").appendTo(e.tree.$container),m=l.find(".fancytree-icon"),n=l.find("ul"),o=k.iconSpacing||m.css("margin-left"),p=k.iconWidth||m.css("width"),q=k.levelOfs||n.css("padding-left");l.remove(),h=o.match(d)[2],o=parseFloat(o,10),i=p.match(d)[2],p=parseFloat(p,10),j=q.match(d)[2],(h!==i||j!==i)&&a.error("iconWidth, iconSpacing, and levelOfs must have the same css measure unit"),this._local.measureUnit=i,this._local.levelOfs=parseFloat(q),this._local.lineOfs=(1+(e.options.checkbox?1:0)+(e.options.icons?1:0))*(p+o)+o,this._local.maxDepth=10,f=this.$container.uniqueId().attr("id"),g=c(f,this._local.maxDepth,this._local.levelOfs,this._local.lineOfs,this._local.measureUnit),b(f,g)},treeDestroy:function(){return b(this.$container.attr("id"),null),this._superApply(arguments)},nodeRenderStatus:function(d){var e,f,g,h=d.node,i=h.getLevel();return g=this._superApply(arguments),i>this._local.maxDepth&&(e=this.$container.attr("id"),this._local.maxDepth*=2,h.debug("Define global ext-wide css up to level "+this._local.maxDepth),f=c(e,this._local.maxDepth,this._local.levelOfs,this._local.lineOfs,this._local.measureUnit),b(e,f)),a(h.span).addClass("fancytree-level-"+i),g}})}(jQuery,window,document); +})); diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/jquery.fancytree.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/jquery.fancytree.js new file mode 100644 index 00000000000..95de0d3735c --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/jquery.fancytree.js @@ -0,0 +1,4515 @@ +/*! + * jquery.fancytree.js + * Tree view control with support for lazy loading and much more. + * https://github.com/mar10/fancytree/ + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +/** Core Fancytree module. + */ + + +// Start of local namespace +;(function($, window, document, undefined) { +"use strict"; + +// prevent duplicate loading +if ( $.ui && $.ui.fancytree ) { + $.ui.fancytree.warn("Fancytree: ignored duplicate include"); + return; +} + + +/* ***************************************************************************** + * Private functions and variables + */ + +function _assert(cond, msg){ + // TODO: see qunit.js extractStacktrace() + if(!cond){ + msg = msg ? ": " + msg : ""; + // consoleApply("assert", [!!cond, msg]); + $.error("Fancytree assertion failed" + msg); + } +} + +_assert($.ui, "Fancytree requires jQuery UI (http://jqueryui.com)"); + +function consoleApply(method, args){ + var i, s, + fn = window.console ? window.console[method] : null; + + if(fn){ + try{ + fn.apply(window.console, args); + } catch(e) { + // IE 8? + s = ""; + for( i=0; i<args.length; i++){ + s += args[i]; + } + fn(s); + } + } +} + +/*Return true if x is a FancytreeNode.*/ +function _isNode(x){ + return !!(x.tree && x.statusNodeType !== undefined); +} + +/** Return true if dotted version string is equal or higher than requested version. + * + * See http://jsfiddle.net/mar10/FjSAN/ + */ +function isVersionAtLeast(dottedVersion, major, minor, patch){ + var i, v, t, + verParts = $.map($.trim(dottedVersion).split("."), function(e){ return parseInt(e, 10); }), + testParts = $.map(Array.prototype.slice.call(arguments, 1), function(e){ return parseInt(e, 10); }); + + for( i = 0; i < testParts.length; i++ ){ + v = verParts[i] || 0; + t = testParts[i] || 0; + if( v !== t ){ + return ( v > t ); + } + } + return true; +} + +/** Return a wrapper that calls sub.methodName() and exposes + * this : tree + * this._local : tree.ext.EXTNAME + * this._super : base.methodName() + */ +function _makeVirtualFunction(methodName, tree, base, extension, extName){ + // $.ui.fancytree.debug("_makeVirtualFunction", methodName, tree, base, extension, extName); + // if(rexTestSuper && !rexTestSuper.test(func)){ + // // extension.methodName() doesn't call _super(), so no wrapper required + // return func; + // } + // Use an immediate function as closure + var proxy = (function(){ + var prevFunc = tree[methodName], // org. tree method or prev. proxy + baseFunc = extension[methodName], // + _local = tree.ext[extName], + _super = function(){ + return prevFunc.apply(tree, arguments); + }, + _superApply = function(args){ + return prevFunc.apply(tree, args); + }; + + // Return the wrapper function + return function(){ + var prevLocal = tree._local, + prevSuper = tree._super, + prevSuperApply = tree._superApply; + + try{ + tree._local = _local; + tree._super = _super; + tree._superApply = _superApply; + return baseFunc.apply(tree, arguments); + }finally{ + tree._local = prevLocal; + tree._super = prevSuper; + tree._superApply = prevSuperApply; + } + }; + })(); // end of Immediate Function + return proxy; +} + +/** + * Subclass `base` by creating proxy functions + */ +function _subclassObject(tree, base, extension, extName){ + // $.ui.fancytree.debug("_subclassObject", tree, base, extension, extName); + for(var attrName in extension){ + if(typeof extension[attrName] === "function"){ + if(typeof tree[attrName] === "function"){ + // override existing method + tree[attrName] = _makeVirtualFunction(attrName, tree, base, extension, extName); + }else if(attrName.charAt(0) === "_"){ + // Create private methods in tree.ext.EXTENSION namespace + tree.ext[extName][attrName] = _makeVirtualFunction(attrName, tree, base, extension, extName); + }else{ + $.error("Could not override tree." + attrName + ". Use prefix '_' to create tree." + extName + "._" + attrName); + } + }else{ + // Create member variables in tree.ext.EXTENSION namespace + if(attrName !== "options"){ + tree.ext[extName][attrName] = extension[attrName]; + } + } + } +} + + +function _getResolvedPromise(context, argArray){ + if(context === undefined){ + return $.Deferred(function(){this.resolve();}).promise(); + }else{ + return $.Deferred(function(){this.resolveWith(context, argArray);}).promise(); + } +} + + +function _getRejectedPromise(context, argArray){ + if(context === undefined){ + return $.Deferred(function(){this.reject();}).promise(); + }else{ + return $.Deferred(function(){this.rejectWith(context, argArray);}).promise(); + } +} + + +function _makeResolveFunc(deferred, context){ + return function(){ + deferred.resolveWith(context); + }; +} + + +function _getElementDataAsDict($el){ + // Evaluate 'data-NAME' attributes with special treatment for 'data-json'. + var d = $.extend({}, $el.data()), + json = d.json; + + delete d.fancytree; // added to container by widget factory (old jQuery UI) + delete d.uiFancytree; // added to container by widget factory + + if( json ) { + delete d.json; + // <li data-json='...'> is already returned as object (http://api.jquery.com/data/#data-html5) + d = $.extend(d, json); + } + return d; +} + + +// TODO: use currying +function _makeNodeTitleMatcher(s){ + s = s.toLowerCase(); + return function(node){ + return node.title.toLowerCase().indexOf(s) >= 0; + }; +} + + +function _makeNodeTitleStartMatcher(s){ + var reMatch = new RegExp("^" + s, "i"); + return function(node){ + return reMatch.test(node.title); + }; +} + +var i, attr, + FT = null, // initialized below + ENTITY_MAP = {"&": "&", "<": "<", ">": ">", "\"": """, "'": "'", "/": "/"}, + IGNORE_KEYCODES = { 16: true, 17: true, 18: true }, + SPECIAL_KEYCODES = { + 8: "backspace", 9: "tab", 10: "return", 13: "return", + // 16: null, 17: null, 18: null, // ignore shift, ctrl, alt + 19: "pause", 20: "capslock", 27: "esc", 32: "space", 33: "pageup", + 34: "pagedown", 35: "end", 36: "home", 37: "left", 38: "up", + 39: "right", 40: "down", 45: "insert", 46: "del", 59: ";", 61: "=", + 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", + 103: "7", 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", + 111: "/", 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: "scroll", 173: "-", 186: ";", 187: "=", + 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", + 221: "]", 222: "'"}, + MOUSE_BUTTONS = { 0: "", 1: "left", 2: "middle", 3: "right" }, + //boolean attributes that can be set with equivalent class names in the LI tags + CLASS_ATTRS = "active expanded focus folder hideCheckbox lazy selected unselectable".split(" "), + CLASS_ATTR_MAP = {}, + // Top-level Fancytree node attributes, that can be set by dict + NODE_ATTRS = "expanded extraClasses folder hideCheckbox key lazy refKey selected title tooltip unselectable".split(" "), + NODE_ATTR_MAP = {}, + // Mapping of lowercase -> real name (because HTML5 data-... attribute only supports lowercase) + NODE_ATTR_LOWERCASE_MAP = {}, + // Attribute names that should NOT be added to node.data + NONE_NODE_DATA_MAP = {"active": true, "children": true, "data": true, "focus": true}; + +for(i=0; i<CLASS_ATTRS.length; i++){ CLASS_ATTR_MAP[CLASS_ATTRS[i]] = true; } +for(i=0; i<NODE_ATTRS.length; i++) { + attr = NODE_ATTRS[i]; + NODE_ATTR_MAP[attr] = true; + if( attr !== attr.toLowerCase() ) { + NODE_ATTR_LOWERCASE_MAP[attr.toLowerCase()] = attr; + } +} + + +/* ***************************************************************************** + * FancytreeNode + */ + + +/** + * Creates a new FancytreeNode + * + * @class FancytreeNode + * @classdesc A FancytreeNode represents the hierarchical data model and operations. + * + * @param {FancytreeNode} parent + * @param {NodeData} obj + * + * @property {Fancytree} tree The tree instance + * @property {FancytreeNode} parent The parent node + * @property {string} key Node id (must be unique inside the tree) + * @property {string} title Display name (may contain HTML) + * @property {object} data Contains all extra data that was passed on node creation + * @property {FancytreeNode[] | null | undefined} children Array of child nodes.<br> + * For lazy nodes, null or undefined means 'not yet loaded'. Use an empty array + * to define a node that has no children. + * @property {boolean} expanded Use isExpanded(), setExpanded() to access this property. + * @property {string} extraClasses Addtional CSS classes, added to the node's `<span>` + * @property {boolean} folder Folder nodes have different default icons and click behavior.<br> + * Note: Also non-folders may have children. + * @property {string} statusNodeType null or type of temporarily generated system node like 'loading', or 'error'. + * @property {boolean} lazy True if this node is loaded on demand, i.e. on first expansion. + * @property {boolean} selected Use isSelected(), setSelected() to access this property. + * @property {string} tooltip Alternative description used as hover banner + */ +function FancytreeNode(parent, obj){ + var i, l, name, cl; + + this.parent = parent; + this.tree = parent.tree; + this.ul = null; + this.li = null; // <li id='key' ftnode=this> tag + this.statusNodeType = null; // if this is a temp. node to display the status of its parent + this._isLoading = false; // if this node itself is loading + this._error = null; // {message: '...'} if a load error occurred + this.data = {}; + + // TODO: merge this code with node.toDict() + // copy attributes from obj object + for(i=0, l=NODE_ATTRS.length; i<l; i++){ + name = NODE_ATTRS[i]; + this[name] = obj[name]; + } + // node.data += obj.data + if(obj.data){ + $.extend(this.data, obj.data); + } + // copy all other attributes to this.data.NAME + for(name in obj){ + if(!NODE_ATTR_MAP[name] && !$.isFunction(obj[name]) && !NONE_NODE_DATA_MAP[name]){ + // node.data.NAME = obj.NAME + this.data[name] = obj[name]; + } + } + + // Fix missing key + if( this.key == null ){ // test for null OR undefined + if( this.tree.options.defaultKey ) { + this.key = this.tree.options.defaultKey(this); + _assert(this.key, "defaultKey() must return a unique key"); + } else { + this.key = "_" + (FT._nextNodeKey++); + } + } else { + this.key = "" + this.key; // Convert to string (#217) + } + + // Fix tree.activeNode + // TODO: not elegant: we use obj.active as marker to set tree.activeNode + // when loading from a dictionary. + if(obj.active){ + _assert(this.tree.activeNode === null, "only one active node allowed"); + this.tree.activeNode = this; + } + if( obj.selected ){ // #186 + this.tree.lastSelectedNode = this; + } + // TODO: handle obj.focus = true + // Create child nodes + cl = obj.children; + if( cl ){ + if( cl.length ){ + this._setChildren(cl); + } else { + // if an empty array was passed for a lazy node, keep it, in order to mark it 'loaded' + this.children = this.lazy ? [] : null; + } + } else { + this.children = null; + } + // Add to key/ref map (except for root node) +// if( parent ) { + this.tree._callHook("treeRegisterNode", this.tree, true, this); +// } +} + + +FancytreeNode.prototype = /** @lends FancytreeNode# */{ + /* Return the direct child FancytreeNode with a given key, index. */ + _findDirectChild: function(ptr){ + var i, l, + cl = this.children; + + if(cl){ + if(typeof ptr === "string"){ + for(i=0, l=cl.length; i<l; i++){ + if(cl[i].key === ptr){ + return cl[i]; + } + } + }else if(typeof ptr === "number"){ + return this.children[ptr]; + }else if(ptr.parent === this){ + return ptr; + } + } + return null; + }, + // TODO: activate() + // TODO: activateSilently() + /* Internal helper called in recursive addChildren sequence.*/ + _setChildren: function(children){ + _assert(children && (!this.children || this.children.length === 0), "only init supported"); + this.children = []; + for(var i=0, l=children.length; i<l; i++){ + this.children.push(new FancytreeNode(this, children[i])); + } + }, + /** + * Append (or insert) a list of child nodes. + * + * @param {NodeData[]} children array of child node definitions (also single child accepted) + * @param {FancytreeNode | string | Integer} [insertBefore] child node (or key or index of such). + * If omitted, the new children are appended. + * @returns {FancytreeNode} first child added + * + * @see FancytreeNode#applyPatch + */ + addChildren: function(children, insertBefore){ + var i, l, pos, + firstNode = null, + nodeList = []; + + if($.isPlainObject(children) ){ + children = [children]; + } + if(!this.children){ + this.children = []; + } + for(i=0, l=children.length; i<l; i++){ + nodeList.push(new FancytreeNode(this, children[i])); + } + firstNode = nodeList[0]; + if(insertBefore == null){ + this.children = this.children.concat(nodeList); + }else{ + insertBefore = this._findDirectChild(insertBefore); + pos = $.inArray(insertBefore, this.children); + _assert(pos >= 0, "insertBefore must be an existing child"); + // insert nodeList after children[pos] + this.children.splice.apply(this.children, [pos, 0].concat(nodeList)); + } + if( !this.parent || this.parent.ul || this.tr ){ + // render if the parent was rendered (or this is a root node) + this.render(); + } + if( this.tree.options.selectMode === 3 ){ + this.fixSelection3FromEndNodes(); + } + return firstNode; + }, + /** + * Append or prepend a node, or append a child node. + * + * This a convenience function that calls addChildren() + * + * @param {NodeData} node node definition + * @param {string} [mode=child] 'before', 'after', 'firstChild', or 'child' ('over' is a synonym for 'child') + * @returns {FancytreeNode} new node + */ + addNode: function(node, mode){ + if(mode === undefined || mode === "over"){ + mode = "child"; + } + switch(mode){ + case "after": + return this.getParent().addChildren(node, this.getNextSibling()); + case "before": + return this.getParent().addChildren(node, this); + case "firstChild": + // Insert before the first child if any + var insertBefore = (this.children ? this.children[0] : null); + return this.addChildren(node, insertBefore); + case "child": + case "over": + return this.addChildren(node); + } + _assert(false, "Invalid mode: " + mode); + }, + /** + * Append new node after this. + * + * This a convenience function that calls addNode(node, 'after') + * + * @param {NodeData} node node definition + * @returns {FancytreeNode} new node + */ + appendSibling: function(node){ + return this.addNode(node, "after"); + }, + /** + * Modify existing child nodes. + * + * @param {NodePatch} patch + * @returns {$.Promise} + * @see FancytreeNode#addChildren + */ + applyPatch: function(patch) { + // patch [key, null] means 'remove' + if(patch === null){ + this.remove(); + return _getResolvedPromise(this); + } + // TODO: make sure that root node is not collapsed or modified + // copy (most) attributes to node.ATTR or node.data.ATTR + var name, promise, v, + IGNORE_MAP = { children: true, expanded: true, parent: true }; // TODO: should be global + + for(name in patch){ + v = patch[name]; + if( !IGNORE_MAP[name] && !$.isFunction(v)){ + if(NODE_ATTR_MAP[name]){ + this[name] = v; + }else{ + this.data[name] = v; + } + } + } + // Remove and/or create children + if(patch.hasOwnProperty("children")){ + this.removeChildren(); + if(patch.children){ // only if not null and not empty list + // TODO: addChildren instead? + this._setChildren(patch.children); + } + // TODO: how can we APPEND or INSERT child nodes? + } + if(this.isVisible()){ + this.renderTitle(); + this.renderStatus(); + } + // Expand collapse (final step, since this may be async) + if(patch.hasOwnProperty("expanded")){ + promise = this.setExpanded(patch.expanded); + }else{ + promise = _getResolvedPromise(this); + } + return promise; + }, + /** Collapse all sibling nodes. + * @returns {$.Promise} + */ + collapseSiblings: function() { + return this.tree._callHook("nodeCollapseSiblings", this); + }, + /** Copy this node as sibling or child of `node`. + * + * @param {FancytreeNode} node source node + * @param {string} [mode=child] 'before' | 'after' | 'child' + * @param {Function} [map] callback function(NodeData) that could modify the new node + * @returns {FancytreeNode} new + */ + copyTo: function(node, mode, map) { + return node.addNode(this.toDict(true, map), mode); + }, + /** Count direct and indirect children. + * + * @param {boolean} [deep=true] pass 'false' to only count direct children + * @returns {int} number of child nodes + */ + countChildren: function(deep) { + var cl = this.children, i, l, n; + if( !cl ){ + return 0; + } + n = cl.length; + if(deep !== false){ + for(i=0, l=n; i<l; i++){ + n += cl[i].countChildren(); + } + } + return n; + }, + // TODO: deactivate() + /** Write to browser console if debugLevel >= 2 (prepending node info) + * + * @param {*} msg string or object or array of such + */ + debug: function(msg){ + if( this.tree.options.debugLevel >= 2 ) { + Array.prototype.unshift.call(arguments, this.toString()); + consoleApply("log", arguments); + } + }, + /** Deprecated. + * @deprecated since 2014-02-16. Use resetLazy() instead. + */ + discard: function(){ + this.warn("FancytreeNode.discard() is deprecated since 2014-02-16. Use .resetLazy() instead."); + return this.resetLazy(); + }, + + // TODO: expand(flag) + + /**Find all nodes that match condition (excluding self). + * + * @param {string | function(node)} match title string to search for, or a + * callback function that returns `true` if a node is matched. + * @returns {FancytreeNode[]} array of nodes (may be empty) + */ + findAll: function(match) { + match = $.isFunction(match) ? match : _makeNodeTitleMatcher(match); + var res = []; + this.visit(function(n){ + if(match(n)){ + res.push(n); + } + }); + return res; + }, + /**Find first node that matches condition (excluding self). + * + * @param {string | function(node)} match title string to search for, or a + * callback function that returns `true` if a node is matched. + * @returns {FancytreeNode} matching node or null + * @see FancytreeNode#findAll + */ + findFirst: function(match) { + match = $.isFunction(match) ? match : _makeNodeTitleMatcher(match); + var res = null; + this.visit(function(n){ + if(match(n)){ + res = n; + return false; + } + }); + return res; + }, + /* Apply selection state (internal use only) */ + _changeSelectStatusAttrs: function (state) { + var changed = false; + + switch(state){ + case false: + changed = ( this.selected || this.partsel ); + this.selected = false; + this.partsel = false; + break; + case true: + changed = ( !this.selected || !this.partsel ); + this.selected = true; + this.partsel = true; + break; + case undefined: + changed = ( this.selected || !this.partsel ); + this.selected = false; + this.partsel = true; + break; + default: + _assert(false, "invalid state: " + state); + } + // this.debug("fixSelection3AfterLoad() _changeSelectStatusAttrs()", state, changed); + if( changed ){ + this.renderStatus(); + } + return changed; + }, + /** + * Fix selection status, after this node was (de)selected in multi-hier mode. + * This includes (de)selecting all children. + */ + fixSelection3AfterClick: function() { + var flag = this.isSelected(); + +// this.debug("fixSelection3AfterClick()"); + + this.visit(function(node){ + node._changeSelectStatusAttrs(flag); + }); + this.fixSelection3FromEndNodes(); + }, + /** + * Fix selection status for multi-hier mode. + * Only end-nodes are considered to update the descendants branch and parents. + * Should be called after this node has loaded new children or after + * children have been modified using the API. + */ + fixSelection3FromEndNodes: function() { +// this.debug("fixSelection3FromEndNodes()"); + _assert(this.tree.options.selectMode === 3, "expected selectMode 3"); + + // Visit all end nodes and adjust their parent's `selected` and `partsel` + // attributes. Return selection state true, false, or undefined. + function _walk(node){ + var i, l, child, s, state, allSelected,someSelected, + children = node.children; + + if( children && children.length ){ + // check all children recursively + allSelected = true; + someSelected = false; + + for( i=0, l=children.length; i<l; i++ ){ + child = children[i]; + // the selection state of a node is not relevant; we need the end-nodes + s = _walk(child); + if( s !== false ) { + someSelected = true; + } + if( s !== true ) { + allSelected = false; + } + } + state = allSelected ? true : (someSelected ? undefined : false); + }else{ + // This is an end-node: simply report the status +// state = ( node.unselectable ) ? undefined : !!node.selected; + state = !!node.selected; + } + node._changeSelectStatusAttrs(state); + return state; + } + _walk(this); + + // Update parent's state + this.visitParents(function(node){ + var i, l, child, state, + children = node.children, + allSelected = true, + someSelected = false; + + for( i=0, l=children.length; i<l; i++ ){ + child = children[i]; + // When fixing the parents, we trust the sibling status (i.e. + // we don't recurse) + if( child.selected || child.partsel ) { + someSelected = true; + } + if( !child.unselectable && !child.selected ) { + allSelected = false; + } + } + state = allSelected ? true : (someSelected ? undefined : false); + node._changeSelectStatusAttrs(state); + }); + }, + // TODO: focus() + /** + * Update node data. If dict contains 'children', then also replace + * the hole sub tree. + * @param {NodeData} dict + * + * @see FancytreeNode#addChildren + * @see FancytreeNode#applyPatch + */ + fromDict: function(dict) { + // copy all other attributes to this.data.xxx + for(var name in dict){ + if(NODE_ATTR_MAP[name]){ + // node.NAME = dict.NAME + this[name] = dict[name]; + }else if(name === "data"){ + // node.data += dict.data + $.extend(this.data, dict.data); + }else if(!$.isFunction(dict[name]) && !NONE_NODE_DATA_MAP[name]){ + // node.data.NAME = dict.NAME + this.data[name] = dict[name]; + } + } + if(dict.children){ + // recursively set children and render + this.removeChildren(); + this.addChildren(dict.children); + } + this.renderTitle(); +/* + var children = dict.children; + if(children === undefined){ + this.data = $.extend(this.data, dict); + this.render(); + return; + } + dict = $.extend({}, dict); + dict.children = undefined; + this.data = $.extend(this.data, dict); + this.removeChildren(); + this.addChild(children); +*/ + }, + /** Return the list of child nodes (undefined for unexpanded lazy nodes). + * @returns {FancytreeNode[] | undefined} + */ + getChildren: function() { + if(this.hasChildren() === undefined){ // TODO: only required for lazy nodes? + return undefined; // Lazy node: unloaded, currently loading, or load error + } + return this.children; + }, + /** Return the first child node or null. + * @returns {FancytreeNode | null} + */ + getFirstChild: function() { + return this.children ? this.children[0] : null; + }, + /** Return the 0-based child index. + * @returns {int} + */ + getIndex: function() { +// return this.parent.children.indexOf(this); + return $.inArray(this, this.parent.children); // indexOf doesn't work in IE7 + }, + /** Return the hierarchical child index (1-based, e.g. '3.2.4'). + * @returns {string} + */ + getIndexHier: function(separator) { + separator = separator || "."; + var res = []; + $.each(this.getParentList(false, true), function(i, o){ + res.push(o.getIndex() + 1); + }); + return res.join(separator); + }, + /** Return the parent keys separated by options.keyPathSeparator, e.g. "id_1/id_17/id_32". + * @param {boolean} [excludeSelf=false] + * @returns {string} + */ + getKeyPath: function(excludeSelf) { + var path = [], + sep = this.tree.options.keyPathSeparator; + this.visitParents(function(n){ + if(n.parent){ + path.unshift(n.key); + } + }, !excludeSelf); + return sep + path.join(sep); + }, + /** Return the last child of this node or null. + * @returns {FancytreeNode | null} + */ + getLastChild: function() { + return this.children ? this.children[this.children.length - 1] : null; + }, + /** Return node depth. 0: System root node, 1: visible top-level node, 2: first sub-level, ... . + * @returns {int} + */ + getLevel: function() { + var level = 0, + dtn = this.parent; + while( dtn ) { + level++; + dtn = dtn.parent; + } + return level; + }, + /** Return the successor node (under the same parent) or null. + * @returns {FancytreeNode | null} + */ + getNextSibling: function() { + // TODO: use indexOf, if available: (not in IE6) + if( this.parent ){ + var i, l, + ac = this.parent.children; + + for(i=0, l=ac.length-1; i<l; i++){ // up to length-2, so next(last) = null + if( ac[i] === this ){ + return ac[i+1]; + } + } + } + return null; + }, + /** Return the parent node (null for the system root node). + * @returns {FancytreeNode | null} + */ + getParent: function() { + // TODO: return null for top-level nodes? + return this.parent; + }, + /** Return an array of all parent nodes (top-down). + * @param {boolean} [includeRoot=false] Include the invisible system root node. + * @param {boolean} [includeSelf=false] Include the node itself. + * @returns {FancytreeNode[]} + */ + getParentList: function(includeRoot, includeSelf) { + var l = [], + dtn = includeSelf ? this : this.parent; + while( dtn ) { + if( includeRoot || dtn.parent ){ + l.unshift(dtn); + } + dtn = dtn.parent; + } + return l; + }, + /** Return the predecessor node (under the same parent) or null. + * @returns {FancytreeNode | null} + */ + getPrevSibling: function() { + if( this.parent ){ + var i, l, + ac = this.parent.children; + + for(i=1, l=ac.length; i<l; i++){ // start with 1, so prev(first) = null + if( ac[i] === this ){ + return ac[i-1]; + } + } + } + return null; + }, + /** Return true if node has children. Return undefined if not sure, i.e. the node is lazy and not yet loaded). + * @returns {boolean | undefined} + */ + hasChildren: function() { + if(this.lazy){ + if(this.children == null ){ + // null or undefined: Not yet loaded + return undefined; + }else if(this.children.length === 0){ + // Loaded, but response was empty + return false; + }else if(this.children.length === 1 && this.children[0].isStatusNode() ){ + // Currently loading or load error + return undefined; + } + return true; + } + return !!( this.children && this.children.length ); + }, + /** Return true if node has keyboard focus. + * @returns {boolean} + */ + hasFocus: function() { + return (this.tree.hasFocus() && this.tree.focusNode === this); + }, + /** Write to browser console if debugLevel >= 1 (prepending node info) + * + * @param {*} msg string or object or array of such + */ + info: function(msg){ + if( this.tree.options.debugLevel >= 1 ) { + Array.prototype.unshift.call(arguments, this.toString()); + consoleApply("info", arguments); + } + }, + /** Return true if node is active (see also FancytreeNode#isSelected). + * @returns {boolean} + */ + isActive: function() { + return (this.tree.activeNode === this); + }, + /** Return true if node is a direct child of otherNode. + * @param {FancytreeNode} otherNode + * @returns {boolean} + */ + isChildOf: function(otherNode) { + return (this.parent && this.parent === otherNode); + }, + /** Return true, if node is a direct or indirect sub node of otherNode. + * @param {FancytreeNode} otherNode + * @returns {boolean} + */ + isDescendantOf: function(otherNode) { + if(!otherNode || otherNode.tree !== this.tree){ + return false; + } + var p = this.parent; + while( p ) { + if( p === otherNode ){ + return true; + } + p = p.parent; + } + return false; + }, + /** Return true if node is expanded. + * @returns {boolean} + */ + isExpanded: function() { + return !!this.expanded; + }, + /** Return true if node is the first node of its parent's children. + * @returns {boolean} + */ + isFirstSibling: function() { + var p = this.parent; + return !p || p.children[0] === this; + }, + /** Return true if node is a folder, i.e. has the node.folder attribute set. + * @returns {boolean} + */ + isFolder: function() { + return !!this.folder; + }, + /** Return true if node is the last node of its parent's children. + * @returns {boolean} + */ + isLastSibling: function() { + var p = this.parent; + return !p || p.children[p.children.length-1] === this; + }, + /** Return true if node is lazy (even if data was already loaded) + * @returns {boolean} + */ + isLazy: function() { + return !!this.lazy; + }, + /** Return true if node is lazy and loaded. For non-lazy nodes always return true. + * @returns {boolean} + */ + isLoaded: function() { + return !this.lazy || this.hasChildren() !== undefined; // Also checks if the only child is a status node + }, + /** Return true if children are currently beeing loaded, i.e. a Ajax request is pending. + * @returns {boolean} + */ + isLoading: function() { + return !!this._isLoading; + }, + /* + * @deprecated since v2.4.0: Use isRootNode() instead + */ + isRoot: function() { + return this.isRootNode(); + }, + /** Return true if this is the (invisible) system root node. + * @returns {boolean} + * @since 2.4 + */ + isRootNode: function() { + return (this.tree.rootNode === this); + }, + /** Return true if node is selected, i.e. has a checkmark set (see also FancytreeNode#isActive). + * @returns {boolean} + */ + isSelected: function() { + return !!this.selected; + }, + /** Return true if this node is a temporarily generated system node like + * 'loading', or 'error' (node.statusNodeType contains the type). + * @returns {boolean} + */ + isStatusNode: function() { + return !!this.statusNodeType; + }, + /** Return true if this a top level node, i.e. a direct child of the (invisible) system root node. + * @returns {boolean} + * @since 2.4 + */ + isTopLevel: function() { + return (this.tree.rootNode === this.parent); + }, + /** Return true if node is lazy and not yet loaded. For non-lazy nodes always return false. + * @returns {boolean} + */ + isUndefined: function() { + return this.hasChildren() === undefined; // also checks if the only child is a status node + }, + /** Return true if all parent nodes are expanded. Note: this does not check + * whether the node is scrolled into the visible part of the screen. + * @returns {boolean} + */ + isVisible: function() { + var i, l, + parents = this.getParentList(false, false); + + for(i=0, l=parents.length; i<l; i++){ + if( ! parents[i].expanded ){ return false; } + } + return true; + }, + /** Deprecated. + * @deprecated since 2014-02-16: use load() instead. + */ + lazyLoad: function(discard) { + this.warn("FancytreeNode.lazyLoad() is deprecated since 2014-02-16. Use .load() instead."); + return this.load(discard); + }, + /** + * Load all children of a lazy node if neccessary. The *expanded* state is maintained. + * @param {boolean} [forceReload=false] Pass true to discard any existing nodes before. + * @returns {$.Promise} + */ + load: function(forceReload) { + var res, source, + that = this; + + _assert( this.isLazy(), "load() requires a lazy node" ); + // _assert( forceReload || this.isUndefined(), "Pass forceReload=true to re-load a lazy node" ); + if( !forceReload && !this.isUndefined() ) { + return _getResolvedPromise(this); + } + if( this.isLoaded() ){ + this.resetLazy(); // also collapses + } + // This method is also called by setExpanded() and loadKeyPath(), so we + // have to avoid recursion. + source = this.tree._triggerNodeEvent("lazyLoad", this); + if( source === false ) { // #69 + return _getResolvedPromise(this); + } + _assert(typeof source !== "boolean", "lazyLoad event must return source in data.result"); + res = this.tree._callHook("nodeLoadChildren", this, source); + if( this.expanded ) { + res.always(function(){ + that.render(); + }); + } + return res; + }, + /** Expand all parents and optionally scroll into visible area as neccessary. + * Promise is resolved, when lazy loading and animations are done. + * @param {object} [opts] passed to `setExpanded()`. + * Defaults to {noAnimation: false, noEvents: false, scrollIntoView: true} + * @returns {$.Promise} + */ + makeVisible: function(opts) { + var i, + that = this, + deferreds = [], + dfd = new $.Deferred(), + parents = this.getParentList(false, false), + len = parents.length, + effects = !(opts && opts.noAnimation === true), + scroll = !(opts && opts.scrollIntoView === false); + + // Expand bottom-up, so only the top node is animated + for(i = len - 1; i >= 0; i--){ + // that.debug("pushexpand" + parents[i]); + deferreds.push(parents[i].setExpanded(true, opts)); + } + $.when.apply($, deferreds).done(function(){ + // All expands have finished + // that.debug("expand DONE", scroll); + if( scroll ){ + that.scrollIntoView(effects).done(function(){ + // that.debug("scroll DONE"); + dfd.resolve(); + }); + } else { + dfd.resolve(); + } + }); + return dfd.promise(); + }, + /** Move this node to targetNode. + * @param {FancytreeNode} targetNode + * @param {string} mode <pre> + * 'child': append this node as last child of targetNode. + * This is the default. To be compatble with the D'n'd + * hitMode, we also accept 'over'. + * 'before': add this node as sibling before targetNode. + * 'after': add this node as sibling after targetNode.</pre> + * @param {function} [map] optional callback(FancytreeNode) to allow modifcations + */ + moveTo: function(targetNode, mode, map) { + if(mode === undefined || mode === "over"){ + mode = "child"; + } + var pos, + prevParent = this.parent, + targetParent = (mode === "child") ? targetNode : targetNode.parent; + + if(this === targetNode){ + return; + }else if( !this.parent ){ + throw "Cannot move system root"; + }else if( targetParent.isDescendantOf(this) ){ + throw "Cannot move a node to its own descendant"; + } + // Unlink this node from current parent + if( this.parent.children.length === 1 ) { + if( this.parent === targetParent ){ + return; // #258 + } + this.parent.children = this.parent.lazy ? [] : null; + this.parent.expanded = false; + } else { + pos = $.inArray(this, this.parent.children); + _assert(pos >= 0, "invalid source parent"); + this.parent.children.splice(pos, 1); + } + // Remove from source DOM parent +// if(this.parent.ul){ +// this.parent.ul.removeChild(this.li); +// } + + // Insert this node to target parent's child list + this.parent = targetParent; + if( targetParent.hasChildren() ) { + switch(mode) { + case "child": + // Append to existing target children + targetParent.children.push(this); + break; + case "before": + // Insert this node before target node + pos = $.inArray(targetNode, targetParent.children); + _assert(pos >= 0, "invalid target parent"); + targetParent.children.splice(pos, 0, this); + break; + case "after": + // Insert this node after target node + pos = $.inArray(targetNode, targetParent.children); + _assert(pos >= 0, "invalid target parent"); + targetParent.children.splice(pos+1, 0, this); + break; + default: + throw "Invalid mode " + mode; + } + } else { + targetParent.children = [ this ]; + } + // Parent has no <ul> tag yet: +// if( !targetParent.ul ) { +// // This is the parent's first child: create UL tag +// // (Hidden, because it will be +// targetParent.ul = document.createElement("ul"); +// targetParent.ul.style.display = "none"; +// targetParent.li.appendChild(targetParent.ul); +// } +// // Issue 319: Add to target DOM parent (only if node was already rendered(expanded)) +// if(this.li){ +// targetParent.ul.appendChild(this.li); +// }^ + + // Let caller modify the nodes + if( map ){ + targetNode.visit(map, true); + } + // Handle cross-tree moves + if( this.tree !== targetNode.tree ) { + // Fix node.tree for all source nodes +// _assert(false, "Cross-tree move is not yet implemented."); + this.warn("Cross-tree moveTo is experimantal!"); + this.visit(function(n){ + // TODO: fix selection state and activation, ... + n.tree = targetNode.tree; + }, true); + } + + // A collaposed node won't re-render children, so we have to remove it manually + // if( !targetParent.expanded ){ + // prevParent.ul.removeChild(this.li); + // } + + // Update HTML markup + if( !prevParent.isDescendantOf(targetParent)) { + prevParent.render(); + } + if( !targetParent.isDescendantOf(prevParent) && targetParent !== prevParent) { + targetParent.render(); + } + // TODO: fix selection state + // TODO: fix active state + +/* + var tree = this.tree; + var opts = tree.options; + var pers = tree.persistence; + + + // Always expand, if it's below minExpandLevel +// tree.logDebug ("%s._addChildNode(%o), l=%o", this, ftnode, ftnode.getLevel()); + if ( opts.minExpandLevel >= ftnode.getLevel() ) { +// tree.logDebug ("Force expand for %o", ftnode); + this.bExpanded = true; + } + + // In multi-hier mode, update the parents selection state + // DT issue #82: only if not initializing, because the children may not exist yet +// if( !ftnode.data.isStatusNode() && opts.selectMode==3 && !isInitializing ) +// ftnode._fixSelectionState(); + + // In multi-hier mode, update the parents selection state + if( ftnode.bSelected && opts.selectMode==3 ) { + var p = this; + while( p ) { + if( !p.hasSubSel ) + p._setSubSel(true); + p = p.parent; + } + } + // render this node and the new child + if ( tree.bEnableUpdate ) + this.render(); + + return ftnode; + +*/ + }, + /** Set focus relative to this node and optionally activate. + * + * @param {number} where The keyCode that would normally trigger this move, + * e.g. `$.ui.keyCode.LEFT` would collapse the node if it + * is expanded or move to the parent oterwise. + * @param {boolean} [activate=true] + * @returns {$.Promise} + */ + // navigate: function(where, activate) { + // console.time("navigate") + // this._navigate(where, activate) + // console.timeEnd("navigate") + // }, + navigate: function(where, activate) { + var i, parents, + handled = true, + KC = $.ui.keyCode, + sib = null; + + // Navigate to node + function _goto(n){ + if( n ){ + try { n.makeVisible(); } catch(e) {} // #272 + // Node may still be hidden by a filter + if( ! $(n.span).is(":visible") ) { + n.debug("Navigate: skipping hidden node"); + n.navigate(where, activate); + return; + } + return activate === false ? n.setFocus() : n.setActive(); + } + } + + switch( where ) { + case KC.BACKSPACE: + if( this.parent && this.parent.parent ) { + _goto(this.parent); + } + break; + case KC.LEFT: + if( this.expanded ) { + this.setExpanded(false); + _goto(this); + } else if( this.parent && this.parent.parent ) { + _goto(this.parent); + } + break; + case KC.RIGHT: + if( !this.expanded && (this.children || this.lazy) ) { + this.setExpanded(); + _goto(this); + } else if( this.children && this.children.length ) { + _goto(this.children[0]); + } + break; + case KC.UP: + sib = this.getPrevSibling(); + // #359: skip hidden sibling nodes, preventing a _goto() recursion + while( sib && !$(sib.span).is(":visible") ) { + sib = sib.getPrevSibling(); + } + while( sib && sib.expanded && sib.children && sib.children.length ) { + sib = sib.children[sib.children.length - 1]; + } + if( !sib && this.parent && this.parent.parent ){ + sib = this.parent; + } + _goto(sib); + break; + case KC.DOWN: + if( this.expanded && this.children && this.children.length ) { + sib = this.children[0]; + } else { + parents = this.getParentList(false, true); + for(i=parents.length-1; i>=0; i--) { + sib = parents[i].getNextSibling(); + // #359: skip hidden sibling nodes, preventing a _goto() recursion + while( sib && !$(sib.span).is(":visible") ) { + sib = sib.getNextSibling(); + } + if( sib ){ break; } + } + } + _goto(sib); + break; + default: + handled = false; + } + }, + /** + * Remove this node (not allowed for system root). + */ + remove: function() { + return this.parent.removeChild(this); + }, + /** + * Remove childNode from list of direct children. + * @param {FancytreeNode} childNode + */ + removeChild: function(childNode) { + return this.tree._callHook("nodeRemoveChild", this, childNode); + }, + /** + * Remove all child nodes and descendents. This converts the node into a leaf.<br> + * If this was a lazy node, it is still considered 'loaded'; call node.resetLazy() + * in order to trigger lazyLoad on next expand. + */ + removeChildren: function() { + return this.tree._callHook("nodeRemoveChildren", this); + }, + /** + * This method renders and updates all HTML markup that is required + * to display this node in its current state.<br> + * Note: + * <ul> + * <li>It should only be neccessary to call this method after the node object + * was modified by direct access to its properties, because the common + * API methods (node.setTitle(), moveTo(), addChildren(), remove(), ...) + * already handle this. + * <li> {@link FancytreeNode#renderTitle} and {@link FancytreeNode#renderStatus} + * are implied. If changes are more local, calling only renderTitle() or + * renderStatus() may be sufficient and faster. + * <li>If a node was created/removed, node.render() must be called <i>on the parent</i>. + * </ul> + * + * @param {boolean} [force=false] re-render, even if html markup was already created + * @param {boolean} [deep=false] also render all descendants, even if parent is collapsed + */ + render: function(force, deep) { + return this.tree._callHook("nodeRender", this, force, deep); + }, + /** Create HTML markup for the node's outer <span> (expander, checkbox, icon, and title). + * Implies {@link FancytreeNode#renderStatus}. + * @see Fancytree_Hooks#nodeRenderTitle + */ + renderTitle: function() { + return this.tree._callHook("nodeRenderTitle", this); + }, + /** Update element's CSS classes according to node state. + * @see Fancytree_Hooks#nodeRenderStatus + */ + renderStatus: function() { + return this.tree._callHook("nodeRenderStatus", this); + }, + /** + * Remove all children, collapse, and set the lazy-flag, so that the lazyLoad + * event is triggered on next expand. + */ + resetLazy: function() { + this.removeChildren(); + this.expanded = false; + this.lazy = true; + this.children = undefined; + this.renderStatus(); + }, + /** Schedule activity for delayed execution (cancel any pending request). + * scheduleAction('cancel') will only cancel a pending request (if any). + * @param {string} mode + * @param {number} ms + */ + scheduleAction: function(mode, ms) { + if( this.tree.timer ) { + clearTimeout(this.tree.timer); +// this.tree.debug("clearTimeout(%o)", this.tree.timer); + } + this.tree.timer = null; + var self = this; // required for closures + switch (mode) { + case "cancel": + // Simply made sure that timer was cleared + break; + case "expand": + this.tree.timer = setTimeout(function(){ + self.tree.debug("setTimeout: trigger expand"); + self.setExpanded(true); + }, ms); + break; + case "activate": + this.tree.timer = setTimeout(function(){ + self.tree.debug("setTimeout: trigger activate"); + self.setActive(true); + }, ms); + break; + default: + throw "Invalid mode " + mode; + } +// this.tree.debug("setTimeout(%s, %s): %s", mode, ms, this.tree.timer); + }, + /** + * + * @param {boolean | PlainObject} [effects=false] animation options. + * @param {object} [options=null] {topNode: null, effects: ..., parent: ...} this node will remain visible in + * any case, even if `this` is outside the scroll pane. + * @returns {$.Promise} + */ + scrollIntoView: function(effects, options) { + if( options !== undefined && _isNode(options) ) { + this.warn("scrollIntoView() with 'topNode' option is deprecated since 2014-05-08. Use 'options.topNode' instead."); + options = {topNode: options}; + } + // this.$scrollParent = (this.options.scrollParent === "auto") ? $ul.scrollParent() : $(this.options.scrollParent); + // this.$scrollParent = this.$scrollParent.length ? this.$scrollParent || this.$container; + + var topNodeY, nodeY, horzScrollbarHeight, containerOffsetTop, + opts = $.extend({ + effects: (effects === true) ? {duration: 200, queue: false} : effects, + scrollOfs: this.tree.options.scrollOfs, + scrollParent: this.tree.options.scrollParent || this.tree.$container, + topNode: null + }, options), + dfd = new $.Deferred(), + that = this, + nodeHeight = $(this.span).height(), + $container = $(opts.scrollParent), + topOfs = opts.scrollOfs.top || 0, + bottomOfs = opts.scrollOfs.bottom || 0, + containerHeight = $container.height(),// - topOfs - bottomOfs, + scrollTop = $container.scrollTop(), + $animateTarget = $container, + isParentWindow = $container[0] === window, + topNode = opts.topNode || null, + newScrollTop = null; + + // this.debug("scrollIntoView(), scrollTop=", scrollTop, opts.scrollOfs); +// _assert($(this.span).is(":visible"), "scrollIntoView node is invisible"); // otherwise we cannot calc offsets + if( !$(this.span).is(":visible") ) { + // We cannot calc offsets for hidden elements + this.warn("scrollIntoView(): node is invisible."); + return _getResolvedPromise(); + } + if( isParentWindow ) { + nodeY = $(this.span).offset().top; + topNodeY = (topNode && topNode.span) ? $(topNode.span).offset().top : 0; + $animateTarget = $("html,body"); + + } else { + _assert($container[0] !== document && $container[0] !== document.body, "scrollParent should be an simple element or `window`, not document or body."); + + containerOffsetTop = $container.offset().top, + nodeY = $(this.span).offset().top - containerOffsetTop + scrollTop; // relative to scroll parent + topNodeY = topNode ? $(topNode.span).offset().top - containerOffsetTop + scrollTop : 0; + horzScrollbarHeight = Math.max(0, ($container.innerHeight() - $container[0].clientHeight)); + containerHeight -= horzScrollbarHeight; + } + + // this.debug(" scrollIntoView(), nodeY=", nodeY, "containerHeight=", containerHeight); + if( nodeY < (scrollTop + topOfs) ){ + // Node is above visible container area + newScrollTop = nodeY - topOfs; + // this.debug(" scrollIntoView(), UPPER newScrollTop=", newScrollTop); + + }else if((nodeY + nodeHeight) > (scrollTop + containerHeight - bottomOfs)){ + newScrollTop = nodeY + nodeHeight - containerHeight + bottomOfs; + // this.debug(" scrollIntoView(), LOWER newScrollTop=", newScrollTop); + // If a topNode was passed, make sure that it is never scrolled + // outside the upper border + if(topNode){ + _assert(topNode.isRootNode() || $(topNode.span).is(":visible"), "topNode must be visible"); + if( topNodeY < newScrollTop ){ + newScrollTop = topNodeY - topOfs; + // this.debug(" scrollIntoView(), TOP newScrollTop=", newScrollTop); + } + } + } + + if(newScrollTop !== null){ + // this.debug(" scrollIntoView(), SET newScrollTop=", newScrollTop); + if(opts.effects){ + opts.effects.complete = function(){ + dfd.resolveWith(that); + }; + $animateTarget.stop(true).animate({ + scrollTop: newScrollTop + }, opts.effects); + }else{ + $animateTarget[0].scrollTop = newScrollTop; + dfd.resolveWith(this); + } + }else{ + dfd.resolveWith(this); + } + return dfd.promise(); + }, + + /**Activate this node. + * @param {boolean} [flag=true] pass false to deactivate + * @param {object} [opts] additional options. Defaults to {noEvents: false} + * @returns {$.Promise} + */ + setActive: function(flag, opts){ + return this.tree._callHook("nodeSetActive", this, flag, opts); + }, + /**Expand or collapse this node. Promise is resolved, when lazy loading and animations are done. + * @param {boolean} [flag=true] pass false to collapse + * @param {object} [opts] additional options. Defaults to {noAnimation: false, noEvents: false} + * @returns {$.Promise} + */ + setExpanded: function(flag, opts){ + return this.tree._callHook("nodeSetExpanded", this, flag, opts); + }, + /**Set keyboard focus to this node. + * @param {boolean} [flag=true] pass false to blur + * @see Fancytree#setFocus + */ + setFocus: function(flag){ + return this.tree._callHook("nodeSetFocus", this, flag); + }, + /**Select this node, i.e. check the checkbox. + * @param {boolean} [flag=true] pass false to deselect + */ + setSelected: function(flag){ + return this.tree._callHook("nodeSetSelected", this, flag); + }, + /**Mark a lazy node as 'error', 'loading', or 'ok'. + * @param {string} status 'error', 'ok' + * @param {string} [message] + * @param {string} [details] + */ + setStatus: function(status, message, details){ + return this.tree._callHook("nodeSetStatus", this, status, message, details); + }, + /**Rename this node. + * @param {string} title + */ + setTitle: function(title){ + this.title = title; + this.renderTitle(); + }, + /**Sort child list by title. + * @param {function} [cmp] custom compare function(a, b) that returns -1, 0, or 1 (defaults to sort by title). + * @param {boolean} [deep=false] pass true to sort all descendant nodes + */ + sortChildren: function(cmp, deep) { + var i,l, + cl = this.children; + + if( !cl ){ + return; + } + cmp = cmp || function(a, b) { + var x = a.title.toLowerCase(), + y = b.title.toLowerCase(); + return x === y ? 0 : x > y ? 1 : -1; + }; + cl.sort(cmp); + if( deep ){ + for(i=0, l=cl.length; i<l; i++){ + if( cl[i].children ){ + cl[i].sortChildren(cmp, "$norender$"); + } + } + } + if( deep !== "$norender$" ){ + this.render(); + } + }, + /** Convert node (or whole branch) into a plain object. + * + * The result is compatible with node.addChildren(). + * + * @param {boolean} [recursive=false] include child nodes + * @param {function} [callback] callback(dict, node) is called for every node, in order to allow modifications + * @returns {NodeData} + */ + toDict: function(recursive, callback) { + var i, l, node, + dict = {}, + self = this; + + $.each(NODE_ATTRS, function(i, a){ + if(self[a] || self[a] === false){ + dict[a] = self[a]; + } + }); + if(!$.isEmptyObject(this.data)){ + dict.data = $.extend({}, this.data); + if($.isEmptyObject(dict.data)){ + delete dict.data; + } + } + if( callback ){ + callback(dict, self); + } + if( recursive ) { + if(this.hasChildren()){ + dict.children = []; + for(i=0, l=this.children.length; i<l; i++ ){ + node = this.children[i]; + if( !node.isStatusNode() ){ + dict.children.push(node.toDict(true, callback)); + } + } + }else{ +// dict.children = null; + } + } + return dict; + }, + /** Flip expanded status. */ + toggleExpanded: function(){ + return this.tree._callHook("nodeToggleExpanded", this); + }, + /** Flip selection status. */ + toggleSelected: function(){ + return this.tree._callHook("nodeToggleSelected", this); + }, + toString: function() { + return "<FancytreeNode(#" + this.key + ", '" + this.title + "')>"; + }, + /** Call fn(node) for all child nodes.<br> + * Stop iteration, if fn() returns false. Skip current branch, if fn() returns "skip".<br> + * Return false if iteration was stopped. + * + * @param {function} fn the callback function. + * Return false to stop iteration, return "skip" to skip this node and + * its children only. + * @param {boolean} [includeSelf=false] + * @returns {boolean} + */ + visit: function(fn, includeSelf) { + var i, l, + res = true, + children = this.children; + + if( includeSelf === true ) { + res = fn(this); + if( res === false || res === "skip" ){ + return res; + } + } + if(children){ + for(i=0, l=children.length; i<l; i++){ + res = children[i].visit(fn, true); + if( res === false ){ + break; + } + } + } + return res; + }, + /** Call fn(node) for all child nodes and recursively load lazy children.<br> + * <b>Note:</b> If you need this method, you probably should consider to review + * your architecture! Recursivley loading nodes is a perfect way for lazy + * programmers to flood the server with requests ;-) + * + * @param {function} [fn] optional callback function. + * Return false to stop iteration, return "skip" to skip this node and + * its children only. + * @param {boolean} [includeSelf=false] + * @returns {$.Promise} + * @since 2.4 + */ + visitAndLoad: function(fn, includeSelf, _recursion) { + var dfd, res, loaders, + node = this; + + // node.debug("visitAndLoad"); + if( fn && includeSelf === true ) { + res = fn(node); + if( res === false || res === "skip" ) { + return _recursion ? res : _getResolvedPromise(); + } + } + if( !node.children && !node.lazy ) { + return _getResolvedPromise(); + } + dfd = new $.Deferred(); + loaders = []; + // node.debug("load()..."); + node.load().done(function(){ + // node.debug("load()... done."); + for(var i=0, l=node.children.length; i<l; i++){ + res = node.children[i].visitAndLoad(fn, true, true); + if( res === false ) { + dfd.reject(); + break; + } else if ( res !== "skip" ) { + loaders.push(res); // Add promise to the list + } + } + $.when.apply(this, loaders).then(function(){ + dfd.resolve(); + }); + }); + return dfd.promise(); + }, + /** Call fn(node) for all parent nodes, bottom-up, including invisible system root.<br> + * Stop iteration, if fn() returns false.<br> + * Return false if iteration was stopped. + * + * @param {function} fn the callback function. + * Return false to stop iteration, return "skip" to skip this node and children only. + * @param {boolean} [includeSelf=false] + * @returns {boolean} + */ + visitParents: function(fn, includeSelf) { + // Visit parent nodes (bottom up) + if(includeSelf && fn(this) === false){ + return false; + } + var p = this.parent; + while( p ) { + if(fn(p) === false){ + return false; + } + p = p.parent; + } + return true; + }, + /** Write warning to browser console (prepending node info) + * + * @param {*} msg string or object or array of such + */ + warn: function(msg){ + Array.prototype.unshift.call(arguments, this.toString()); + consoleApply("warn", arguments); + } +}; + + +/* ***************************************************************************** + * Fancytree + */ +/** + * Construct a new tree object. + * + * @class Fancytree + * @classdesc The controller behind a fancytree. + * This class also contains 'hook methods': see {@link Fancytree_Hooks}. + * + * @param {Widget} widget + * + * @property {string} _id Automatically generated unique tree instance ID, e.g. "1". + * @property {string} _ns Automatically generated unique tree namespace, e.g. ".fancytree-1". + * @property {FancytreeNode} activeNode Currently active node or null. + * @property {string} ariaPropName Property name of FancytreeNode that contains the element which will receive the aria attributes. + * Typically "li", but "tr" for table extension. + * @property {jQueryObject} $container Outer <ul> element (or <table> element for ext-table). + * @property {jQueryObject} $div A jQuery object containing the element used to instantiate the tree widget (`widget.element`) + * @property {object} data Metadata, i.e. properties that may be passed to `source` in addition to a children array. + * @property {object} ext Hash of all active plugin instances. + * @property {FancytreeNode} focusNode Currently focused node or null. + * @property {FancytreeNode} lastSelectedNode Used to implement selectMode 1 (single select) + * @property {string} nodeContainerAttrName Property name of FancytreeNode that contains the outer element of single nodes. + * Typically "li", but "tr" for table extension. + * @property {FancytreeOptions} options Current options, i.e. default options + options passed to constructor. + * @property {FancytreeNode} rootNode Invisible system root node. + * @property {string} statusClassPropName Property name of FancytreeNode that contains the element which will receive the status classes. + * Typically "span", but "tr" for table extension. + * @property {object} widget Base widget instance. + */ +function Fancytree(widget) { + this.widget = widget; + this.$div = widget.element; + this.options = widget.options; + if( this.options ) { + if( $.isFunction(this.options.lazyload ) && !$.isFunction(this.options.lazyLoad) ) { + this.options.lazyLoad = function() { + FT.warn("The 'lazyload' event is deprecated since 2014-02-25. Use 'lazyLoad' (with uppercase L) instead."); + return widget.options.lazyload.apply(this, arguments); + }; + } + if( $.isFunction(this.options.loaderror) ) { + $.error("The 'loaderror' event was renamed since 2014-07-03. Use 'loadError' (with uppercase E) instead."); + } + if( this.options.fx !== undefined ) { + FT.warn("The 'fx' options was replaced by 'toggleEffect' since 2014-11-30."); + } + } + this.ext = {}; // Active extension instances + // allow to init tree.data.foo from <div data-foo=''> + this.data = _getElementDataAsDict(this.$div); + // TODO: use widget.uuid instead? + this._id = $.ui.fancytree._nextId++; + // TODO: use widget.eventNamespace instead? + this._ns = ".fancytree-" + this._id; // append for namespaced events + this.activeNode = null; + this.focusNode = null; + this._hasFocus = null; + this.lastSelectedNode = null; + this.systemFocusElement = null; + this.lastQuicksearchTerm = ""; + this.lastQuicksearchTime = 0; + + this.statusClassPropName = "span"; + this.ariaPropName = "li"; + this.nodeContainerAttrName = "li"; + + // Remove previous markup if any + this.$div.find(">ul.fancytree-container").remove(); + + // Create a node without parent. + var fakeParent = { tree: this }, + $ul; + this.rootNode = new FancytreeNode(fakeParent, { + title: "root", + key: "root_" + this._id, + children: null, + expanded: true + }); + this.rootNode.parent = null; + + // Create root markup + $ul = $("<ul>", { + "class": "ui-fancytree fancytree-container fancytree-plain" + }).appendTo(this.$div); + this.$container = $ul; + this.rootNode.ul = $ul[0]; + + if(this.options.debugLevel == null){ + this.options.debugLevel = FT.debugLevel; + } + // Add container to the TAB chain + // See http://www.w3.org/TR/wai-aria-practices/#focus_activedescendant + this.$container.attr("tabindex", this.options.tabbable ? "0" : "-1"); + if(this.options.aria){ + this.$container + .attr("role", "tree") + .attr("aria-multiselectable", true); + } +} + + +Fancytree.prototype = /** @lends Fancytree# */{ + /* Return a context object that can be re-used for _callHook(). + * @param {Fancytree | FancytreeNode | EventData} obj + * @param {Event} originalEvent + * @param {Object} extra + * @returns {EventData} + */ + _makeHookContext: function(obj, originalEvent, extra) { + var ctx, tree; + if(obj.node !== undefined){ + // obj is already a context object + if(originalEvent && obj.originalEvent !== originalEvent){ + $.error("invalid args"); + } + ctx = obj; + }else if(obj.tree){ + // obj is a FancytreeNode + tree = obj.tree; + ctx = { node: obj, tree: tree, widget: tree.widget, options: tree.widget.options, originalEvent: originalEvent }; + }else if(obj.widget){ + // obj is a Fancytree + ctx = { node: null, tree: obj, widget: obj.widget, options: obj.widget.options, originalEvent: originalEvent }; + }else{ + $.error("invalid args"); + } + if(extra){ + $.extend(ctx, extra); + } + return ctx; + }, + /* Trigger a hook function: funcName(ctx, [...]). + * + * @param {string} funcName + * @param {Fancytree|FancytreeNode|EventData} contextObject + * @param {any} [_extraArgs] optional additional arguments + * @returns {any} + */ + _callHook: function(funcName, contextObject, _extraArgs) { + var ctx = this._makeHookContext(contextObject), + fn = this[funcName], + args = Array.prototype.slice.call(arguments, 2); + if(!$.isFunction(fn)){ + $.error("_callHook('" + funcName + "') is not a function"); + } + args.unshift(ctx); +// this.debug("_hook", funcName, ctx.node && ctx.node.toString() || ctx.tree.toString(), args); + return fn.apply(this, args); + }, + /* Check if current extensions dependencies are met and throw an error if not. + * + * This method may be called inside the `treeInit` hook for custom extensions. + * + * @param {string} extension name of the required extension + * @param {boolean} [required=true] pass `false` if the extension is optional, but we want to check for order if it is present + * @param {boolean} [before] `true` if `name` must be included before this, `false` otherwise (use `null` if order doesn't matter) + * @param {string} [message] optional error message (defaults to a descriptve error message) + */ + _requireExtension: function(name, required, before, message) { + before = !!before; + var thisName = this._local.name, + extList = this.options.extensions, + isBefore = $.inArray(name, extList) < $.inArray(thisName, extList), + isMissing = required && this.ext[name] == null, + badOrder = !isMissing && before != null && (before !== isBefore); + + _assert(thisName && thisName !== name, "invalid or same name"); + + if( isMissing || badOrder ){ + if( !message ){ + if( isMissing || required ){ + message = "'" + thisName + "' extension requires '" + name + "'"; + if( badOrder ){ + message += " to be registered " + (before ? "before" : "after") + " itself"; + } + }else{ + message = "If used together, `" + name + "` must be registered " + (before ? "before" : "after") + " `" + thisName + "`"; + } + } + $.error(message); + return false; + } + return true; + }, + /** Activate node with a given key and fire focus and activate events. + * + * A prevously activated node will be deactivated. + * If activeVisible option is set, all parents will be expanded as necessary. + * Pass key = false, to deactivate the current node only. + * @param {string} key + * @returns {FancytreeNode} activated node (null, if not found) + */ + activateKey: function(key) { + var node = this.getNodeByKey(key); + if(node){ + node.setActive(); + }else if(this.activeNode){ + this.activeNode.setActive(false); + } + return node; + }, + /** (experimental) + * + * @param {Array} patchList array of [key, NodePatch] arrays + * @returns {$.Promise} resolved, when all patches have been applied + * @see TreePatch + */ + applyPatch: function(patchList) { + var dfd, i, p2, key, patch, node, + patchCount = patchList.length, + deferredList = []; + + for(i=0; i<patchCount; i++){ + p2 = patchList[i]; + _assert(p2.length === 2, "patchList must be an array of length-2-arrays"); + key = p2[0]; + patch = p2[1]; + node = (key === null) ? this.rootNode : this.getNodeByKey(key); + if(node){ + dfd = new $.Deferred(); + deferredList.push(dfd); + node.applyPatch(patch).always(_makeResolveFunc(dfd, node)); + }else{ + this.warn("could not find node with key '" + key + "'"); + } + } + // Return a promise that is resolved, when ALL patches were applied + return $.when.apply($, deferredList).promise(); + }, + /* TODO: implement in dnd extension + cancelDrag: function() { + var dd = $.ui.ddmanager.current; + if(dd){ + dd.cancel(); + } + }, + */ + /** Return the number of nodes. + * @returns {integer} + */ + count: function() { + return this.rootNode.countChildren(); + }, + /** Write to browser console if debugLevel >= 2 (prepending tree name) + * + * @param {*} msg string or object or array of such + */ + debug: function(msg){ + if( this.options.debugLevel >= 2 ) { + Array.prototype.unshift.call(arguments, this.toString()); + consoleApply("log", arguments); + } + }, + // TODO: disable() + // TODO: enable() + // TODO: enableUpdate() + + /**Find all nodes that matches condition. + * + * @param {string | function(node)} match title string to search for, or a + * callback function that returns `true` if a node is matched. + * @returns {FancytreeNode[]} array of nodes (may be empty) + * @see FancytreeNode#findAll + * @since 2.12 + */ + findAll: function(match) { + return this.rootNode.findAll(match); + }, + /**Find first node that matches condition. + * + * @param {string | function(node)} match title string to search for, or a + * callback function that returns `true` if a node is matched. + * @returns {FancytreeNode} matching node or null + * @see FancytreeNode#findFirst + * @since 2.12 + */ + findFirst: function(match) { + return this.rootNode.findFirst(match); + }, + /** Find the next visible node that starts with `match`, starting at `startNode` + * and wrap-around at the end. + * + * @param {string|function} match + * @param {FancytreeNode} [startNode] defaults to first node + * @returns {FancytreeNode} matching node or null + */ + findNextNode: function(match, startNode, visibleOnly) { + var stopNode = null, + parentChildren = startNode.parent.children, + matchingNode = null, + walkVisible = function(parent, idx, fn) { + var i, grandParent, + parentChildren = parent.children, + siblingCount = parentChildren.length, + node = parentChildren[idx]; + // visit node itself + if( node && fn(node) === false ) { + return false; + } + // visit descendants + if( node && node.children && node.expanded ) { + if( walkVisible(node, 0, fn) === false ) { + return false; + } + } + // visit subsequent siblings + for( i = idx + 1; i < siblingCount; i++ ) { + if( walkVisible(parent, i, fn) === false ) { + return false; + } + } + // visit parent's subsequent siblings + grandParent = parent.parent; + if( grandParent ) { + return walkVisible(grandParent, grandParent.children.indexOf(parent) + 1, fn); + } else { + // wrap-around: restart with first node + return walkVisible(parent, 0, fn); + } + }; + + match = (typeof match === "string") ? _makeNodeTitleStartMatcher(match) : match; + startNode = startNode || this.getFirstChild(); + + walkVisible(startNode.parent, parentChildren.indexOf(startNode), function(node){ + // Stop iteration if we see the start node a second time + if( node === stopNode ) { + return false; + } + stopNode = stopNode || node; + // Ignore nodes hidden by a filter + if( ! $(node.span).is(":visible") ) { + node.debug("quicksearch: skipping hidden node"); + return; + } + // Test if we found a match, but search for a second match if this + // was the currently active node + if( match(node) ) { + // node.debug("quicksearch match " + node.title, startNode); + matchingNode = node; + if( matchingNode !== startNode ) { + return false; + } + } + }); + return matchingNode; + }, + // TODO: fromDict + /** + * Generate INPUT elements that can be submitted with html forms. + * + * In selectMode 3 only the topmost selected nodes are considered, unless + * `opts.stopOnParents: false` is passed. + * + * @param {boolean | string} [selected=true] Pass false to disable, pass a string to overide the field name (default: 'ft_ID[]') + * @param {boolean | string} [active=true] Pass false to disable, pass a string to overide the field name (default: 'ft_ID_active') + * @param {object} [opts] default { stopOnParents: true } + */ + generateFormElements: function(selected, active, opts) { + // TODO: test case + opts = opts || {}; + + var nodeList, + selectedName = (typeof selected === "string") ? selected : "ft_" + this._id + "[]", + activeName = (typeof active === "string") ? active : "ft_" + this._id + "_active", + id = "fancytree_result_" + this._id, + $result = $("#" + id), + stopOnParents = this.options.selectMode === 3 && opts.stopOnParents !== false; + + if($result.length){ + $result.empty(); + }else{ + $result = $("<div>", { + id: id + }).hide().insertAfter(this.$container); + } + if(selected !== false){ + nodeList = this.getSelectedNodes(stopOnParents); + $.each(nodeList, function(idx, node){ + $result.append($("<input>", { + type: "checkbox", + name: selectedName, + value: node.key, + checked: true + })); + }); + } + if(active !== false && this.activeNode){ + $result.append($("<input>", { + type: "radio", + name: activeName, + value: this.activeNode.key, + checked: true + })); + } + }, + /** + * Return the currently active node or null. + * @returns {FancytreeNode} + */ + getActiveNode: function() { + return this.activeNode; + }, + /** Return the first top level node if any (not the invisible root node). + * @returns {FancytreeNode | null} + */ + getFirstChild: function() { + return this.rootNode.getFirstChild(); + }, + /** + * Return node that has keyboard focus or null. + * @returns {FancytreeNode} + */ + getFocusNode: function() { + return this.focusNode; + }, + /** + * Return node with a given key or null if not found. + * @param {string} key + * @param {FancytreeNode} [searchRoot] only search below this node + * @returns {FancytreeNode | null} + */ + getNodeByKey: function(key, searchRoot) { + // Search the DOM by element ID (assuming this is faster than traversing all nodes). + // $("#...") has problems, if the key contains '.', so we use getElementById() + var el, match; + if(!searchRoot){ + el = document.getElementById(this.options.idPrefix + key); + if( el ){ + return el.ftnode ? el.ftnode : null; + } + } + // Not found in the DOM, but still may be in an unrendered part of tree + // TODO: optimize with specialized loop + // TODO: consider keyMap? + searchRoot = searchRoot || this.rootNode; + match = null; + searchRoot.visit(function(node){ +// window.console.log("getNodeByKey(" + key + "): ", node.key); + if(node.key === key) { + match = node; + return false; + } + }, true); + return match; + }, + /** Return the invisible system root node. + * @returns {FancytreeNode} + */ + getRootNode: function() { + return this.rootNode; + }, + /** + * Return an array of selected nodes. + * @param {boolean} [stopOnParents=false] only return the topmost selected + * node (useful with selectMode 3) + * @returns {FancytreeNode[]} + */ + getSelectedNodes: function(stopOnParents) { + var nodeList = []; + this.rootNode.visit(function(node){ + if( node.selected ) { + nodeList.push(node); + if( stopOnParents === true ){ + return "skip"; // stop processing this branch + } + } + }); + return nodeList; + }, + /** Return true if the tree control has keyboard focus + * @returns {boolean} + */ + hasFocus: function(){ + return !!this._hasFocus; + }, + /** Write to browser console if debugLevel >= 1 (prepending tree name) + * @param {*} msg string or object or array of such + */ + info: function(msg){ + if( this.options.debugLevel >= 1 ) { + Array.prototype.unshift.call(arguments, this.toString()); + consoleApply("info", arguments); + } + }, +/* + TODO: isInitializing: function() { + return ( this.phase=="init" || this.phase=="postInit" ); + }, + TODO: isReloading: function() { + return ( this.phase=="init" || this.phase=="postInit" ) && this.options.persist && this.persistence.cookiesFound; + }, + TODO: isUserEvent: function() { + return ( this.phase=="userEvent" ); + }, +*/ + + /** + * Make sure that a node with a given ID is loaded, by traversing - and + * loading - its parents. This method is ment for lazy hierarchies. + * A callback is executed for every node as we go. + * @example + * tree.loadKeyPath("/_3/_23/_26/_27", function(node, status){ + * if(status === "loaded") { + * console.log("loaded intermiediate node " + node); + * }else if(status === "ok") { + * node.activate(); + * } + * }); + * + * @param {string | string[]} keyPathList one or more key paths (e.g. '/3/2_1/7') + * @param {function} callback callback(node, status) is called for every visited node ('loading', 'loaded', 'ok', 'error') + * @returns {$.Promise} + */ + loadKeyPath: function(keyPathList, callback, _rootNode) { + var deferredList, dfd, i, path, key, loadMap, node, root, segList, + sep = this.options.keyPathSeparator, + self = this; + + if(!$.isArray(keyPathList)){ + keyPathList = [keyPathList]; + } + // Pass 1: handle all path segments for nodes that are already loaded + // Collect distinct top-most lazy nodes in a map + loadMap = {}; + + for(i=0; i<keyPathList.length; i++){ + root = _rootNode || this.rootNode; + path = keyPathList[i]; + // strip leading slash + if(path.charAt(0) === sep){ + path = path.substr(1); + } + // traverse and strip keys, until we hit a lazy, unloaded node + segList = path.split(sep); + while(segList.length){ + key = segList.shift(); +// node = _findDirectChild(root, key); + node = root._findDirectChild(key); + if(!node){ + this.warn("loadKeyPath: key not found: " + key + " (parent: " + root + ")"); + callback.call(this, key, "error"); + break; + }else if(segList.length === 0){ + callback.call(this, node, "ok"); + break; + }else if(!node.lazy || (node.hasChildren() !== undefined )){ + callback.call(this, node, "loaded"); + root = node; + }else{ + callback.call(this, node, "loaded"); +// segList.unshift(key); + if(loadMap[key]){ + loadMap[key].push(segList.join(sep)); + }else{ + loadMap[key] = [segList.join(sep)]; + } + break; + } + } + } +// alert("loadKeyPath: loadMap=" + JSON.stringify(loadMap)); + // Now load all lazy nodes and continue itearation for remaining paths + deferredList = []; + // Avoid jshint warning 'Don't make functions within a loop.': + function __lazyload(key, node, dfd){ + callback.call(self, node, "loading"); + node.load().done(function(){ + self.loadKeyPath.call(self, loadMap[key], callback, node).always(_makeResolveFunc(dfd, self)); + }).fail(function(errMsg){ + self.warn("loadKeyPath: error loading: " + key + " (parent: " + root + ")"); + callback.call(self, node, "error"); + dfd.reject(); + }); + } + for(key in loadMap){ + node = root._findDirectChild(key); +// alert("loadKeyPath: lazy node(" + key + ") = " + node); + dfd = new $.Deferred(); + deferredList.push(dfd); + __lazyload(key, node, dfd); + } + // Return a promise that is resolved, when ALL paths were loaded + return $.when.apply($, deferredList).promise(); + }, + /** Re-fire beforeActivate and activate events. */ + reactivate: function(setFocus) { + var res, + node = this.activeNode; + + if( !node ) { + return _getResolvedPromise(); + } + this.activeNode = null; // Force re-activating + res = node.setActive(); + if( setFocus ){ + node.setFocus(); + } + return res; + }, + /** Reload tree from source and return a promise. + * @param [source] optional new source (defaults to initial source data) + * @returns {$.Promise} + */ + reload: function(source) { + this._callHook("treeClear", this); + return this._callHook("treeLoad", this, source); + }, + /**Render tree (i.e. create DOM elements for all top-level nodes). + * @param {boolean} [force=false] create DOM elemnts, even is parent is collapsed + * @param {boolean} [deep=false] + */ + render: function(force, deep) { + return this.rootNode.render(force, deep); + }, + // TODO: selectKey: function(key, select) + // TODO: serializeArray: function(stopOnParents) + /** + * @param {boolean} [flag=true] + */ + setFocus: function(flag) { + return this._callHook("treeSetFocus", this, flag); + }, + /** + * Return all nodes as nested list of {@link NodeData}. + * + * @param {boolean} [includeRoot=false] Returns the hidden system root node (and its children) + * @param {function} [callback] callback(dict, node) is called for every node, in order to allow modifications + * @returns {Array | object} + * @see FancytreeNode#toDict + */ + toDict: function(includeRoot, callback){ + var res = this.rootNode.toDict(true, callback); + return includeRoot ? res : res.children; + }, + /* Implicitly called for string conversions. + * @returns {string} + */ + toString: function(){ + return "<Fancytree(#" + this._id + ")>"; + }, + /* _trigger a widget event with additional node ctx. + * @see EventData + */ + _triggerNodeEvent: function(type, node, originalEvent, extra) { +// this.debug("_trigger(" + type + "): '" + ctx.node.title + "'", ctx); + var ctx = this._makeHookContext(node, originalEvent, extra), + res = this.widget._trigger(type, originalEvent, ctx); + if(res !== false && ctx.result !== undefined){ + return ctx.result; + } + return res; + }, + /* _trigger a widget event with additional tree data. */ + _triggerTreeEvent: function(type, originalEvent, extra) { +// this.debug("_trigger(" + type + ")", ctx); + var ctx = this._makeHookContext(this, originalEvent, extra), + res = this.widget._trigger(type, originalEvent, ctx); + + if(res !== false && ctx.result !== undefined){ + return ctx.result; + } + return res; + }, + /** Call fn(node) for all nodes. + * + * @param {function} fn the callback function. + * Return false to stop iteration, return "skip" to skip this node and children only. + * @returns {boolean} false, if the iterator was stopped. + */ + visit: function(fn) { + return this.rootNode.visit(fn, false); + }, + /** Write warning to browser console (prepending tree info) + * + * @param {*} msg string or object or array of such + */ + warn: function(msg){ + Array.prototype.unshift.call(arguments, this.toString()); + consoleApply("warn", arguments); + } +}; + +/** + * These additional methods of the {@link Fancytree} class are 'hook functions' + * that can be used and overloaded by extensions. + * (See <a href="https://github.com/mar10/fancytree/wiki/TutorialExtensions">writing extensions</a>.) + * @mixin Fancytree_Hooks + */ +$.extend(Fancytree.prototype, + /** @lends Fancytree_Hooks# */ + { + /** Default handling for mouse click events. + * + * @param {EventData} ctx + */ + nodeClick: function(ctx) { + var activate, expand, + // event = ctx.originalEvent, + targetType = ctx.targetType, + node = ctx.node; + +// this.debug("ftnode.onClick(" + event.type + "): ftnode:" + this + ", button:" + event.button + ", which: " + event.which, ctx); + // TODO: use switch + // TODO: make sure clicks on embedded <input> doesn't steal focus (see table sample) + if( targetType === "expander" ) { + if( node.isLoading() ) { + // #495: we probably got a click event while a lazy load is pending. + // The 'expanded' state is not yet set, so 'toggle' would expand + // and trigger lazyLoad again. + // It would be better to allow to collapse/expand the status node + // while loading (instead of ignoring), but that would require some + // more work. + node.debug("Got 2nd click while loading: ignored"); + return; + } + // Clicking the expander icon always expands/collapses + this._callHook("nodeToggleExpanded", ctx); + + } else if( targetType === "checkbox" ) { + // Clicking the checkbox always (de)selects + this._callHook("nodeToggleSelected", ctx); + if( ctx.options.focusOnSelect ) { // #358 + this._callHook("nodeSetFocus", ctx, true); + } + + } else { + // Honor `clickFolderMode` for + expand = false; + activate = true; + if( node.folder ) { + switch( ctx.options.clickFolderMode ) { + case 2: // expand only + expand = true; + activate = false; + break; + case 3: // expand and activate + activate = true; + expand = true; //!node.isExpanded(); + break; + // else 1 or 4: just activate + } + } + if( activate ) { + this.nodeSetFocus(ctx); + this._callHook("nodeSetActive", ctx, true); + } + if( expand ) { + if(!activate){ +// this._callHook("nodeSetFocus", ctx); + } +// this._callHook("nodeSetExpanded", ctx, true); + this._callHook("nodeToggleExpanded", ctx); + } + } + // Make sure that clicks stop, otherwise <a href='#'> jumps to the top + // if(event.target.localName === "a" && event.target.className === "fancytree-title"){ + // event.preventDefault(); + // } + // TODO: return promise? + }, + /** Collapse all other children of same parent. + * + * @param {EventData} ctx + * @param {object} callOpts + */ + nodeCollapseSiblings: function(ctx, callOpts) { + // TODO: return promise? + var ac, i, l, + node = ctx.node; + + if( node.parent ){ + ac = node.parent.children; + for (i=0, l=ac.length; i<l; i++) { + if ( ac[i] !== node && ac[i].expanded ){ + this._callHook("nodeSetExpanded", ac[i], false, callOpts); + } + } + } + }, + /** Default handling for mouse douleclick events. + * @param {EventData} ctx + */ + nodeDblclick: function(ctx) { + // TODO: return promise? + if( ctx.targetType === "title" && ctx.options.clickFolderMode === 4) { +// this.nodeSetFocus(ctx); +// this._callHook("nodeSetActive", ctx, true); + this._callHook("nodeToggleExpanded", ctx); + } + // TODO: prevent text selection on dblclicks + if( ctx.targetType === "title" ) { + ctx.originalEvent.preventDefault(); + } + }, + /** Default handling for mouse keydown events. + * + * NOTE: this may be called with node == null if tree (but no node) has focus. + * @param {EventData} ctx + */ + nodeKeydown: function(ctx) { + // TODO: return promise? + var matchNode, stamp, res, focusNode, + event = ctx.originalEvent, + node = ctx.node, + tree = ctx.tree, + opts = ctx.options, + which = event.which, + whichChar = String.fromCharCode(which), + clean = !(event.altKey || event.ctrlKey || event.metaKey || event.shiftKey), + $target = $(event.target), + handled = true, + activate = !(event.ctrlKey || !opts.autoActivate ); + +// (node || FT).debug("ftnode.nodeKeydown(" + event.type + "): ftnode:" + this + ", charCode:" + event.charCode + ", keyCode: " + event.keyCode + ", which: " + event.which); +// FT.debug("eventToString", which, '"' + String.fromCharCode(which) + '"', '"' + FT.eventToString(event) + '"'); + + // Set focus to active (or first node) if no other node has the focus yet + if( !node ){ + focusNode = (this.getActiveNode() || this.getFirstChild()); + if (focusNode){ + focusNode.setFocus(); + node = ctx.node = this.focusNode; + node.debug("Keydown force focus on active node"); + } + } + + if( opts.quicksearch && clean && /\w/.test(whichChar) && !$target.is(":input:enabled") ) { + // Allow to search for longer streaks if typed in quickly + stamp = new Date().getTime(); + if( stamp - tree.lastQuicksearchTime > 500 ) { + tree.lastQuicksearchTerm = ""; + } + tree.lastQuicksearchTime = stamp; + tree.lastQuicksearchTerm += whichChar; + // tree.debug("quicksearch find", tree.lastQuicksearchTerm); + matchNode = tree.findNextNode(tree.lastQuicksearchTerm, tree.getActiveNode()); + if( matchNode ) { + matchNode.setActive(); + } + event.preventDefault(); + return; + } + switch( FT.eventToString(event) ) { + case "+": + case "=": // 187: '+' @ Chrome, Safari + tree.nodeSetExpanded(ctx, true); + break; + case "-": + tree.nodeSetExpanded(ctx, false); + break; + case "space": + if(opts.checkbox){ + tree.nodeToggleSelected(ctx); + }else{ + tree.nodeSetActive(ctx, true); + } + break; + case "return": + tree.nodeSetActive(ctx, true); + break; + case "backspace": + case "left": + case "right": + case "up": + case "down": + res = node.navigate(event.which, activate); + break; + default: + handled = false; + } + if(handled){ + event.preventDefault(); + } + }, + + + // /** Default handling for mouse keypress events. */ + // nodeKeypress: function(ctx) { + // var event = ctx.originalEvent; + // }, + + // /** Trigger lazyLoad event (async). */ + // nodeLazyLoad: function(ctx) { + // var node = ctx.node; + // if(this._triggerNodeEvent()) + // }, + /** Load child nodes (async). + * + * @param {EventData} ctx + * @param {object[]|object|string|$.Promise|function} source + * @returns {$.Promise} The deferred will be resolved as soon as the (ajax) + * data was rendered. + */ + nodeLoadChildren: function(ctx, source) { + var ajax, delay, dfd, + tree = ctx.tree, + node = ctx.node; + + if($.isFunction(source)){ + source = source(); + } + // TOTHINK: move to 'ajax' extension? + if(source.url){ + // `source` is an Ajax options object + ajax = $.extend({}, ctx.options.ajax, source); + if(ajax.debugDelay){ + // simulate a slow server + delay = ajax.debugDelay; + if($.isArray(delay)){ // random delay range [min..max] + delay = delay[0] + Math.random() * (delay[1] - delay[0]); + } + + node.debug("nodeLoadChildren waiting debug delay " + Math.round(delay) + "ms"); + ajax.debugDelay = false; + dfd = $.Deferred(function (dfd) { + setTimeout(function () { + $.ajax(ajax) + .done(function () { dfd.resolveWith(this, arguments); }) + .fail(function () { dfd.rejectWith(this, arguments); }); + }, delay); + }); + }else{ + dfd = $.ajax(ajax); + } + + // Defer the deferred: we want to be able to reject, even if ajax + // resolved ok. + source = new $.Deferred(); + dfd.done(function (data, textStatus, jqXHR) { + var errorObj, res; + if(this.dataType === "json" && typeof data === "string"){ + $.error("Ajax request returned a string (did you get the JSON dataType wrong?)."); + } + // postProcess is similar to the standard ajax dataFilter hook, + // but it is also called for JSONP + if( ctx.options.postProcess ){ + res = tree._triggerNodeEvent("postProcess", ctx, ctx.originalEvent, {response: data, error: null, dataType: this.dataType}); + if( res.error ) { + errorObj = $.isPlainObject(res.error) ? res.error : {message: res.error}; + errorObj = tree._makeHookContext(node, null, errorObj); + source.rejectWith(this, [errorObj]); + return; + } + data = $.isArray(res) ? res : data; + + } else if (data && data.hasOwnProperty("d") && ctx.options.enableAspx ) { + // Process ASPX WebMethod JSON object inside "d" property + data = (typeof data.d === "string") ? $.parseJSON(data.d) : data.d; + } + source.resolveWith(this, [data]); + }).fail(function (jqXHR, textStatus, errorThrown) { + var errorObj = tree._makeHookContext(node, null, { + error: jqXHR, + args: Array.prototype.slice.call(arguments), + message: errorThrown, + details: jqXHR.status + ": " + errorThrown + }); + source.rejectWith(this, [errorObj]); + }); + } + // #383: accept and convert ECMAScript 6 Promise + if( $.isFunction(source.then) && $.isFunction(source["catch"]) ) { + dfd = source; + source = new $.Deferred(); + dfd.then(function(value){ + source.resolve(value); + }, function(reason){ + source.reject(reason); + }); + } + if($.isFunction(source.promise)){ + // `source` is a deferred, i.e. ajax request + _assert(!node.isLoading(), "recursive load"); + // node._isLoading = true; + tree.nodeSetStatus(ctx, "loading"); + + source.done(function (children) { + tree.nodeSetStatus(ctx, "ok"); + }).fail(function(error){ + var ctxErr; + if (error.node && error.error && error.message) { + // error is already a context object + ctxErr = error; + } else { + ctxErr = tree._makeHookContext(node, null, { + error: error, // it can be jqXHR or any custom error + args: Array.prototype.slice.call(arguments), + message: error ? (error.message || error.toString()) : "" + }); + } + if( tree._triggerNodeEvent("loadError", ctxErr, null) !== false ) { + tree.nodeSetStatus(ctx, "error", ctxErr.message, ctxErr.details); + } + }); + } + // $.when(source) resolves also for non-deferreds + return $.when(source).done(function(children){ + var metaData; + + if( $.isPlainObject(children) ){ + // We got {foo: 'abc', children: [...]} + // Copy extra properties to tree.data.foo + _assert(node.isRootNode(), "source may only be an object for root nodes (expecting an array of child objects otherwise)"); + _assert($.isArray(children.children), "if an object is passed as source, it must contain a 'children' array (all other properties are added to 'tree.data')"); + metaData = children; + children = children.children; + delete metaData.children; + $.extend(tree.data, metaData); + } + _assert($.isArray(children), "expected array of children"); + node._setChildren(children); + // trigger fancytreeloadchildren + tree._triggerNodeEvent("loadChildren", node); + // }).always(function(){ + // node._isLoading = false; + }); + }, + /** [Not Implemented] */ + nodeLoadKeyPath: function(ctx, keyPathList) { + // TODO: implement and improve + // http://code.google.com/p/dynatree/issues/detail?id=222 + }, + /** + * Remove a single direct child of ctx.node. + * @param {EventData} ctx + * @param {FancytreeNode} childNode dircect child of ctx.node + */ + nodeRemoveChild: function(ctx, childNode) { + var idx, + node = ctx.node, + opts = ctx.options, + subCtx = $.extend({}, ctx, {node: childNode}), + children = node.children; + + // FT.debug("nodeRemoveChild()", node.toString(), childNode.toString()); + + if( children.length === 1 ) { + _assert(childNode === children[0], "invalid single child"); + return this.nodeRemoveChildren(ctx); + } + if( this.activeNode && (childNode === this.activeNode || this.activeNode.isDescendantOf(childNode))){ + this.activeNode.setActive(false); // TODO: don't fire events + } + if( this.focusNode && (childNode === this.focusNode || this.focusNode.isDescendantOf(childNode))){ + this.focusNode = null; + } + // TODO: persist must take care to clear select and expand cookies + this.nodeRemoveMarkup(subCtx); + this.nodeRemoveChildren(subCtx); + idx = $.inArray(childNode, children); + _assert(idx >= 0, "invalid child"); + // Unlink to support GC + childNode.visit(function(n){ + n.parent = null; + }, true); + this._callHook("treeRegisterNode", this, false, childNode); + if ( opts.removeNode ){ + opts.removeNode.call(ctx.tree, {type: "removeNode"}, subCtx); + } + // remove from child list + children.splice(idx, 1); + }, + /**Remove HTML markup for all descendents of ctx.node. + * @param {EventData} ctx + */ + nodeRemoveChildMarkup: function(ctx) { + var node = ctx.node; + + // FT.debug("nodeRemoveChildMarkup()", node.toString()); + // TODO: Unlink attr.ftnode to support GC + if(node.ul){ + if( node.isRootNode() ) { + $(node.ul).empty(); + } else { + $(node.ul).remove(); + node.ul = null; + } + node.visit(function(n){ + n.li = n.ul = null; + }); + } + }, + /**Remove all descendants of ctx.node. + * @param {EventData} ctx + */ + nodeRemoveChildren: function(ctx) { + var subCtx, + tree = ctx.tree, + node = ctx.node, + children = node.children, + opts = ctx.options; + + // FT.debug("nodeRemoveChildren()", node.toString()); + if(!children){ + return; + } + if( this.activeNode && this.activeNode.isDescendantOf(node)){ + this.activeNode.setActive(false); // TODO: don't fire events + } + if( this.focusNode && this.focusNode.isDescendantOf(node)){ + this.focusNode = null; + } + // TODO: persist must take care to clear select and expand cookies + this.nodeRemoveChildMarkup(ctx); + // Unlink children to support GC + // TODO: also delete this.children (not possible using visit()) + subCtx = $.extend({}, ctx); + node.visit(function(n){ + n.parent = null; + tree._callHook("treeRegisterNode", tree, false, n); + if ( opts.removeNode ){ + subCtx.node = n; + opts.removeNode.call(ctx.tree, {type: "removeNode"}, subCtx); + } + }); + if( node.lazy ){ + // 'undefined' would be interpreted as 'not yet loaded' for lazy nodes + node.children = []; + } else{ + node.children = null; + } + if( !node.isRootNode() ) { + node.expanded = false; // #449, #459 + } + this.nodeRenderStatus(ctx); + }, + /**Remove HTML markup for ctx.node and all its descendents. + * @param {EventData} ctx + */ + nodeRemoveMarkup: function(ctx) { + var node = ctx.node; + // FT.debug("nodeRemoveMarkup()", node.toString()); + // TODO: Unlink attr.ftnode to support GC + if(node.li){ + $(node.li).remove(); + node.li = null; + } + this.nodeRemoveChildMarkup(ctx); + }, + /** + * Create `<li><span>..</span> .. </li>` tags for this node. + * + * This method takes care that all HTML markup is created that is required + * to display this node in it's current state. + * + * Call this method to create new nodes, or after the strucuture + * was changed (e.g. after moving this node or adding/removing children) + * nodeRenderTitle() and nodeRenderStatus() are implied. + * + * Note: if a node was created/removed, nodeRender() must be called for the + * parent. + * <code> + * <li id='KEY' ftnode=NODE> + * <span class='fancytree-node fancytree-expanded fancytree-has-children fancytree-lastsib fancytree-exp-el fancytree-ico-e'> + * <span class="fancytree-expander"></span> + * <span class="fancytree-checkbox"></span> // only present in checkbox mode + * <span class="fancytree-icon"></span> + * <a href="#" class="fancytree-title"> Node 1 </a> + * </span> + * <ul> // only present if node has children + * <li id='KEY' ftnode=NODE> child1 ... </li> + * <li id='KEY' ftnode=NODE> child2 ... </li> + * </ul> + * </li> + * </code> + * + * @param {EventData} ctx + * @param {boolean} [force=false] re-render, even if html markup was already created + * @param {boolean} [deep=false] also render all descendants, even if parent is collapsed + * @param {boolean} [collapsed=false] force root node to be collapsed, so we can apply animated expand later + */ + nodeRender: function(ctx, force, deep, collapsed, _recursive) { + /* This method must take care of all cases where the current data mode + * (i.e. node hierarchy) does not match the current markup. + * + * - node was not yet rendered: + * create markup + * - node was rendered: exit fast + * - children have been added + * - children have been removed + */ + var childLI, childNode1, childNode2, i, l, next, subCtx, + node = ctx.node, + tree = ctx.tree, + opts = ctx.options, + aria = opts.aria, + firstTime = false, + parent = node.parent, + isRootNode = !parent, + children = node.children, + successorLi = null; + // FT.debug("nodeRender(" + !!force + ", " + !!deep + ")", node.toString()); + + if( ! isRootNode && ! parent.ul ) { + // Calling node.collapse on a deep, unrendered node + return; + } + _assert(isRootNode || parent.ul, "parent UL must exist"); + + // Render the node + if( !isRootNode ){ + // Discard markup on force-mode, or if it is not linked to parent <ul> + if(node.li && (force || (node.li.parentNode !== node.parent.ul) ) ){ + if( node.li.parentNode === node.parent.ul ){ + // #486: store following node, so we can insert the new markup there later + successorLi = node.li.nextSibling; + }else{ + // May happen, when a top-level node was dropped over another + this.debug("Unlinking " + node + " (must be child of " + node.parent + ")"); + } +// this.debug("nodeRemoveMarkup..."); + this.nodeRemoveMarkup(ctx); + } + // Create <li><span /> </li> +// node.debug("render..."); + if( !node.li ) { +// node.debug("render... really"); + firstTime = true; + node.li = document.createElement("li"); + node.li.ftnode = node; + if(aria){ + // TODO: why doesn't this work: +// node.li.role = "treeitem"; +// $(node.li).attr("role", "treeitem") +// .attr("aria-labelledby", "ftal_" + node.key); + } + if( node.key && opts.generateIds ){ + node.li.id = opts.idPrefix + node.key; + } + node.span = document.createElement("span"); + node.span.className = "fancytree-node"; + if(aria){ + $(node.span).attr("aria-labelledby", "ftal_" + node.key); + } + node.li.appendChild(node.span); + + // Create inner HTML for the <span> (expander, checkbox, icon, and title) + this.nodeRenderTitle(ctx); + + // Allow tweaking and binding, after node was created for the first time + if ( opts.createNode ){ + opts.createNode.call(tree, {type: "createNode"}, ctx); + } + }else{ +// this.nodeRenderTitle(ctx); + this.nodeRenderStatus(ctx); + } + // Allow tweaking after node state was rendered + if ( opts.renderNode ){ + opts.renderNode.call(tree, {type: "renderNode"}, ctx); + } + } + + // Visit child nodes + if( children ){ + if( isRootNode || node.expanded || deep === true ) { + // Create a UL to hold the children + if( !node.ul ){ + node.ul = document.createElement("ul"); + if((collapsed === true && !_recursive) || !node.expanded){ + // hide top UL, so we can use an animation to show it later + node.ul.style.display = "none"; + } + if(aria){ + $(node.ul).attr("role", "group"); + } + if ( node.li ) { // issue #67 + node.li.appendChild(node.ul); + } else { + node.tree.$div.append(node.ul); + } + } + // Add child markup + for(i=0, l=children.length; i<l; i++) { + subCtx = $.extend({}, ctx, {node: children[i]}); + this.nodeRender(subCtx, force, deep, false, true); + } + // Remove <li> if nodes have moved to another parent + childLI = node.ul.firstChild; + while( childLI ){ + childNode2 = childLI.ftnode; + if( childNode2 && childNode2.parent !== node ) { + node.debug("_fixParent: remove missing " + childNode2, childLI); + next = childLI.nextSibling; + childLI.parentNode.removeChild(childLI); + childLI = next; + }else{ + childLI = childLI.nextSibling; + } + } + // Make sure, that <li> order matches node.children order. + childLI = node.ul.firstChild; + for(i=0, l=children.length-1; i<l; i++) { + childNode1 = children[i]; + childNode2 = childLI.ftnode; + if( childNode1 !== childNode2 ) { + // node.debug("_fixOrder: mismatch at index " + i + ": " + childNode1 + " != " + childNode2); + node.ul.insertBefore(childNode1.li, childNode2.li); + } else { + childLI = childLI.nextSibling; + } + } + } + }else{ + // No children: remove markup if any + if( node.ul ){ +// alert("remove child markup for " + node); + this.warn("remove child markup for " + node); + this.nodeRemoveChildMarkup(ctx); + } + } + if( !isRootNode ){ + // Update element classes according to node state + // this.nodeRenderStatus(ctx); + // Finally add the whole structure to the DOM, so the browser can render + if( firstTime ){ + // #486: successorLi is set, if we re-rendered (i.e. discarded) + // existing markup, which we want to insert at the same position. + // (null is equivalent to append) +// parent.ul.appendChild(node.li); + parent.ul.insertBefore(node.li, successorLi); + } + } + }, + /** Create HTML inside the node's outer <span> (i.e. expander, checkbox, + * icon, and title). + * + * nodeRenderStatus() is implied. + * @param {EventData} ctx + * @param {string} [title] optinal new title + */ + nodeRenderTitle: function(ctx, title) { + // set node connector images, links and text + var id, iconSpanClass, nodeTitle, role, tabindex, tooltip, + node = ctx.node, + tree = ctx.tree, + opts = ctx.options, + aria = opts.aria, + level = node.getLevel(), + ares = [], + iconSrc = node.data.icon; + + if(title !== undefined){ + node.title = title; + } + if(!node.span){ + // Silently bail out if node was not rendered yet, assuming + // node.render() will be called as the node becomes visible + return; + } + // connector (expanded, expandable or simple) + // TODO: optimize this if clause + if( level < opts.minExpandLevel ) { + if( !node.lazy ) { + node.expanded = true; + } + if(level > 1){ + if(aria){ + ares.push("<span role='button' class='fancytree-expander fancytree-expander-fixed'></span>"); + }else{ + ares.push("<span class='fancytree-expander fancytree-expander-fixed''></span>"); + } + } + // .. else (i.e. for root level) skip expander/connector alltogether + } else { + if(aria){ + ares.push("<span role='button' class='fancytree-expander'></span>"); + }else{ + ares.push("<span class='fancytree-expander'></span>"); + } + } + // Checkbox mode + if( opts.checkbox && node.hideCheckbox !== true && !node.isStatusNode() ) { + if(aria){ + ares.push("<span role='checkbox' class='fancytree-checkbox'></span>"); + }else{ + ares.push("<span class='fancytree-checkbox'></span>"); + } + } + // folder or doctype icon + role = aria ? " role='img'" : ""; + if( iconSrc === true || (iconSrc !== false && opts.icons !== false) ) { + // opts.icons defines the default behavior, node.icon == true/false can override this + if ( iconSrc && typeof iconSrc === "string" ) { + // node.icon is an image url + iconSrc = (iconSrc.charAt(0) === "/") ? iconSrc : ((opts.imagePath || "") + iconSrc); + ares.push("<img src='" + iconSrc + "' class='fancytree-icon' alt='' />"); + } else { + // See if node.iconclass or opts.iconClass() define a class name + iconSpanClass = (opts.iconClass && opts.iconClass.call(tree, {type: "iconClass"}, ctx)) || node.data.iconclass || null; + if( iconSpanClass ) { + ares.push("<span " + role + " class='fancytree-custom-icon " + iconSpanClass + "'></span>"); + } else { + ares.push("<span " + role + " class='fancytree-icon'></span>"); + } + } + } + + // node title + nodeTitle = ""; + if ( opts.renderTitle ){ + nodeTitle = opts.renderTitle.call(tree, {type: "renderTitle"}, ctx) || ""; + } + if(!nodeTitle){ + tooltip = node.tooltip ? " title='" + FT.escapeHtml(node.tooltip) + "'" : ""; + id = aria ? " id='ftal_" + node.key + "'" : ""; + role = aria ? " role='treeitem'" : ""; + tabindex = opts.titlesTabbable ? " tabindex='0'" : ""; + + nodeTitle = "<span " + role + " class='fancytree-title'" + id + tooltip + tabindex + ">" + node.title + "</span>"; + } + ares.push(nodeTitle); + // Note: this will trigger focusout, if node had the focus + //$(node.span).html(ares.join("")); // it will cleanup the jQuery data currently associated with SPAN (if any), but it executes more slowly + node.span.innerHTML = ares.join(""); + // Update CSS classes + this.nodeRenderStatus(ctx); + }, + /** Update element classes according to node state. + * @param {EventData} ctx + */ + nodeRenderStatus: function(ctx) { + // Set classes for current status + var node = ctx.node, + tree = ctx.tree, + opts = ctx.options, +// nodeContainer = node[tree.nodeContainerAttrName], + hasChildren = node.hasChildren(), + isLastSib = node.isLastSibling(), + aria = opts.aria, +// $ariaElem = aria ? $(node[tree.ariaPropName]) : null, + $ariaElem = $(node.span).find(".fancytree-title"), + cn = opts._classNames, + cnList = [], + statusElem = node[tree.statusClassPropName]; + + if( !statusElem ){ + // if this function is called for an unrendered node, ignore it (will be updated on nect render anyway) + return; + } + // Build a list of class names that we will add to the node <span> + cnList.push(cn.node); + if( tree.activeNode === node ){ + cnList.push(cn.active); +// $(">span.fancytree-title", statusElem).attr("tabindex", "0"); +// tree.$container.removeAttr("tabindex"); + // }else{ +// $(">span.fancytree-title", statusElem).removeAttr("tabindex"); +// tree.$container.attr("tabindex", "0"); + } + if( tree.focusNode === node ){ + cnList.push(cn.focused); + if(aria){ +// $(">span.fancytree-title", statusElem).attr("tabindex", "0"); +// $(">span.fancytree-title", statusElem).attr("tabindex", "-1"); + // TODO: is this the right element for this attribute? + $ariaElem + .attr("aria-activedescendant", true); +// .attr("tabindex", "-1"); + } + }else if(aria){ +// $(">span.fancytree-title", statusElem).attr("tabindex", "-1"); + $ariaElem + .removeAttr("aria-activedescendant"); +// .removeAttr("tabindex"); + } + if( node.expanded ){ + cnList.push(cn.expanded); + if(aria){ + $ariaElem.attr("aria-expanded", true); + } + }else if(aria){ + $ariaElem.removeAttr("aria-expanded"); + } + if( node.folder ){ + cnList.push(cn.folder); + } + if( hasChildren !== false ){ + cnList.push(cn.hasChildren); + } + // TODO: required? + if( isLastSib ){ + cnList.push(cn.lastsib); + } + if( node.lazy && node.children == null ){ + cnList.push(cn.lazy); + } + if( node.partsel ){ + cnList.push(cn.partsel); + } + if( node.unselectable ){ + cnList.push(cn.unselectable); + } + if( node._isLoading ){ + cnList.push(cn.loading); + } + if( node._error ){ + cnList.push(cn.error); + } + if( node.selected ){ + cnList.push(cn.selected); + if(aria){ + $ariaElem.attr("aria-selected", true); + } + }else if(aria){ + $ariaElem.attr("aria-selected", false); + } + if( node.extraClasses ){ + cnList.push(node.extraClasses); + } + // IE6 doesn't correctly evaluate multiple class names, + // so we create combined class names that can be used in the CSS + if( hasChildren === false ){ + cnList.push(cn.combinedExpanderPrefix + "n" + + (isLastSib ? "l" : "") + ); + }else{ + cnList.push(cn.combinedExpanderPrefix + + (node.expanded ? "e" : "c") + + (node.lazy && node.children == null ? "d" : "") + + (isLastSib ? "l" : "") + ); + } + cnList.push(cn.combinedIconPrefix + + (node.expanded ? "e" : "c") + + (node.folder ? "f" : "") + ); +// node.span.className = cnList.join(" "); + statusElem.className = cnList.join(" "); + + // TODO: we should not set this in the <span> tag also, if we set it here: + // Maybe most (all) of the classes should be set in LI instead of SPAN? + if(node.li){ + node.li.className = isLastSib ? cn.lastsib : ""; + } + }, + /** Activate node. + * flag defaults to true. + * If flag is true, the node is activated (must be a synchronous operation) + * If flag is false, the node is deactivated (must be a synchronous operation) + * @param {EventData} ctx + * @param {boolean} [flag=true] + * @param {object} [opts] additional options. Defaults to {noEvents: false, noFocus: false} + * @returns {$.Promise} + */ + nodeSetActive: function(ctx, flag, callOpts) { + // Handle user click / [space] / [enter], according to clickFolderMode. + callOpts = callOpts || {}; + var subCtx, + node = ctx.node, + tree = ctx.tree, + opts = ctx.options, + noEvents = (callOpts.noEvents === true), + noFocus = (callOpts.noFocus === true), + isActive = (node === tree.activeNode); + + // flag defaults to true + flag = (flag !== false); + // node.debug("nodeSetActive", flag); + + if(isActive === flag){ + // Nothing to do + return _getResolvedPromise(node); + }else if(flag && !noEvents && this._triggerNodeEvent("beforeActivate", node, ctx.originalEvent) === false ){ + // Callback returned false + return _getRejectedPromise(node, ["rejected"]); + } + if(flag){ + if(tree.activeNode){ + _assert(tree.activeNode !== node, "node was active (inconsistency)"); + subCtx = $.extend({}, ctx, {node: tree.activeNode}); + tree.nodeSetActive(subCtx, false); + _assert(tree.activeNode === null, "deactivate was out of sync?"); + } + if(opts.activeVisible){ + // tree.nodeMakeVisible(ctx); + node.makeVisible({scrollIntoView: false}); // nodeSetFocus will scroll + } + tree.activeNode = node; + tree.nodeRenderStatus(ctx); + if( !noFocus ) { + tree.nodeSetFocus(ctx); + } + if( !noEvents ) { + tree._triggerNodeEvent("activate", node, ctx.originalEvent); + } + }else{ + _assert(tree.activeNode === node, "node was not active (inconsistency)"); + tree.activeNode = null; + this.nodeRenderStatus(ctx); + if( !noEvents ) { + ctx.tree._triggerNodeEvent("deactivate", node, ctx.originalEvent); + } + } + return _getResolvedPromise(node); + }, + /** Expand or collapse node, return Deferred.promise. + * + * @param {EventData} ctx + * @param {boolean} [flag=true] + * @param {object} [opts] additional options. Defaults to {noAnimation: false, noEvents: false} + * @returns {$.Promise} The deferred will be resolved as soon as the (lazy) + * data was retrieved, rendered, and the expand animation finshed. + */ + nodeSetExpanded: function(ctx, flag, callOpts) { + callOpts = callOpts || {}; + var _afterLoad, dfd, i, l, parents, prevAC, + node = ctx.node, + tree = ctx.tree, + opts = ctx.options, + noAnimation = (callOpts.noAnimation === true), + noEvents = (callOpts.noEvents === true); + + // flag defaults to true + flag = (flag !== false); + + // node.debug("nodeSetExpanded(" + flag + ")"); + + if((node.expanded && flag) || (!node.expanded && !flag)){ + // Nothing to do + // node.debug("nodeSetExpanded(" + flag + "): nothing to do"); + return _getResolvedPromise(node); + }else if(flag && !node.lazy && !node.hasChildren() ){ + // Prevent expanding of empty nodes + // return _getRejectedPromise(node, ["empty"]); + return _getResolvedPromise(node); + }else if( !flag && node.getLevel() < opts.minExpandLevel ) { + // Prevent collapsing locked levels + return _getRejectedPromise(node, ["locked"]); + }else if ( !noEvents && this._triggerNodeEvent("beforeExpand", node, ctx.originalEvent) === false ){ + // Callback returned false + return _getRejectedPromise(node, ["rejected"]); + } + // If this node inside a collpased node, no animation and scrolling is needed + if( !noAnimation && !node.isVisible() ) { + noAnimation = callOpts.noAnimation = true; + } + + dfd = new $.Deferred(); + + // Auto-collapse mode: collapse all siblings + if( flag && !node.expanded && opts.autoCollapse ) { + parents = node.getParentList(false, true); + prevAC = opts.autoCollapse; + try{ + opts.autoCollapse = false; + for(i=0, l=parents.length; i<l; i++){ + // TODO: should return promise? + this._callHook("nodeCollapseSiblings", parents[i], callOpts); + } + }finally{ + opts.autoCollapse = prevAC; + } + } + // Trigger expand/collapse after expanding + dfd.done(function(){ + var lastChild = node.getLastChild(); + if( flag && opts.autoScroll && !noAnimation && lastChild ) { + // Scroll down to last child, but keep current node visible + lastChild.scrollIntoView(true, {topNode: node}).always(function(){ + if( !noEvents ) { + ctx.tree._triggerNodeEvent(flag ? "expand" : "collapse", ctx); + } + }); + } else { + if( !noEvents ) { + ctx.tree._triggerNodeEvent(flag ? "expand" : "collapse", ctx); + } + } + }); + // vvv Code below is executed after loading finished: + _afterLoad = function(callback){ + var isVisible, isExpanded, + effect = opts.toggleEffect; + + node.expanded = flag; + // Create required markup, but make sure the top UL is hidden, so we + // can animate later + tree._callHook("nodeRender", ctx, false, false, true); + + // If the currently active node is now hidden, deactivate it + // if( opts.activeVisible && this.activeNode && ! this.activeNode.isVisible() ) { + // this.activeNode.deactivate(); + // } + + // Expanding a lazy node: set 'loading...' and call callback + // if( bExpand && this.data.isLazy && this.childList === null && !this._isLoading ) { + // this._loadContent(); + // return; + // } + // Hide children, if node is collapsed + if( node.ul ) { + isVisible = (node.ul.style.display !== "none"); + isExpanded = !!node.expanded; + if ( isVisible === isExpanded ) { + node.warn("nodeSetExpanded: UL.style.display already set"); + + } else if ( !effect || noAnimation ) { + node.ul.style.display = ( node.expanded || !parent ) ? "" : "none"; + + } else { + // The UI toggle() effect works with the ext-wide extension, + // while jQuery.animate() has problems when the title span + // has positon: absolute + + // duration = opts.fx.duration || 200; + // easing = opts.fx.easing; + // $(node.ul).animate(opts.fx, duration, easing, function(){ + + // node.debug("nodeSetExpanded: animate start..."); + $(node.ul).toggle(effect.effect, effect.options, effect.duration, function(){ + // node.debug("nodeSetExpanded: animate done"); + callback(); + }); + return; + } + } + callback(); + }; + // ^^^ Code above is executed after loading finshed. + + // Load lazy nodes, if any. Then continue with _afterLoad() + if(flag && node.lazy && node.hasChildren() === undefined){ + // node.debug("nodeSetExpanded: load start..."); + node.load().done(function(){ + // node.debug("nodeSetExpanded: load done"); + if(dfd.notifyWith){ // requires jQuery 1.6+ + dfd.notifyWith(node, ["loaded"]); + } + _afterLoad(function () { dfd.resolveWith(node); }); + }).fail(function(errMsg){ + _afterLoad(function () { dfd.rejectWith(node, ["load failed (" + errMsg + ")"]); }); + }); +/* + var source = tree._triggerNodeEvent("lazyLoad", node, ctx.originalEvent); + _assert(typeof source !== "boolean", "lazyLoad event must return source in data.result"); + node.debug("nodeSetExpanded: load start..."); + this._callHook("nodeLoadChildren", ctx, source).done(function(){ + node.debug("nodeSetExpanded: load done"); + if(dfd.notifyWith){ // requires jQuery 1.6+ + dfd.notifyWith(node, ["loaded"]); + } + _afterLoad.call(tree); + }).fail(function(errMsg){ + dfd.rejectWith(node, ["load failed (" + errMsg + ")"]); + }); +*/ + }else{ + _afterLoad(function () { dfd.resolveWith(node); }); + } + // node.debug("nodeSetExpanded: returns"); + return dfd.promise(); + }, + /** Focus or blur this node. + * @param {EventData} ctx + * @param {boolean} [flag=true] + */ + nodeSetFocus: function(ctx, flag) { + // ctx.node.debug("nodeSetFocus(" + flag + ")"); + var ctx2, + tree = ctx.tree, + node = ctx.node; + + flag = (flag !== false); + + // Blur previous node if any + if(tree.focusNode){ + if(tree.focusNode === node && flag){ + // node.debug("nodeSetFocus(" + flag + "): nothing to do"); + return; + } + ctx2 = $.extend({}, ctx, {node: tree.focusNode}); + tree.focusNode = null; + this._triggerNodeEvent("blur", ctx2); + this._callHook("nodeRenderStatus", ctx2); + } + // Set focus to container and node + if(flag){ + if( !this.hasFocus() ){ + node.debug("nodeSetFocus: forcing container focus"); + this._callHook("treeSetFocus", ctx, true, {calledByNode: true}); + } + node.makeVisible({scrollIntoView: false}); + tree.focusNode = node; +// node.debug("FOCUS..."); +// $(node.span).find(".fancytree-title").focus(); + this._triggerNodeEvent("focus", ctx); +// if(ctx.options.autoActivate){ +// tree.nodeSetActive(ctx, true); +// } + if(ctx.options.autoScroll){ + node.scrollIntoView(); + } + this._callHook("nodeRenderStatus", ctx); + } + }, + /** (De)Select node, return new status (sync). + * + * @param {EventData} ctx + * @param {boolean} [flag=true] + */ + nodeSetSelected: function(ctx, flag) { + var node = ctx.node, + tree = ctx.tree, + opts = ctx.options; + // flag defaults to true + flag = (flag !== false); + + node.debug("nodeSetSelected(" + flag + ")", ctx); + if( node.unselectable){ + return; + } + // TODO: !!node.expanded is nicer, but doesn't pass jshint + // https://github.com/jshint/jshint/issues/455 +// if( !!node.expanded === !!flag){ + if((node.selected && flag) || (!node.selected && !flag)){ + return !!node.selected; + }else if ( this._triggerNodeEvent("beforeSelect", node, ctx.originalEvent) === false ){ + return !!node.selected; + } + if(flag && opts.selectMode === 1){ + // single selection mode + if(tree.lastSelectedNode){ + tree.lastSelectedNode.setSelected(false); + } + }else if(opts.selectMode === 3){ + // multi.hier selection mode + node.selected = flag; +// this._fixSelectionState(node); + node.fixSelection3AfterClick(); + } + node.selected = flag; + this.nodeRenderStatus(ctx); + tree.lastSelectedNode = flag ? node : null; + tree._triggerNodeEvent("select", ctx); + }, + /** Show node status (ok, loading, error) using styles and a dummy child node. + * + * @param {EventData} ctx + * @param status + * @param message + * @param details + * @since 2.3 + */ + nodeSetStatus: function(ctx, status, message, details) { + var node = ctx.node, + tree = ctx.tree; + // cn = ctx.options._classNames; + + function _clearStatusNode() { + // Remove dedicated dummy node, if any + var firstChild = ( node.children ? node.children[0] : null ); + if ( firstChild && firstChild.isStatusNode() ) { + try{ + // I've seen exceptions here with loadKeyPath... + if(node.ul){ + node.ul.removeChild(firstChild.li); + firstChild.li = null; // avoid leaks (DT issue 215) + } + }catch(e){} + if( node.children.length === 1 ){ + node.children = []; + }else{ + node.children.shift(); + } + } + } + function _setStatusNode(data, type) { + // Create/modify the dedicated dummy node for 'loading...' or + // 'error!' status. (only called for direct child of the invisible + // system root) + var firstChild = ( node.children ? node.children[0] : null ); + if ( firstChild && firstChild.isStatusNode() ) { + $.extend(firstChild, data); + // tree._callHook("nodeRender", firstChild); + tree._callHook("nodeRenderTitle", firstChild); + } else { + data.key = "_statusNode"; + node._setChildren([data]); + node.children[0].statusNodeType = type; + tree.render(); + } + return node.children[0]; + } + + switch( status ){ + case "ok": + _clearStatusNode(); + // $(node.span).removeClass(cn.loading).removeClass(cn.error); + node._isLoading = false; + node._error = null; + node.renderStatus(); + break; + case "loading": + // $(node.span).removeClass(cn.error).addClass(cn.loading); + if( !node.parent ) { + _setStatusNode({ + title: tree.options.strings.loading + (message ? " (" + message + ") " : ""), + tooltip: details, + extraClasses: "fancytree-statusnode-wait" + }, status); + } + node._isLoading = true; + node._error = null; + node.renderStatus(); + break; + case "error": + // $(node.span).removeClass(cn.loading).addClass(cn.error); + _setStatusNode({ + title: tree.options.strings.loadError + (message ? " (" + message + ") " : ""), + tooltip: details, + extraClasses: "fancytree-statusnode-error" + }, status); + node._isLoading = false; + node._error = { message: message, details: details }; + node.renderStatus(); + break; + default: + $.error("invalid node status " + status); + } + }, + /** + * + * @param {EventData} ctx + */ + nodeToggleExpanded: function(ctx) { + return this.nodeSetExpanded(ctx, !ctx.node.expanded); + }, + /** + * @param {EventData} ctx + */ + nodeToggleSelected: function(ctx) { + return this.nodeSetSelected(ctx, !ctx.node.selected); + }, + /** Remove all nodes. + * @param {EventData} ctx + */ + treeClear: function(ctx) { + var tree = ctx.tree; + tree.activeNode = null; + tree.focusNode = null; + tree.$div.find(">ul.fancytree-container").empty(); + // TODO: call destructors and remove reference loops + tree.rootNode.children = null; + }, + /** Widget was created (called only once, even it re-initialized). + * @param {EventData} ctx + */ + treeCreate: function(ctx) { + }, + /** Widget was destroyed. + * @param {EventData} ctx + */ + treeDestroy: function(ctx) { + this.$div.find(">ul.fancytree-container").remove(); + this.$source && this.$source.removeClass("ui-helper-hidden"); + }, + /** Widget was (re-)initialized. + * @param {EventData} ctx + */ + treeInit: function(ctx) { + //this.debug("Fancytree.treeInit()"); + this.treeLoad(ctx); + }, + /** Parse Fancytree from source, as configured in the options. + * @param {EventData} ctx + * @param {object} [source] optional new source (use last data otherwise) + */ + treeLoad: function(ctx, source) { + var type, $ul, + tree = ctx.tree, + $container = ctx.widget.element, + dfd, + // calling context for root node + rootCtx = $.extend({}, ctx, {node: this.rootNode}); + + if(tree.rootNode.children){ + this.treeClear(ctx); + } + source = source || this.options.source; + + if(!source){ + type = $container.data("type") || "html"; + switch(type){ + case "html": + $ul = $container.find(">ul:first"); + $ul.addClass("ui-fancytree-source ui-helper-hidden"); + source = $.ui.fancytree.parseHtml($ul); + // allow to init tree.data.foo from <ul data-foo=''> + this.data = $.extend(this.data, _getElementDataAsDict($ul)); + break; + case "json": + // $().addClass("ui-helper-hidden"); + source = $.parseJSON($container.text()); + if(source.children){ + if(source.title){tree.title = source.title;} + source = source.children; + } + break; + default: + $.error("Invalid data-type: " + type); + } + }else if(typeof source === "string"){ + // TODO: source is an element ID + $.error("Not implemented"); + } + + // Trigger fancytreeinit after nodes have been loaded + dfd = this.nodeLoadChildren(rootCtx, source).done(function(){ + tree.render(); + if( ctx.options.selectMode === 3 ){ + tree.rootNode.fixSelection3FromEndNodes(); + } + if( tree.activeNode && tree.options.activeVisible ) { + tree.activeNode.makeVisible(); + } + tree._triggerTreeEvent("init", null, { status: true }); + }).fail(function(){ + tree.render(); + tree._triggerTreeEvent("init", null, { status: false }); + }); + return dfd; + }, + /** Node was inserted into or removed from the tree. + * @param {EventData} ctx + * @param {boolean} add + * @param {FancytreeNode} node + */ + treeRegisterNode: function(ctx, add, node) { + }, + /** Widget got focus. + * @param {EventData} ctx + * @param {boolean} [flag=true] + */ + treeSetFocus: function(ctx, flag, callOpts) { + flag = (flag !== false); + + // this.debug("treeSetFocus(" + flag + "), callOpts: " + callOpts, this.hasFocus()); + // this.debug(" focusNode: " + this.focusNode); + // this.debug(" activeNode: " + this.activeNode); + if( flag !== this.hasFocus() ){ + this._hasFocus = flag; + if( !flag && this.focusNode ) { + // Node also looses focus if widget blurs + this.focusNode.setFocus(false); + } + this.$container.toggleClass("fancytree-treefocus", flag); + this._triggerTreeEvent(flag ? "focusTree" : "blurTree"); + } + } +}); + + +/* ****************************************************************************** + * jQuery UI widget boilerplate + */ + +/** + * The plugin (derrived from <a href=" http://api.jqueryui.com/jQuery.widget/">jQuery.Widget</a>).<br> + * This constructor is not called directly. Use `$(selector).fancytree({})` + * to initialize the plugin instead.<br> + * <pre class="sh_javascript sunlight-highlight-javascript">// Access widget methods and members: + * var tree = $("#tree").fancytree("getTree"); + * var node = $("#tree").fancytree("getActiveNode", "1234"); + * </pre> + * + * @mixin Fancytree_Widget + */ + +$.widget("ui.fancytree", + /** @lends Fancytree_Widget# */ + { + /**These options will be used as defaults + * @type {FancytreeOptions} + */ + options: + { + activeVisible: true, + ajax: { + type: "GET", + cache: false, // false: Append random '_' argument to the request url to prevent caching. +// timeout: 0, // >0: Make sure we get an ajax error if server is unreachable + dataType: "json" // Expect json format and pass json object to callbacks. + }, // + aria: false, // TODO: default to true + autoActivate: true, + autoCollapse: false, +// autoFocus: false, + autoScroll: false, + checkbox: false, + /**defines click behavior*/ + clickFolderMode: 4, + debugLevel: null, // 0..2 (null: use global setting $.ui.fancytree.debugInfo) + disabled: false, // TODO: required anymore? + enableAspx: true, // TODO: document + extensions: [], + // fx: { height: "toggle", duration: 200 }, + // toggleEffect: { effect: "drop", options: {direction: "left"}, duration: 200 }, + // toggleEffect: { effect: "slide", options: {direction: "up"}, duration: 200 }, + toggleEffect: { effect: "blind", options: {direction: "vertical", scale: "box"}, duration: 200 }, + generateIds: false, + icons: true, + idPrefix: "ft_", + focusOnSelect: false, + keyboard: true, + keyPathSeparator: "/", + minExpandLevel: 1, + quicksearch: false, + scrollOfs: {top: 0, bottom: 0}, + scrollParent: null, + selectMode: 2, + strings: { + loading: "Loading…", + loadError: "Load error!" + }, + tabbable: true, + titlesTabbable: false, + _classNames: { + node: "fancytree-node", + folder: "fancytree-folder", + combinedExpanderPrefix: "fancytree-exp-", + combinedIconPrefix: "fancytree-ico-", + hasChildren: "fancytree-has-children", + active: "fancytree-active", + selected: "fancytree-selected", + expanded: "fancytree-expanded", + lazy: "fancytree-lazy", + focused: "fancytree-focused", + partsel: "fancytree-partsel", + unselectable: "fancytree-unselectable", + lastsib: "fancytree-lastsib", + loading: "fancytree-loading", + error: "fancytree-error" + }, + // events + lazyLoad: null, + postProcess: null + }, + /* Set up the widget, Called on first $().fancytree() */ + _create: function() { + this.tree = new Fancytree(this); + + this.$source = this.source || this.element.data("type") === "json" ? this.element + : this.element.find(">ul:first"); + // Subclass Fancytree instance with all enabled extensions + var extension, extName, i, + extensions = this.options.extensions, + base = this.tree; + + for(i=0; i<extensions.length; i++){ + extName = extensions[i]; + extension = $.ui.fancytree._extensions[extName]; + if(!extension){ + $.error("Could not apply extension '" + extName + "' (it is not registered, did you forget to include it?)"); + } + // Add extension options as tree.options.EXTENSION +// _assert(!this.tree.options[extName], "Extension name must not exist as option name: " + extName); + this.tree.options[extName] = $.extend(true, {}, extension.options, this.tree.options[extName]); + // Add a namespace tree.ext.EXTENSION, to hold instance data + _assert(this.tree.ext[extName] === undefined, "Extension name must not exist as Fancytree.ext attribute: '" + extName + "'"); +// this.tree[extName] = extension; + this.tree.ext[extName] = {}; + // Subclass Fancytree methods using proxies. + _subclassObject(this.tree, base, extension, extName); + // current extension becomes base for the next extension + base = extension; + } + // + this.tree._callHook("treeCreate", this.tree); + // Note: 'fancytreecreate' event is fired by widget base class +// this.tree._triggerTreeEvent("create"); + }, + + /* Called on every $().fancytree() */ + _init: function() { + this.tree._callHook("treeInit", this.tree); + // TODO: currently we call bind after treeInit, because treeInit + // might change tree.$container. + // It would be better, to move ebent binding into hooks altogether + this._bind(); + }, + + /* Use the _setOption method to respond to changes to options */ + _setOption: function(key, value) { + var callDefault = true, + rerender = false; + switch( key ) { + case "aria": + case "checkbox": + case "icons": + case "minExpandLevel": + case "tabbable": +// case "nolink": + this.tree._callHook("treeCreate", this.tree); + rerender = true; + break; + case "source": + callDefault = false; + this.tree._callHook("treeLoad", this.tree, value); + break; + } + this.tree.debug("set option " + key + "=" + value + " <" + typeof(value) + ">"); + if(callDefault){ + // In jQuery UI 1.8, you have to manually invoke the _setOption method from the base widget + $.Widget.prototype._setOption.apply(this, arguments); + // TODO: In jQuery UI 1.9 and above, you use the _super method instead +// this._super( "_setOption", key, value ); + } + if(rerender){ + this.tree.render(true, false); // force, not-deep + } + }, + + /** Use the destroy method to clean up any modifications your widget has made to the DOM */ + destroy: function() { + this._unbind(); + this.tree._callHook("treeDestroy", this.tree); + // In jQuery UI 1.8, you must invoke the destroy method from the base widget + $.Widget.prototype.destroy.call(this); + // TODO: delete tree and nodes to make garbage collect easier? + // TODO: In jQuery UI 1.9 and above, you would define _destroy instead of destroy and not call the base method + }, + + // ------------------------------------------------------------------------- + + /* Remove all event handlers for our namespace */ + _unbind: function() { + var ns = this.tree._ns; + this.element.unbind(ns); + this.tree.$container.unbind(ns); + $(document).unbind(ns); + }, + /* Add mouse and kyboard handlers to the container */ + _bind: function() { + var that = this, + opts = this.options, + tree = this.tree, + ns = tree._ns + // selstartEvent = ( $.support.selectstart ? "selectstart" : "mousedown" ) + ; + + // Remove all previuous handlers for this tree + this._unbind(); + + //alert("keydown" + ns + "foc=" + tree.hasFocus() + tree.$container); + // tree.debug("bind events; container: ", tree.$container); + tree.$container.on("focusin" + ns + " focusout" + ns, function(event){ + var node = FT.getNode(event), + flag = (event.type === "focusin"); + // tree.debug("Tree container got event " + event.type, node, event); + // tree.treeOnFocusInOut.call(tree, event); + if(node){ + // For example clicking into an <input> that is part of a node + tree._callHook("nodeSetFocus", node, flag); + }else{ + tree._callHook("treeSetFocus", tree, flag); + } + }).on("selectstart" + ns, "span.fancytree-title", function(event){ + // prevent mouse-drags to select text ranges + // tree.debug("<span title> got event " + event.type); + event.preventDefault(); + }).on("keydown" + ns, function(event){ + // TODO: also bind keyup and keypress + // tree.debug("got event " + event.type + ", hasFocus:" + tree.hasFocus()); + // if(opts.disabled || opts.keyboard === false || !tree.hasFocus() ){ + if(opts.disabled || opts.keyboard === false ){ + return true; + } + var res, + node = tree.focusNode, // node may be null + ctx = tree._makeHookContext(node || tree, event), + prevPhase = tree.phase; + + try { + tree.phase = "userEvent"; + // If a 'fancytreekeydown' handler returns false, skip the default + // handling (implemented by tree.nodeKeydown()). + if(node){ + res = tree._triggerNodeEvent("keydown", node, event); + }else{ + res = tree._triggerTreeEvent("keydown", event); + } + if ( res === "preventNav" ){ + res = true; // prevent keyboard navigation, but don't prevent default handling of embedded input controls + } else if ( res !== false ){ + res = tree._callHook("nodeKeydown", ctx); + } + return res; + } finally { + tree.phase = prevPhase; + } + }).on("click" + ns + " dblclick" + ns, function(event){ + // that.tree.debug("event(" + event + "): !"); + if(opts.disabled){ + return true; + } + var ctx, + et = FT.getEventTarget(event), + node = et.node, + tree = that.tree, + prevPhase = tree.phase; + + // that.tree.debug("event(" + event.type + "): node: ", node); + if( !node ){ + return true; // Allow bubbling of other events + } + ctx = tree._makeHookContext(node, event); +// that.tree.debug("event(" + event.type + "): node: ", node); + try { + tree.phase = "userEvent"; + switch(event.type) { + case "click": + ctx.targetType = et.type; + return ( tree._triggerNodeEvent("click", ctx, event) === false ) ? false : tree._callHook("nodeClick", ctx); + case "dblclick": + ctx.targetType = et.type; + return ( tree._triggerNodeEvent("dblclick", ctx, event) === false ) ? false : tree._callHook("nodeDblclick", ctx); + } +// } catch(e) { +// // var _ = null; // DT issue 117 // TODO +// $.error(e); + } finally { + tree.phase = prevPhase; + } + }); + }, + /** Return the active node or null. + * @returns {FancytreeNode} + */ + getActiveNode: function() { + return this.tree.activeNode; + }, + /** Return the matching node or null. + * @param {string} key + * @returns {FancytreeNode} + */ + getNodeByKey: function(key) { + return this.tree.getNodeByKey(key); + }, + /** Return the invisible system root node. + * @returns {FancytreeNode} + */ + getRootNode: function() { + return this.tree.rootNode; + }, + /** Return the current tree instance. + * @returns {Fancytree} + */ + getTree: function() { + return this.tree; + } +}); + +// $.ui.fancytree was created by the widget factory. Create a local shortcut: +FT = $.ui.fancytree; + +/** + * Static members in the `$.ui.fancytree` namespace.<br> + * <br> + * <pre class="sh_javascript sunlight-highlight-javascript">// Access static members: + * var node = $.ui.fancytree.getNode(element); + * alert($.ui.fancytree.version); + * </pre> + * + * @mixin Fancytree_Static + */ +$.extend($.ui.fancytree, + /** @lends Fancytree_Static# */ + { + /** @type {string} */ + version: "2.13.0", // Set to semver by 'grunt release' + /** @type {string} */ + buildType: "production", // Set to 'production' by 'grunt build' + /** @type {int} */ + debugLevel: 1, // Set to 1 by 'grunt build' + // Used by $.ui.fancytree.debug() and as default for tree.options.debugLevel + + _nextId: 1, + _nextNodeKey: 1, + _extensions: {}, + // focusTree: null, + + /** Expose class object as $.ui.fancytree._FancytreeClass */ + _FancytreeClass: Fancytree, + /** Expose class object as $.ui.fancytree._FancytreeNodeClass */ + _FancytreeNodeClass: FancytreeNode, + /* Feature checks to provide backwards compatibility */ + jquerySupports: { + // http://jqueryui.com/upgrade-guide/1.9/#deprecated-offset-option-merged-into-my-and-at + positionMyOfs: isVersionAtLeast($.ui.version, 1, 9) + }, + /** Throw an error if condition fails (debug method). + * @param {boolean} cond + * @param {string} msg + */ + assert: function(cond, msg){ + return _assert(cond, msg); + }, + /** Return a function that executes *fn* at most every *timeout* ms. + * @param {integer} timeout + * @param {function} fn + * @param {boolean} [invokeAsap=false] + * @param {any} [ctx] + */ + debounce: function(timeout, fn, invokeAsap, ctx) { + var timer; + if(arguments.length === 3 && typeof invokeAsap !== "boolean") { + ctx = invokeAsap; + invokeAsap = false; + } + return function() { + var args = arguments; + ctx = ctx || this; + invokeAsap && !timer && fn.apply(ctx, args); + clearTimeout(timer); + timer = setTimeout(function() { + invokeAsap || fn.apply(ctx, args); + timer = null; + }, timeout); + }; + }, + /** Write message to console if debugLevel >= 2 + * @param {string} msg + */ + debug: function(msg){ + /*jshint expr:true */ + ($.ui.fancytree.debugLevel >= 2) && consoleApply("log", arguments); + }, + /** Write error message to console. + * @param {string} msg + */ + error: function(msg){ + consoleApply("error", arguments); + }, + /** Convert <, >, &, ", ', / to the equivalent entities. + * + * @param {string} s + * @returns {string} + */ + escapeHtml: function(s){ + return ("" + s).replace(/[&<>"'\/]/g, function (s) { + return ENTITY_MAP[s]; + }); + }, + /** Make jQuery.position() arguments backwards compatible, i.e. if + * jQuery UI version <= 1.8, convert + * { my: "left+3 center", at: "left bottom", of: $target } + * to + * { my: "left center", at: "left bottom", of: $target, offset: "3 0" } + * + * See http://jqueryui.com/upgrade-guide/1.9/#deprecated-offset-option-merged-into-my-and-at + * and http://jsfiddle.net/mar10/6xtu9a4e/ + */ + fixPositionOptions: function(opts) { + if( opts.offset || ("" + opts.my + opts.at ).indexOf("%") >= 0 ) { + $.error("expected new position syntax (but '%' is not supported)"); + } + if( ! $.ui.fancytree.jquerySupports.positionMyOfs ) { + var // parse 'left+3 center' into ['left+3 center', 'left', '+3', 'center', undefined] + myParts = /(\w+)([+-]?\d+)?\s+(\w+)([+-]?\d+)?/.exec(opts.my), + atParts = /(\w+)([+-]?\d+)?\s+(\w+)([+-]?\d+)?/.exec(opts.at), + // convert to numbers + dx = (myParts[2] ? (+myParts[2]) : 0) + (atParts[2] ? (+atParts[2]) : 0), + dy = (myParts[4] ? (+myParts[4]) : 0) + (atParts[4] ? (+atParts[4]) : 0); + + opts = $.extend({}, opts, { // make a copy and overwrite + my: myParts[1] + " " + myParts[3], + at: atParts[1] + " " + atParts[3] + }); + if( dx || dy ) { + opts.offset = "" + dx + " " + dy; + } + } + return opts; + }, + /** Return a {node: FancytreeNode, type: TYPE} object for a mouse event. + * + * @param {Event} event Mouse event, e.g. click, ... + * @returns {string} 'title' | 'prefix' | 'expander' | 'checkbox' | 'icon' | undefined + */ + getEventTargetType: function(event){ + return this.getEventTarget(event).type; + }, + /** Return a {node: FancytreeNode, type: TYPE} object for a mouse event. + * + * @param {Event} event Mouse event, e.g. click, ... + * @returns {object} Return a {node: FancytreeNode, type: TYPE} object + * TYPE: 'title' | 'prefix' | 'expander' | 'checkbox' | 'icon' | undefined + */ + getEventTarget: function(event){ + var tcn = event && event.target ? event.target.className : "", + res = {node: this.getNode(event.target), type: undefined}; + // We use a fast version of $(res.node).hasClass() + // See http://jsperf.com/test-for-classname/2 + if( /\bfancytree-title\b/.test(tcn) ){ + res.type = "title"; + }else if( /\bfancytree-expander\b/.test(tcn) ){ + res.type = (res.node.hasChildren() === false ? "prefix" : "expander"); + }else if( /\bfancytree-checkbox\b/.test(tcn) || /\bfancytree-radio\b/.test(tcn) ){ + res.type = "checkbox"; + }else if( /\bfancytree-icon\b/.test(tcn) ){ + res.type = "icon"; + }else if( /\bfancytree-node\b/.test(tcn) ){ + // Somewhere near the title + res.type = "title"; + }else if( event && event.target && $(event.target).closest(".fancytree-title").length ) { + // #228: clicking an embedded element inside a title + res.type = "title"; + } + return res; + }, + /** Return a FancytreeNode instance from element, event, or jQuery object. + * + * @param {Element | jQueryObject | Event} el + * @returns {FancytreeNode} matching node or null + */ + getNode: function(el){ + if(el instanceof FancytreeNode){ + return el; // el already was a FancytreeNode + }else if(el.selector !== undefined){ + el = el[0]; // el was a jQuery object: use the DOM element + }else if(el.originalEvent !== undefined){ + el = el.target; // el was an Event + } + while( el ) { + if(el.ftnode) { + return el.ftnode; + } + el = el.parentNode; + } + return null; + }, + /** Return a Fancytree instance, from element, index, event, or jQueryObject. + * + * @param {Element | jQueryObject | Event | integer | string} [el] + * @returns {Fancytree} matching tree or null + * @example + * $.ui.fancytree.getTree(); // Get first Fancytree instance on page + * $.ui.fancytree.getTree(1); // Get second Fancytree instance on page + * $.ui.fancytree.getTree("#tree"); // Get tree for this matching element + * + * @since 2.13 + */ + getTree: function(el){ + var widget; + + if( el instanceof Fancytree ) { + return el; // el already was a Fancytree + } + if( el === undefined ) { + el = 0; // get first tree + } + if( typeof el === "number" ) { + el = $(".fancytree-container").eq(el); // el was an integer: return nth instance + } else if( typeof el === "string" ) { + el = $(el).eq(0); // el was a selector: use first match + } else if( el.selector !== undefined ) { + el = el.eq(0); // el was a jQuery object: use the first DOM element + } else if( el.originalEvent !== undefined ) { + el = $(el.target); // el was an Event + } + el = el.closest(":ui-fancytree"); + widget = el.data("ui-fancytree") || el.data("fancytree"); // the latter is required by jQuery <= 1.8 + return widget ? widget.tree : null; + }, + /** Write message to console if debugLevel >= 1 + * @param {string} msg + */ + info: function(msg){ + /*jshint expr:true */ + ($.ui.fancytree.debugLevel >= 1) && consoleApply("info", arguments); + }, + /** Convert a keydown or mouse event to a canonical string like 'ctrl+a', 'ctrl+shift+f2', 'shift+leftdblclick'. + * This is especially handy for switch-statements in event handlers. + * @param {event} + * @returns {string} + */ + eventToString: function(event) { + // Poor-man's hotkeys. See here for a complete implementation: + // https://github.com/jeresig/jquery.hotkeys + var which = event.which, + et = event.type, + s = []; + + if( event.altKey ) { s.push("alt"); } + if( event.ctrlKey ) { s.push("ctrl"); } + if( event.metaKey ) { s.push("meta"); } + if( event.shiftKey ) { s.push("shift"); } + + if( et === "click" || et === "dblclick" ) { + s.push(MOUSE_BUTTONS[event.button] + et); + } else { + if( !IGNORE_KEYCODES[which] ) { + s.push( SPECIAL_KEYCODES[which] || String.fromCharCode(which).toLowerCase() ); + } + } + return s.join("+"); + }, + /* @deprecated: use eventToString(event) instead. + */ + keyEventToString: function(event) { + this.warn("keyEventToString() is deprecated: use eventToString()"); + return this.eventToString(event); + }, + /** + * Parse tree data from HTML <ul> markup + * + * @param {jQueryObject} $ul + * @returns {NodeData[]} + */ + parseHtml: function($ul) { + // TODO: understand this: + /*jshint validthis:true */ + var classes, className, extraClasses, i, iPos, l, tmp, tmp2, + $children = $ul.find(">li"), + children = []; + + $children.each(function() { + var allData, lowerCaseAttr, + $li = $(this), + $liSpan = $li.find(">span:first", this), + $liA = $liSpan.length ? null : $li.find(">a:first"), + d = { tooltip: null, data: {} }; + + if( $liSpan.length ) { + d.title = $liSpan.html(); + + } else if( $liA && $liA.length ) { + // If a <li><a> tag is specified, use it literally and extract href/target. + d.title = $liA.html(); + d.data.href = $liA.attr("href"); + d.data.target = $liA.attr("target"); + d.tooltip = $liA.attr("title"); + + } else { + // If only a <li> tag is specified, use the trimmed string up to + // the next child <ul> tag. + d.title = $li.html(); + iPos = d.title.search(/<ul/i); + if( iPos >= 0 ){ + d.title = d.title.substring(0, iPos); + } + } + d.title = $.trim(d.title); + + // Make sure all fields exist + for(i=0, l=CLASS_ATTRS.length; i<l; i++){ + d[CLASS_ATTRS[i]] = undefined; + } + // Initialize to `true`, if class is set and collect extraClasses + classes = this.className.split(" "); + extraClasses = []; + for(i=0, l=classes.length; i<l; i++){ + className = classes[i]; + if(CLASS_ATTR_MAP[className]){ + d[className] = true; + }else{ + extraClasses.push(className); + } + } + d.extraClasses = extraClasses.join(" "); + + // Parse node options from ID, title and class attributes + tmp = $li.attr("title"); + if( tmp ){ + d.tooltip = tmp; // overrides <a title='...'> + } + tmp = $li.attr("id"); + if( tmp ){ + d.key = tmp; + } + // Add <li data-NAME='...'> as node.data.NAME + allData = _getElementDataAsDict($li); + if( allData && !$.isEmptyObject(allData) ) { + // #507: convert data-hidecheckbox (lower case) to hideCheckbox + for( lowerCaseAttr in NODE_ATTR_LOWERCASE_MAP ) { + if( allData.hasOwnProperty(lowerCaseAttr) ) { + allData[NODE_ATTR_LOWERCASE_MAP[lowerCaseAttr]] = allData[lowerCaseAttr]; + delete allData[lowerCaseAttr]; + } + } + // #56: Allow to set special node.attributes from data-... + for(i=0, l=NODE_ATTRS.length; i<l; i++){ + tmp = NODE_ATTRS[i]; + tmp2 = allData[tmp]; + if( tmp2 != null ) { + delete allData[tmp]; + d[tmp] = tmp2; + } + } + // All other data-... goes to node.data... + $.extend(d.data, allData); + } + // Recursive reading of child nodes, if LI tag contains an UL tag + $ul = $li.find(">ul:first"); + if( $ul.length ) { + d.children = $.ui.fancytree.parseHtml($ul); + }else{ + d.children = d.lazy ? undefined : null; + } + children.push(d); +// FT.debug("parse ", d, children); + }); + return children; + }, + /** Add Fancytree extension definition to the list of globally available extensions. + * + * @param {object} definition + */ + registerExtension: function(definition){ + _assert(definition.name != null, "extensions must have a `name` property."); + _assert(definition.version != null, "extensions must have a `version` property."); + $.ui.fancytree._extensions[definition.name] = definition; + }, + /** Inverse of escapeHtml(). + * + * @param {string} s + * @returns {string} + */ + unescapeHtml: function(s){ + var e = document.createElement("div"); + e.innerHTML = s; + return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue; + }, + /** Write warning message to console. + * @param {string} msg + */ + warn: function(msg){ + consoleApply("warn", arguments); + } +}); + +}(jQuery, window, document)); diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/jquery.fancytree.min.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/jquery.fancytree.min.js new file mode 100644 index 00000000000..13a2db40969 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/jquery.fancytree.min.js @@ -0,0 +1,14 @@ +/*! + * jquery.fancytree.js + * Tree view control with support for lazy loading and much more. + * https://github.com/mar10/fancytree/ + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ +!function(a,b,c,d){"use strict";function e(b,c){b||(c=c?": "+c:"",a.error("Fancytree assertion failed"+c))}function f(a,c){var d,e,f=b.console?b.console[a]:null;if(f)try{f.apply(b.console,c)}catch(g){for(e="",d=0;d<c.length;d++)e+=c[d];f(e)}}function g(a){return!(!a.tree||a.statusNodeType===d)}function h(b){var c,d,e,f=a.map(a.trim(b).split("."),function(a){return parseInt(a,10)}),g=a.map(Array.prototype.slice.call(arguments,1),function(a){return parseInt(a,10)});for(c=0;c<g.length;c++)if(d=f[c]||0,e=g[c]||0,d!==e)return d>e;return!0}function i(a,b,c,d,e){var f=function(){var c=b[a],f=d[a],g=b.ext[e],h=function(){return c.apply(b,arguments)},i=function(a){return c.apply(b,a)};return function(){var a=b._local,c=b._super,d=b._superApply;try{return b._local=g,b._super=h,b._superApply=i,f.apply(b,arguments)}finally{b._local=a,b._super=c,b._superApply=d}}}();return f}function j(b,c,d,e){for(var f in d)"function"==typeof d[f]?"function"==typeof b[f]?b[f]=i(f,b,c,d,e):"_"===f.charAt(0)?b.ext[e][f]=i(f,b,c,d,e):a.error("Could not override tree."+f+". Use prefix '_' to create tree."+e+"._"+f):"options"!==f&&(b.ext[e][f]=d[f])}function k(b,c){return b===d?a.Deferred(function(){this.resolve()}).promise():a.Deferred(function(){this.resolveWith(b,c)}).promise()}function l(b,c){return b===d?a.Deferred(function(){this.reject()}).promise():a.Deferred(function(){this.rejectWith(b,c)}).promise()}function m(a,b){return function(){a.resolveWith(b)}}function n(b){var c=a.extend({},b.data()),d=c.json;return delete c.fancytree,delete c.uiFancytree,d&&(delete c.json,c=a.extend(c,d)),c}function o(a){return a=a.toLowerCase(),function(b){return b.title.toLowerCase().indexOf(a)>=0}}function p(a){var b=new RegExp("^"+a,"i");return function(a){return b.test(a.title)}}function q(b,c){var d,f,g,h;for(this.parent=b,this.tree=b.tree,this.ul=null,this.li=null,this.statusNodeType=null,this._isLoading=!1,this._error=null,this.data={},d=0,f=B.length;f>d;d++)g=B[d],this[g]=c[g];c.data&&a.extend(this.data,c.data);for(g in c)C[g]||a.isFunction(c[g])||E[g]||(this.data[g]=c[g]);null==this.key?this.tree.options.defaultKey?(this.key=this.tree.options.defaultKey(this),e(this.key,"defaultKey() must return a unique key")):this.key="_"+u._nextNodeKey++:this.key=""+this.key,c.active&&(e(null===this.tree.activeNode,"only one active node allowed"),this.tree.activeNode=this),c.selected&&(this.tree.lastSelectedNode=this),h=c.children,h?h.length?this._setChildren(h):this.children=this.lazy?[]:null:this.children=null,this.tree._callHook("treeRegisterNode",this.tree,!0,this)}function r(b){this.widget=b,this.$div=b.element,this.options=b.options,this.options&&(a.isFunction(this.options.lazyload)&&!a.isFunction(this.options.lazyLoad)&&(this.options.lazyLoad=function(){return u.warn("The 'lazyload' event is deprecated since 2014-02-25. Use 'lazyLoad' (with uppercase L) instead."),b.options.lazyload.apply(this,arguments)}),a.isFunction(this.options.loaderror)&&a.error("The 'loaderror' event was renamed since 2014-07-03. Use 'loadError' (with uppercase E) instead."),this.options.fx!==d&&u.warn("The 'fx' options was replaced by 'toggleEffect' since 2014-11-30.")),this.ext={},this.data=n(this.$div),this._id=a.ui.fancytree._nextId++,this._ns=".fancytree-"+this._id,this.activeNode=null,this.focusNode=null,this._hasFocus=null,this.lastSelectedNode=null,this.systemFocusElement=null,this.lastQuicksearchTerm="",this.lastQuicksearchTime=0,this.statusClassPropName="span",this.ariaPropName="li",this.nodeContainerAttrName="li",this.$div.find(">ul.fancytree-container").remove();var c,e={tree:this};this.rootNode=new q(e,{title:"root",key:"root_"+this._id,children:null,expanded:!0}),this.rootNode.parent=null,c=a("<ul>",{"class":"ui-fancytree fancytree-container fancytree-plain"}).appendTo(this.$div),this.$container=c,this.rootNode.ul=c[0],null==this.options.debugLevel&&(this.options.debugLevel=u.debugLevel),this.$container.attr("tabindex",this.options.tabbable?"0":"-1"),this.options.aria&&this.$container.attr("role","tree").attr("aria-multiselectable",!0)}if(a.ui&&a.ui.fancytree)return void a.ui.fancytree.warn("Fancytree: ignored duplicate include");e(a.ui,"Fancytree requires jQuery UI (http://jqueryui.com)");var s,t,u=null,v={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"},w={16:!0,17:!0,18:!0},x={8:"backspace",9:"tab",10:"return",13:"return",19:"pause",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"insert",46:"del",59:";",61:"=",96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9",106:"*",107:"+",109:"-",110:".",111:"/",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:"scroll",173:"-",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},y={0:"",1:"left",2:"middle",3:"right"},z="active expanded focus folder hideCheckbox lazy selected unselectable".split(" "),A={},B="expanded extraClasses folder hideCheckbox key lazy refKey selected title tooltip unselectable".split(" "),C={},D={},E={active:!0,children:!0,data:!0,focus:!0};for(s=0;s<z.length;s++)A[z[s]]=!0;for(s=0;s<B.length;s++)t=B[s],C[t]=!0,t!==t.toLowerCase()&&(D[t.toLowerCase()]=t);q.prototype={_findDirectChild:function(a){var b,c,d=this.children;if(d)if("string"==typeof a){for(b=0,c=d.length;c>b;b++)if(d[b].key===a)return d[b]}else{if("number"==typeof a)return this.children[a];if(a.parent===this)return a}return null},_setChildren:function(a){e(a&&(!this.children||0===this.children.length),"only init supported"),this.children=[];for(var b=0,c=a.length;c>b;b++)this.children.push(new q(this,a[b]))},addChildren:function(b,c){var d,f,g,h=null,i=[];for(a.isPlainObject(b)&&(b=[b]),this.children||(this.children=[]),d=0,f=b.length;f>d;d++)i.push(new q(this,b[d]));return h=i[0],null==c?this.children=this.children.concat(i):(c=this._findDirectChild(c),g=a.inArray(c,this.children),e(g>=0,"insertBefore must be an existing child"),this.children.splice.apply(this.children,[g,0].concat(i))),(!this.parent||this.parent.ul||this.tr)&&this.render(),3===this.tree.options.selectMode&&this.fixSelection3FromEndNodes(),h},addNode:function(a,b){switch((b===d||"over"===b)&&(b="child"),b){case"after":return this.getParent().addChildren(a,this.getNextSibling());case"before":return this.getParent().addChildren(a,this);case"firstChild":var c=this.children?this.children[0]:null;return this.addChildren(a,c);case"child":case"over":return this.addChildren(a)}e(!1,"Invalid mode: "+b)},appendSibling:function(a){return this.addNode(a,"after")},applyPatch:function(b){if(null===b)return this.remove(),k(this);var c,d,e,f={children:!0,expanded:!0,parent:!0};for(c in b)e=b[c],f[c]||a.isFunction(e)||(C[c]?this[c]=e:this.data[c]=e);return b.hasOwnProperty("children")&&(this.removeChildren(),b.children&&this._setChildren(b.children)),this.isVisible()&&(this.renderTitle(),this.renderStatus()),d=b.hasOwnProperty("expanded")?this.setExpanded(b.expanded):k(this)},collapseSiblings:function(){return this.tree._callHook("nodeCollapseSiblings",this)},copyTo:function(a,b,c){return a.addNode(this.toDict(!0,c),b)},countChildren:function(a){var b,c,d,e=this.children;if(!e)return 0;if(d=e.length,a!==!1)for(b=0,c=d;c>b;b++)d+=e[b].countChildren();return d},debug:function(){this.tree.options.debugLevel>=2&&(Array.prototype.unshift.call(arguments,this.toString()),f("log",arguments))},discard:function(){return this.warn("FancytreeNode.discard() is deprecated since 2014-02-16. Use .resetLazy() instead."),this.resetLazy()},findAll:function(b){b=a.isFunction(b)?b:o(b);var c=[];return this.visit(function(a){b(a)&&c.push(a)}),c},findFirst:function(b){b=a.isFunction(b)?b:o(b);var c=null;return this.visit(function(a){return b(a)?(c=a,!1):void 0}),c},_changeSelectStatusAttrs:function(a){var b=!1;switch(a){case!1:b=this.selected||this.partsel,this.selected=!1,this.partsel=!1;break;case!0:b=!this.selected||!this.partsel,this.selected=!0,this.partsel=!0;break;case d:b=this.selected||!this.partsel,this.selected=!1,this.partsel=!0;break;default:e(!1,"invalid state: "+a)}return b&&this.renderStatus(),b},fixSelection3AfterClick:function(){var a=this.isSelected();this.visit(function(b){b._changeSelectStatusAttrs(a)}),this.fixSelection3FromEndNodes()},fixSelection3FromEndNodes:function(){function a(b){var c,e,f,g,h,i,j,k=b.children;if(k&&k.length){for(i=!0,j=!1,c=0,e=k.length;e>c;c++)f=k[c],g=a(f),g!==!1&&(j=!0),g!==!0&&(i=!1);h=i?!0:j?d:!1}else h=!!b.selected;return b._changeSelectStatusAttrs(h),h}e(3===this.tree.options.selectMode,"expected selectMode 3"),a(this),this.visitParents(function(a){var b,c,e,f,g=a.children,h=!0,i=!1;for(b=0,c=g.length;c>b;b++)e=g[b],(e.selected||e.partsel)&&(i=!0),e.unselectable||e.selected||(h=!1);f=h?!0:i?d:!1,a._changeSelectStatusAttrs(f)})},fromDict:function(b){for(var c in b)C[c]?this[c]=b[c]:"data"===c?a.extend(this.data,b.data):a.isFunction(b[c])||E[c]||(this.data[c]=b[c]);b.children&&(this.removeChildren(),this.addChildren(b.children)),this.renderTitle()},getChildren:function(){return this.hasChildren()===d?d:this.children},getFirstChild:function(){return this.children?this.children[0]:null},getIndex:function(){return a.inArray(this,this.parent.children)},getIndexHier:function(b){b=b||".";var c=[];return a.each(this.getParentList(!1,!0),function(a,b){c.push(b.getIndex()+1)}),c.join(b)},getKeyPath:function(a){var b=[],c=this.tree.options.keyPathSeparator;return this.visitParents(function(a){a.parent&&b.unshift(a.key)},!a),c+b.join(c)},getLastChild:function(){return this.children?this.children[this.children.length-1]:null},getLevel:function(){for(var a=0,b=this.parent;b;)a++,b=b.parent;return a},getNextSibling:function(){if(this.parent){var a,b,c=this.parent.children;for(a=0,b=c.length-1;b>a;a++)if(c[a]===this)return c[a+1]}return null},getParent:function(){return this.parent},getParentList:function(a,b){for(var c=[],d=b?this:this.parent;d;)(a||d.parent)&&c.unshift(d),d=d.parent;return c},getPrevSibling:function(){if(this.parent){var a,b,c=this.parent.children;for(a=1,b=c.length;b>a;a++)if(c[a]===this)return c[a-1]}return null},hasChildren:function(){return this.lazy?null==this.children?d:0===this.children.length?!1:1===this.children.length&&this.children[0].isStatusNode()?d:!0:!(!this.children||!this.children.length)},hasFocus:function(){return this.tree.hasFocus()&&this.tree.focusNode===this},info:function(){this.tree.options.debugLevel>=1&&(Array.prototype.unshift.call(arguments,this.toString()),f("info",arguments))},isActive:function(){return this.tree.activeNode===this},isChildOf:function(a){return this.parent&&this.parent===a},isDescendantOf:function(a){if(!a||a.tree!==this.tree)return!1;for(var b=this.parent;b;){if(b===a)return!0;b=b.parent}return!1},isExpanded:function(){return!!this.expanded},isFirstSibling:function(){var a=this.parent;return!a||a.children[0]===this},isFolder:function(){return!!this.folder},isLastSibling:function(){var a=this.parent;return!a||a.children[a.children.length-1]===this},isLazy:function(){return!!this.lazy},isLoaded:function(){return!this.lazy||this.hasChildren()!==d},isLoading:function(){return!!this._isLoading},isRoot:function(){return this.isRootNode()},isRootNode:function(){return this.tree.rootNode===this},isSelected:function(){return!!this.selected},isStatusNode:function(){return!!this.statusNodeType},isTopLevel:function(){return this.tree.rootNode===this.parent},isUndefined:function(){return this.hasChildren()===d},isVisible:function(){var a,b,c=this.getParentList(!1,!1);for(a=0,b=c.length;b>a;a++)if(!c[a].expanded)return!1;return!0},lazyLoad:function(a){return this.warn("FancytreeNode.lazyLoad() is deprecated since 2014-02-16. Use .load() instead."),this.load(a)},load:function(a){var b,c,d=this;return e(this.isLazy(),"load() requires a lazy node"),a||this.isUndefined()?(this.isLoaded()&&this.resetLazy(),c=this.tree._triggerNodeEvent("lazyLoad",this),c===!1?k(this):(e("boolean"!=typeof c,"lazyLoad event must return source in data.result"),b=this.tree._callHook("nodeLoadChildren",this,c),this.expanded&&b.always(function(){d.render()}),b)):k(this)},makeVisible:function(b){var c,d=this,e=[],f=new a.Deferred,g=this.getParentList(!1,!1),h=g.length,i=!(b&&b.noAnimation===!0),j=!(b&&b.scrollIntoView===!1);for(c=h-1;c>=0;c--)e.push(g[c].setExpanded(!0,b));return a.when.apply(a,e).done(function(){j?d.scrollIntoView(i).done(function(){f.resolve()}):f.resolve()}),f.promise()},moveTo:function(b,c,f){(c===d||"over"===c)&&(c="child");var g,h=this.parent,i="child"===c?b:b.parent;if(this!==b){if(!this.parent)throw"Cannot move system root";if(i.isDescendantOf(this))throw"Cannot move a node to its own descendant";if(1===this.parent.children.length){if(this.parent===i)return;this.parent.children=this.parent.lazy?[]:null,this.parent.expanded=!1}else g=a.inArray(this,this.parent.children),e(g>=0,"invalid source parent"),this.parent.children.splice(g,1);if(this.parent=i,i.hasChildren())switch(c){case"child":i.children.push(this);break;case"before":g=a.inArray(b,i.children),e(g>=0,"invalid target parent"),i.children.splice(g,0,this);break;case"after":g=a.inArray(b,i.children),e(g>=0,"invalid target parent"),i.children.splice(g+1,0,this);break;default:throw"Invalid mode "+c}else i.children=[this];f&&b.visit(f,!0),this.tree!==b.tree&&(this.warn("Cross-tree moveTo is experimantal!"),this.visit(function(a){a.tree=b.tree},!0)),h.isDescendantOf(i)||h.render(),i.isDescendantOf(h)||i===h||i.render()}},navigate:function(b,c){function d(d){if(d){try{d.makeVisible()}catch(e){}return a(d.span).is(":visible")?c===!1?d.setFocus():d.setActive():(d.debug("Navigate: skipping hidden node"),void d.navigate(b,c))}}var e,f,g=!0,h=a.ui.keyCode,i=null;switch(b){case h.BACKSPACE:this.parent&&this.parent.parent&&d(this.parent);break;case h.LEFT:this.expanded?(this.setExpanded(!1),d(this)):this.parent&&this.parent.parent&&d(this.parent);break;case h.RIGHT:this.expanded||!this.children&&!this.lazy?this.children&&this.children.length&&d(this.children[0]):(this.setExpanded(),d(this));break;case h.UP:for(i=this.getPrevSibling();i&&!a(i.span).is(":visible");)i=i.getPrevSibling();for(;i&&i.expanded&&i.children&&i.children.length;)i=i.children[i.children.length-1];!i&&this.parent&&this.parent.parent&&(i=this.parent),d(i);break;case h.DOWN:if(this.expanded&&this.children&&this.children.length)i=this.children[0];else for(f=this.getParentList(!1,!0),e=f.length-1;e>=0;e--){for(i=f[e].getNextSibling();i&&!a(i.span).is(":visible");)i=i.getNextSibling();if(i)break}d(i);break;default:g=!1}},remove:function(){return this.parent.removeChild(this)},removeChild:function(a){return this.tree._callHook("nodeRemoveChild",this,a)},removeChildren:function(){return this.tree._callHook("nodeRemoveChildren",this)},render:function(a,b){return this.tree._callHook("nodeRender",this,a,b)},renderTitle:function(){return this.tree._callHook("nodeRenderTitle",this)},renderStatus:function(){return this.tree._callHook("nodeRenderStatus",this)},resetLazy:function(){this.removeChildren(),this.expanded=!1,this.lazy=!0,this.children=d,this.renderStatus()},scheduleAction:function(a,b){this.tree.timer&&clearTimeout(this.tree.timer),this.tree.timer=null;var c=this;switch(a){case"cancel":break;case"expand":this.tree.timer=setTimeout(function(){c.tree.debug("setTimeout: trigger expand"),c.setExpanded(!0)},b);break;case"activate":this.tree.timer=setTimeout(function(){c.tree.debug("setTimeout: trigger activate"),c.setActive(!0)},b);break;default:throw"Invalid mode "+a}},scrollIntoView:function(f,h){h!==d&&g(h)&&(this.warn("scrollIntoView() with 'topNode' option is deprecated since 2014-05-08. Use 'options.topNode' instead."),h={topNode:h});var i,j,l,m,n=a.extend({effects:f===!0?{duration:200,queue:!1}:f,scrollOfs:this.tree.options.scrollOfs,scrollParent:this.tree.options.scrollParent||this.tree.$container,topNode:null},h),o=new a.Deferred,p=this,q=a(this.span).height(),r=a(n.scrollParent),s=n.scrollOfs.top||0,t=n.scrollOfs.bottom||0,u=r.height(),v=r.scrollTop(),w=r,x=r[0]===b,y=n.topNode||null,z=null;return a(this.span).is(":visible")?(x?(j=a(this.span).offset().top,i=y&&y.span?a(y.span).offset().top:0,w=a("html,body")):(e(r[0]!==c&&r[0]!==c.body,"scrollParent should be an simple element or `window`, not document or body."),m=r.offset().top,j=a(this.span).offset().top-m+v,i=y?a(y.span).offset().top-m+v:0,l=Math.max(0,r.innerHeight()-r[0].clientHeight),u-=l),v+s>j?z=j-s:j+q>v+u-t&&(z=j+q-u+t,y&&(e(y.isRootNode()||a(y.span).is(":visible"),"topNode must be visible"),z>i&&(z=i-s))),null!==z?n.effects?(n.effects.complete=function(){o.resolveWith(p)},w.stop(!0).animate({scrollTop:z},n.effects)):(w[0].scrollTop=z,o.resolveWith(this)):o.resolveWith(this),o.promise()):(this.warn("scrollIntoView(): node is invisible."),k())},setActive:function(a,b){return this.tree._callHook("nodeSetActive",this,a,b)},setExpanded:function(a,b){return this.tree._callHook("nodeSetExpanded",this,a,b)},setFocus:function(a){return this.tree._callHook("nodeSetFocus",this,a)},setSelected:function(a){return this.tree._callHook("nodeSetSelected",this,a)},setStatus:function(a,b,c){return this.tree._callHook("nodeSetStatus",this,a,b,c)},setTitle:function(a){this.title=a,this.renderTitle()},sortChildren:function(a,b){var c,d,e=this.children;if(e){if(a=a||function(a,b){var c=a.title.toLowerCase(),d=b.title.toLowerCase();return c===d?0:c>d?1:-1},e.sort(a),b)for(c=0,d=e.length;d>c;c++)e[c].children&&e[c].sortChildren(a,"$norender$");"$norender$"!==b&&this.render()}},toDict:function(b,c){var d,e,f,g={},h=this;if(a.each(B,function(a,b){(h[b]||h[b]===!1)&&(g[b]=h[b])}),a.isEmptyObject(this.data)||(g.data=a.extend({},this.data),a.isEmptyObject(g.data)&&delete g.data),c&&c(g,h),b&&this.hasChildren())for(g.children=[],d=0,e=this.children.length;e>d;d++)f=this.children[d],f.isStatusNode()||g.children.push(f.toDict(!0,c));return g},toggleExpanded:function(){return this.tree._callHook("nodeToggleExpanded",this)},toggleSelected:function(){return this.tree._callHook("nodeToggleSelected",this)},toString:function(){return"<FancytreeNode(#"+this.key+", '"+this.title+"')>"},visit:function(a,b){var c,d,e=!0,f=this.children;if(b===!0&&(e=a(this),e===!1||"skip"===e))return e;if(f)for(c=0,d=f.length;d>c&&(e=f[c].visit(a,!0),e!==!1);c++);return e},visitAndLoad:function(b,c,d){var e,f,g,h=this;return b&&c===!0&&(f=b(h),f===!1||"skip"===f)?d?f:k():h.children||h.lazy?(e=new a.Deferred,g=[],h.load().done(function(){for(var c=0,d=h.children.length;d>c;c++){if(f=h.children[c].visitAndLoad(b,!0,!0),f===!1){e.reject();break}"skip"!==f&&g.push(f)}a.when.apply(this,g).then(function(){e.resolve()})}),e.promise()):k()},visitParents:function(a,b){if(b&&a(this)===!1)return!1;for(var c=this.parent;c;){if(a(c)===!1)return!1;c=c.parent}return!0},warn:function(){Array.prototype.unshift.call(arguments,this.toString()),f("warn",arguments)}},r.prototype={_makeHookContext:function(b,c,e){var f,g;return b.node!==d?(c&&b.originalEvent!==c&&a.error("invalid args"),f=b):b.tree?(g=b.tree,f={node:b,tree:g,widget:g.widget,options:g.widget.options,originalEvent:c}):b.widget?f={node:null,tree:b,widget:b.widget,options:b.widget.options,originalEvent:c}:a.error("invalid args"),e&&a.extend(f,e),f},_callHook:function(b,c){var d=this._makeHookContext(c),e=this[b],f=Array.prototype.slice.call(arguments,2);return a.isFunction(e)||a.error("_callHook('"+b+"') is not a function"),f.unshift(d),e.apply(this,f)},_requireExtension:function(b,c,d,f){d=!!d;var g=this._local.name,h=this.options.extensions,i=a.inArray(b,h)<a.inArray(g,h),j=c&&null==this.ext[b],k=!j&&null!=d&&d!==i;return e(g&&g!==b,"invalid or same name"),j||k?(f||(j||c?(f="'"+g+"' extension requires '"+b+"'",k&&(f+=" to be registered "+(d?"before":"after")+" itself")):f="If used together, `"+b+"` must be registered "+(d?"before":"after")+" `"+g+"`"),a.error(f),!1):!0},activateKey:function(a){var b=this.getNodeByKey(a);return b?b.setActive():this.activeNode&&this.activeNode.setActive(!1),b},applyPatch:function(b){var c,d,f,g,h,i,j=b.length,k=[];for(d=0;j>d;d++)f=b[d],e(2===f.length,"patchList must be an array of length-2-arrays"),g=f[0],h=f[1],i=null===g?this.rootNode:this.getNodeByKey(g),i?(c=new a.Deferred,k.push(c),i.applyPatch(h).always(m(c,i))):this.warn("could not find node with key '"+g+"'");return a.when.apply(a,k).promise()},count:function(){return this.rootNode.countChildren()},debug:function(){this.options.debugLevel>=2&&(Array.prototype.unshift.call(arguments,this.toString()),f("log",arguments))},findAll:function(a){return this.rootNode.findAll(a)},findFirst:function(a){return this.rootNode.findFirst(a)},findNextNode:function(b,c){var d=null,e=c.parent.children,f=null,g=function(a,b,c){var d,e,f=a.children,h=f.length,i=f[b];if(i&&c(i)===!1)return!1;if(i&&i.children&&i.expanded&&g(i,0,c)===!1)return!1;for(d=b+1;h>d;d++)if(g(a,d,c)===!1)return!1;return e=a.parent,e?g(e,e.children.indexOf(a)+1,c):g(a,0,c)};return b="string"==typeof b?p(b):b,c=c||this.getFirstChild(),g(c.parent,e.indexOf(c),function(e){return e===d?!1:(d=d||e,a(e.span).is(":visible")?b(e)&&(f=e,f!==c)?!1:void 0:void e.debug("quicksearch: skipping hidden node"))}),f},generateFormElements:function(b,c,d){d=d||{};var e,f="string"==typeof b?b:"ft_"+this._id+"[]",g="string"==typeof c?c:"ft_"+this._id+"_active",h="fancytree_result_"+this._id,i=a("#"+h),j=3===this.options.selectMode&&d.stopOnParents!==!1;i.length?i.empty():i=a("<div>",{id:h}).hide().insertAfter(this.$container),b!==!1&&(e=this.getSelectedNodes(j),a.each(e,function(b,c){i.append(a("<input>",{type:"checkbox",name:f,value:c.key,checked:!0}))})),c!==!1&&this.activeNode&&i.append(a("<input>",{type:"radio",name:g,value:this.activeNode.key,checked:!0}))},getActiveNode:function(){return this.activeNode},getFirstChild:function(){return this.rootNode.getFirstChild()},getFocusNode:function(){return this.focusNode},getNodeByKey:function(a,b){var d,e;return!b&&(d=c.getElementById(this.options.idPrefix+a))?d.ftnode?d.ftnode:null:(b=b||this.rootNode,e=null,b.visit(function(b){return b.key===a?(e=b,!1):void 0},!0),e)},getRootNode:function(){return this.rootNode},getSelectedNodes:function(a){var b=[];return this.rootNode.visit(function(c){return c.selected&&(b.push(c),a===!0)?"skip":void 0}),b},hasFocus:function(){return!!this._hasFocus},info:function(){this.options.debugLevel>=1&&(Array.prototype.unshift.call(arguments,this.toString()),f("info",arguments))},loadKeyPath:function(b,c,e){function f(a,b,d){c.call(r,b,"loading"),b.load().done(function(){r.loadKeyPath.call(r,l[a],c,b).always(m(d,r))}).fail(function(){r.warn("loadKeyPath: error loading: "+a+" (parent: "+o+")"),c.call(r,b,"error"),d.reject()})}var g,h,i,j,k,l,n,o,p,q=this.options.keyPathSeparator,r=this;for(a.isArray(b)||(b=[b]),l={},i=0;i<b.length;i++)for(o=e||this.rootNode,j=b[i],j.charAt(0)===q&&(j=j.substr(1)),p=j.split(q);p.length;){if(k=p.shift(),n=o._findDirectChild(k),!n){this.warn("loadKeyPath: key not found: "+k+" (parent: "+o+")"),c.call(this,k,"error");break}if(0===p.length){c.call(this,n,"ok");break}if(n.lazy&&n.hasChildren()===d){c.call(this,n,"loaded"),l[k]?l[k].push(p.join(q)):l[k]=[p.join(q)];break}c.call(this,n,"loaded"),o=n}g=[];for(k in l)n=o._findDirectChild(k),h=new a.Deferred,g.push(h),f(k,n,h);return a.when.apply(a,g).promise()},reactivate:function(a){var b,c=this.activeNode;return c?(this.activeNode=null,b=c.setActive(),a&&c.setFocus(),b):k()},reload:function(a){return this._callHook("treeClear",this),this._callHook("treeLoad",this,a)},render:function(a,b){return this.rootNode.render(a,b)},setFocus:function(a){return this._callHook("treeSetFocus",this,a)},toDict:function(a,b){var c=this.rootNode.toDict(!0,b);return a?c:c.children},toString:function(){return"<Fancytree(#"+this._id+")>"},_triggerNodeEvent:function(a,b,c,e){var f=this._makeHookContext(b,c,e),g=this.widget._trigger(a,c,f);return g!==!1&&f.result!==d?f.result:g},_triggerTreeEvent:function(a,b,c){var e=this._makeHookContext(this,b,c),f=this.widget._trigger(a,b,e);return f!==!1&&e.result!==d?e.result:f},visit:function(a){return this.rootNode.visit(a,!1)},warn:function(){Array.prototype.unshift.call(arguments,this.toString()),f("warn",arguments)}},a.extend(r.prototype,{nodeClick:function(a){var b,c,d=a.targetType,e=a.node;if("expander"===d){if(e.isLoading())return void e.debug("Got 2nd click while loading: ignored");this._callHook("nodeToggleExpanded",a)}else if("checkbox"===d)this._callHook("nodeToggleSelected",a),a.options.focusOnSelect&&this._callHook("nodeSetFocus",a,!0);else{if(c=!1,b=!0,e.folder)switch(a.options.clickFolderMode){case 2:c=!0,b=!1;break;case 3:b=!0,c=!0}b&&(this.nodeSetFocus(a),this._callHook("nodeSetActive",a,!0)),c&&this._callHook("nodeToggleExpanded",a)}},nodeCollapseSiblings:function(a,b){var c,d,e,f=a.node;if(f.parent)for(c=f.parent.children,d=0,e=c.length;e>d;d++)c[d]!==f&&c[d].expanded&&this._callHook("nodeSetExpanded",c[d],!1,b)},nodeDblclick:function(a){"title"===a.targetType&&4===a.options.clickFolderMode&&this._callHook("nodeToggleExpanded",a),"title"===a.targetType&&a.originalEvent.preventDefault()},nodeKeydown:function(b){var c,d,e,f,g=b.originalEvent,h=b.node,i=b.tree,j=b.options,k=g.which,l=String.fromCharCode(k),m=!(g.altKey||g.ctrlKey||g.metaKey||g.shiftKey),n=a(g.target),o=!0,p=!(g.ctrlKey||!j.autoActivate);if(h||(f=this.getActiveNode()||this.getFirstChild(),f&&(f.setFocus(),h=b.node=this.focusNode,h.debug("Keydown force focus on active node"))),j.quicksearch&&m&&/\w/.test(l)&&!n.is(":input:enabled"))return d=(new Date).getTime(),d-i.lastQuicksearchTime>500&&(i.lastQuicksearchTerm=""),i.lastQuicksearchTime=d,i.lastQuicksearchTerm+=l,c=i.findNextNode(i.lastQuicksearchTerm,i.getActiveNode()),c&&c.setActive(),void g.preventDefault();switch(u.eventToString(g)){case"+":case"=":i.nodeSetExpanded(b,!0);break;case"-":i.nodeSetExpanded(b,!1);break;case"space":j.checkbox?i.nodeToggleSelected(b):i.nodeSetActive(b,!0);break;case"return":i.nodeSetActive(b,!0);break;case"backspace":case"left":case"right":case"up":case"down":e=h.navigate(g.which,p);break;default:o=!1}o&&g.preventDefault()},nodeLoadChildren:function(b,c){var d,f,g,h=b.tree,i=b.node;return a.isFunction(c)&&(c=c()),c.url&&(d=a.extend({},b.options.ajax,c),d.debugDelay?(f=d.debugDelay,a.isArray(f)&&(f=f[0]+Math.random()*(f[1]-f[0])),i.debug("nodeLoadChildren waiting debug delay "+Math.round(f)+"ms"),d.debugDelay=!1,g=a.Deferred(function(b){setTimeout(function(){a.ajax(d).done(function(){b.resolveWith(this,arguments)}).fail(function(){b.rejectWith(this,arguments)})},f)})):g=a.ajax(d),c=new a.Deferred,g.done(function(d){var e,f;if("json"===this.dataType&&"string"==typeof d&&a.error("Ajax request returned a string (did you get the JSON dataType wrong?)."),b.options.postProcess){if(f=h._triggerNodeEvent("postProcess",b,b.originalEvent,{response:d,error:null,dataType:this.dataType}),f.error)return e=a.isPlainObject(f.error)?f.error:{message:f.error},e=h._makeHookContext(i,null,e),void c.rejectWith(this,[e]);d=a.isArray(f)?f:d}else d&&d.hasOwnProperty("d")&&b.options.enableAspx&&(d="string"==typeof d.d?a.parseJSON(d.d):d.d);c.resolveWith(this,[d])}).fail(function(a,b,d){var e=h._makeHookContext(i,null,{error:a,args:Array.prototype.slice.call(arguments),message:d,details:a.status+": "+d});c.rejectWith(this,[e])})),a.isFunction(c.then)&&a.isFunction(c["catch"])&&(g=c,c=new a.Deferred,g.then(function(a){c.resolve(a)},function(a){c.reject(a)})),a.isFunction(c.promise)&&(e(!i.isLoading(),"recursive load"),h.nodeSetStatus(b,"loading"),c.done(function(){h.nodeSetStatus(b,"ok")}).fail(function(a){var c;c=a.node&&a.error&&a.message?a:h._makeHookContext(i,null,{error:a,args:Array.prototype.slice.call(arguments),message:a?a.message||a.toString():""}),h._triggerNodeEvent("loadError",c,null)!==!1&&h.nodeSetStatus(b,"error",c.message,c.details)})),a.when(c).done(function(b){var c;a.isPlainObject(b)&&(e(i.isRootNode(),"source may only be an object for root nodes (expecting an array of child objects otherwise)"),e(a.isArray(b.children),"if an object is passed as source, it must contain a 'children' array (all other properties are added to 'tree.data')"),c=b,b=b.children,delete c.children,a.extend(h.data,c)),e(a.isArray(b),"expected array of children"),i._setChildren(b),h._triggerNodeEvent("loadChildren",i)})},nodeLoadKeyPath:function(){},nodeRemoveChild:function(b,c){var d,f=b.node,g=b.options,h=a.extend({},b,{node:c}),i=f.children;return 1===i.length?(e(c===i[0],"invalid single child"),this.nodeRemoveChildren(b)):(this.activeNode&&(c===this.activeNode||this.activeNode.isDescendantOf(c))&&this.activeNode.setActive(!1),this.focusNode&&(c===this.focusNode||this.focusNode.isDescendantOf(c))&&(this.focusNode=null),this.nodeRemoveMarkup(h),this.nodeRemoveChildren(h),d=a.inArray(c,i),e(d>=0,"invalid child"),c.visit(function(a){a.parent=null},!0),this._callHook("treeRegisterNode",this,!1,c),g.removeNode&&g.removeNode.call(b.tree,{type:"removeNode"},h),void i.splice(d,1))},nodeRemoveChildMarkup:function(b){var c=b.node;c.ul&&(c.isRootNode()?a(c.ul).empty():(a(c.ul).remove(),c.ul=null),c.visit(function(a){a.li=a.ul=null}))},nodeRemoveChildren:function(b){var c,d=b.tree,e=b.node,f=e.children,g=b.options;f&&(this.activeNode&&this.activeNode.isDescendantOf(e)&&this.activeNode.setActive(!1),this.focusNode&&this.focusNode.isDescendantOf(e)&&(this.focusNode=null),this.nodeRemoveChildMarkup(b),c=a.extend({},b),e.visit(function(a){a.parent=null,d._callHook("treeRegisterNode",d,!1,a),g.removeNode&&(c.node=a,g.removeNode.call(b.tree,{type:"removeNode"},c))}),e.children=e.lazy?[]:null,e.isRootNode()||(e.expanded=!1),this.nodeRenderStatus(b))},nodeRemoveMarkup:function(b){var c=b.node;c.li&&(a(c.li).remove(),c.li=null),this.nodeRemoveChildMarkup(b)},nodeRender:function(b,d,f,g,h){var i,j,k,l,m,n,o,p=b.node,q=b.tree,r=b.options,s=r.aria,t=!1,u=p.parent,v=!u,w=p.children,x=null;if(v||u.ul){if(e(v||u.ul,"parent UL must exist"),v||(p.li&&(d||p.li.parentNode!==p.parent.ul)&&(p.li.parentNode===p.parent.ul?x=p.li.nextSibling:this.debug("Unlinking "+p+" (must be child of "+p.parent+")"),this.nodeRemoveMarkup(b)),p.li?this.nodeRenderStatus(b):(t=!0,p.li=c.createElement("li"),p.li.ftnode=p,p.key&&r.generateIds&&(p.li.id=r.idPrefix+p.key),p.span=c.createElement("span"),p.span.className="fancytree-node",s&&a(p.span).attr("aria-labelledby","ftal_"+p.key),p.li.appendChild(p.span),this.nodeRenderTitle(b),r.createNode&&r.createNode.call(q,{type:"createNode"},b)),r.renderNode&&r.renderNode.call(q,{type:"renderNode"},b)),w){if(v||p.expanded||f===!0){for(p.ul||(p.ul=c.createElement("ul"),(g===!0&&!h||!p.expanded)&&(p.ul.style.display="none"),s&&a(p.ul).attr("role","group"),p.li?p.li.appendChild(p.ul):p.tree.$div.append(p.ul)),l=0,m=w.length;m>l;l++)o=a.extend({},b,{node:w[l]}),this.nodeRender(o,d,f,!1,!0);for(i=p.ul.firstChild;i;)k=i.ftnode,k&&k.parent!==p?(p.debug("_fixParent: remove missing "+k,i),n=i.nextSibling,i.parentNode.removeChild(i),i=n):i=i.nextSibling;for(i=p.ul.firstChild,l=0,m=w.length-1;m>l;l++)j=w[l],k=i.ftnode,j!==k?p.ul.insertBefore(j.li,k.li):i=i.nextSibling}}else p.ul&&(this.warn("remove child markup for "+p),this.nodeRemoveChildMarkup(b));v||t&&u.ul.insertBefore(p.li,x)}},nodeRenderTitle:function(a,b){var c,e,f,g,h,i,j=a.node,k=a.tree,l=a.options,m=l.aria,n=j.getLevel(),o=[],p=j.data.icon;b!==d&&(j.title=b),j.span&&(n<l.minExpandLevel?(j.lazy||(j.expanded=!0),n>1&&o.push(m?"<span role='button' class='fancytree-expander fancytree-expander-fixed'></span>":"<span class='fancytree-expander fancytree-expander-fixed''></span>")):o.push(m?"<span role='button' class='fancytree-expander'></span>":"<span class='fancytree-expander'></span>"),l.checkbox&&j.hideCheckbox!==!0&&!j.isStatusNode()&&o.push(m?"<span role='checkbox' class='fancytree-checkbox'></span>":"<span class='fancytree-checkbox'></span>"),g=m?" role='img'":"",(p===!0||p!==!1&&l.icons!==!1)&&(p&&"string"==typeof p?(p="/"===p.charAt(0)?p:(l.imagePath||"")+p,o.push("<img src='"+p+"' class='fancytree-icon' alt='' />")):(e=l.iconClass&&l.iconClass.call(k,{type:"iconClass"},a)||j.data.iconclass||null,o.push(e?"<span "+g+" class='fancytree-custom-icon "+e+"'></span>":"<span "+g+" class='fancytree-icon'></span>"))),f="",l.renderTitle&&(f=l.renderTitle.call(k,{type:"renderTitle"},a)||""),f||(i=j.tooltip?" title='"+u.escapeHtml(j.tooltip)+"'":"",c=m?" id='ftal_"+j.key+"'":"",g=m?" role='treeitem'":"",h=l.titlesTabbable?" tabindex='0'":"",f="<span "+g+" class='fancytree-title'"+c+i+h+">"+j.title+"</span>"),o.push(f),j.span.innerHTML=o.join(""),this.nodeRenderStatus(a)) +},nodeRenderStatus:function(b){var c=b.node,d=b.tree,e=b.options,f=c.hasChildren(),g=c.isLastSibling(),h=e.aria,i=a(c.span).find(".fancytree-title"),j=e._classNames,k=[],l=c[d.statusClassPropName];l&&(k.push(j.node),d.activeNode===c&&k.push(j.active),d.focusNode===c?(k.push(j.focused),h&&i.attr("aria-activedescendant",!0)):h&&i.removeAttr("aria-activedescendant"),c.expanded?(k.push(j.expanded),h&&i.attr("aria-expanded",!0)):h&&i.removeAttr("aria-expanded"),c.folder&&k.push(j.folder),f!==!1&&k.push(j.hasChildren),g&&k.push(j.lastsib),c.lazy&&null==c.children&&k.push(j.lazy),c.partsel&&k.push(j.partsel),c.unselectable&&k.push(j.unselectable),c._isLoading&&k.push(j.loading),c._error&&k.push(j.error),c.selected?(k.push(j.selected),h&&i.attr("aria-selected",!0)):h&&i.attr("aria-selected",!1),c.extraClasses&&k.push(c.extraClasses),k.push(f===!1?j.combinedExpanderPrefix+"n"+(g?"l":""):j.combinedExpanderPrefix+(c.expanded?"e":"c")+(c.lazy&&null==c.children?"d":"")+(g?"l":"")),k.push(j.combinedIconPrefix+(c.expanded?"e":"c")+(c.folder?"f":"")),l.className=k.join(" "),c.li&&(c.li.className=g?j.lastsib:""))},nodeSetActive:function(b,c,d){d=d||{};var f,g=b.node,h=b.tree,i=b.options,j=d.noEvents===!0,m=d.noFocus===!0,n=g===h.activeNode;return c=c!==!1,n===c?k(g):c&&!j&&this._triggerNodeEvent("beforeActivate",g,b.originalEvent)===!1?l(g,["rejected"]):(c?(h.activeNode&&(e(h.activeNode!==g,"node was active (inconsistency)"),f=a.extend({},b,{node:h.activeNode}),h.nodeSetActive(f,!1),e(null===h.activeNode,"deactivate was out of sync?")),i.activeVisible&&g.makeVisible({scrollIntoView:!1}),h.activeNode=g,h.nodeRenderStatus(b),m||h.nodeSetFocus(b),j||h._triggerNodeEvent("activate",g,b.originalEvent)):(e(h.activeNode===g,"node was not active (inconsistency)"),h.activeNode=null,this.nodeRenderStatus(b),j||b.tree._triggerNodeEvent("deactivate",g,b.originalEvent)),k(g))},nodeSetExpanded:function(b,c,e){e=e||{};var f,g,h,i,j,m,n=b.node,o=b.tree,p=b.options,q=e.noAnimation===!0,r=e.noEvents===!0;if(c=c!==!1,n.expanded&&c||!n.expanded&&!c)return k(n);if(c&&!n.lazy&&!n.hasChildren())return k(n);if(!c&&n.getLevel()<p.minExpandLevel)return l(n,["locked"]);if(!r&&this._triggerNodeEvent("beforeExpand",n,b.originalEvent)===!1)return l(n,["rejected"]);if(q||n.isVisible()||(q=e.noAnimation=!0),g=new a.Deferred,c&&!n.expanded&&p.autoCollapse){j=n.getParentList(!1,!0),m=p.autoCollapse;try{for(p.autoCollapse=!1,h=0,i=j.length;i>h;h++)this._callHook("nodeCollapseSiblings",j[h],e)}finally{p.autoCollapse=m}}return g.done(function(){var a=n.getLastChild();c&&p.autoScroll&&!q&&a?a.scrollIntoView(!0,{topNode:n}).always(function(){r||b.tree._triggerNodeEvent(c?"expand":"collapse",b)}):r||b.tree._triggerNodeEvent(c?"expand":"collapse",b)}),f=function(d){var e,f,g=p.toggleEffect;if(n.expanded=c,o._callHook("nodeRender",b,!1,!1,!0),n.ul)if(e="none"!==n.ul.style.display,f=!!n.expanded,e===f)n.warn("nodeSetExpanded: UL.style.display already set");else{if(g&&!q)return void a(n.ul).toggle(g.effect,g.options,g.duration,function(){d()});n.ul.style.display=n.expanded||!parent?"":"none"}d()},c&&n.lazy&&n.hasChildren()===d?n.load().done(function(){g.notifyWith&&g.notifyWith(n,["loaded"]),f(function(){g.resolveWith(n)})}).fail(function(a){f(function(){g.rejectWith(n,["load failed ("+a+")"])})}):f(function(){g.resolveWith(n)}),g.promise()},nodeSetFocus:function(b,c){var d,e=b.tree,f=b.node;if(c=c!==!1,e.focusNode){if(e.focusNode===f&&c)return;d=a.extend({},b,{node:e.focusNode}),e.focusNode=null,this._triggerNodeEvent("blur",d),this._callHook("nodeRenderStatus",d)}c&&(this.hasFocus()||(f.debug("nodeSetFocus: forcing container focus"),this._callHook("treeSetFocus",b,!0,{calledByNode:!0})),f.makeVisible({scrollIntoView:!1}),e.focusNode=f,this._triggerNodeEvent("focus",b),b.options.autoScroll&&f.scrollIntoView(),this._callHook("nodeRenderStatus",b))},nodeSetSelected:function(a,b){var c=a.node,d=a.tree,e=a.options;if(b=b!==!1,c.debug("nodeSetSelected("+b+")",a),!c.unselectable){if(c.selected&&b||!c.selected&&!b)return!!c.selected;if(this._triggerNodeEvent("beforeSelect",c,a.originalEvent)===!1)return!!c.selected;b&&1===e.selectMode?d.lastSelectedNode&&d.lastSelectedNode.setSelected(!1):3===e.selectMode&&(c.selected=b,c.fixSelection3AfterClick()),c.selected=b,this.nodeRenderStatus(a),d.lastSelectedNode=b?c:null,d._triggerNodeEvent("select",a)}},nodeSetStatus:function(b,c,d,e){function f(){var a=h.children?h.children[0]:null;if(a&&a.isStatusNode()){try{h.ul&&(h.ul.removeChild(a.li),a.li=null)}catch(b){}1===h.children.length?h.children=[]:h.children.shift()}}function g(b,c){var d=h.children?h.children[0]:null;return d&&d.isStatusNode()?(a.extend(d,b),i._callHook("nodeRenderTitle",d)):(b.key="_statusNode",h._setChildren([b]),h.children[0].statusNodeType=c,i.render()),h.children[0]}var h=b.node,i=b.tree;switch(c){case"ok":f(),h._isLoading=!1,h._error=null,h.renderStatus();break;case"loading":h.parent||g({title:i.options.strings.loading+(d?" ("+d+") ":""),tooltip:e,extraClasses:"fancytree-statusnode-wait"},c),h._isLoading=!0,h._error=null,h.renderStatus();break;case"error":g({title:i.options.strings.loadError+(d?" ("+d+") ":""),tooltip:e,extraClasses:"fancytree-statusnode-error"},c),h._isLoading=!1,h._error={message:d,details:e},h.renderStatus();break;default:a.error("invalid node status "+c)}},nodeToggleExpanded:function(a){return this.nodeSetExpanded(a,!a.node.expanded)},nodeToggleSelected:function(a){return this.nodeSetSelected(a,!a.node.selected)},treeClear:function(a){var b=a.tree;b.activeNode=null,b.focusNode=null,b.$div.find(">ul.fancytree-container").empty(),b.rootNode.children=null},treeCreate:function(){},treeDestroy:function(){this.$div.find(">ul.fancytree-container").remove(),this.$source&&this.$source.removeClass("ui-helper-hidden")},treeInit:function(a){this.treeLoad(a)},treeLoad:function(b,c){var d,e,f,g=b.tree,h=b.widget.element,i=a.extend({},b,{node:this.rootNode});if(g.rootNode.children&&this.treeClear(b),c=c||this.options.source)"string"==typeof c&&a.error("Not implemented");else switch(d=h.data("type")||"html"){case"html":e=h.find(">ul:first"),e.addClass("ui-fancytree-source ui-helper-hidden"),c=a.ui.fancytree.parseHtml(e),this.data=a.extend(this.data,n(e));break;case"json":c=a.parseJSON(h.text()),c.children&&(c.title&&(g.title=c.title),c=c.children);break;default:a.error("Invalid data-type: "+d)}return f=this.nodeLoadChildren(i,c).done(function(){g.render(),3===b.options.selectMode&&g.rootNode.fixSelection3FromEndNodes(),g.activeNode&&g.options.activeVisible&&g.activeNode.makeVisible(),g._triggerTreeEvent("init",null,{status:!0})}).fail(function(){g.render(),g._triggerTreeEvent("init",null,{status:!1})})},treeRegisterNode:function(){},treeSetFocus:function(a,b){b=b!==!1,b!==this.hasFocus()&&(this._hasFocus=b,!b&&this.focusNode&&this.focusNode.setFocus(!1),this.$container.toggleClass("fancytree-treefocus",b),this._triggerTreeEvent(b?"focusTree":"blurTree"))}}),a.widget("ui.fancytree",{options:{activeVisible:!0,ajax:{type:"GET",cache:!1,dataType:"json"},aria:!1,autoActivate:!0,autoCollapse:!1,autoScroll:!1,checkbox:!1,clickFolderMode:4,debugLevel:null,disabled:!1,enableAspx:!0,extensions:[],toggleEffect:{effect:"blind",options:{direction:"vertical",scale:"box"},duration:200},generateIds:!1,icons:!0,idPrefix:"ft_",focusOnSelect:!1,keyboard:!0,keyPathSeparator:"/",minExpandLevel:1,quicksearch:!1,scrollOfs:{top:0,bottom:0},scrollParent:null,selectMode:2,strings:{loading:"Loading…",loadError:"Load error!"},tabbable:!0,titlesTabbable:!1,_classNames:{node:"fancytree-node",folder:"fancytree-folder",combinedExpanderPrefix:"fancytree-exp-",combinedIconPrefix:"fancytree-ico-",hasChildren:"fancytree-has-children",active:"fancytree-active",selected:"fancytree-selected",expanded:"fancytree-expanded",lazy:"fancytree-lazy",focused:"fancytree-focused",partsel:"fancytree-partsel",unselectable:"fancytree-unselectable",lastsib:"fancytree-lastsib",loading:"fancytree-loading",error:"fancytree-error"},lazyLoad:null,postProcess:null},_create:function(){this.tree=new r(this),this.$source=this.source||"json"===this.element.data("type")?this.element:this.element.find(">ul:first");var b,c,f,g=this.options.extensions,h=this.tree;for(f=0;f<g.length;f++)c=g[f],b=a.ui.fancytree._extensions[c],b||a.error("Could not apply extension '"+c+"' (it is not registered, did you forget to include it?)"),this.tree.options[c]=a.extend(!0,{},b.options,this.tree.options[c]),e(this.tree.ext[c]===d,"Extension name must not exist as Fancytree.ext attribute: '"+c+"'"),this.tree.ext[c]={},j(this.tree,h,b,c),h=b;this.tree._callHook("treeCreate",this.tree)},_init:function(){this.tree._callHook("treeInit",this.tree),this._bind()},_setOption:function(b,c){var d=!0,e=!1;switch(b){case"aria":case"checkbox":case"icons":case"minExpandLevel":case"tabbable":this.tree._callHook("treeCreate",this.tree),e=!0;break;case"source":d=!1,this.tree._callHook("treeLoad",this.tree,c)}this.tree.debug("set option "+b+"="+c+" <"+typeof c+">"),d&&a.Widget.prototype._setOption.apply(this,arguments),e&&this.tree.render(!0,!1)},destroy:function(){this._unbind(),this.tree._callHook("treeDestroy",this.tree),a.Widget.prototype.destroy.call(this)},_unbind:function(){var b=this.tree._ns;this.element.unbind(b),this.tree.$container.unbind(b),a(c).unbind(b)},_bind:function(){var a=this,b=this.options,c=this.tree,d=c._ns;this._unbind(),c.$container.on("focusin"+d+" focusout"+d,function(a){var b=u.getNode(a),d="focusin"===a.type;b?c._callHook("nodeSetFocus",b,d):c._callHook("treeSetFocus",c,d)}).on("selectstart"+d,"span.fancytree-title",function(a){a.preventDefault()}).on("keydown"+d,function(a){if(b.disabled||b.keyboard===!1)return!0;var d,e=c.focusNode,f=c._makeHookContext(e||c,a),g=c.phase;try{return c.phase="userEvent",d=e?c._triggerNodeEvent("keydown",e,a):c._triggerTreeEvent("keydown",a),"preventNav"===d?d=!0:d!==!1&&(d=c._callHook("nodeKeydown",f)),d}finally{c.phase=g}}).on("click"+d+" dblclick"+d,function(c){if(b.disabled)return!0;var d,e=u.getEventTarget(c),f=e.node,g=a.tree,h=g.phase;if(!f)return!0;d=g._makeHookContext(f,c);try{switch(g.phase="userEvent",c.type){case"click":return d.targetType=e.type,g._triggerNodeEvent("click",d,c)===!1?!1:g._callHook("nodeClick",d);case"dblclick":return d.targetType=e.type,g._triggerNodeEvent("dblclick",d,c)===!1?!1:g._callHook("nodeDblclick",d)}}finally{g.phase=h}})},getActiveNode:function(){return this.tree.activeNode},getNodeByKey:function(a){return this.tree.getNodeByKey(a)},getRootNode:function(){return this.tree.rootNode},getTree:function(){return this.tree}}),u=a.ui.fancytree,a.extend(a.ui.fancytree,{version:"2.13.0",buildType: "production",debugLevel: 1,_nextId:1,_nextNodeKey:1,_extensions:{},_FancytreeClass:r,_FancytreeNodeClass:q,jquerySupports:{positionMyOfs:h(a.ui.version,1,9)},assert:function(a,b){return e(a,b)},debounce:function(a,b,c,d){var e;return 3===arguments.length&&"boolean"!=typeof c&&(d=c,c=!1),function(){var f=arguments;d=d||this,c&&!e&&b.apply(d,f),clearTimeout(e),e=setTimeout(function(){c||b.apply(d,f),e=null},a)}},debug:function(){a.ui.fancytree.debugLevel>=2&&f("log",arguments)},error:function(){f("error",arguments)},escapeHtml:function(a){return(""+a).replace(/[&<>"'\/]/g,function(a){return v[a]})},fixPositionOptions:function(b){if((b.offset||(""+b.my+b.at).indexOf("%")>=0)&&a.error("expected new position syntax (but '%' is not supported)"),!a.ui.fancytree.jquerySupports.positionMyOfs){var c=/(\w+)([+-]?\d+)?\s+(\w+)([+-]?\d+)?/.exec(b.my),d=/(\w+)([+-]?\d+)?\s+(\w+)([+-]?\d+)?/.exec(b.at),e=(c[2]?+c[2]:0)+(d[2]?+d[2]:0),f=(c[4]?+c[4]:0)+(d[4]?+d[4]:0);b=a.extend({},b,{my:c[1]+" "+c[3],at:d[1]+" "+d[3]}),(e||f)&&(b.offset=""+e+" "+f)}return b},getEventTargetType:function(a){return this.getEventTarget(a).type},getEventTarget:function(b){var c=b&&b.target?b.target.className:"",e={node:this.getNode(b.target),type:d};return/\bfancytree-title\b/.test(c)?e.type="title":/\bfancytree-expander\b/.test(c)?e.type=e.node.hasChildren()===!1?"prefix":"expander":/\bfancytree-checkbox\b/.test(c)||/\bfancytree-radio\b/.test(c)?e.type="checkbox":/\bfancytree-icon\b/.test(c)?e.type="icon":/\bfancytree-node\b/.test(c)?e.type="title":b&&b.target&&a(b.target).closest(".fancytree-title").length&&(e.type="title"),e},getNode:function(a){if(a instanceof q)return a;for(a.selector!==d?a=a[0]:a.originalEvent!==d&&(a=a.target);a;){if(a.ftnode)return a.ftnode;a=a.parentNode}return null},getTree:function(b){var c;return b instanceof r?b:(b===d&&(b=0),"number"==typeof b?b=a(".fancytree-container").eq(b):"string"==typeof b?b=a(b).eq(0):b.selector!==d?b=b.eq(0):b.originalEvent!==d&&(b=a(b.target)),b=b.closest(":ui-fancytree"),c=b.data("ui-fancytree")||b.data("fancytree"),c?c.tree:null)},info:function(){a.ui.fancytree.debugLevel>=1&&f("info",arguments)},eventToString:function(a){var b=a.which,c=a.type,d=[];return a.altKey&&d.push("alt"),a.ctrlKey&&d.push("ctrl"),a.metaKey&&d.push("meta"),a.shiftKey&&d.push("shift"),"click"===c||"dblclick"===c?d.push(y[a.button]+c):w[b]||d.push(x[b]||String.fromCharCode(b).toLowerCase()),d.join("+")},keyEventToString:function(a){return this.warn("keyEventToString() is deprecated: use eventToString()"),this.eventToString(a)},parseHtml:function(b){var c,e,f,g,h,i,j,k,l=b.find(">li"),m=[];return l.each(function(){var l,o,p=a(this),q=p.find(">span:first",this),r=q.length?null:p.find(">a:first"),s={tooltip:null,data:{}};for(q.length?s.title=q.html():r&&r.length?(s.title=r.html(),s.data.href=r.attr("href"),s.data.target=r.attr("target"),s.tooltip=r.attr("title")):(s.title=p.html(),h=s.title.search(/<ul/i),h>=0&&(s.title=s.title.substring(0,h))),s.title=a.trim(s.title),g=0,i=z.length;i>g;g++)s[z[g]]=d;for(c=this.className.split(" "),f=[],g=0,i=c.length;i>g;g++)e=c[g],A[e]?s[e]=!0:f.push(e);if(s.extraClasses=f.join(" "),j=p.attr("title"),j&&(s.tooltip=j),j=p.attr("id"),j&&(s.key=j),l=n(p),l&&!a.isEmptyObject(l)){for(o in D)l.hasOwnProperty(o)&&(l[D[o]]=l[o],delete l[o]);for(g=0,i=B.length;i>g;g++)j=B[g],k=l[j],null!=k&&(delete l[j],s[j]=k);a.extend(s.data,l)}b=p.find(">ul:first"),s.children=b.length?a.ui.fancytree.parseHtml(b):s.lazy?d:null,m.push(s)}),m},registerExtension:function(b){e(null!=b.name,"extensions must have a `name` property."),e(null!=b.version,"extensions must have a `version` property."),a.ui.fancytree._extensions[b.name]=b},unescapeHtml:function(a){var b=c.createElement("div");return b.innerHTML=a,0===b.childNodes.length?"":b.childNodes[0].nodeValue},warn:function(){f("warn",arguments)}})}(jQuery,window,document); \ No newline at end of file diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-awesome/ui.fancytree.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-awesome/ui.fancytree.css new file mode 100644 index 00000000000..58eab4630eb --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-awesome/ui.fancytree.css @@ -0,0 +1,361 @@ +/*! + * Fancytree "awesome" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ +/******************************************************************************* + * Common Styles for Fancytree Skins. + * + * This section is automatically generated from the `skin-common.less` template. + ******************************************************************************/ +/*------------------------------------------------------------------------------ + * Helpers + *----------------------------------------------------------------------------*/ +.ui-helper-hidden { + display: none; +} +/*------------------------------------------------------------------------------ + * Container and UL / LI + *----------------------------------------------------------------------------*/ +ul.fancytree-container { + font-family: tahoma, arial, helvetica; + font-size: 10pt; + white-space: nowrap; + padding: 3px; + margin: 0; + background-color: white; + border: 1px dotted gray; + overflow: auto; + min-height: 0%; + position: relative; +} +ul.fancytree-container ul { + padding: 0 0 0 16px; + margin: 0; +} +ul.fancytree-container li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0em 0em; + background-repeat: repeat-y; + background-image: none; + margin: 0; +} +ul.fancytree-container li.fancytree-lastsib { + background-image: none; +} +ul.fancytree-no-connector > li { + background-image: none; +} +.ui-fancytree-disabled ul.fancytree-container { + opacity: 0.5; + background-color: silver; +} +/*------------------------------------------------------------------------------ + * Common icon definitions + *----------------------------------------------------------------------------*/ +span.fancytree-empty, +span.fancytree-vline, +span.fancytree-expander, +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-radio, +span.fancytree-drag-helper-img, +#fancytree-drop-marker { + width: 1em; + height: 1em; + display: inline-block; + vertical-align: top; + background-repeat: no-repeat; + background-position: left; + background-position: 0em 0em; +} +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-expander, +span.fancytree-radio, +span.fancytree-custom-icon { + margin-top: 0px; +} +/* Used by iconclass option and iconClass callback: */ +span.fancytree-custom-icon { + display: inline-block; + margin-left: 0.5em; +} +/* Used by 'icon' node option: */ +img.fancytree-icon { + width: 1em; + height: 1em; + margin-left: 0.5em; + margin-top: 0px; + vertical-align: top; + border-style: none; +} +/*------------------------------------------------------------------------------ + * Expander icon + * + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-exp- + * 1st character: 'e': expanded, 'c': collapsed, 'n': no children + * 2nd character (optional): 'd': lazy (Delayed) + * 3rd character (optional): 'l': Last sibling + *----------------------------------------------------------------------------*/ +span.fancytree-expander { + cursor: pointer; +} +.fancytree-exp-n span.fancytree-expander, +.fancytree-exp-nl span.fancytree-expander { + background-image: none; + cursor: default; +} +/*------------------------------------------------------------------------------ + * Checkbox icon + *----------------------------------------------------------------------------*/ +span.fancytree-checkbox { + margin-left: 0.5em; +} +.fancytree-unselectable span.fancytree-checkbox { + opacity: 0.4; + filter: alpha(opacity=40); +} +/*------------------------------------------------------------------------------ + * Radiobutton icon + * This is a customization, that may be activated by overriding the 'checkbox' + * class name as 'fancytree-radio' in the tree options. + *----------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------ + * Node type icon + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-ico- + * 1st character: 'e': expanded, 'c': collapsed + * 2nd character (optional): 'f': folder + *----------------------------------------------------------------------------*/ +span.fancytree-icon { + margin-left: 0.5em; +} +/* Documents */ +/* Folders */ +.fancytree-loading span.fancytree-expander, +.fancytree-loading span.fancytree-expander:hover, +.fancytree-statusnode-wait span.fancytree-icon, +.fancytree-statusnode-wait span.fancytree-icon:hover { + background-image: url("loading.gif"); +} +/* Status node icons */ +/*------------------------------------------------------------------------------ + * Node titles and highlighting + *----------------------------------------------------------------------------*/ +span.fancytree-node { + /* See #117 */ + display: inherit; + width: 100%; + margin-top: 1px; + min-height: 1em; +} +span.fancytree-title { + color: #000000; + cursor: pointer; + display: inline-block; + vertical-align: top; + min-height: 1em; + padding: 0 3px 0 3px; + margin: 0px 0 0 0.5em; + border: 1px solid transparent; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + -ms-border-radius: 0px; + -o-border-radius: 0px; + border-radius: 0px; +} +span.fancytree-node.fancytree-error span.fancytree-title { + color: #ff0000; +} +/*------------------------------------------------------------------------------ + * Drag'n'drop support + *----------------------------------------------------------------------------*/ +div.fancytree-drag-helper span.fancytree-childcounter, +div.fancytree-drag-helper span.fancytree-dnd-modifier { + display: inline-block; + color: #fff; + background: #337ab7; + border: 1px solid gray; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +div.fancytree-drag-helper span.fancytree-childcounter { + position: absolute; + top: -6px; + right: -6px; +} +div.fancytree-drag-helper span.fancytree-dnd-modifier { + background: #5cb85c; + border: none; + font-weight: bolder; +} +/*** Drop marker icon *********************************************************/ +#fancytree-drop-marker { + width: 2em; + position: absolute; + margin: 0; +} +#fancytree-drop-marker.fancytree-drop-after, +#fancytree-drop-marker.fancytree-drop-before { + width: 4em; +} +/*** Source node while dragging ***********************************************/ +span.fancytree-drag-source.fancytree-drag-remove { + opacity: 0.15; +} +/*** Target node while dragging cursor is over it *****************************/ +/*------------------------------------------------------------------------------ + * 'table' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-table { + border-collapse: collapse; +} +table.fancytree-ext-table span.fancytree-node { + display: inline-block; +} +/*------------------------------------------------------------------------------ + * 'columnview' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-columnview tbody tr td { + position: relative; + border: 1px solid gray; + vertical-align: top; + overflow: auto; +} +table.fancytree-ext-columnview tbody tr td > ul { + padding: 0; +} +table.fancytree-ext-columnview tbody tr td > ul li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0em 0em; + background-repeat: repeat-y; + background-image: none; + /* no v-lines */ + margin: 0; +} +table.fancytree-ext-columnview span.fancytree-node { + position: relative; + /* allow positioning of embedded spans */ + display: inline-block; +} +table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded { + background-color: #CBE8F6; +} +table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right { + position: absolute; + right: 3px; +} +/*------------------------------------------------------------------------------ + * 'filter' extension + *----------------------------------------------------------------------------*/ +.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title { + color: #c0c0c0; + font-weight: lighter; +} +.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: bold; +} +.fancytree-ext-filter-hide tr.fancytree-hide, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide { + display: none; +} +.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title { + color: #c0c0c0; + font-weight: lighter; +} +.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-childcounter span.fancytree-icon, +.fancytree-ext-filter span.fancytree-icon { + position: relative; +} +.fancytree-ext-childcounter span.fancytree-childcounter, +.fancytree-ext-filter span.fancytree-childcounter { + color: #fff; + background: #777; + border: 1px solid gray; + position: absolute; + top: -6px; + right: -6px; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +/*------------------------------------------------------------------------------ + * 'wide' extension + *----------------------------------------------------------------------------*/ +ul.fancytree-ext-wide { + position: relative; + min-width: 100%; + z-index: 2; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +ul.fancytree-ext-wide span.fancytree-node > span { + position: relative; + z-index: 2; +} +ul.fancytree-ext-wide span.fancytree-node span.fancytree-title { + position: absolute; + z-index: 1; + left: 0px; + width: 100%; + margin-left: 0; + margin-right: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +/******************************************************************************* + * Styles specific to this skin. + * + * This section is automatically generated from the `ui-fancytree.less` template. + ******************************************************************************/ +ul.fancytree-container ul { + padding: 0.3em 0 0 1em; + margin: 0; +} diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-awesome/ui.fancytree.less b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-awesome/ui.fancytree.less new file mode 100644 index 00000000000..f2b48163134 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-awesome/ui.fancytree.less @@ -0,0 +1,53 @@ +/*! + * Fancytree "awesome" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ + +// Import common styles +@import "../skin-common.less"; + + +/******************************************************************************* + * Styles specific to this skin. + * + * This section is automatically generated from the `ui-fancytree.less` template. + ******************************************************************************/ + +// Borders have NO radius and NO gradients are used! + +// both: +// unselected background: white +// hover bar (unselected, inactive): #E5F3FB (border: #70C0E7) 'very light blue' +// active node: #CBE8F6 (border: #26A0DA) 'light blue' +// active node with hover: wie active node + +// Tree view: +// active node, tree inactive: #F7F7F7 (border: #DEDEDE) 'light gray, selected, but tree not active' + +// List view: +// selected bar: --> active bar +// focus bar: transparent(white) + border 1px solid #3399FF () + +// table left/right border: #EDEDED 'light gray' + +// local vars +@fancy-my-icon-size: 16px; + +// Override the variable after the import. +// NOTE: Variables are always resolved as the last definition, even if it is +// after where it is used. +@fancy-use-sprites: false; // false: suppress all background images (i.e. icons) +@fancy-hide-connectors: true; + +@fancy-icon-width: 1em; +@fancy-icon-height: 1em; +@fancy-line-height: 1em; +@fancy-icon-spacing: 0.5em; + +ul.fancytree-container ul +{ + padding: 0.3em 0 0 1em; + margin: 0; +} diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-awesome/ui.fancytree.min.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-awesome/ui.fancytree.min.css new file mode 100644 index 00000000000..2fcc7174281 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-awesome/ui.fancytree.min.css @@ -0,0 +1,6 @@ +/*! + * Fancytree "awesome" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */.ui-helper-hidden{display:none}ul.fancytree-container{font-family:tahoma,arial,helvetica;font-size:10pt;white-space:nowrap;padding:3px;margin:0;background-color:#fff;border:1px dotted gray;overflow:auto;min-height:0;position:relative}ul.fancytree-container li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0}ul.fancytree-container li.fancytree-lastsib,ul.fancytree-no-connector>li{background-image:none}.ui-fancytree-disabled ul.fancytree-container{opacity:.5;background-color:silver}#fancytree-drop-marker,span.fancytree-checkbox,span.fancytree-drag-helper-img,span.fancytree-empty,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio,span.fancytree-vline{width:1em;height:1em;display:inline-block;vertical-align:top;background-repeat:no-repeat;background-position:left;background-position:0 0}span.fancytree-checkbox,span.fancytree-custom-icon,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio{margin-top:0}span.fancytree-custom-icon{display:inline-block;margin-left:.5em}img.fancytree-icon{width:1em;height:1em;margin-left:.5em;margin-top:0;vertical-align:top;border-style:none}span.fancytree-expander{cursor:pointer}.fancytree-exp-n span.fancytree-expander,.fancytree-exp-nl span.fancytree-expander{background-image:none;cursor:default}span.fancytree-checkbox{margin-left:.5em}.fancytree-unselectable span.fancytree-checkbox{opacity:.4;filter:alpha(opacity=40)}span.fancytree-icon{margin-left:.5em}.fancytree-loading span.fancytree-expander,.fancytree-loading span.fancytree-expander:hover,.fancytree-statusnode-wait span.fancytree-icon,.fancytree-statusnode-wait span.fancytree-icon:hover{background-image:url(loading.gif)}span.fancytree-node{display:inherit;width:100%;margin-top:1px;min-height:1em}span.fancytree-title{color:#000;cursor:pointer;display:inline-block;vertical-align:top;min-height:1em;padding:0 3px;margin:0 0 0 .5em;border:1px solid transparent;-webkit-border-radius:0;-moz-border-radius:0;-ms-border-radius:0;-o-border-radius:0;border-radius:0}span.fancytree-node.fancytree-error span.fancytree-title{color:red}div.fancytree-drag-helper span.fancytree-childcounter,div.fancytree-drag-helper span.fancytree-dnd-modifier{display:inline-block;color:#fff;background:#337ab7;border:1px solid gray;min-width:10px;height:10px;line-height:1;vertical-align:baseline;border-radius:10px;padding:2px;text-align:center;font-size:9px}div.fancytree-drag-helper span.fancytree-childcounter{position:absolute;top:-6px;right:-6px}div.fancytree-drag-helper span.fancytree-dnd-modifier{background:#5cb85c;border:0;font-weight:bolder}#fancytree-drop-marker{width:2em;position:absolute;margin:0}#fancytree-drop-marker.fancytree-drop-after,#fancytree-drop-marker.fancytree-drop-before{width:4em}span.fancytree-drag-source.fancytree-drag-remove{opacity:.15}table.fancytree-ext-table{border-collapse:collapse}table.fancytree-ext-table span.fancytree-node{display:inline-block}table.fancytree-ext-columnview tbody tr td{position:relative;border:1px solid gray;vertical-align:top;overflow:auto}table.fancytree-ext-columnview tbody tr td>ul{padding:0}table.fancytree-ext-columnview tbody tr td>ul li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0}table.fancytree-ext-columnview span.fancytree-node{position:relative;display:inline-block}table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded{background-color:#CBE8F6}table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right{position:absolute;right:3px}.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title{color:silver;font-weight:lighter}.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title,.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title{color:#000;font-weight:400}.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title,.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title{color:#000;font-weight:700}.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide,.fancytree-ext-filter-hide tr.fancytree-hide{display:none}.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title,.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title{color:silver;font-weight:lighter}.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title,.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title{color:#000;font-weight:400}.fancytree-ext-childcounter span.fancytree-icon,.fancytree-ext-filter span.fancytree-icon{position:relative}.fancytree-ext-childcounter span.fancytree-childcounter,.fancytree-ext-filter span.fancytree-childcounter{color:#fff;background:#777;border:1px solid gray;position:absolute;top:-6px;right:-6px;min-width:10px;height:10px;line-height:1;vertical-align:baseline;border-radius:10px;padding:2px;text-align:center;font-size:9px}ul.fancytree-ext-wide{position:relative;min-width:100%;z-index:2;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}ul.fancytree-ext-wide span.fancytree-node>span{position:relative;z-index:2}ul.fancytree-ext-wide span.fancytree-node span.fancytree-title{position:absolute;z-index:1;left:0;width:100%;margin-left:0;margin-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}ul.fancytree-container ul{padding:.3em 0 0 1em;margin:0} \ No newline at end of file diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap-n/ui.fancytree.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap-n/ui.fancytree.css new file mode 100644 index 00000000000..54beaa42986 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap-n/ui.fancytree.css @@ -0,0 +1,441 @@ +/*! + * Fancytree "bootstrap" skin (highlighting the node span instead of title-only). + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ +/******************************************************************************* + * Common Styles for Fancytree Skins. + * + * This section is automatically generated from the `skin-common.less` template. + ******************************************************************************/ +/*------------------------------------------------------------------------------ + * Helpers + *----------------------------------------------------------------------------*/ +.ui-helper-hidden { + display: none; +} +/*------------------------------------------------------------------------------ + * Container and UL / LI + *----------------------------------------------------------------------------*/ +ul.fancytree-container { + font-family: tahoma, arial, helvetica; + font-size: 10pt; + white-space: nowrap; + padding: 3px; + margin: 0; + background-color: white; + border: 1px dotted gray; + overflow: auto; + min-height: 0%; + position: relative; +} +ul.fancytree-container ul { + padding: 0 0 0 16px; + margin: 0; +} +ul.fancytree-container li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0em 0em; + background-repeat: repeat-y; + background-image: none; + margin: 0; +} +ul.fancytree-container li.fancytree-lastsib { + background-image: none; +} +ul.fancytree-no-connector > li { + background-image: none; +} +.ui-fancytree-disabled ul.fancytree-container { + opacity: 0.5; + background-color: silver; +} +/*------------------------------------------------------------------------------ + * Common icon definitions + *----------------------------------------------------------------------------*/ +span.fancytree-empty, +span.fancytree-vline, +span.fancytree-expander, +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-radio, +span.fancytree-drag-helper-img, +#fancytree-drop-marker { + width: 1em; + height: 1em; + display: inline-block; + vertical-align: top; + background-repeat: no-repeat; + background-position: left; + background-position: 0em 0em; +} +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-expander, +span.fancytree-radio, +span.fancytree-custom-icon { + margin-top: 0px; +} +/* Used by iconclass option and iconClass callback: */ +span.fancytree-custom-icon { + display: inline-block; + margin-left: 0.5em; +} +/* Used by 'icon' node option: */ +img.fancytree-icon { + width: 1em; + height: 1em; + margin-left: 0.5em; + margin-top: 0px; + vertical-align: top; + border-style: none; +} +/*------------------------------------------------------------------------------ + * Expander icon + * + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-exp- + * 1st character: 'e': expanded, 'c': collapsed, 'n': no children + * 2nd character (optional): 'd': lazy (Delayed) + * 3rd character (optional): 'l': Last sibling + *----------------------------------------------------------------------------*/ +span.fancytree-expander { + cursor: pointer; +} +.fancytree-exp-n span.fancytree-expander, +.fancytree-exp-nl span.fancytree-expander { + background-image: none; + cursor: default; +} +/*------------------------------------------------------------------------------ + * Checkbox icon + *----------------------------------------------------------------------------*/ +span.fancytree-checkbox { + margin-left: 0.5em; +} +.fancytree-unselectable span.fancytree-checkbox { + opacity: 0.4; + filter: alpha(opacity=40); +} +/*------------------------------------------------------------------------------ + * Radiobutton icon + * This is a customization, that may be activated by overriding the 'checkbox' + * class name as 'fancytree-radio' in the tree options. + *----------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------ + * Node type icon + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-ico- + * 1st character: 'e': expanded, 'c': collapsed + * 2nd character (optional): 'f': folder + *----------------------------------------------------------------------------*/ +span.fancytree-icon { + margin-left: 0.5em; +} +/* Documents */ +/* Folders */ +.fancytree-loading span.fancytree-expander, +.fancytree-loading span.fancytree-expander:hover, +.fancytree-statusnode-wait span.fancytree-icon, +.fancytree-statusnode-wait span.fancytree-icon:hover { + background-image: url("loading.gif"); +} +/* Status node icons */ +/*------------------------------------------------------------------------------ + * Node titles and highlighting + *----------------------------------------------------------------------------*/ +span.fancytree-node { + /* See #117 */ + display: inherit; + width: 100%; + margin-top: 1px; + min-height: 1em; +} +span.fancytree-title { + color: #000000; + cursor: pointer; + display: inline-block; + vertical-align: top; + min-height: 1em; + padding: 0 3px 0 3px; + margin: 0px 0 0 0.5em; + border: 1px solid transparent; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + -ms-border-radius: 0px; + -o-border-radius: 0px; + border-radius: 0px; +} +span.fancytree-node.fancytree-error span.fancytree-title { + color: #ff0000; +} +/*------------------------------------------------------------------------------ + * Drag'n'drop support + *----------------------------------------------------------------------------*/ +div.fancytree-drag-helper span.fancytree-childcounter, +div.fancytree-drag-helper span.fancytree-dnd-modifier { + display: inline-block; + color: #fff; + background: #337ab7; + border: 1px solid gray; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +div.fancytree-drag-helper span.fancytree-childcounter { + position: absolute; + top: -6px; + right: -6px; +} +div.fancytree-drag-helper span.fancytree-dnd-modifier { + background: #5cb85c; + border: none; + font-weight: bolder; +} +/*** Drop marker icon *********************************************************/ +#fancytree-drop-marker { + width: 2em; + position: absolute; + margin: 0; +} +#fancytree-drop-marker.fancytree-drop-after, +#fancytree-drop-marker.fancytree-drop-before { + width: 4em; +} +/*** Source node while dragging ***********************************************/ +span.fancytree-drag-source.fancytree-drag-remove { + opacity: 0.15; +} +/*** Target node while dragging cursor is over it *****************************/ +/*------------------------------------------------------------------------------ + * 'table' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-table { + border-collapse: collapse; +} +table.fancytree-ext-table span.fancytree-node { + display: inline-block; +} +/*------------------------------------------------------------------------------ + * 'columnview' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-columnview tbody tr td { + position: relative; + border: 1px solid gray; + vertical-align: top; + overflow: auto; +} +table.fancytree-ext-columnview tbody tr td > ul { + padding: 0; +} +table.fancytree-ext-columnview tbody tr td > ul li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0em 0em; + background-repeat: repeat-y; + background-image: none; + /* no v-lines */ + margin: 0; +} +table.fancytree-ext-columnview span.fancytree-node { + position: relative; + /* allow positioning of embedded spans */ + display: inline-block; +} +table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded { + background-color: #CBE8F6; +} +table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right { + position: absolute; + right: 3px; +} +/*------------------------------------------------------------------------------ + * 'filter' extension + *----------------------------------------------------------------------------*/ +.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title { + color: #c0c0c0; + font-weight: lighter; +} +.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: bold; +} +.fancytree-ext-filter-hide tr.fancytree-hide, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide { + display: none; +} +.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title { + color: #c0c0c0; + font-weight: lighter; +} +.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-childcounter span.fancytree-icon, +.fancytree-ext-filter span.fancytree-icon { + position: relative; +} +.fancytree-ext-childcounter span.fancytree-childcounter, +.fancytree-ext-filter span.fancytree-childcounter { + color: #fff; + background: #777; + border: 1px solid gray; + position: absolute; + top: -6px; + right: -6px; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +/*------------------------------------------------------------------------------ + * 'wide' extension + *----------------------------------------------------------------------------*/ +ul.fancytree-ext-wide { + position: relative; + min-width: 100%; + z-index: 2; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +ul.fancytree-ext-wide span.fancytree-node > span { + position: relative; + z-index: 2; +} +ul.fancytree-ext-wide span.fancytree-node span.fancytree-title { + position: absolute; + z-index: 1; + left: 0px; + width: 100%; + margin-left: 0; + margin-right: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +/******************************************************************************* + * Styles specific to this skin. + * + * This section is automatically generated from the `ui-fancytree.less` template. + ******************************************************************************/ +ul.fancytree-container ul { + padding: 0 0 0 1.5em; + margin: 0; +} +/* Prevent focus frame */ +.fancytree-container:focus { + outline: none; +} +span.fancytree-node { + border: 1px solid transparent; + border-radius: 3px; + padding-left: 8px; +} +span.fancytree-title { + border-radius: 3px; +} +span.fancytree-node.fancytree-selected { + background-color: #80c780; + border-color: #80c780; +} +span.fancytree-node.fancytree-selected span.fancytree-title { + background-color: #80c780; +} +span.fancytree-node.fancytree-active { + background-color: #6aa3d5; +} +.fancytree-container.fancytree-treefocus span.fancytree-node:hover { + background-color: #e9f2f9; +} +.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-focused { + border-color: #428bca; +} +.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-selected { + background-color: #5cb85c; +} +.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-selected span.fancytree-title { + background-color: #5cb85c; +} +.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-active { + background-color: #428bca; + border-color: #428bca; +} +/******************************************************************************* + * 'table' extension + */ +table.fancytree-ext-table tbody tr td { + border: 1px solid #eeeeee; +} +table.fancytree-ext-table tbody tr.fancytree-selected { + background-color: #80c780; +} +table.fancytree-ext-table tbody tr.fancytree-selected span.fancytree-node { + background-color: #80c780; +} +table.fancytree-ext-table tbody tr.fancytree-selected span.fancytree-title { + background-color: #80c780; +} +table.fancytree-ext-table tbody tr.fancytree-active { + background-color: #6aa3d5; +} +table.fancytree-ext-table tbody tr.fancytree-active span.fancytree-node { + background-color: #6aa3d5; +} +table.fancytree-ext-table.fancytree-treefocus tbody tr:hover { + background-color: #e9f2f9; +} +table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-focused span.fancytree-title { + outline: 1px dotted #428bca; +} +table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-selected { + background-color: #5cb85c; +} +table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-selected span.fancytree-node { + background-color: #5cb85c; +} +table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-selected span.fancytree-title { + background-color: #5cb85c; +} +table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-active { + background-color: #428bca; +} +table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-active span.fancytree-node { + background-color: #428bca; +} diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap-n/ui.fancytree.less b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap-n/ui.fancytree.less new file mode 100644 index 00000000000..6871248db6c --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap-n/ui.fancytree.less @@ -0,0 +1,173 @@ +/*! + * Fancytree "bootstrap" skin (highlighting the node span instead of title-only). + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ + +// Import common styles +@import "../skin-common.less"; + + +/******************************************************************************* + * Styles specific to this skin. + * + * This section is automatically generated from the `ui-fancytree.less` template. + ******************************************************************************/ + + +// local vars +@fancy-my-icon-size: 16px; + +// Override the variable after the import. +// NOTE: Variables are always resolved as the last definition, even if it is +// after where it is used. +@fancy-use-sprites: false; // false: suppress all background images (i.e. icons) +@fancy-hide-connectors: true; + +@fancy-icon-width: 1em; +@fancy-icon-height: 1em; +@fancy-line-height: 1em; +@fancy-icon-spacing: 0.5em; + +// Use 'data-uri(...)' to embed the image into CSS instead of linking to 'loading.gif': +// @fancy-loading-url: data-uri("@{fancy-image-dir}/loading.gif"); +// Set to `true` to use `data-uri(...)` which will embed icons.gif into CSS +// instead of linking to that file: +// @fancy-inline-sprites: true; + + +ul.fancytree-container ul { + padding: 0 0 0 1.5em; + margin: 0; +} +/* Prevent focus frame */ +.fancytree-container:focus { + outline: none; +} + +///// +// Original bootstrap colors (http://getbootstrap.com/css/#responsive-utilities) +@gray-darker: lighten(#000, 13.5%); // #222 +@gray-dark: lighten(#000, 20%); // #333 +@gray: lighten(#000, 33.5%); // #555 +@gray-light: lighten(#000, 60%); // #999 +@gray-lighter: lighten(#000, 93.5%); // #eee + +@brand-primary: #428bca; // blue +@brand-success: #5cb85c; // green +@brand-info: #5bc0de; // light blue +@brand-warning: #f0ad4e; // orange +@brand-danger: #d9534f; // red + +@border-radius-base: 4px; +@border-radius-large: 6px; +@border-radius-small: 3px; +///////////// + +span.fancytree-node { + border: @fancy-node-border-width solid transparent; // avoid jumping, when a border is added on hover + border-radius: @border-radius-small; + padding-left: 8px; +} +span.fancytree-title { + border-radius: @border-radius-small; +} +// Inactive tree: +span.fancytree-node.fancytree-selected { // selected nodes inside inactive tree + background-color: lighten(@brand-success, 10%); + border-color: lighten(@brand-success, 10%); + span.fancytree-title { + background-color: lighten(@brand-success, 10%); // green title, even when active + } +} +span.fancytree-node.fancytree-active { // active nodes inside inactive tree + background-color: lighten(@brand-primary, 10%); +} +// Active tree: +.fancytree-container.fancytree-treefocus { + span.fancytree-node:hover { + background-color: lighten(@brand-primary, 42%); + } + span.fancytree-node.fancytree-focused { + border-color: @brand-primary; + } + span.fancytree-node.fancytree-selected { + background-color: @brand-success; + span.fancytree-title { + background-color: @brand-success; // green title, even when active + } + } + span.fancytree-node.fancytree-active { + background-color: @brand-primary; + border-color: @brand-primary; + } +} + +/******************************************************************************* + * 'table' extension + */ +table.fancytree-ext-table tbody { + tr td { + border: 1px solid @gray-lighter; + } + // span.fancytree-node, + // span.fancytree-node:hover { // undo standard tree css + // border: none; + // background: none; + // } + // // Title get's a white background, when hovered. Undo standard node formatting + // span.fancytree-title:hover { + // border: none; + // background: inherit; + // background: transparent; + // background: none; + // filter: none; + // } + // dimmed, if inside inactive tree + tr.fancytree-selected { + background-color: lighten(@brand-success, 10%); + span.fancytree-node { + background-color: lighten(@brand-success, 10%); + } + span.fancytree-title { + background-color: lighten(@brand-success, 10%); // green title, even when active + } + } + tr.fancytree-active { // dimmed, if inside inactive tree + background-color: lighten(@brand-primary, 10%); + span.fancytree-node { + background-color: lighten(@brand-primary, 10%); + } + } +} + +table.fancytree-ext-table.fancytree-treefocus tbody { + tr:hover { + background-color: lighten(@brand-primary, 42%); + // outline: 1px solid @brand-primary; + } + tr.fancytree-focused span.fancytree-title { + outline: 1px dotted @brand-primary; + } + tr.fancytree-active:hover, + tr.fancytree-selected:hover { + // background-color: #CBE8F6; + // outline: 1px solid #26A0DA; + } + tr.fancytree-selected { + background-color: @brand-success; + span.fancytree-node { + background-color: @brand-success; + } + span.fancytree-title { + background-color: @brand-success; // green title, even when active + } + } + tr.fancytree-active { + background-color: @brand-primary; + span.fancytree-node { + background-color: @brand-primary; + } + } +} diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap-n/ui.fancytree.min.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap-n/ui.fancytree.min.css new file mode 100644 index 00000000000..ba00e2a31c1 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap-n/ui.fancytree.min.css @@ -0,0 +1,6 @@ +/*! + * Fancytree "bootstrap" skin (highlighting the node span instead of title-only). + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */.ui-helper-hidden{display:none}ul.fancytree-container{font-family:tahoma,arial,helvetica;font-size:10pt;white-space:nowrap;padding:3px;margin:0;background-color:#fff;border:1px dotted gray;overflow:auto;min-height:0;position:relative}ul.fancytree-container li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0}ul.fancytree-container li.fancytree-lastsib,ul.fancytree-no-connector>li{background-image:none}.ui-fancytree-disabled ul.fancytree-container{opacity:.5;background-color:silver}#fancytree-drop-marker,span.fancytree-checkbox,span.fancytree-drag-helper-img,span.fancytree-empty,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio,span.fancytree-vline{width:1em;height:1em;display:inline-block;vertical-align:top;background-repeat:no-repeat;background-position:left;background-position:0 0}span.fancytree-checkbox,span.fancytree-custom-icon,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio{margin-top:0}span.fancytree-custom-icon{display:inline-block;margin-left:.5em}img.fancytree-icon{width:1em;height:1em;margin-left:.5em;margin-top:0;vertical-align:top;border-style:none}span.fancytree-expander{cursor:pointer}.fancytree-exp-n span.fancytree-expander,.fancytree-exp-nl span.fancytree-expander{background-image:none;cursor:default}span.fancytree-checkbox{margin-left:.5em}.fancytree-unselectable span.fancytree-checkbox{opacity:.4;filter:alpha(opacity=40)}span.fancytree-icon{margin-left:.5em}.fancytree-loading span.fancytree-expander,.fancytree-loading span.fancytree-expander:hover,.fancytree-statusnode-wait span.fancytree-icon,.fancytree-statusnode-wait span.fancytree-icon:hover{background-image:url(loading.gif)}span.fancytree-node{display:inherit;width:100%;margin-top:1px;min-height:1em}span.fancytree-title{color:#000;cursor:pointer;display:inline-block;vertical-align:top;min-height:1em;padding:0 3px;margin:0 0 0 .5em;border:1px solid transparent;-webkit-border-radius:0;-moz-border-radius:0;-ms-border-radius:0;-o-border-radius:0}span.fancytree-node.fancytree-error span.fancytree-title{color:red}div.fancytree-drag-helper span.fancytree-childcounter,div.fancytree-drag-helper span.fancytree-dnd-modifier{display:inline-block;color:#fff;background:#337ab7;border:1px solid gray;min-width:10px;height:10px;line-height:1;vertical-align:baseline;border-radius:10px;padding:2px;text-align:center;font-size:9px}div.fancytree-drag-helper span.fancytree-childcounter{position:absolute;top:-6px;right:-6px}div.fancytree-drag-helper span.fancytree-dnd-modifier{background:#5cb85c;border:0;font-weight:bolder}#fancytree-drop-marker{width:2em;position:absolute;margin:0}#fancytree-drop-marker.fancytree-drop-after,#fancytree-drop-marker.fancytree-drop-before{width:4em}span.fancytree-drag-source.fancytree-drag-remove{opacity:.15}table.fancytree-ext-table{border-collapse:collapse}table.fancytree-ext-table span.fancytree-node{display:inline-block}table.fancytree-ext-columnview tbody tr td{position:relative;border:1px solid gray;vertical-align:top;overflow:auto}table.fancytree-ext-columnview tbody tr td>ul{padding:0}table.fancytree-ext-columnview tbody tr td>ul li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0}table.fancytree-ext-columnview span.fancytree-node{position:relative;display:inline-block}table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded{background-color:#CBE8F6}table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right{position:absolute;right:3px}.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title{color:silver;font-weight:lighter}.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title,.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title{color:#000;font-weight:400}.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title,.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title{color:#000;font-weight:700}.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide,.fancytree-ext-filter-hide tr.fancytree-hide{display:none}.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title,.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title{color:silver;font-weight:lighter}.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title,.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title{color:#000;font-weight:400}.fancytree-ext-childcounter span.fancytree-icon,.fancytree-ext-filter span.fancytree-icon{position:relative}.fancytree-ext-childcounter span.fancytree-childcounter,.fancytree-ext-filter span.fancytree-childcounter{color:#fff;background:#777;border:1px solid gray;position:absolute;top:-6px;right:-6px;min-width:10px;height:10px;line-height:1;vertical-align:baseline;border-radius:10px;padding:2px;text-align:center;font-size:9px}ul.fancytree-ext-wide{position:relative;min-width:100%;z-index:2;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}ul.fancytree-ext-wide span.fancytree-node>span{position:relative;z-index:2}ul.fancytree-ext-wide span.fancytree-node span.fancytree-title{position:absolute;z-index:1;left:0;width:100%;margin-left:0;margin-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}ul.fancytree-container ul{padding:0 0 0 1.5em;margin:0}.fancytree-container:focus{outline:0}span.fancytree-node{border:1px solid transparent;border-radius:3px;padding-left:8px}span.fancytree-title{border-radius:3px}span.fancytree-node.fancytree-selected{background-color:#80c780;border-color:#80c780}span.fancytree-node.fancytree-selected span.fancytree-title{background-color:#80c780}span.fancytree-node.fancytree-active{background-color:#6aa3d5}.fancytree-container.fancytree-treefocus span.fancytree-node:hover{background-color:#e9f2f9}.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-focused{border-color:#428bca}.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-selected,.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-selected span.fancytree-title{background-color:#5cb85c}.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-active{background-color:#428bca;border-color:#428bca}table.fancytree-ext-table tbody tr td{border:1px solid #eee}table.fancytree-ext-table tbody tr.fancytree-selected,table.fancytree-ext-table tbody tr.fancytree-selected span.fancytree-node,table.fancytree-ext-table tbody tr.fancytree-selected span.fancytree-title{background-color:#80c780}table.fancytree-ext-table tbody tr.fancytree-active,table.fancytree-ext-table tbody tr.fancytree-active span.fancytree-node{background-color:#6aa3d5}table.fancytree-ext-table.fancytree-treefocus tbody tr:hover{background-color:#e9f2f9}table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-focused span.fancytree-title{outline:1px dotted #428bca}table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-selected,table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-selected span.fancytree-node,table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-selected span.fancytree-title{background-color:#5cb85c}table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-active,table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-active span.fancytree-node{background-color:#428bca} \ No newline at end of file diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap/ui.fancytree.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap/ui.fancytree.css new file mode 100644 index 00000000000..487a0ee05e3 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap/ui.fancytree.css @@ -0,0 +1,492 @@ +/*! + * Fancytree "bootstrap" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ +/******************************************************************************* + * Common Styles for Fancytree Skins. + * + * This section is automatically generated from the `skin-common.less` template. + ******************************************************************************/ +/*------------------------------------------------------------------------------ + * Helpers + *----------------------------------------------------------------------------*/ +.ui-helper-hidden { + display: none; +} +/*------------------------------------------------------------------------------ + * Container and UL / LI + *----------------------------------------------------------------------------*/ +ul.fancytree-container { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + white-space: nowrap; + padding: 3px; + margin: 0; + background-color: white; + border: 1px dotted gray; + overflow: auto; + min-height: 0%; + position: relative; +} +ul.fancytree-container ul { + padding: 0 0 0 16px; + margin: 0; +} +ul.fancytree-container li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0em 0em; + background-repeat: repeat-y; + background-image: none; + margin: 0; +} +ul.fancytree-container li.fancytree-lastsib { + background-image: none; +} +ul.fancytree-no-connector > li { + background-image: none; +} +.ui-fancytree-disabled ul.fancytree-container { + opacity: 0.5; + background-color: silver; +} +/*------------------------------------------------------------------------------ + * Common icon definitions + *----------------------------------------------------------------------------*/ +span.fancytree-empty, +span.fancytree-vline, +span.fancytree-expander, +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-radio, +span.fancytree-drag-helper-img, +#fancytree-drop-marker { + width: 1em; + height: 1em; + display: inline-block; + vertical-align: top; + background-repeat: no-repeat; + background-position: left; + background-position: 0em 0em; +} +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-expander, +span.fancytree-radio, +span.fancytree-custom-icon { + margin-top: 2px; +} +/* Used by iconclass option and iconClass callback: */ +span.fancytree-custom-icon { + display: inline-block; + margin-left: 0.5em; +} +/* Used by 'icon' node option: */ +img.fancytree-icon { + width: 1em; + height: 1em; + margin-left: 0.5em; + margin-top: 2px; + vertical-align: top; + border-style: none; +} +/*------------------------------------------------------------------------------ + * Expander icon + * + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-exp- + * 1st character: 'e': expanded, 'c': collapsed, 'n': no children + * 2nd character (optional): 'd': lazy (Delayed) + * 3rd character (optional): 'l': Last sibling + *----------------------------------------------------------------------------*/ +span.fancytree-expander { + cursor: pointer; +} +.fancytree-exp-n span.fancytree-expander, +.fancytree-exp-nl span.fancytree-expander { + background-image: none; + cursor: default; +} +/*------------------------------------------------------------------------------ + * Checkbox icon + *----------------------------------------------------------------------------*/ +span.fancytree-checkbox { + margin-left: 0.5em; +} +.fancytree-unselectable span.fancytree-checkbox { + opacity: 0.4; + filter: alpha(opacity=40); +} +/*------------------------------------------------------------------------------ + * Radiobutton icon + * This is a customization, that may be activated by overriding the 'checkbox' + * class name as 'fancytree-radio' in the tree options. + *----------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------ + * Node type icon + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-ico- + * 1st character: 'e': expanded, 'c': collapsed + * 2nd character (optional): 'f': folder + *----------------------------------------------------------------------------*/ +span.fancytree-icon { + margin-left: 0.5em; +} +/* Documents */ +/* Folders */ +.fancytree-loading span.fancytree-expander, +.fancytree-loading span.fancytree-expander:hover, +.fancytree-statusnode-wait span.fancytree-icon, +.fancytree-statusnode-wait span.fancytree-icon:hover { + background-image: none; +} +/* Status node icons */ +/*------------------------------------------------------------------------------ + * Node titles and highlighting + *----------------------------------------------------------------------------*/ +span.fancytree-node { + /* See #117 */ + display: inherit; + width: 100%; + margin-top: 0px; + min-height: 1em; +} +span.fancytree-title { + color: #333333; + cursor: pointer; + display: inline-block; + vertical-align: top; + min-height: 1em; + padding: 0 3px 0 3px; + margin: 0px 0 0 0.5em; + border: 1px solid transparent; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + -ms-border-radius: 3px; + -o-border-radius: 3px; + border-radius: 3px; +} +span.fancytree-node.fancytree-error span.fancytree-title { + color: #d9534f; +} +/*------------------------------------------------------------------------------ + * Drag'n'drop support + *----------------------------------------------------------------------------*/ +div.fancytree-drag-helper span.fancytree-childcounter, +div.fancytree-drag-helper span.fancytree-dnd-modifier { + display: inline-block; + color: #fff; + background: #337ab7; + border: 1px solid gray; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +div.fancytree-drag-helper span.fancytree-childcounter { + position: absolute; + top: -6px; + right: -6px; +} +div.fancytree-drag-helper span.fancytree-dnd-modifier { + background: #5cb85c; + border: none; + font-weight: bolder; +} +/*** Drop marker icon *********************************************************/ +#fancytree-drop-marker { + width: 2em; + position: absolute; + margin: 0; +} +#fancytree-drop-marker.fancytree-drop-after, +#fancytree-drop-marker.fancytree-drop-before { + width: 4em; +} +/*** Source node while dragging ***********************************************/ +span.fancytree-drag-source.fancytree-drag-remove { + opacity: 0.15; +} +/*** Target node while dragging cursor is over it *****************************/ +/*------------------------------------------------------------------------------ + * 'table' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-table { + border-collapse: collapse; +} +table.fancytree-ext-table span.fancytree-node { + display: inline-block; +} +/*------------------------------------------------------------------------------ + * 'columnview' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-columnview tbody tr td { + position: relative; + border: 1px solid gray; + vertical-align: top; + overflow: auto; +} +table.fancytree-ext-columnview tbody tr td > ul { + padding: 0; +} +table.fancytree-ext-columnview tbody tr td > ul li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0em 0em; + background-repeat: repeat-y; + background-image: none; + /* no v-lines */ + margin: 0; +} +table.fancytree-ext-columnview span.fancytree-node { + position: relative; + /* allow positioning of embedded spans */ + display: inline-block; +} +table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded { + background-color: #CBE8F6; +} +table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right { + position: absolute; + right: 3px; +} +/*------------------------------------------------------------------------------ + * 'filter' extension + *----------------------------------------------------------------------------*/ +.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title { + color: #333333; + font-weight: lighter; +} +.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: bold; +} +.fancytree-ext-filter-hide tr.fancytree-hide, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide { + display: none; +} +.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title { + color: #333333; + font-weight: lighter; +} +.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-childcounter span.fancytree-icon, +.fancytree-ext-filter span.fancytree-icon { + position: relative; +} +.fancytree-ext-childcounter span.fancytree-childcounter, +.fancytree-ext-filter span.fancytree-childcounter { + color: #fff; + background: #777; + border: 1px solid gray; + position: absolute; + top: -6px; + right: -6px; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +/*------------------------------------------------------------------------------ + * 'wide' extension + *----------------------------------------------------------------------------*/ +ul.fancytree-ext-wide { + position: relative; + min-width: 100%; + z-index: 2; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +ul.fancytree-ext-wide span.fancytree-node > span { + position: relative; + z-index: 2; +} +ul.fancytree-ext-wide span.fancytree-node span.fancytree-title { + position: absolute; + z-index: 1; + left: 0px; + width: 100%; + margin-left: 0; + margin-right: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +/******************************************************************************* + * Styles specific to this skin. + * + * This section is automatically generated from the `ui-fancytree.less` template. + ******************************************************************************/ +/******************************************************************************* + * Plain tree + * Modifier classes on <ul> container: + * table-hover : Enable a light mouse hover effect + * fancytree-colorize-selected: Give selected (checked) rows a color + */ +ul.fancytree-container ul { + padding: 0 0 0 1.5em; + margin: 0; +} +/* Prevent focus frame */ +.fancytree-container:focus { + outline: none; +} +.fancytree-container .fancytree-active span.fancytree-title input, +.fancytree-container.fancytree-colorize-selected .fancytree-selected span.fancytree-title input { + color: black; +} +div.fancytree-drag-helper.fancytree-drop-reject, +div.fancytree-drag-helper.fancytree-drop-reject span.fancytree-title { + color: #d9534f; +} +span.fancytree-node.fancytree-drag-source { + background-color: #5bc0de !important; +} +span.fancytree-node.fancytree-drop-target.fancytree-drop-reject span.fancytree.title { + background-color: #d9534f !important; +} +.fancytree-plain.fancytree-colorize-selected span.fancytree-node.fancytree-selected, +.fancytree-plain.fancytree-colorize-selected span.fancytree-node.fancytree-selected span.fancytree-title { + background-color: #80c780; + border-color: #80c780; + color: #ffffff; +} +.fancytree-plain.fancytree-colorize-selected span.fancytree-node.fancytree-selected:hover span.fancytree-title { + background-color: #6ec06e; +} +.fancytree-plain.fancytree-colorize-selected span.fancytree-node.fancytree-active.fancytree-selected span.fancytree-title { + color: #80c780; +} +.fancytree-plain.fancytree-colorize-selected.fancytree-treefocus span.fancytree-title:hover { + background-color: #f5f5f5; +} +.fancytree-plain.fancytree-colorize-selected.fancytree-treefocus span.fancytree-node.fancytree-selected span.fancytree-title { + background-color: #5cb85c; +} +.fancytree-plain.fancytree-colorize-selected.fancytree-treefocus span.fancytree-node.fancytree-selected:hover span.fancytree-title { + background-color: #4cae4c; +} +.fancytree-plain.fancytree-colorize-selected.fancytree-treefocus span.fancytree-node.fancytree-active.fancytree-selected span.fancytree-title { + color: #5cb85c; +} +.fancytree-plain.fancytree-container span.fancytree-node { + margin-top: 2px; + margin-bottom: 2px; +} +.fancytree-plain.fancytree-container span.fancytree-title { + border: 1px solid transparent; + border-radius: 3px; + outline-radius: 3px; +} +.fancytree-plain.fancytree-container span.fancytree-title:hover { + background-color: #f5f5f5; +} +.fancytree-plain.fancytree-container span.fancytree-node.fancytree-active span.fancytree-title { + background-color: #5094ce; + color: #ffffff; +} +.fancytree-plain.fancytree-container span.fancytree-node.fancytree-active:hover span.fancytree-title { + background-color: #3c87c8; +} +.fancytree-plain.fancytree-container.fancytree-ext-wide span.fancytree-node.fancytree-active { + color: #ffffff; +} +.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-focused span.fancytree-title { + border-color: #337ab7; +} +.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-active span.fancytree-title { + background-color: #337ab7; + border-color: #337ab7; +} +.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-active:hover span.fancytree-title { + background-color: #2e6da4; +} +/******************************************************************************* + * 'table' extension + * Modifier classes on <table>: + * table-hover : Enable a light mouse hover effect + * fancytree-colorize-selected: Give selected (checked) rows a color + */ +table.fancytree-ext-table > tbody > tr > td span.fancytree-title { + border: none; +} +table.fancytree-ext-table.fancytree-colorize-selected > tbody > tr.fancytree-selected > td { + background-color: #80c780; +} +table.fancytree-ext-table.fancytree-colorize-selected > tbody > tr.fancytree-selected > td, +table.fancytree-ext-table.fancytree-colorize-selected > tbody > tr.fancytree-selected > td span.fancytree-title { + color: #ffffff; +} +table.fancytree-ext-table.fancytree-colorize-selected.fancytree-treefocus > tbody > tr.fancytree-selected > td { + background-color: #5cb85c; +} +table.fancytree-ext-table.fancytree-colorize-selected.table-hover > tbody > tr.fancytree-selected:hover > td { + background-color: #6ec06e; +} +table.fancytree-ext-table.fancytree-colorize-selected.fancytree-treefocus.table-hover > tbody > tr.fancytree-selected:hover > td { + background-color: #4cae4c; +} +table.fancytree-ext-table.fancytree-colorize-selected.fancytree-treefocus.table-hover > tbody > tr.fancytree-selected.fancytree-active:hover > td, +table.fancytree-ext-table.fancytree-colorize-selected.table-hover > tbody > tr.fancytree-selected.fancytree-active:hover > td { + background-color: #2e6da4; +} +table.fancytree-ext-table.fancytree-colorize-selected > tbody > tr.fancytree-active.fancytree-selected { + outline-width: 2px; + outline-offset: -2px; + outline-style: solid; + outline-color: #80c780; +} +table.fancytree-ext-table.fancytree-container > tbody > tr.fancytree-active > td { + background-color: #5094ce; +} +table.fancytree-ext-table.fancytree-container > tbody > tr.fancytree-active > td, +table.fancytree-ext-table.fancytree-container > tbody > tr.fancytree-active > td span.fancytree-title { + color: #ffffff; +} +table.fancytree-ext-table.fancytree-treefocus.fancytree-container > tbody > tr.fancytree-focused span.fancytree-title { + outline: 1px dotted #000; +} +table.fancytree-ext-table.fancytree-treefocus.fancytree-container > tbody > tr.fancytree-active > td { + background-color: #337ab7; +} +table.fancytree-ext-table.fancytree-treefocus.fancytree-container.table-hover > tbody > tr.fancytree-active:hover > td { + background-color: #2e6da4; +} diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap/ui.fancytree.less b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap/ui.fancytree.less new file mode 100644 index 00000000000..b5857532892 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap/ui.fancytree.less @@ -0,0 +1,333 @@ +/*! + * Fancytree "bootstrap" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ + +// Import common styles +@import "../skin-common.less"; + + +/******************************************************************************* + * Styles specific to this skin. + * + * This section is automatically generated from the `ui-fancytree.less` template. + ******************************************************************************/ + + +// local vars +// @fancy-my-icon-size: 16px; + +//------------------------------------------------------------------------------ +// Original bootstrap colors +// See http://getbootstrap.com/css/#less-variables-colors and +// https://github.com/twbs/bootstrap/blob/master/less/variables.less +@gray-base: #000; +@gray-darker: lighten(@gray-base, 13.5%); // #222 +@gray-dark: lighten(@gray-base, 20%); // #333 +@gray: lighten(@gray-base, 33.5%); // #555 +@gray-light: lighten(@gray-base, 46.7%); // #777 +@gray-lighter: lighten(@gray-base, 93.5%); // #eee + +@brand-primary: darken(#428bca, 6.5%); // blue, #337ab7 +@brand-success: #5cb85c; // green +@brand-info: #5bc0de; // light blue +@brand-warning: #f0ad4e; // orange +@brand-danger: #d9534f; // red + +@font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif; +@font-family-serif: Georgia, "Times New Roman", Times, serif; +//** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`. +@font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace; +@font-family-base: @font-family-sans-serif; + +@font-size-base: 14px; +@font-size-large: ceil((@font-size-base * 1.25)); // ~18px +@font-size-small: ceil((@font-size-base * 0.85)); // ~12px + +@border-radius-base: 4px; +@border-radius-large: 6px; +@border-radius-small: 3px; + +@text-color: @gray-dark; +//** Default background color used for all tables. +@table-bg: transparent; +//** Background color used for `.table-striped`. +@table-bg-accent: #f9f9f9; +//** Background color used for `.table-hover`. +@table-bg-hover: #f5f5f5; +@table-bg-active: @table-bg-hover; + +//** Border color for table and cell borders. +@table-border-color: #ddd; + +//------------------------------------------------------------------------------ + +// Override the variable after the import. +// NOTE: Variables are always resolved as the last definition, even if it is +// after where it is used. +@fancy-use-sprites: false; // false: suppress all background images (i.e. icons) +@fancy-hide-connectors: true; +@fancy-loading-url: none; + +@fancy-line-height: 1em; // height of a nodes selection bar including borders +@fancy-node-v-spacing: 0px; // gap between two node borders +@fancy-icon-width: 1em; +@fancy-icon-height: 1em; +@fancy-icon-spacing: 0.5em; // margin between icon/icon or icon/title +@fancy-icon-ofs-top: 2px; // extra vertical offset for expander, checkbox and icon +@fancy-title-ofs-top: 0px; // extra vertical offset for title +@fancy-node-border-width: 1px; +@fancy-node-border-radius: @border-radius-small; +@fancy-node-outline-width: 1px; + +@fancy-font-family: @font-family-base; +@fancy-font-size: @font-size-base; +@fancy-font-color: @text-color; +@fancy-font-color-dimm: @gray-dark; +@fancy-font-error-color: @brand-danger; + +@fancy-active-text: #fff; +@fancy-active-color: @brand-primary; +@fancy-select-color: @brand-success; +@fancy-hover-color: @table-bg-hover; + +/******************************************************************************* + * Plain tree + * Modifier classes on <ul> container: + * table-hover : Enable a light mouse hover effect + * fancytree-colorize-selected: Give selected (checked) rows a color + */ +ul.fancytree-container ul { + padding: 0 0 0 1.5em; + margin: 0; +} +/* Prevent focus frame */ +.fancytree-container:focus { + outline: none; +} + +// Active and (optionally) selected nodes are white on colored bg. Undo this for input controls: +.fancytree-container .fancytree-active span.fancytree-title input, +.fancytree-container.fancytree-colorize-selected .fancytree-selected span.fancytree-title input { + color: black; +} + +// ------------------------------------------------------------------------------ +// * Drag'n'drop support +// *---------------------------------------------------------------------------- +// div.fancytree-drag-helper { +// } +// div.fancytree-drag-helper a { +// border: 1px solid gray; +// background-color: white; +// padding-left: 5px; +// padding-right: 5px; +// opacity: 0.8; +// } +// span.fancytree-drag-helper-img { +// // position: relative; +// // left: -16px; +// } +div.fancytree-drag-helper.fancytree-drop-reject, +div.fancytree-drag-helper.fancytree-drop-reject span.fancytree-title +{ + color: @fancy-font-error-color; +} +// div.fancytree-drop-accept span.fancytree-drag-helper-img { +// .useSprite(2, 7); +// } +// div.fancytree-drop-reject span.fancytree-drag-helper-img { +// .useSprite(1, 7); +// } + +// //--- Drop marker icon --------------------------------------------------------- +// #fancytree-drop-marker { +// width: 2 * @fancy-icon-width; // was 24px, but 32 should be correct +// position: absolute; +// .useSprite(0, 8); +// margin: 0; +// &.fancytree-drop-after, +// &.fancytree-drop-before { +// width: 4 * @fancy-icon-width; // 64px; +// .useSprite(0, 9); +// } +// &.fancytree-drop-copy { +// .useSprite(4, 8); +// } +// &.fancytree-drop-move { +// .useSprite(2, 8); +// } +// } + +//--- Source node while dragging ----------------------------------------------- + +span.fancytree-node.fancytree-drag-source { + background-color: @brand-info !important; + span.fancytree.title { + // outline: 1px solid @brand-info; + // color: @brand-primary; + } +} + +//--- Target node while dragging cursor is over it ----------------------------- + +span.fancytree-node.fancytree-drop-target { + &.fancytree-drop-accept span.fancytree.title { + // background-color: @brand-danger !important; + // outline: 1px solid @brand-success; + // color: white !important; + } + &.fancytree-drop-reject span.fancytree.title { + background-color: @brand-danger !important; + // outline: 1px solid @brand-danger; + // color: white !important; + } +} + +// Inactive tree: +.fancytree-plain { + &.fancytree-colorize-selected { + span.fancytree-node.fancytree-selected, + span.fancytree-node.fancytree-selected span.fancytree-title { // selected nodes inside inactive tree + background-color: lighten(@fancy-select-color, 10%); + border-color: lighten(@fancy-select-color, 10%); + color: @fancy-active-text; + } + span.fancytree-node.fancytree-selected:hover span.fancytree-title { + background-color: lighten(@fancy-select-color, 5%); + } + span.fancytree-node.fancytree-active.fancytree-selected span.fancytree-title { // active nodes inside inactive tree + color: lighten(@fancy-select-color, 10%); + } + &.fancytree-treefocus { + span.fancytree-title:hover { + background-color: @fancy-hover-color; + } + span.fancytree-node.fancytree-selected span.fancytree-title { + background-color: @fancy-select-color; + } + span.fancytree-node.fancytree-selected:hover span.fancytree-title { + background-color: darken(@fancy-select-color, 5%); + } + span.fancytree-node.fancytree-active.fancytree-selected span.fancytree-title { + color: @fancy-select-color; + } + } + } + + &.fancytree-container { // adding this class to increase specificity, so we can override .fancytree-colorize-selected + span.fancytree-node { + margin-top: 2px; + margin-bottom: 2px; + } + span.fancytree-title { + border: @fancy-node-border-width solid transparent; // avoid jumping, when a border is added on hover + border-radius: @border-radius-small; + outline-radius: @border-radius-small; + } + span.fancytree-title:hover { + background-color: @fancy-hover-color; + } + span.fancytree-node.fancytree-active span.fancytree-title { // active nodes inside inactive tree + background-color: lighten(@fancy-active-color, 10%); + color: @fancy-active-text; + } + span.fancytree-node.fancytree-active:hover span.fancytree-title { + background-color: lighten(@fancy-active-color, 5%); + } + &.fancytree-ext-wide span.fancytree-node.fancytree-active { // in wide mode, icons of active nodes must be white-on-color + color: @fancy-active-text; + } + + // Active tree: + &.fancytree-treefocus { + span.fancytree-node.fancytree-focused span.fancytree-title { + border-color: @brand-primary; + } + span.fancytree-node.fancytree-active span.fancytree-title { + background-color: @fancy-active-color; + border-color: @fancy-active-color; + } + span.fancytree-node.fancytree-active:hover span.fancytree-title { + background-color: darken(@fancy-active-color, 5%); + } + } + } +} + +/******************************************************************************* + * 'table' extension + * Modifier classes on <table>: + * table-hover : Enable a light mouse hover effect + * fancytree-colorize-selected: Give selected (checked) rows a color + */ +table.fancytree-ext-table { + >tbody >tr >td span.fancytree-title { + border: none; + } + + // Give a separate color for selected (checked) rows + // Define *before* the .fancytree-active rules, because active color should + // override selected color. + &.fancytree-colorize-selected { + >tbody >tr.fancytree-selected >td { + // dimmed, if inside inactive tree + background-color: lighten(@fancy-select-color, 10%); + // white text for selected nodes + &, + span.fancytree-title { + color: @fancy-active-text; + } + } + &.fancytree-treefocus >tbody >tr.fancytree-selected >td { + background-color: @fancy-select-color; + } + &.table-hover >tbody >tr.fancytree-selected:hover >td { + // dimmed, if inside inactive tree + background-color: lighten(@fancy-select-color, 5%); + } + &.fancytree-treefocus.table-hover >tbody >tr.fancytree-selected:hover >td { + background-color: darken(@fancy-select-color, 5%); + } + &.fancytree-treefocus.table-hover >tbody >tr.fancytree-selected.fancytree-active:hover >td, + &.table-hover >tbody >tr.fancytree-selected.fancytree-active:hover >td { + background-color: darken(@fancy-active-color, 5%); + } + >tbody >tr.fancytree-active.fancytree-selected { + outline-width: 2px; + outline-offset: -2px; + outline-style: solid; + outline-color: lighten(@fancy-select-color, 10%); + } + } + + // General tree (slightly dimmed, since we also define colors for inactive + // mode here). + + &.fancytree-container >tbody >tr.fancytree-active >td { + background-color: lighten(@fancy-active-color, 10%); + // white text for selected nodes + &, + span.fancytree-title { + color: @fancy-active-text; + } + } + + // Reset to standard colors if tree has keyboard focus. + // We add .fancytree-container to increase specificity, so we can override + // .fancytree-colorize-selected defined above + + &.fancytree-treefocus.fancytree-container { + >tbody >tr.fancytree-focused span.fancytree-title { + outline: 1px dotted #000; + } + >tbody >tr.fancytree-active >td { + background-color: @fancy-active-color; + } + &.table-hover >tbody >tr.fancytree-active:hover >td { + background-color: darken(@fancy-active-color, 5%); + } + } +} diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap/ui.fancytree.min.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap/ui.fancytree.min.css new file mode 100644 index 00000000000..8d7e4dd622e --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-bootstrap/ui.fancytree.min.css @@ -0,0 +1,6 @@ +/*! + * Fancytree "bootstrap" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */.ui-helper-hidden{display:none}ul.fancytree-container{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;white-space:nowrap;padding:3px;margin:0;background-color:#fff;border:1px dotted gray;overflow:auto;min-height:0;position:relative}ul.fancytree-container li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0}ul.fancytree-container li.fancytree-lastsib,ul.fancytree-no-connector>li{background-image:none}.ui-fancytree-disabled ul.fancytree-container{opacity:.5;background-color:silver}#fancytree-drop-marker,span.fancytree-checkbox,span.fancytree-drag-helper-img,span.fancytree-empty,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio,span.fancytree-vline{width:1em;height:1em;display:inline-block;vertical-align:top;background-repeat:no-repeat;background-position:left;background-position:0 0}span.fancytree-checkbox,span.fancytree-custom-icon,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio{margin-top:2px}span.fancytree-custom-icon{display:inline-block;margin-left:.5em}img.fancytree-icon{width:1em;height:1em;margin-left:.5em;margin-top:2px;vertical-align:top;border-style:none}span.fancytree-expander{cursor:pointer}.fancytree-exp-n span.fancytree-expander,.fancytree-exp-nl span.fancytree-expander{background-image:none;cursor:default}span.fancytree-checkbox{margin-left:.5em}.fancytree-unselectable span.fancytree-checkbox{opacity:.4;filter:alpha(opacity=40)}span.fancytree-icon{margin-left:.5em}.fancytree-loading span.fancytree-expander,.fancytree-loading span.fancytree-expander:hover,.fancytree-statusnode-wait span.fancytree-icon,.fancytree-statusnode-wait span.fancytree-icon:hover{background-image:none}span.fancytree-node{display:inherit;width:100%;margin-top:0;min-height:1em}span.fancytree-title{color:#333;cursor:pointer;display:inline-block;vertical-align:top;min-height:1em;padding:0 3px;margin:0 0 0 .5em;border:1px solid transparent;-webkit-border-radius:3px;-moz-border-radius:3px;-ms-border-radius:3px;-o-border-radius:3px;border-radius:3px}span.fancytree-node.fancytree-error span.fancytree-title{color:#d9534f}div.fancytree-drag-helper span.fancytree-childcounter,div.fancytree-drag-helper span.fancytree-dnd-modifier{display:inline-block;color:#fff;background:#337ab7;border:1px solid gray;min-width:10px;height:10px;line-height:1;vertical-align:baseline;border-radius:10px;padding:2px;text-align:center;font-size:9px}div.fancytree-drag-helper span.fancytree-childcounter{position:absolute;top:-6px;right:-6px}div.fancytree-drag-helper span.fancytree-dnd-modifier{background:#5cb85c;border:0;font-weight:bolder}#fancytree-drop-marker{width:2em;position:absolute;margin:0}#fancytree-drop-marker.fancytree-drop-after,#fancytree-drop-marker.fancytree-drop-before{width:4em}span.fancytree-drag-source.fancytree-drag-remove{opacity:.15}table.fancytree-ext-table{border-collapse:collapse}table.fancytree-ext-table span.fancytree-node{display:inline-block}table.fancytree-ext-columnview tbody tr td{position:relative;border:1px solid gray;vertical-align:top;overflow:auto}table.fancytree-ext-columnview tbody tr td>ul{padding:0}table.fancytree-ext-columnview tbody tr td>ul li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0}table.fancytree-ext-columnview span.fancytree-node{position:relative;display:inline-block}table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded{background-color:#CBE8F6}table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right{position:absolute;right:3px}.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title{color:#333;font-weight:lighter}.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title,.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title{color:#000;font-weight:400}.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title,.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title{color:#000;font-weight:700}.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide,.fancytree-ext-filter-hide tr.fancytree-hide{display:none}.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title,.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title{color:#333;font-weight:lighter}.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title,.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title{color:#000;font-weight:400}.fancytree-ext-childcounter span.fancytree-icon,.fancytree-ext-filter span.fancytree-icon{position:relative}.fancytree-ext-childcounter span.fancytree-childcounter,.fancytree-ext-filter span.fancytree-childcounter{color:#fff;background:#777;border:1px solid gray;position:absolute;top:-6px;right:-6px;min-width:10px;height:10px;line-height:1;vertical-align:baseline;border-radius:10px;padding:2px;text-align:center;font-size:9px}ul.fancytree-ext-wide{position:relative;min-width:100%;z-index:2;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}ul.fancytree-ext-wide span.fancytree-node>span{position:relative;z-index:2}ul.fancytree-ext-wide span.fancytree-node span.fancytree-title{position:absolute;z-index:1;left:0;width:100%;margin-left:0;margin-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}ul.fancytree-container ul{padding:0 0 0 1.5em;margin:0}.fancytree-container:focus{outline:0}.fancytree-container .fancytree-active span.fancytree-title input,.fancytree-container.fancytree-colorize-selected .fancytree-selected span.fancytree-title input{color:#000}div.fancytree-drag-helper.fancytree-drop-reject,div.fancytree-drag-helper.fancytree-drop-reject span.fancytree-title{color:#d9534f}span.fancytree-node.fancytree-drag-source{background-color:#5bc0de!important}span.fancytree-node.fancytree-drop-target.fancytree-drop-reject span.fancytree.title{background-color:#d9534f!important}.fancytree-plain.fancytree-colorize-selected span.fancytree-node.fancytree-selected,.fancytree-plain.fancytree-colorize-selected span.fancytree-node.fancytree-selected span.fancytree-title{background-color:#80c780;border-color:#80c780;color:#fff}.fancytree-plain.fancytree-colorize-selected span.fancytree-node.fancytree-selected:hover span.fancytree-title{background-color:#6ec06e}.fancytree-plain.fancytree-colorize-selected span.fancytree-node.fancytree-active.fancytree-selected span.fancytree-title{color:#80c780}.fancytree-plain.fancytree-colorize-selected.fancytree-treefocus span.fancytree-title:hover{background-color:#f5f5f5}.fancytree-plain.fancytree-colorize-selected.fancytree-treefocus span.fancytree-node.fancytree-selected span.fancytree-title{background-color:#5cb85c}.fancytree-plain.fancytree-colorize-selected.fancytree-treefocus span.fancytree-node.fancytree-selected:hover span.fancytree-title{background-color:#4cae4c}.fancytree-plain.fancytree-colorize-selected.fancytree-treefocus span.fancytree-node.fancytree-active.fancytree-selected span.fancytree-title{color:#5cb85c}.fancytree-plain.fancytree-container span.fancytree-node{margin-top:2px;margin-bottom:2px}.fancytree-plain.fancytree-container span.fancytree-title{border:1px solid transparent;border-radius:3px;outline-radius:3px}.fancytree-plain.fancytree-container span.fancytree-title:hover{background-color:#f5f5f5}.fancytree-plain.fancytree-container span.fancytree-node.fancytree-active span.fancytree-title{background-color:#5094ce;color:#fff}.fancytree-plain.fancytree-container span.fancytree-node.fancytree-active:hover span.fancytree-title{background-color:#3c87c8}.fancytree-plain.fancytree-container.fancytree-ext-wide span.fancytree-node.fancytree-active{color:#fff}.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-focused span.fancytree-title{border-color:#337ab7}.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-active span.fancytree-title{background-color:#337ab7;border-color:#337ab7}.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-active:hover span.fancytree-title{background-color:#2e6da4}table.fancytree-ext-table>tbody>tr>td span.fancytree-title{border:0}table.fancytree-ext-table.fancytree-colorize-selected>tbody>tr.fancytree-selected>td{background-color:#80c780}table.fancytree-ext-table.fancytree-colorize-selected>tbody>tr.fancytree-selected>td,table.fancytree-ext-table.fancytree-colorize-selected>tbody>tr.fancytree-selected>td span.fancytree-title{color:#fff}table.fancytree-ext-table.fancytree-colorize-selected.fancytree-treefocus>tbody>tr.fancytree-selected>td{background-color:#5cb85c}table.fancytree-ext-table.fancytree-colorize-selected.table-hover>tbody>tr.fancytree-selected:hover>td{background-color:#6ec06e}table.fancytree-ext-table.fancytree-colorize-selected.fancytree-treefocus.table-hover>tbody>tr.fancytree-selected:hover>td{background-color:#4cae4c}table.fancytree-ext-table.fancytree-colorize-selected.fancytree-treefocus.table-hover>tbody>tr.fancytree-selected.fancytree-active:hover>td,table.fancytree-ext-table.fancytree-colorize-selected.table-hover>tbody>tr.fancytree-selected.fancytree-active:hover>td{background-color:#2e6da4}table.fancytree-ext-table.fancytree-colorize-selected>tbody>tr.fancytree-active.fancytree-selected{outline-width:2px;outline-offset:-2px;outline-style:solid;outline-color:#80c780}table.fancytree-ext-table.fancytree-container>tbody>tr.fancytree-active>td{background-color:#5094ce}table.fancytree-ext-table.fancytree-container>tbody>tr.fancytree-active>td,table.fancytree-ext-table.fancytree-container>tbody>tr.fancytree-active>td span.fancytree-title{color:#fff}table.fancytree-ext-table.fancytree-treefocus.fancytree-container>tbody>tr.fancytree-focused span.fancytree-title{outline:1px dotted #000}table.fancytree-ext-table.fancytree-treefocus.fancytree-container>tbody>tr.fancytree-active>td{background-color:#337ab7}table.fancytree-ext-table.fancytree-treefocus.fancytree-container.table-hover>tbody>tr.fancytree-active:hover>td{background-color:#2e6da4} \ No newline at end of file diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-common.less b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-common.less new file mode 100644 index 00000000000..1275f503157 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-common.less @@ -0,0 +1,685 @@ +/******************************************************************************* + * Common Styles for Fancytree Skins. + * + * This section is automatically generated from the `skin-common.less` template. + ******************************************************************************/ + +// Variables (defaults, may be overwritten by the including .less files) +@fancy-use-sprites: true; // false: suppress all background images (i.e. icons) +@fancy-hide-connectors: true; // false: show vertical connector lines + +@fancy-level-indent: 16px; +@fancy-line-height: 16px; // height of a nodes selection bar including borders +@fancy-node-v-spacing: 1px; // gap between two node borders +@fancy-icon-width: 16px; +@fancy-icon-height: 16px; +@fancy-icon-spacing: 3px; // margin between icon/icon or icon/title +@fancy-icon-ofs-top: 0px; // extra vertical offset for expander, checkbox and icon +@fancy-title-ofs-top: 0px; // extra vertical offset for title +@fancy-node-border-width: 1px; +@fancy-node-border-radius: 0px; +@fancy-node-outline-width: 1px; + +// @fancy-line-ofs-top: (@fancy-line-height - @fancy-icon-height) / 2; + +@fancy-image-dir: "."; + +// Use 'url(...)' to link to the throbber image, or +// use data-uri(...)' to inline the data in css instead: +@fancy-loading-url: url("@{fancy-image-dir}/loading.gif"); +// @fancy-loading-url: data-uri("@{fancy-image-dir}/loading.gif"); + +// Set to `true` to use `data-uri(...)` instead of a `url(...)` link: +@fancy-inline-sprites: false; + +@fancy-font-size: 10pt; +@fancy-font-family: tahoma, arial, helvetica; +@fancy-font-color: black; +@fancy-font-color-dimm: silver; +@fancy-font-error-color: red; + +//------------------------------------------------------------------------------ +// Mixins +//------------------------------------------------------------------------------ +.setBgPos(@x, @y, @cond:true) when (@cond){ + background-position: (@x * -@fancy-icon-width) (@y * -@fancy-icon-height); +} +.clearBgImage(@cond:true) when (@cond){ + background-image: none; +} +.setBgImageUrl(@url) when (@fancy-use-sprites) and not (@fancy-inline-sprites) { + background-image: url("@{fancy-image-dir}/@{url}"); +} +.setBgImageUrl(@url) when (@fancy-use-sprites) and (@fancy-inline-sprites) { + background-image: data-uri("@{fancy-image-dir}/@{url}"); +} +.useSprite(@x, @y) when (@fancy-use-sprites){ + .setBgPos(@x, @y); +} +.rounded-corners(@radius) { + -webkit-border-radius: @radius; + -moz-border-radius: @radius; + -ms-border-radius: @radius; + -o-border-radius: @radius; + border-radius: @radius; +} +.spanStyleMixin(@color, @bgcolor, @bordercolor){ + border-color: @bordercolor; + background: @bgcolor; + color: @color; +} +.spanStyleMixin(@color, @bgcolor, @bordercolor, @startColor, @stopColor){ + .spanStyleMixin(@color, @bgcolor, @bordercolor); + // @c-start: argb(@startColor); + // @c-end: argb(@stopColor); + background: -moz-linear-gradient(top, @startColor 0%, @stopColor 100%); // FF3.6+ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,@startColor), color-stop(100%,@stopColor)); // Chrome,Safari4+ + background: -webkit-linear-gradient(top, @startColor 0%,@stopColor 100%); // Chrome10+,Safari5.1+ + background: -o-linear-gradient(top, @startColor 0%,@stopColor 100%); // Opera 11.10+ + background: -ms-linear-gradient(top, @startColor 0%,@stopColor 100%); // IE10+ + background: linear-gradient(to bottom, @startColor 0%,@stopColor 100%); // W3C + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='@{startColor}', endColorstr='@{stopColor}',GradientType=0 ); // IE6-9 +} + +/*------------------------------------------------------------------------------ + * Helpers + *----------------------------------------------------------------------------*/ +// Redefine, in case jQuery-UI is not included +.ui-helper-hidden { + display: none; +} + +/*------------------------------------------------------------------------------ + * Container and UL / LI + *----------------------------------------------------------------------------*/ + +ul.fancytree-container { + font-family: @fancy-font-family; + font-size: @fancy-font-size; + white-space: nowrap; + padding: 3px; + margin: 0; // DT issue 201 + background-color: white; + border: 1px dotted gray; + overflow: auto; +// height: 100%; // DT issue 263, 470 + min-height: 0%; // #192 + position: relative; // #235 + ul { + padding: 0 0 0 @fancy-level-indent; + margin: 0; + } + li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + .setBgPos(0, 0); + background-repeat: repeat-y; + background-image: none; // no v-lines + + margin: 0; +// padding: 1px 0 0 0; // issue #246 + } + // Suppress lines for last child node + li.fancytree-lastsib { + background-image: none; + } +} + +// Suppress lines if level is fixed expanded (option minExpandLevel) +ul.fancytree-no-connector > li { + background-image: none; +} + +// Style, when control is disabled +.ui-fancytree-disabled ul.fancytree-container { + opacity: 0.5; +// filter: alpha(opacity=50); // Yields a css warning + background-color: silver; +} + +/*------------------------------------------------------------------------------ + * Common icon definitions + *----------------------------------------------------------------------------*/ + +span.fancytree-empty, +span.fancytree-vline, +span.fancytree-expander, +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-radio, +span.fancytree-drag-helper-img, +#fancytree-drop-marker { + width: @fancy-icon-width; + height: @fancy-icon-height; +// display: -moz-inline-box; // @ FF 1+2 removed for issue 221 +// -moz-box-align: start; /* issue 221 */ + display: inline-block; // Required to make a span sizeable + vertical-align: top; + background-repeat: no-repeat; + background-position: left; + .setBgImageUrl("icons.gif"); + .setBgPos(0, 0); +} +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-expander, +span.fancytree-radio, +span.fancytree-custom-icon { + margin-top: @fancy-icon-ofs-top; +} +/* Used by iconclass option and iconClass callback: */ +span.fancytree-custom-icon { + display: inline-block; + margin-left: @fancy-icon-spacing; +} +/* Used by 'icon' node option: */ +img.fancytree-icon { + width: @fancy-icon-width; + height: @fancy-icon-height; + margin-left: @fancy-icon-spacing; + margin-top: @fancy-icon-ofs-top; + vertical-align: top; + border-style: none; +} + + +/*------------------------------------------------------------------------------ + * Expander icon + * + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-exp- + * 1st character: 'e': expanded, 'c': collapsed, 'n': no children + * 2nd character (optional): 'd': lazy (Delayed) + * 3rd character (optional): 'l': Last sibling + *----------------------------------------------------------------------------*/ + +span.fancytree-expander { + // .useSprite(0, 5); + cursor: pointer; +} +// span.fancytree-expander:hover { +// // .useSprite(1, 5); +// } + +// --- End nodes (use connectors instead of expanders) + +.fancytree-exp-n span.fancytree-expander, +.fancytree-exp-nl span.fancytree-expander { + .clearBgImage( @fancy-hide-connectors ); + cursor: default; +} +.fancytree-exp-n span.fancytree-expander, // End-node, not last sibling +.fancytree-exp-n span.fancytree-expander:hover { + .useSprite(0, 4); +} +.fancytree-exp-nl span.fancytree-expander, // End-node, last sibling +.fancytree-exp-nl span.fancytree-expander:hover { + .useSprite(1, 4); +} + +// --- Collapsed + +.fancytree-exp-c span.fancytree-expander { // Collapsed, not delayed, not last sibling + .useSprite(0, 5); +} +.fancytree-exp-c span.fancytree-expander:hover { + .useSprite(1, 5); +} +.fancytree-exp-cl span.fancytree-expander { // Collapsed, not delayed, last sibling + .useSprite(0, 6); +} +.fancytree-exp-cl span.fancytree-expander:hover { + .useSprite(1, 6); +} +.fancytree-exp-cd span.fancytree-expander { // Collapsed, delayed, not last sibling + .useSprite(4, 5); +} +.fancytree-exp-cd span.fancytree-expander:hover { + .useSprite(5, 5); +} +.fancytree-exp-cdl span.fancytree-expander { // Collapsed, delayed, last sibling + .useSprite(4, 6); +} +.fancytree-exp-cdl span.fancytree-expander:hover { + .useSprite(5, 6); +} + +// --- Expanded + +.fancytree-exp-e span.fancytree-expander, // Expanded, not delayed, not last sibling +.fancytree-exp-ed span.fancytree-expander { // Expanded, delayed, not last sibling + .useSprite(2, 5); +} +.fancytree-exp-e span.fancytree-expander:hover, +.fancytree-exp-ed span.fancytree-expander:hover { + .useSprite(3, 5); +} +.fancytree-exp-el span.fancytree-expander, // Expanded, not delayed, last sibling +.fancytree-exp-edl span.fancytree-expander { // Expanded, delayed, last sibling + .useSprite(2, 6); +} +.fancytree-exp-el span.fancytree-expander:hover, +.fancytree-exp-edl span.fancytree-expander:hover { + .useSprite(3, 6); +} + +/*------------------------------------------------------------------------------ + * Checkbox icon + *----------------------------------------------------------------------------*/ + +span.fancytree-checkbox { + margin-left: @fancy-icon-spacing; + .useSprite(0, 2); + &:hover { .useSprite(1, 2); } +} +.fancytree-partsel span.fancytree-checkbox { + .useSprite(4, 2); + &:hover { .useSprite(5, 2); } +} +// selected after partsel, so it takes precedence: +.fancytree-selected span.fancytree-checkbox { + .useSprite(2, 2); + &:hover { .useSprite(3, 2); } +} +// Unselectable is dimmed, without hover effects +.fancytree-unselectable { + span.fancytree-checkbox { + opacity: 0.4; + filter: alpha(opacity=40); + } + span.fancytree-checkbox:hover { + .useSprite(0, 2); + } + &.fancytree-partsel span.fancytree-checkbox:hover { + .useSprite(4, 2); + } + &.fancytree-selected span.fancytree-checkbox:hover { + .useSprite(2, 2); + } +} + +/*------------------------------------------------------------------------------ + * Radiobutton icon + * This is a customization, that may be activated by overriding the 'checkbox' + * class name as 'fancytree-radio' in the tree options. + *----------------------------------------------------------------------------*/ + +.fancytree-radio { + span.fancytree-checkbox { + .useSprite(0, 3); + &:hover { .useSprite(1, 3); } + } + .fancytree-partsel span.fancytree-checkbox { + .useSprite(4, 3); + &:hover { .useSprite(5, 3); } + } + // Selected after partsel, so it takes precedence: + .fancytree-selected span.fancytree-checkbox { + .useSprite(2, 3); + &:hover { .useSprite(3, 3); } + } + // Unselectable is dimmed, without hover effects + .fancytree-unselectable { + span.fancytree-checkbox, + span.fancytree-checkbox:hover { + .useSprite(0, 3); + } + } +} + +/*------------------------------------------------------------------------------ + * Node type icon + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-ico- + * 1st character: 'e': expanded, 'c': collapsed + * 2nd character (optional): 'f': folder + *----------------------------------------------------------------------------*/ + +span.fancytree-icon { // Default icon + margin-left: @fancy-icon-spacing; + .useSprite(0, 0); +} + +/* Documents */ +.fancytree-ico-c span.fancytree-icon { // Collapsed folder (empty) + // .useSprite(0, 0); +} +.fancytree-ico-c span.fancytree-icon:hover { + .useSprite(1, 0); +} +.fancytree-has-children.fancytree-ico-c span.fancytree-icon { // Collapsed folder (not empty) + .useSprite(2, 0); +} +.fancytree-has-children.fancytree-ico-c span.fancytree-icon:hover { + .useSprite(3, 0); +} +.fancytree-ico-e span.fancytree-icon { // Expanded folder + .useSprite(4, 0); +} +.fancytree-ico-e span.fancytree-icon:hover { + .useSprite(5, 0); +} + +/* Folders */ +.fancytree-ico-cf span.fancytree-icon { // Collapsed folder (empty) + .useSprite(0, 1); +} +.fancytree-ico-cf span.fancytree-icon:hover { + .useSprite(1, 1); +} +.fancytree-has-children.fancytree-ico-cf span.fancytree-icon { // Collapsed folder (not empty) + .useSprite(2, 1); +} +.fancytree-has-children.fancytree-ico-cf span.fancytree-icon:hover { + .useSprite(3, 1); +} +.fancytree-ico-ef span.fancytree-icon { // Expanded folder + .useSprite(4, 1); +} +.fancytree-ico-ef span.fancytree-icon:hover { + .useSprite(5, 1); +} + +// 'Loading' status overrides all others +.fancytree-loading span.fancytree-expander, +.fancytree-loading span.fancytree-expander:hover, +.fancytree-statusnode-wait span.fancytree-icon, +.fancytree-statusnode-wait span.fancytree-icon:hover { + background-image: @fancy-loading-url; + .useSprite(0, 0); +} + +/* Status node icons */ + +.fancytree-statusnode-error span.fancytree-icon, +.fancytree-statusnode-error span.fancytree-icon:hover { + .useSprite(0, 7); +} + + +/*------------------------------------------------------------------------------ + * Node titles and highlighting + *----------------------------------------------------------------------------*/ + +span.fancytree-node { + /* See #117 */ + display: inherit; // #117, resolves to 'display: list-item;' for standard trees + width: 100%; + margin-top: @fancy-node-v-spacing; + min-height: @fancy-line-height; +} +span.fancytree-title { + color: @fancy-font-color; // inherit doesn't work on IE + cursor: pointer; + display: inline-block; // Better alignment, when title contains <br> + vertical-align: top; + min-height: @fancy-line-height; + padding: 0 3px 0 3px; // Otherwise italic font will be outside right bounds + margin: @fancy-title-ofs-top 0 0 @fancy-icon-spacing; + // margin: 0px; + // margin-top: @fancy-line-ofs-top; + // margin-left: @fancy-icon-spacing; + border: @fancy-node-border-width solid transparent; // avoid jumping, when a border is added on hover + .rounded-corners(@fancy-node-border-radius); +// outline: 0; // @ Firefox, prevent dotted border after click +// Set transparent border to prevent jumping when active node gets a border +// (we can do this, because this theme doesn't use vertical lines) +// border: 1px solid white; // Note: 'transparent' would not work in IE6 +} +span.fancytree-node.fancytree-error span.fancytree-title { + color: @fancy-font-error-color; +} + +/*------------------------------------------------------------------------------ + * Drag'n'drop support + *----------------------------------------------------------------------------*/ +div.fancytree-drag-helper { + span.fancytree-childcounter, + span.fancytree-dnd-modifier { + display: inline-block; + color: #fff; + background: #337ab7; // bootstrap blue + border: 1px solid gray; + min-width: 10px; + // min-height: 16px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; + } + span.fancytree-childcounter { + position: absolute; + // left: 16px; + top: -6px; + right: -6px; + } + span.fancytree-dnd-modifier { + background: #5cb85c; // bootstrap green + border: none; + // min-height: 16px; + // font-size: 12px; + font-weight: bolder; + } + &.fancytree-drop-accept { + span.fancytree-drag-helper-img { + .useSprite(2, 7); + } + } + &.fancytree-drop-reject { + span.fancytree-drag-helper-img { + .useSprite(1, 7); + } + } +} + + +/*** Drop marker icon *********************************************************/ +#fancytree-drop-marker { + width: 2 * @fancy-icon-width; // was 24px, but 32 should be correct + position: absolute; + .useSprite(0, 8); + margin: 0; + &.fancytree-drop-after, + &.fancytree-drop-before { + width: 4 * @fancy-icon-width; // 64px; + .useSprite(0, 9); + } + &.fancytree-drop-copy { + .useSprite(4, 8); + } + &.fancytree-drop-move { + .useSprite(2, 8); + } +} + +/*** Source node while dragging ***********************************************/ + +span.fancytree-drag-source { + &.fancytree-drag-remove { +// text-decoration: line-through; + opacity: 0.15; + } +} + +/*** Target node while dragging cursor is over it *****************************/ + +span.fancytree-drop-target { + &.fancytree-drop-accept { + // outline: 1px dotted #5cb85c; // bootstrap sucess + } +} +span.fancytree-drop-reject { + // outline: 1px dotted #d9534f; // boostrap warning +} + + +/*------------------------------------------------------------------------------ + * 'table' extension + *----------------------------------------------------------------------------*/ + +table.fancytree-ext-table { + border-collapse: collapse; + span.fancytree-node { + display: inline-block; // #117 + } +} + +/*------------------------------------------------------------------------------ + * 'columnview' extension + *----------------------------------------------------------------------------*/ + +table.fancytree-ext-columnview { +// border-collapse: collapse; +// width: 100%; + tbody tr td { + position: relative; + border: 1px solid gray; + vertical-align: top; + overflow: auto; + >ul { + padding: 0; + li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip:border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + .setBgPos(0, 0); + background-repeat: repeat-y; + background-image: none; /* no v-lines */ + + margin: 0; +// padding: 1px 0 0 0; // issue #246 + } + } + } + span.fancytree-node { + position: relative; /* allow positioning of embedded spans */ + display: inline-block; // #117 + } + span.fancytree-node.fancytree-expanded { + background-color: #CBE8F6; + } + // table.fancytree-ext-columnview span.fancytree-node.fancytree-active { + // background-color: royalblue; + // } + .fancytree-has-children span.fancytree-cv-right { + position: absolute; + right: 3px; + .useSprite(0, 5); + &:hover { + .useSprite(1, 5); + } + } +} + +/*------------------------------------------------------------------------------ + * 'filter' extension + *----------------------------------------------------------------------------*/ + +.fancytree-ext-filter-dimm { + span.fancytree-node span.fancytree-title { + color: @fancy-font-color-dimm; + font-weight: lighter; + } + tr.fancytree-submatch span.fancytree-title, + span.fancytree-node.fancytree-submatch span.fancytree-title { + color: black; + font-weight: normal; + } + tr.fancytree-match span.fancytree-title, + span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: bold; + } +} +.fancytree-ext-filter-hide { + tr.fancytree-hide, + span.fancytree-node.fancytree-hide { + display: none; + } + tr.fancytree-submatch span.fancytree-title, + span.fancytree-node.fancytree-submatch span.fancytree-title { + color: @fancy-font-color-dimm; + font-weight: lighter; + } + tr.fancytree-match span.fancytree-title, + span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: normal; + } +} + +.fancytree-ext-childcounter, +.fancytree-ext-filter { + // span.fancytree-title mark { + // font-style: normal; + // background-color: #ead61c; // yellow + // border-radius: 3px; + // } + span.fancytree-icon { + position: relative; + } + span.fancytree-childcounter { + color: #fff; + background: #777; // #337ab7; // bootstrap blue + border: 1px solid gray; + position: absolute; + top: -6px; + right: -6px; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; + } +} +/*------------------------------------------------------------------------------ + * 'wide' extension + *----------------------------------------------------------------------------*/ + +ul.fancytree-ext-wide { + position: relative; + min-width: 100%; + z-index: 2; + + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + + span.fancytree-node >span { + position: relative; + z-index: 2; + } + span.fancytree-node span.fancytree-title { + position: absolute; // Allow left: 0. Note: prevents smooth dropdown animation + z-index: 1; // Behind expander and checkbox + left: 0px; + width: 100%; + margin-left: 0; + margin-right: 0; + + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } +} diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-custom-1/README.md b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-custom-1/README.md new file mode 100644 index 00000000000..da573d61e4c --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-custom-1/README.md @@ -0,0 +1,14 @@ +### Creating Custom Skins + +1. Create a folder like this (recommended name: 'src/skin-custom-...') +2. For a start copy files from one of the existing skin folders (src/skin-...) + to the custom folder: + - ui.fancytree.less (required) + - icons.gif (if needed) + - loading.gif (if needed) +3. cd to your fancytree folder and run `grunt dev` from the connsole.<br> + Note: NPM and Grunt are required. + Read [how to install the toolset](https://github.com/mar10/fancytree/wiki/HowtoContribute#install-the-source-code-and-tools-for-debugging-and-contributing). +4. Edit and save your ui.fancytree.less file.<br> + The `ui.fancytree.css` will be generated and updated automatically from + the LESS file. diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-lion/icons.gif b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-lion/icons.gif new file mode 100644 index 0000000000000000000000000000000000000000..305d75bd7539f224f8c85429b7701c0c537d28c6 GIT binary patch literal 5906 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 a7jqlG%xQyjxJ~mq*7LgC=450bmj4IAEko%5 literal 0 HcmV?d00001 diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-lion/loading.gif b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-lion/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..5b33f7e54f4e55b6b8774d86d96895db9af044b4 GIT binary patch literal 1849 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 EAHN$8j{pDw literal 0 HcmV?d00001 diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-lion/ui.fancytree.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-lion/ui.fancytree.css new file mode 100644 index 00000000000..4ae213c3186 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-lion/ui.fancytree.css @@ -0,0 +1,565 @@ +/*! + * Fancytree "Lion" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ +/* + Lion colors: + gray highlight bar: #D4D4D4 + blue highlight-bar and -border #3875D7 + +*/ +/******************************************************************************* + * Common Styles for Fancytree Skins. + * + * This section is automatically generated from the `skin-common.less` template. + ******************************************************************************/ +/*------------------------------------------------------------------------------ + * Helpers + *----------------------------------------------------------------------------*/ +.ui-helper-hidden { + display: none; +} +/*------------------------------------------------------------------------------ + * Container and UL / LI + *----------------------------------------------------------------------------*/ +ul.fancytree-container { + font-family: tahoma, arial, helvetica; + font-size: 10pt; + white-space: nowrap; + padding: 3px; + margin: 0; + background-color: white; + border: 1px dotted gray; + overflow: auto; + min-height: 0%; + position: relative; +} +ul.fancytree-container ul { + padding: 0 0 0 16px; + margin: 0; +} +ul.fancytree-container li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0px 0px; + background-repeat: repeat-y; + background-image: none; + margin: 0; +} +ul.fancytree-container li.fancytree-lastsib { + background-image: none; +} +ul.fancytree-no-connector > li { + background-image: none; +} +.ui-fancytree-disabled ul.fancytree-container { + opacity: 0.5; + background-color: silver; +} +/*------------------------------------------------------------------------------ + * Common icon definitions + *----------------------------------------------------------------------------*/ +span.fancytree-empty, +span.fancytree-vline, +span.fancytree-expander, +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-radio, +span.fancytree-drag-helper-img, +#fancytree-drop-marker { + width: 16px; + height: 16px; + display: inline-block; + vertical-align: top; + background-repeat: no-repeat; + background-position: left; + background-image: url("icons.gif"); + background-position: 0px 0px; +} +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-expander, +span.fancytree-radio, +span.fancytree-custom-icon { + margin-top: 0px; +} +/* Used by iconclass option and iconClass callback: */ +span.fancytree-custom-icon { + display: inline-block; + margin-left: 3px; +} +/* Used by 'icon' node option: */ +img.fancytree-icon { + width: 16px; + height: 16px; + margin-left: 3px; + margin-top: 0px; + vertical-align: top; + border-style: none; +} +/*------------------------------------------------------------------------------ + * Expander icon + * + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-exp- + * 1st character: 'e': expanded, 'c': collapsed, 'n': no children + * 2nd character (optional): 'd': lazy (Delayed) + * 3rd character (optional): 'l': Last sibling + *----------------------------------------------------------------------------*/ +span.fancytree-expander { + cursor: pointer; +} +.fancytree-exp-n span.fancytree-expander, +.fancytree-exp-nl span.fancytree-expander { + background-image: none; + cursor: default; +} +.fancytree-exp-n span.fancytree-expander, +.fancytree-exp-n span.fancytree-expander:hover { + background-position: 0px -64px; +} +.fancytree-exp-nl span.fancytree-expander, +.fancytree-exp-nl span.fancytree-expander:hover { + background-position: -16px -64px; +} +.fancytree-exp-c span.fancytree-expander { + background-position: 0px -80px; +} +.fancytree-exp-c span.fancytree-expander:hover { + background-position: -16px -80px; +} +.fancytree-exp-cl span.fancytree-expander { + background-position: 0px -96px; +} +.fancytree-exp-cl span.fancytree-expander:hover { + background-position: -16px -96px; +} +.fancytree-exp-cd span.fancytree-expander { + background-position: -64px -80px; +} +.fancytree-exp-cd span.fancytree-expander:hover { + background-position: -80px -80px; +} +.fancytree-exp-cdl span.fancytree-expander { + background-position: -64px -96px; +} +.fancytree-exp-cdl span.fancytree-expander:hover { + background-position: -80px -96px; +} +.fancytree-exp-e span.fancytree-expander, +.fancytree-exp-ed span.fancytree-expander { + background-position: -32px -80px; +} +.fancytree-exp-e span.fancytree-expander:hover, +.fancytree-exp-ed span.fancytree-expander:hover { + background-position: -48px -80px; +} +.fancytree-exp-el span.fancytree-expander, +.fancytree-exp-edl span.fancytree-expander { + background-position: -32px -96px; +} +.fancytree-exp-el span.fancytree-expander:hover, +.fancytree-exp-edl span.fancytree-expander:hover { + background-position: -48px -96px; +} +/*------------------------------------------------------------------------------ + * Checkbox icon + *----------------------------------------------------------------------------*/ +span.fancytree-checkbox { + margin-left: 3px; + background-position: 0px -32px; +} +span.fancytree-checkbox:hover { + background-position: -16px -32px; +} +.fancytree-partsel span.fancytree-checkbox { + background-position: -64px -32px; +} +.fancytree-partsel span.fancytree-checkbox:hover { + background-position: -80px -32px; +} +.fancytree-selected span.fancytree-checkbox { + background-position: -32px -32px; +} +.fancytree-selected span.fancytree-checkbox:hover { + background-position: -48px -32px; +} +.fancytree-unselectable span.fancytree-checkbox { + opacity: 0.4; + filter: alpha(opacity=40); +} +.fancytree-unselectable span.fancytree-checkbox:hover { + background-position: 0px -32px; +} +.fancytree-unselectable.fancytree-partsel span.fancytree-checkbox:hover { + background-position: -64px -32px; +} +.fancytree-unselectable.fancytree-selected span.fancytree-checkbox:hover { + background-position: -32px -32px; +} +/*------------------------------------------------------------------------------ + * Radiobutton icon + * This is a customization, that may be activated by overriding the 'checkbox' + * class name as 'fancytree-radio' in the tree options. + *----------------------------------------------------------------------------*/ +.fancytree-radio span.fancytree-checkbox { + background-position: 0px -48px; +} +.fancytree-radio span.fancytree-checkbox:hover { + background-position: -16px -48px; +} +.fancytree-radio .fancytree-partsel span.fancytree-checkbox { + background-position: -64px -48px; +} +.fancytree-radio .fancytree-partsel span.fancytree-checkbox:hover { + background-position: -80px -48px; +} +.fancytree-radio .fancytree-selected span.fancytree-checkbox { + background-position: -32px -48px; +} +.fancytree-radio .fancytree-selected span.fancytree-checkbox:hover { + background-position: -48px -48px; +} +.fancytree-radio .fancytree-unselectable span.fancytree-checkbox, +.fancytree-radio .fancytree-unselectable span.fancytree-checkbox:hover { + background-position: 0px -48px; +} +/*------------------------------------------------------------------------------ + * Node type icon + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-ico- + * 1st character: 'e': expanded, 'c': collapsed + * 2nd character (optional): 'f': folder + *----------------------------------------------------------------------------*/ +span.fancytree-icon { + margin-left: 3px; + background-position: 0px 0px; +} +/* Documents */ +.fancytree-ico-c span.fancytree-icon:hover { + background-position: -16px 0px; +} +.fancytree-has-children.fancytree-ico-c span.fancytree-icon { + background-position: -32px 0px; +} +.fancytree-has-children.fancytree-ico-c span.fancytree-icon:hover { + background-position: -48px 0px; +} +.fancytree-ico-e span.fancytree-icon { + background-position: -64px 0px; +} +.fancytree-ico-e span.fancytree-icon:hover { + background-position: -80px 0px; +} +/* Folders */ +.fancytree-ico-cf span.fancytree-icon { + background-position: 0px -16px; +} +.fancytree-ico-cf span.fancytree-icon:hover { + background-position: -16px -16px; +} +.fancytree-has-children.fancytree-ico-cf span.fancytree-icon { + background-position: -32px -16px; +} +.fancytree-has-children.fancytree-ico-cf span.fancytree-icon:hover { + background-position: -48px -16px; +} +.fancytree-ico-ef span.fancytree-icon { + background-position: -64px -16px; +} +.fancytree-ico-ef span.fancytree-icon:hover { + background-position: -80px -16px; +} +.fancytree-loading span.fancytree-expander, +.fancytree-loading span.fancytree-expander:hover, +.fancytree-statusnode-wait span.fancytree-icon, +.fancytree-statusnode-wait span.fancytree-icon:hover { + background-image: url('data:image/gif;base64,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'); + background-position: 0px 0px; +} +/* Status node icons */ +.fancytree-statusnode-error span.fancytree-icon, +.fancytree-statusnode-error span.fancytree-icon:hover { + background-position: 0px -112px; +} +/*------------------------------------------------------------------------------ + * Node titles and highlighting + *----------------------------------------------------------------------------*/ +span.fancytree-node { + /* See #117 */ + display: inherit; + width: 100%; + margin-top: 1px; + min-height: 16px; +} +span.fancytree-title { + color: #000000; + cursor: pointer; + display: inline-block; + vertical-align: top; + min-height: 16px; + padding: 0 3px 0 3px; + margin: 0px 0 0 3px; + border: 1px solid transparent; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + -ms-border-radius: 0px; + -o-border-radius: 0px; + border-radius: 0px; +} +span.fancytree-node.fancytree-error span.fancytree-title { + color: #ff0000; +} +/*------------------------------------------------------------------------------ + * Drag'n'drop support + *----------------------------------------------------------------------------*/ +div.fancytree-drag-helper span.fancytree-childcounter, +div.fancytree-drag-helper span.fancytree-dnd-modifier { + display: inline-block; + color: #fff; + background: #337ab7; + border: 1px solid gray; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +div.fancytree-drag-helper span.fancytree-childcounter { + position: absolute; + top: -6px; + right: -6px; +} +div.fancytree-drag-helper span.fancytree-dnd-modifier { + background: #5cb85c; + border: none; + font-weight: bolder; +} +div.fancytree-drag-helper.fancytree-drop-accept span.fancytree-drag-helper-img { + background-position: -32px -112px; +} +div.fancytree-drag-helper.fancytree-drop-reject span.fancytree-drag-helper-img { + background-position: -16px -112px; +} +/*** Drop marker icon *********************************************************/ +#fancytree-drop-marker { + width: 32px; + position: absolute; + background-position: 0px -128px; + margin: 0; +} +#fancytree-drop-marker.fancytree-drop-after, +#fancytree-drop-marker.fancytree-drop-before { + width: 64px; + background-position: 0px -144px; +} +#fancytree-drop-marker.fancytree-drop-copy { + background-position: -64px -128px; +} +#fancytree-drop-marker.fancytree-drop-move { + background-position: -32px -128px; +} +/*** Source node while dragging ***********************************************/ +span.fancytree-drag-source.fancytree-drag-remove { + opacity: 0.15; +} +/*** Target node while dragging cursor is over it *****************************/ +/*------------------------------------------------------------------------------ + * 'table' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-table { + border-collapse: collapse; +} +table.fancytree-ext-table span.fancytree-node { + display: inline-block; +} +/*------------------------------------------------------------------------------ + * 'columnview' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-columnview tbody tr td { + position: relative; + border: 1px solid gray; + vertical-align: top; + overflow: auto; +} +table.fancytree-ext-columnview tbody tr td > ul { + padding: 0; +} +table.fancytree-ext-columnview tbody tr td > ul li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0px 0px; + background-repeat: repeat-y; + background-image: none; + /* no v-lines */ + margin: 0; +} +table.fancytree-ext-columnview span.fancytree-node { + position: relative; + /* allow positioning of embedded spans */ + display: inline-block; +} +table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded { + background-color: #CBE8F6; +} +table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right { + position: absolute; + right: 3px; + background-position: 0px -80px; +} +table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right:hover { + background-position: -16px -80px; +} +/*------------------------------------------------------------------------------ + * 'filter' extension + *----------------------------------------------------------------------------*/ +.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title { + color: #c0c0c0; + font-weight: lighter; +} +.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: bold; +} +.fancytree-ext-filter-hide tr.fancytree-hide, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide { + display: none; +} +.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title { + color: #c0c0c0; + font-weight: lighter; +} +.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-childcounter span.fancytree-icon, +.fancytree-ext-filter span.fancytree-icon { + position: relative; +} +.fancytree-ext-childcounter span.fancytree-childcounter, +.fancytree-ext-filter span.fancytree-childcounter { + color: #fff; + background: #777; + border: 1px solid gray; + position: absolute; + top: -6px; + right: -6px; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +/*------------------------------------------------------------------------------ + * 'wide' extension + *----------------------------------------------------------------------------*/ +ul.fancytree-ext-wide { + position: relative; + min-width: 100%; + z-index: 2; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +ul.fancytree-ext-wide span.fancytree-node > span { + position: relative; + z-index: 2; +} +ul.fancytree-ext-wide span.fancytree-node span.fancytree-title { + position: absolute; + z-index: 1; + left: 0px; + width: 100%; + margin-left: 0; + margin-right: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +/******************************************************************************* + * Styles specific to this skin. + * + * This section is automatically generated from the `ui-fancytree.less` template. + ******************************************************************************/ +/******************************************************************************* + * Node titles + */ +span.fancytree-title { + border: 1px solid transparent; + border-radius: 0; +} +span.fancytree-focused span.fancytree-title { + outline: 1px dotted black; +} +span.fancytree-selected span.fancytree-title, +span.fancytree-active span.fancytree-title { + background-color: #D4D4D4; +} +span.fancytree-selected span.fancytree-title { + font-style: italic; +} +.fancytree-treefocus span.fancytree-selected span.fancytree-title, +.fancytree-treefocus span.fancytree-active span.fancytree-title { + color: white; + background-color: #3875D7; +} +/******************************************************************************* + * 'table' extension + */ +table.fancytree-ext-table { + border-collapse: collapse; +} +table.fancytree-ext-table tbody tr.fancytree-focused { + background-color: #99DEFD; +} +table.fancytree-ext-table tbody tr.fancytree-active { + background-color: royalblue; +} +table.fancytree-ext-table tbody tr.fancytree-selected { + background-color: #99DEFD; +} +/******************************************************************************* + * 'columnview' extension + */ +table.fancytree-ext-columnview tbody tr td { + border: 1px solid gray; +} +table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded { + background-color: #ccc; +} +table.fancytree-ext-columnview span.fancytree-node.fancytree-active { + background-color: royalblue; +} diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-lion/ui.fancytree.less b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-lion/ui.fancytree.less new file mode 100644 index 00000000000..7baf8380e65 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-lion/ui.fancytree.less @@ -0,0 +1,95 @@ + /*! + * Fancytree "Lion" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ + +/* + Lion colors: + gray highlight bar: #D4D4D4 + blue highlight-bar and -border #3875D7 + +*/ +// Import common styles +@import "../skin-common.less"; + + +/******************************************************************************* + * Styles specific to this skin. + * + * This section is automatically generated from the `ui-fancytree.less` template. + ******************************************************************************/ + +// Override the variable after the import. +// NOTE: Variables are always resolved as the last definition, even if it is +// after where it is used. +@fancy-use-sprites: true; // false: suppress all background images (i.e. icons) +@fancy-hide-connectors: true; + +@fancy-icon-width: 16px; +@fancy-icon-height: 16px; +@fancy-line-height: 16px; +@fancy-icon-spacing: 3px; + +// Use 'data-uri(...)' to embed the image into CSS instead of linking to 'loading.gif': +@fancy-loading-url: data-uri("@{fancy-image-dir}/loading.gif"); +// Set to `true` to use `data-uri(...)` which will embed icons.gif into CSS +// instead of linking to that file: +// @fancy-inline-sprites: true; + + +/******************************************************************************* + * Node titles + */ +span.fancytree-title { + border: 1px solid transparent; // reserve some space for status borders + border-radius: 0; +} +span.fancytree-focused span.fancytree-title { + outline: 1px dotted black; +} +span.fancytree-selected span.fancytree-title, +span.fancytree-active span.fancytree-title { + background-color: #D4D4D4; // gray +} +span.fancytree-selected span.fancytree-title { + font-style: italic; +} +.fancytree-treefocus span.fancytree-selected span.fancytree-title, +.fancytree-treefocus span.fancytree-active span.fancytree-title { + color: white; + background-color: #3875D7; // blue +} + +/******************************************************************************* + * 'table' extension + */ +table.fancytree-ext-table { + border-collapse: collapse; + tbody { + tr.fancytree-focused { + background-color: #99DEFD; + } + tr.fancytree-active { + background-color: royalblue; + } + tr.fancytree-selected { + background-color: #99DEFD; + } + } +} + +/******************************************************************************* + * 'columnview' extension + */ + +table.fancytree-ext-columnview tbody tr td { + border: 1px solid gray; +} +table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded { + background-color: #ccc; +} +table.fancytree-ext-columnview span.fancytree-node.fancytree-active { + background-color: royalblue; +} diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-lion/ui.fancytree.min.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-lion/ui.fancytree.min.css new file mode 100644 index 00000000000..d21c5fbbd7a --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-lion/ui.fancytree.min.css @@ -0,0 +1,6 @@ +/*! + * Fancytree "Lion" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */.ui-helper-hidden{display:none}ul.fancytree-container{font-family:tahoma,arial,helvetica;font-size:10pt;white-space:nowrap;padding:3px;margin:0;background-color:#fff;border:1px dotted gray;overflow:auto;min-height:0;position:relative}ul.fancytree-container ul{padding:0 0 0 16px;margin:0}ul.fancytree-container li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0}ul.fancytree-container li.fancytree-lastsib,ul.fancytree-no-connector>li{background-image:none}.ui-fancytree-disabled ul.fancytree-container{opacity:.5;background-color:silver}#fancytree-drop-marker,span.fancytree-checkbox,span.fancytree-drag-helper-img,span.fancytree-empty,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio,span.fancytree-vline{width:16px;height:16px;display:inline-block;vertical-align:top;background-repeat:no-repeat;background-image:url(icons.gif);background-position:0 0}span.fancytree-checkbox,span.fancytree-custom-icon,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio{margin-top:0}span.fancytree-custom-icon{display:inline-block;margin-left:3px}img.fancytree-icon{width:16px;height:16px;margin-left:3px;margin-top:0;vertical-align:top;border-style:none}span.fancytree-expander{cursor:pointer}.fancytree-exp-n span.fancytree-expander,.fancytree-exp-nl span.fancytree-expander{background-image:none;cursor:default}.fancytree-exp-n span.fancytree-expander,.fancytree-exp-n span.fancytree-expander:hover{background-position:0 -64px}.fancytree-exp-nl span.fancytree-expander,.fancytree-exp-nl span.fancytree-expander:hover{background-position:-16px -64px}.fancytree-exp-c span.fancytree-expander{background-position:0 -80px}.fancytree-exp-c span.fancytree-expander:hover{background-position:-16px -80px}.fancytree-exp-cl span.fancytree-expander{background-position:0 -96px}.fancytree-exp-cl span.fancytree-expander:hover{background-position:-16px -96px}.fancytree-exp-cd span.fancytree-expander{background-position:-64px -80px}.fancytree-exp-cd span.fancytree-expander:hover{background-position:-80px -80px}.fancytree-exp-cdl span.fancytree-expander{background-position:-64px -96px}.fancytree-exp-cdl span.fancytree-expander:hover{background-position:-80px -96px}.fancytree-exp-e span.fancytree-expander,.fancytree-exp-ed span.fancytree-expander{background-position:-32px -80px}.fancytree-exp-e span.fancytree-expander:hover,.fancytree-exp-ed span.fancytree-expander:hover{background-position:-48px -80px}.fancytree-exp-edl span.fancytree-expander,.fancytree-exp-el span.fancytree-expander{background-position:-32px -96px}.fancytree-exp-edl span.fancytree-expander:hover,.fancytree-exp-el span.fancytree-expander:hover{background-position:-48px -96px}span.fancytree-checkbox{margin-left:3px;background-position:0 -32px}span.fancytree-checkbox:hover{background-position:-16px -32px}.fancytree-partsel span.fancytree-checkbox{background-position:-64px -32px}.fancytree-partsel span.fancytree-checkbox:hover{background-position:-80px -32px}.fancytree-selected span.fancytree-checkbox{background-position:-32px -32px}.fancytree-selected span.fancytree-checkbox:hover{background-position:-48px -32px}.fancytree-unselectable span.fancytree-checkbox{opacity:.4;filter:alpha(opacity=40)}.fancytree-unselectable span.fancytree-checkbox:hover{background-position:0 -32px}.fancytree-unselectable.fancytree-partsel span.fancytree-checkbox:hover{background-position:-64px -32px}.fancytree-unselectable.fancytree-selected span.fancytree-checkbox:hover{background-position:-32px -32px}.fancytree-radio span.fancytree-checkbox{background-position:0 -48px}.fancytree-radio span.fancytree-checkbox:hover{background-position:-16px -48px}.fancytree-radio .fancytree-partsel span.fancytree-checkbox{background-position:-64px -48px}.fancytree-radio .fancytree-partsel span.fancytree-checkbox:hover{background-position:-80px -48px}.fancytree-radio .fancytree-selected span.fancytree-checkbox{background-position:-32px -48px}.fancytree-radio .fancytree-selected span.fancytree-checkbox:hover{background-position:-48px -48px}.fancytree-radio .fancytree-unselectable span.fancytree-checkbox,.fancytree-radio .fancytree-unselectable span.fancytree-checkbox:hover{background-position:0 -48px}span.fancytree-icon{margin-left:3px;background-position:0 0}.fancytree-ico-c span.fancytree-icon:hover{background-position:-16px 0}.fancytree-has-children.fancytree-ico-c span.fancytree-icon{background-position:-32px 0}.fancytree-has-children.fancytree-ico-c span.fancytree-icon:hover{background-position:-48px 0}.fancytree-ico-e span.fancytree-icon{background-position:-64px 0}.fancytree-ico-e span.fancytree-icon:hover{background-position:-80px 0}.fancytree-ico-cf span.fancytree-icon{background-position:0 -16px}.fancytree-ico-cf span.fancytree-icon:hover{background-position:-16px -16px}.fancytree-has-children.fancytree-ico-cf span.fancytree-icon{background-position:-32px -16px}.fancytree-has-children.fancytree-ico-cf span.fancytree-icon:hover{background-position:-48px -16px}.fancytree-ico-ef span.fancytree-icon{background-position:-64px -16px}.fancytree-ico-ef span.fancytree-icon:hover{background-position:-80px -16px}.fancytree-loading span.fancytree-expander,.fancytree-loading span.fancytree-expander:hover,.fancytree-statusnode-wait span.fancytree-icon,.fancytree-statusnode-wait span.fancytree-icon:hover{background-image:url(data:image/gif;base64,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);background-position:0 0}.fancytree-statusnode-error span.fancytree-icon,.fancytree-statusnode-error span.fancytree-icon:hover{background-position:0 -112px}span.fancytree-node{display:inherit;width:100%;margin-top:1px;min-height:16px}span.fancytree-title{color:#000;cursor:pointer;display:inline-block;vertical-align:top;min-height:16px;padding:0 3px;margin:0 0 0 3px;-webkit-border-radius:0;-moz-border-radius:0;-ms-border-radius:0;-o-border-radius:0}span.fancytree-node.fancytree-error span.fancytree-title{color:red}div.fancytree-drag-helper span.fancytree-childcounter,div.fancytree-drag-helper span.fancytree-dnd-modifier{display:inline-block;color:#fff;background:#337ab7;border:1px solid gray;min-width:10px;height:10px;line-height:1;vertical-align:baseline;border-radius:10px;padding:2px;text-align:center;font-size:9px}div.fancytree-drag-helper span.fancytree-childcounter{position:absolute;top:-6px;right:-6px}div.fancytree-drag-helper span.fancytree-dnd-modifier{background:#5cb85c;border:0;font-weight:bolder}div.fancytree-drag-helper.fancytree-drop-accept span.fancytree-drag-helper-img{background-position:-32px -112px}div.fancytree-drag-helper.fancytree-drop-reject span.fancytree-drag-helper-img{background-position:-16px -112px}#fancytree-drop-marker{width:32px;position:absolute;background-position:0 -128px;margin:0}#fancytree-drop-marker.fancytree-drop-after,#fancytree-drop-marker.fancytree-drop-before{width:64px;background-position:0 -144px}#fancytree-drop-marker.fancytree-drop-copy{background-position:-64px -128px}#fancytree-drop-marker.fancytree-drop-move{background-position:-32px -128px}span.fancytree-drag-source.fancytree-drag-remove{opacity:.15}table.fancytree-ext-table span.fancytree-node{display:inline-block}table.fancytree-ext-columnview tbody tr td{position:relative;vertical-align:top;overflow:auto}table.fancytree-ext-columnview tbody tr td>ul{padding:0}table.fancytree-ext-columnview tbody tr td>ul li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0}table.fancytree-ext-columnview span.fancytree-node{position:relative;display:inline-block}table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right{position:absolute;right:3px;background-position:0 -80px}table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right:hover{background-position:-16px -80px}.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title{color:silver;font-weight:lighter}.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title,.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title{color:#000;font-weight:400}.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title,.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title{color:#000;font-weight:700}.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide,.fancytree-ext-filter-hide tr.fancytree-hide{display:none}.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title,.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title{color:silver;font-weight:lighter}.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title,.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title{color:#000;font-weight:400}.fancytree-ext-childcounter span.fancytree-icon,.fancytree-ext-filter span.fancytree-icon{position:relative}.fancytree-ext-childcounter span.fancytree-childcounter,.fancytree-ext-filter span.fancytree-childcounter{color:#fff;background:#777;border:1px solid gray;position:absolute;top:-6px;right:-6px;min-width:10px;height:10px;line-height:1;vertical-align:baseline;border-radius:10px;padding:2px;text-align:center;font-size:9px}ul.fancytree-ext-wide{position:relative;min-width:100%;z-index:2;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}ul.fancytree-ext-wide span.fancytree-node>span{position:relative;z-index:2}ul.fancytree-ext-wide span.fancytree-node span.fancytree-title{position:absolute;z-index:1;left:0;width:100%;margin-left:0;margin-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}span.fancytree-title{border:1px solid transparent;border-radius:0}span.fancytree-focused span.fancytree-title{outline:1px dotted #000}span.fancytree-active span.fancytree-title,span.fancytree-selected span.fancytree-title{background-color:#D4D4D4}span.fancytree-selected span.fancytree-title{font-style:italic}.fancytree-treefocus span.fancytree-active span.fancytree-title,.fancytree-treefocus span.fancytree-selected span.fancytree-title{color:#fff;background-color:#3875D7}table.fancytree-ext-table{border-collapse:collapse}table.fancytree-ext-table tbody tr.fancytree-focused{background-color:#99DEFD}table.fancytree-ext-table tbody tr.fancytree-active{background-color:#4169e1}table.fancytree-ext-table tbody tr.fancytree-selected{background-color:#99DEFD}table.fancytree-ext-columnview tbody tr td{border:1px solid gray}table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded{background-color:#ccc}table.fancytree-ext-columnview span.fancytree-node.fancytree-active{background-color:#4169e1} \ No newline at end of file diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-themeroller/icons.gif b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-themeroller/icons.gif new file mode 100644 index 0000000000000000000000000000000000000000..813eb8385c40a954a85b0fc8379a6446aec3acd8 GIT binary patch literal 5492 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 literal 0 HcmV?d00001 diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-themeroller/loading.gif b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-themeroller/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..ef88497ccc2f6c2a3a0c5e41f3cbfc7a18ff5329 GIT binary patch literal 3234 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 RGR}AoOL=)|H48+m{|ju`J$C>A literal 0 HcmV?d00001 diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-themeroller/ui.fancytree.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-themeroller/ui.fancytree.css new file mode 100644 index 00000000000..07961f26f92 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-themeroller/ui.fancytree.css @@ -0,0 +1,505 @@ +/* + * Fancytree for use with ext-themeroller extension. + */ +.ui-helper-hidden { + display: none; +} + +.fancytree-container +{ + white-space: nowrap; + padding: 3px; + margin: 0; /* issue 201 */ + overflow: auto; +/* height: 100%; /* issue 263 */ +/* + font-family: tahoma, arial, helvetica; + font-size: 10pt; + background-color: white; + border: 1px dotted gray; +*/ +} + +ul.fancytree-container ul +{ + padding: 0 0 0 16px; + margin: 0; +} + +ul.fancytree-container li +{ + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip:border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0 0; + background-repeat: repeat-y; + background-image: none; /* no v-lines */ + + margin:0; + padding:1px 0 0 0; +} +/* Suppress lines for last child node */ +ul.fancytree-container li.fancytree-lastsib +{ + background-image: none; +} +/* Suppress lines if level is fixed expanded (option minExpandLevel) */ +ul.fancytree-no-connector > li +{ + background-image: none; +} + +/* Style, when control is disabled */ +/* +.ui-fancytree-disabled ul.fancytree-container +{ + opacity: 0.5; +} +*/ + +span.fancytree-node +{ + display: inline-block; + width: 100%; + border: 1px solid transparent; +} + +/******************************************************************************* + * Common icon definitions + */ +span.fancytree-empty, +span.fancytree-vline, +/*span.fancytree-connector,*/ +span.fancytree-expander, +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-radio, +span.fancytree-drag-helper-img, +#fancytree-drop-marker +{ + width: 16px; + height: 16px; + display: inline-block; /* Required to make a span sizable */ + vertical-align: top; + background-repeat: no-repeat; + background-position: left; + background-image: url("icons.gif"); + background-position: 0 0; +} +/** Used by iconclass option and iconClass callback: */ +span.fancytree-custom-icon { + display: inline-block; +} +/** Used by 'icon' node option: */ +.fancytree-container img +{ + width: 16px; + height: 16px; + margin-left: 3px; + vertical-align: top; + border-style: none; +} + + +/******************************************************************************* + * Lines and connectors + */ +/* span.fancytree-connector +{ + background-image: none; +} + */ +/******************************************************************************* + * Expander icon + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-exp- + * 1st character: 'e': expanded, 'c': collapsed, 'n': no children + * 2nd character (optional): 'd': lazy (Delayed) + * 3rd character (optional): 'l': Last sibling + */ + +span.fancytree-expander +{ + background-position: 0px -80px; + cursor: pointer; +} +span.fancytree-expander:hover +{ + background-position: -16px -80px; +} +.fancytree-exp-n span.fancytree-expander:hover /* Collapsed, not delayed, not last sibling */ +{ + background-position: -16px -80px; +} +.fancytree-exp-cl span.fancytree-expander /* Collapsed, not delayed, last sibling */ +{ +} +.fancytree-exp-cd span.fancytree-expander /* Collapsed, delayed, not last sibling */ +{ +} +.fancytree-exp-cdl span.fancytree-expander /* Collapsed, delayed, last sibling */ +{ +} +.fancytree-exp-e span.fancytree-expander, /* Expanded, not delayed, not last sibling */ +.fancytree-exp-ed span.fancytree-expander, /* Expanded, delayed, not last sibling */ +.fancytree-exp-el span.fancytree-expander, /* Expanded, not delayed, last sibling */ +.fancytree-exp-edl span.fancytree-expander /* Expanded, delayed, last sibling */ +{ + background-position: -32px -80px; +} +.fancytree-exp-e span.fancytree-expander:hover, /* Expanded, not delayed, not last sibling */ +.fancytree-exp-ed span.fancytree-expander:hover, /* Expanded, delayed, not last sibling */ +.fancytree-exp-el span.fancytree-expander:hover, /* Expanded, not delayed, last sibling */ +.fancytree-exp-edl span.fancytree-expander:hover /* Expanded, delayed, last sibling */ +{ + background-position: -48px -80px; +} +.fancytree-loading span.fancytree-expander /* 'Loading' status overrides all others */ +{ + background-position: 0 0; + background-image: url("loading.gif"); +} + +.fancytree-exp-n span.fancytree-expander, /* Connector instead of expander, if node has no children */ +.fancytree-exp-nl span.fancytree-expander +{ + background-image: none; + cursor: default; +} + + +/******************************************************************************* + * Checkbox icon + */ +span.fancytree-checkbox +{ + margin-left: 3px; + background-position: 0px -32px; +} +span.fancytree-checkbox:hover +{ + background-position: -16px -32px; +} + +.fancytree-partsel span.fancytree-checkbox +{ + background-position: -64px -32px; +} +.fancytree-partsel span.fancytree-checkbox:hover +{ + background-position: -80px -32px; +} + +.fancytree-selected span.fancytree-checkbox +{ + background-position: -32px -32px; +} +.fancytree-selected span.fancytree-checkbox:hover +{ + background-position: -48px -32px; +} + +/******************************************************************************* + * Radiobutton icon + * This is a customization, that may be activated by overriding the 'checkbox' + * class name as 'fancytree-radio' in the tree options. + */ +.fancytree-radio span.fancytree-checkbox +{ + margin-left: 3px; + background-position: 0px -48px; +} +.fancytree-radio span.fancytree-checkbox:hover +{ + background-position: -16px -48px; +} + +.fancytree-radio .fancytree-partsel span.fancytree-checkbox +{ + background-position: -64px -48px; +} +.fancytree-radio .fancytree-partsel span.fancytree-checkbox:hover +{ + background-position: -80px -48px; +} + +.fancytree-radio .fancytree-selected span.fancytree-checkbox +{ + background-position: -32px -48px; +} +.fancytree-radio .fancytree-selected span.fancytree-checkbox:hover +{ + background-position: -48px -48px; +} + + +/******************************************************************************* + * Node type icon + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-ico- + * 1st character: 'e': expanded, 'c': collapsed + * 2nd character (optional): 'f': folder + */ + +span.fancytree-icon /* Default icon */ +{ + margin-left: 3px; + background-position: 0px 0px; +} + +.fancytree-has-children span.fancytree-icon /* Default icon */ +{ +/* background-position: 0px -16px; */ +} + +.fancytree-ico-cf span.fancytree-icon /* Collapsed Folder */ +{ + background-position: 0px -16px; +} + +.fancytree-ico-ef span.fancytree-icon /* Expanded Folder */ +{ + background-position: -64px -16px; +} + +/* Status node icons */ + +.fancytree-statusnode-wait span.fancytree-icon +{ + background-image: url("loading.gif"); +} + +.fancytree-statusnode-error span.fancytree-icon +{ + background-position: 0px -112px; +/* background-image: url("ltError.gif");*/ +} + +/******************************************************************************* + * Node titles + */ + +span.fancytree-title +{ + display: inline-block; +} +.fancytree-title +{ + display: inline-block; /* Better alignment, when title contains <br> */ + padding-left: 3px; + padding-right: 3px; /* Otherwise italic font will be outside bounds */ +/* color: black; /* inherit doesn't work on IE */ + vertical-align: top; + margin: 0px; + margin-left: 3px; + cursor: pointer; +} + +/******************************************************************************* + * 'table' extension + */ + +/* +table.fancytree-ext-table { + border-collapse: collapse; + width: 100%; +} +table.fancytree-ext-table tbody tr:nth-child(even){ + background-color: #f4f4f8; +} +table.fancytree-ext-table tbody tr td { + border: 1px solid lightgray; +} +*/ +table.fancytree-ext-table { + border-collapse: collapse; +} + +/******************************************************************************* + * 'columnview' extension + */ + +/* +table.fancytree-ext-columnview { + border-collapse: collapse; + width: 100%; +} +*/ +table.fancytree-ext-columnview td +{ + position: relative; +} +table.fancytree-ext-columnview td >ul +{ + padding: 0; +} +table.fancytree-ext-columnview td >ul li +{ + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip:border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0 0; + background-repeat: repeat-y; + background-image: none; /* no v-lines */ + + margin: 0; + padding: 1px 0 0 0; +} +/* +table.fancytree-ext-columnview tbody tr[0] { + height: 200px; +} +*/ +table.fancytree-ext-columnview tbody tr td { + border: 1px solid gray; + vertical-align: top; + overflow: auto; +} +table.fancytree-ext-columnview span.fancytree-node { + position: relative; /* allow positioning of embedded spans*/ +} +/* +table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded { + background-color: #CBE8F6; +} +table.fancytree-ext-columnview span.fancytree-node.fancytree-active { + background-color: royalblue; +} +*/ +table.fancytree-ext-columnview span.fancytree-cv-right { + background-position: 0px -80px; + position: absolute; + right: 3px; +} + +/******************************************************************************* + * 'filter' extension + */ +.fancytree-ext-filter .fancytree-node .fancytree-title { + color: silver; + font-weight: lighter; +} +.fancytree-ext-filter .fancytree-node.fancytree-submatch .fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-filter .fancytree-node.fancytree-match .fancytree-title { + color: black; + font-weight: bold; +} + + +/******************************************************************************* + * Drag'n'drop support + */ + +/*** Helper object ************************************************************/ +div.fancytree-drag-helper +{ +} +div.fancytree-drag-helper a +{ + border: 1px solid gray; + background-color: white; + padding-left: 5px; + padding-right: 5px; + opacity: 0.8; +} +span.fancytree-drag-helper-img +{ + /* + position: relative; + left: -16px; + */ +} +div.fancytree-drag-helper /*.fancytree-drop-accept*/ +{ +/* border-color: green; + background-color: red;*/ +} +div.fancytree-drop-accept span.fancytree-drag-helper-img +{ + background-position: -32px -112px; +} +div.fancytree-drag-helper.fancytree-drop-reject +{ + border-color: red; +} +div.fancytree-drop-reject span.fancytree-drag-helper-img +{ + background-position: -16px -112px; +} + +/*** Drop marker icon *********************************************************/ + +#fancytree-drop-marker +{ + width: 24px; + position: absolute; + background-position: 0 -128px; + margin: 0; +} +#fancytree-drop-marker.fancytree-drop-after, +#fancytree-drop-marker.fancytree-drop-before +{ + width:64px; + background-position: 0 -144px; +} +#fancytree-drop-marker.fancytree-drop-copy +{ + background-position: -64px -128px; +} +#fancytree-drop-marker.fancytree-drop-move +{ + background-position: -64px -128px; +} + +/*** Source node while dragging ***********************************************/ + +span.fancytree-drag-source +{ + /* border: 1px dotted gray; */ + background-color: #e0e0e0; +} +span.fancytree-drag-source a +{ + color: gray; +} + +/*** Target node while dragging cursor is over it *****************************/ + +span.fancytree-drop-target +{ + /*border: 1px solid gray;*/ +} +span.fancytree-drop-target a +{ +} +span.fancytree-drop-target.fancytree-drop-accept a +{ + /*border: 1px solid green;*/ + background-color: #3169C6 !important; + color: white !important; /* @ IE6 */ + text-decoration: none; +} +span.fancytree-drop-target.fancytree-drop-reject +{ + /*border: 1px solid red;*/ +} +span.fancytree-drop-target.fancytree-drop-after a +{ +} diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-themeroller/ui.fancytree.min.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-themeroller/ui.fancytree.min.css new file mode 100644 index 00000000000..cc276ec9dd6 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-themeroller/ui.fancytree.min.css @@ -0,0 +1 @@ +.ui-helper-hidden{display:none}.fancytree-container{white-space:nowrap;padding:3px;margin:0;overflow:auto}ul.fancytree-container ul{padding:0 0 0 16px;margin:0}ul.fancytree-container li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0;padding:1px 0 0}ul.fancytree-container li.fancytree-lastsib,ul.fancytree-no-connector>li{background-image:none}span.fancytree-node{display:inline-block;width:100%;border:1px solid transparent}#fancytree-drop-marker,span.fancytree-checkbox,span.fancytree-drag-helper-img,span.fancytree-empty,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio,span.fancytree-vline{width:16px;height:16px;display:inline-block;vertical-align:top;background-repeat:no-repeat;background-image:url(icons.gif);background-position:0 0}span.fancytree-custom-icon{display:inline-block}.fancytree-container img{width:16px;height:16px;margin-left:3px;vertical-align:top;border-style:none}span.fancytree-expander{background-position:0 -80px;cursor:pointer}.fancytree-exp-n span.fancytree-expander:hover,span.fancytree-expander:hover{background-position:-16px -80px}.fancytree-exp-e span.fancytree-expander,.fancytree-exp-ed span.fancytree-expander,.fancytree-exp-edl span.fancytree-expander,.fancytree-exp-el span.fancytree-expander{background-position:-32px -80px}.fancytree-exp-e span.fancytree-expander:hover,.fancytree-exp-ed span.fancytree-expander:hover,.fancytree-exp-edl span.fancytree-expander:hover,.fancytree-exp-el span.fancytree-expander:hover{background-position:-48px -80px}.fancytree-loading span.fancytree-expander{background-position:0 0;background-image:url(loading.gif)}.fancytree-exp-n span.fancytree-expander,.fancytree-exp-nl span.fancytree-expander{background-image:none;cursor:default}span.fancytree-checkbox{margin-left:3px;background-position:0 -32px}span.fancytree-checkbox:hover{background-position:-16px -32px}.fancytree-partsel span.fancytree-checkbox{background-position:-64px -32px}.fancytree-partsel span.fancytree-checkbox:hover{background-position:-80px -32px}.fancytree-selected span.fancytree-checkbox{background-position:-32px -32px}.fancytree-selected span.fancytree-checkbox:hover{background-position:-48px -32px}.fancytree-radio span.fancytree-checkbox{margin-left:3px;background-position:0 -48px}.fancytree-radio span.fancytree-checkbox:hover{background-position:-16px -48px}.fancytree-radio .fancytree-partsel span.fancytree-checkbox{background-position:-64px -48px}.fancytree-radio .fancytree-partsel span.fancytree-checkbox:hover{background-position:-80px -48px}.fancytree-radio .fancytree-selected span.fancytree-checkbox{background-position:-32px -48px}.fancytree-radio .fancytree-selected span.fancytree-checkbox:hover{background-position:-48px -48px}span.fancytree-icon{margin-left:3px;background-position:0 0}.fancytree-ico-cf span.fancytree-icon{background-position:0 -16px}.fancytree-ico-ef span.fancytree-icon{background-position:-64px -16px}.fancytree-statusnode-wait span.fancytree-icon{background-image:url(loading.gif)}.fancytree-statusnode-error span.fancytree-icon{background-position:0 -112px}span.fancytree-title{display:inline-block}.fancytree-title{display:inline-block;padding-left:3px;padding-right:3px;vertical-align:top;margin:0;margin-left:3px;cursor:pointer}table.fancytree-ext-table{border-collapse:collapse}table.fancytree-ext-columnview td{position:relative}table.fancytree-ext-columnview td >ul{padding:0}table.fancytree-ext-columnview td >ul li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0;padding:1px 0 0}table.fancytree-ext-columnview tbody tr td{border:1px solid gray;vertical-align:top;overflow:auto}table.fancytree-ext-columnview span.fancytree-node{position:relative}table.fancytree-ext-columnview span.fancytree-cv-right{background-position:0 -80px;position:absolute;right:3px}.fancytree-ext-filter .fancytree-node .fancytree-title{color:silver;font-weight:lighter}.fancytree-ext-filter .fancytree-node.fancytree-submatch .fancytree-title{color:#000;font-weight:400}.fancytree-ext-filter .fancytree-node.fancytree-match .fancytree-title{color:#000;font-weight:700}div.fancytree-drag-helper a{border:1px solid gray;background-color:#fff;padding-left:5px;padding-right:5px;opacity:.8}div.fancytree-drop-accept span.fancytree-drag-helper-img{background-position:-32px -112px}div.fancytree-drag-helper.fancytree-drop-reject{border-color:red}div.fancytree-drop-reject span.fancytree-drag-helper-img{background-position:-16px -112px}#fancytree-drop-marker{width:24px;position:absolute;background-position:0 -128px;margin:0}#fancytree-drop-marker.fancytree-drop-after,#fancytree-drop-marker.fancytree-drop-before{width:64px;background-position:0 -144px}#fancytree-drop-marker.fancytree-drop-copy,#fancytree-drop-marker.fancytree-drop-move{background-position:-64px -128px}span.fancytree-drag-source{background-color:#e0e0e0}span.fancytree-drag-source a{color:gray}span.fancytree-drop-target.fancytree-drop-accept a{background-color:#3169C6!important;color:#fff!important;text-decoration:none} \ No newline at end of file diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-vista/icons.gif b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-vista/icons.gif new file mode 100644 index 0000000000000000000000000000000000000000..65719ccc28fb0b78fbed90cb04341280b4cd6ac0 GIT binary patch literal 5492 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 literal 0 HcmV?d00001 diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-vista/loading.gif b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-vista/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..ef88497ccc2f6c2a3a0c5e41f3cbfc7a18ff5329 GIT binary patch literal 3234 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 RGR}AoOL=)|H48+m{|ju`J$C>A literal 0 HcmV?d00001 diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-vista/ui.fancytree.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-vista/ui.fancytree.css new file mode 100644 index 00000000000..df1637f60e6 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-vista/ui.fancytree.css @@ -0,0 +1,571 @@ +/*! + * Fancytree "Vista" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ +/* +both: + unselected background: #FCFCFC 'nearly white' + hover bar (unselected, inactive): #F8FCFE..#EFF9FE (border: #D8F0FA) 'very light blue' + active node: #F6FBFD..#D5EFFC (border: #99DEFD) 'light blue' + active node with hover: #F2F9FD..#C4E8FA (border: #B6E6FB) + +Tree view: + active node, tree inactive: #FAFAFB..#E5E5E5 (border: #D9D9D9) 'light gray, selected, but tree not active' + +List view: + selected bar: --> active bar + focus bar: active + border 1px dotted #090402 (inside the blue border) + + table left/right border: #EDEDED 'light gray' + */ +/******************************************************************************* + * Common Styles for Fancytree Skins. + * + * This section is automatically generated from the `skin-common.less` template. + ******************************************************************************/ +/*------------------------------------------------------------------------------ + * Helpers + *----------------------------------------------------------------------------*/ +.ui-helper-hidden { + display: none; +} +/*------------------------------------------------------------------------------ + * Container and UL / LI + *----------------------------------------------------------------------------*/ +ul.fancytree-container { + font-family: tahoma, arial, helvetica; + font-size: 10pt; + white-space: nowrap; + padding: 3px; + margin: 0; + background-color: white; + border: 1px dotted gray; + overflow: auto; + min-height: 0%; + position: relative; +} +ul.fancytree-container ul { + padding: 0 0 0 16px; + margin: 0; +} +ul.fancytree-container li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0px 0px; + background-repeat: repeat-y; + background-image: none; + margin: 0; +} +ul.fancytree-container li.fancytree-lastsib { + background-image: none; +} +ul.fancytree-no-connector > li { + background-image: none; +} +.ui-fancytree-disabled ul.fancytree-container { + opacity: 0.5; + background-color: silver; +} +/*------------------------------------------------------------------------------ + * Common icon definitions + *----------------------------------------------------------------------------*/ +span.fancytree-empty, +span.fancytree-vline, +span.fancytree-expander, +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-radio, +span.fancytree-drag-helper-img, +#fancytree-drop-marker { + width: 16px; + height: 16px; + display: inline-block; + vertical-align: top; + background-repeat: no-repeat; + background-position: left; + background-image: url("icons.gif"); + background-position: 0px 0px; +} +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-expander, +span.fancytree-radio, +span.fancytree-custom-icon { + margin-top: 0px; +} +/* Used by iconclass option and iconClass callback: */ +span.fancytree-custom-icon { + display: inline-block; + margin-left: 3px; +} +/* Used by 'icon' node option: */ +img.fancytree-icon { + width: 16px; + height: 16px; + margin-left: 3px; + margin-top: 0px; + vertical-align: top; + border-style: none; +} +/*------------------------------------------------------------------------------ + * Expander icon + * + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-exp- + * 1st character: 'e': expanded, 'c': collapsed, 'n': no children + * 2nd character (optional): 'd': lazy (Delayed) + * 3rd character (optional): 'l': Last sibling + *----------------------------------------------------------------------------*/ +span.fancytree-expander { + cursor: pointer; +} +.fancytree-exp-n span.fancytree-expander, +.fancytree-exp-nl span.fancytree-expander { + background-image: none; + cursor: default; +} +.fancytree-exp-n span.fancytree-expander, +.fancytree-exp-n span.fancytree-expander:hover { + background-position: 0px -64px; +} +.fancytree-exp-nl span.fancytree-expander, +.fancytree-exp-nl span.fancytree-expander:hover { + background-position: -16px -64px; +} +.fancytree-exp-c span.fancytree-expander { + background-position: 0px -80px; +} +.fancytree-exp-c span.fancytree-expander:hover { + background-position: -16px -80px; +} +.fancytree-exp-cl span.fancytree-expander { + background-position: 0px -96px; +} +.fancytree-exp-cl span.fancytree-expander:hover { + background-position: -16px -96px; +} +.fancytree-exp-cd span.fancytree-expander { + background-position: -64px -80px; +} +.fancytree-exp-cd span.fancytree-expander:hover { + background-position: -80px -80px; +} +.fancytree-exp-cdl span.fancytree-expander { + background-position: -64px -96px; +} +.fancytree-exp-cdl span.fancytree-expander:hover { + background-position: -80px -96px; +} +.fancytree-exp-e span.fancytree-expander, +.fancytree-exp-ed span.fancytree-expander { + background-position: -32px -80px; +} +.fancytree-exp-e span.fancytree-expander:hover, +.fancytree-exp-ed span.fancytree-expander:hover { + background-position: -48px -80px; +} +.fancytree-exp-el span.fancytree-expander, +.fancytree-exp-edl span.fancytree-expander { + background-position: -32px -96px; +} +.fancytree-exp-el span.fancytree-expander:hover, +.fancytree-exp-edl span.fancytree-expander:hover { + background-position: -48px -96px; +} +/*------------------------------------------------------------------------------ + * Checkbox icon + *----------------------------------------------------------------------------*/ +span.fancytree-checkbox { + margin-left: 3px; + background-position: 0px -32px; +} +span.fancytree-checkbox:hover { + background-position: -16px -32px; +} +.fancytree-partsel span.fancytree-checkbox { + background-position: -64px -32px; +} +.fancytree-partsel span.fancytree-checkbox:hover { + background-position: -80px -32px; +} +.fancytree-selected span.fancytree-checkbox { + background-position: -32px -32px; +} +.fancytree-selected span.fancytree-checkbox:hover { + background-position: -48px -32px; +} +.fancytree-unselectable span.fancytree-checkbox { + opacity: 0.4; + filter: alpha(opacity=40); +} +.fancytree-unselectable span.fancytree-checkbox:hover { + background-position: 0px -32px; +} +.fancytree-unselectable.fancytree-partsel span.fancytree-checkbox:hover { + background-position: -64px -32px; +} +.fancytree-unselectable.fancytree-selected span.fancytree-checkbox:hover { + background-position: -32px -32px; +} +/*------------------------------------------------------------------------------ + * Radiobutton icon + * This is a customization, that may be activated by overriding the 'checkbox' + * class name as 'fancytree-radio' in the tree options. + *----------------------------------------------------------------------------*/ +.fancytree-radio span.fancytree-checkbox { + background-position: 0px -48px; +} +.fancytree-radio span.fancytree-checkbox:hover { + background-position: -16px -48px; +} +.fancytree-radio .fancytree-partsel span.fancytree-checkbox { + background-position: -64px -48px; +} +.fancytree-radio .fancytree-partsel span.fancytree-checkbox:hover { + background-position: -80px -48px; +} +.fancytree-radio .fancytree-selected span.fancytree-checkbox { + background-position: -32px -48px; +} +.fancytree-radio .fancytree-selected span.fancytree-checkbox:hover { + background-position: -48px -48px; +} +.fancytree-radio .fancytree-unselectable span.fancytree-checkbox, +.fancytree-radio .fancytree-unselectable span.fancytree-checkbox:hover { + background-position: 0px -48px; +} +/*------------------------------------------------------------------------------ + * Node type icon + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-ico- + * 1st character: 'e': expanded, 'c': collapsed + * 2nd character (optional): 'f': folder + *----------------------------------------------------------------------------*/ +span.fancytree-icon { + margin-left: 3px; + background-position: 0px 0px; +} +/* Documents */ +.fancytree-ico-c span.fancytree-icon:hover { + background-position: -16px 0px; +} +.fancytree-has-children.fancytree-ico-c span.fancytree-icon { + background-position: -32px 0px; +} +.fancytree-has-children.fancytree-ico-c span.fancytree-icon:hover { + background-position: -48px 0px; +} +.fancytree-ico-e span.fancytree-icon { + background-position: -64px 0px; +} +.fancytree-ico-e span.fancytree-icon:hover { + background-position: -80px 0px; +} +/* Folders */ +.fancytree-ico-cf span.fancytree-icon { + background-position: 0px -16px; +} +.fancytree-ico-cf span.fancytree-icon:hover { + background-position: -16px -16px; +} +.fancytree-has-children.fancytree-ico-cf span.fancytree-icon { + background-position: -32px -16px; +} +.fancytree-has-children.fancytree-ico-cf span.fancytree-icon:hover { + background-position: -48px -16px; +} +.fancytree-ico-ef span.fancytree-icon { + background-position: -64px -16px; +} +.fancytree-ico-ef span.fancytree-icon:hover { + background-position: -80px -16px; +} +.fancytree-loading span.fancytree-expander, +.fancytree-loading span.fancytree-expander:hover, +.fancytree-statusnode-wait span.fancytree-icon, +.fancytree-statusnode-wait span.fancytree-icon:hover { + background-image: url('data:image/gif;base64,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'); + background-position: 0px 0px; +} +/* Status node icons */ +.fancytree-statusnode-error span.fancytree-icon, +.fancytree-statusnode-error span.fancytree-icon:hover { + background-position: 0px -112px; +} +/*------------------------------------------------------------------------------ + * Node titles and highlighting + *----------------------------------------------------------------------------*/ +span.fancytree-node { + /* See #117 */ + display: inherit; + width: 100%; + margin-top: 1px; + min-height: 16px; +} +span.fancytree-title { + color: #000000; + cursor: pointer; + display: inline-block; + vertical-align: top; + min-height: 16px; + padding: 0 3px 0 3px; + margin: 0px 0 0 3px; + border: 1px solid transparent; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + -ms-border-radius: 0px; + -o-border-radius: 0px; + border-radius: 0px; +} +span.fancytree-node.fancytree-error span.fancytree-title { + color: #ff0000; +} +/*------------------------------------------------------------------------------ + * Drag'n'drop support + *----------------------------------------------------------------------------*/ +div.fancytree-drag-helper span.fancytree-childcounter, +div.fancytree-drag-helper span.fancytree-dnd-modifier { + display: inline-block; + color: #fff; + background: #337ab7; + border: 1px solid gray; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +div.fancytree-drag-helper span.fancytree-childcounter { + position: absolute; + top: -6px; + right: -6px; +} +div.fancytree-drag-helper span.fancytree-dnd-modifier { + background: #5cb85c; + border: none; + font-weight: bolder; +} +div.fancytree-drag-helper.fancytree-drop-accept span.fancytree-drag-helper-img { + background-position: -32px -112px; +} +div.fancytree-drag-helper.fancytree-drop-reject span.fancytree-drag-helper-img { + background-position: -16px -112px; +} +/*** Drop marker icon *********************************************************/ +#fancytree-drop-marker { + width: 32px; + position: absolute; + background-position: 0px -128px; + margin: 0; +} +#fancytree-drop-marker.fancytree-drop-after, +#fancytree-drop-marker.fancytree-drop-before { + width: 64px; + background-position: 0px -144px; +} +#fancytree-drop-marker.fancytree-drop-copy { + background-position: -64px -128px; +} +#fancytree-drop-marker.fancytree-drop-move { + background-position: -32px -128px; +} +/*** Source node while dragging ***********************************************/ +span.fancytree-drag-source.fancytree-drag-remove { + opacity: 0.15; +} +/*** Target node while dragging cursor is over it *****************************/ +/*------------------------------------------------------------------------------ + * 'table' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-table { + border-collapse: collapse; +} +table.fancytree-ext-table span.fancytree-node { + display: inline-block; +} +/*------------------------------------------------------------------------------ + * 'columnview' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-columnview tbody tr td { + position: relative; + border: 1px solid gray; + vertical-align: top; + overflow: auto; +} +table.fancytree-ext-columnview tbody tr td > ul { + padding: 0; +} +table.fancytree-ext-columnview tbody tr td > ul li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0px 0px; + background-repeat: repeat-y; + background-image: none; + /* no v-lines */ + margin: 0; +} +table.fancytree-ext-columnview span.fancytree-node { + position: relative; + /* allow positioning of embedded spans */ + display: inline-block; +} +table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded { + background-color: #CBE8F6; +} +table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right { + position: absolute; + right: 3px; + background-position: 0px -80px; +} +table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right:hover { + background-position: -16px -80px; +} +/*------------------------------------------------------------------------------ + * 'filter' extension + *----------------------------------------------------------------------------*/ +.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title { + color: #c0c0c0; + font-weight: lighter; +} +.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: bold; +} +.fancytree-ext-filter-hide tr.fancytree-hide, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide { + display: none; +} +.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title { + color: #c0c0c0; + font-weight: lighter; +} +.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-childcounter span.fancytree-icon, +.fancytree-ext-filter span.fancytree-icon { + position: relative; +} +.fancytree-ext-childcounter span.fancytree-childcounter, +.fancytree-ext-filter span.fancytree-childcounter { + color: #fff; + background: #777; + border: 1px solid gray; + position: absolute; + top: -6px; + right: -6px; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +/*------------------------------------------------------------------------------ + * 'wide' extension + *----------------------------------------------------------------------------*/ +ul.fancytree-ext-wide { + position: relative; + min-width: 100%; + z-index: 2; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +ul.fancytree-ext-wide span.fancytree-node > span { + position: relative; + z-index: 2; +} +ul.fancytree-ext-wide span.fancytree-node span.fancytree-title { + position: absolute; + z-index: 1; + left: 0px; + width: 100%; + margin-left: 0; + margin-right: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +/******************************************************************************* + * Styles specific to this skin. + * + * This section is automatically generated from the `ui-fancytree.less` template. + ******************************************************************************/ +/******************************************************************************* + * Node titles + */ +span.fancytree-title { + border: 1px solid transparent; +} +span.fancytree-title:hover { + background-color: #F2F7FD; + border-color: #B8D6FB; +} +span.fancytree-focused span.fancytree-title { + background-color: #EFEBDE; + outline: 1px dotted gray; +} +span.fancytree-selected span.fancytree-title { + font-style: italic; +} +span.fancytree-active span.fancytree-title { + border: 1px solid #99DEFD; + background-color: #D8F0FA; +} +/******************************************************************************* + * 'table' extension + */ +table.fancytree-ext-table { + border-collapse: collapse; +} +table.fancytree-ext-table tbody tr.fancytree-focused { + background-color: #99DEFD; +} +table.fancytree-ext-table tbody tr.fancytree-active { + background-color: royalblue; +} +table.fancytree-ext-table tbody tr.fancytree-selected { + background-color: #99FDDE; +} +/******************************************************************************* + * 'columnview' extension + */ +table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded { + background-color: #ccc; +} +table.fancytree-ext-columnview span.fancytree-node.fancytree-active { + background-color: royalblue; +} diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-vista/ui.fancytree.less b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-vista/ui.fancytree.less new file mode 100644 index 00000000000..06d55deb21e --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-vista/ui.fancytree.less @@ -0,0 +1,112 @@ +/*! + * Fancytree "Vista" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ + +/* +both: + unselected background: #FCFCFC 'nearly white' + hover bar (unselected, inactive): #F8FCFE..#EFF9FE (border: #D8F0FA) 'very light blue' + active node: #F6FBFD..#D5EFFC (border: #99DEFD) 'light blue' + active node with hover: #F2F9FD..#C4E8FA (border: #B6E6FB) + +Tree view: + active node, tree inactive: #FAFAFB..#E5E5E5 (border: #D9D9D9) 'light gray, selected, but tree not active' + +List view: + selected bar: --> active bar + focus bar: active + border 1px dotted #090402 (inside the blue border) + + table left/right border: #EDEDED 'light gray' + */ + +// Import common styles +@import "../skin-common.less"; + + +/******************************************************************************* + * Styles specific to this skin. + * + * This section is automatically generated from the `ui-fancytree.less` template. + ******************************************************************************/ + + +// Override the variable after the import. +// NOTE: Variables are always resolved as the last definition, even if it is +// after where it is used. +@fancy-use-sprites: true; // false: suppress all background images (i.e. icons) + +@fancy-hide-connectors: true; +@fancy-icon-width: 16px; +@fancy-icon-height: 16px; +@fancy-line-height: 16px; +@fancy-icon-spacing: 3px; + +// Use 'data-uri(...)' to embed the image into CSS instead of linking to 'loading.gif': +@fancy-loading-url: data-uri("@{fancy-image-dir}/loading.gif"); +// Set to `true` to use `data-uri(...)` which will embed icons.gif into CSS +// instead of linking to that file: +// @fancy-inline-sprites: true; + + +/******************************************************************************* + * Node titles + */ +span.fancytree-title { + border: @fancy-node-border-width solid transparent; // avoid jumping, when a border is added on hover +} +span.fancytree-title:hover { + background-color: #F2F7FD; // light blue + border-color: #B8D6FB; // darker light blue +} +.fancytree-folder span.fancytree-title { + // font-weight: bold; +} +span.fancytree-focused span.fancytree-title { + background-color: #EFEBDE; // gray + outline: 1px dotted gray; +} +span.fancytree-has-children span.fancytree-title { + // font-style: oblique; +} +span.fancytree-expanded span.fancytree-title { +} +span.fancytree-selected span.fancytree-title { + font-style: italic; +} +span.fancytree-active span.fancytree-title { + border: 1px solid #99DEFD; + background-color: #D8F0FA; +} + +/******************************************************************************* + * 'table' extension + */ + +table.fancytree-ext-table { + border-collapse: collapse; + tbody tr.fancytree-focused { + background-color: #99DEFD; + } + tbody tr.fancytree-active { + background-color: royalblue; + } + tbody tr.fancytree-selected { + background-color: #99FDDE; + } +} + +/******************************************************************************* + * 'columnview' extension + */ + +table.fancytree-ext-columnview { + span.fancytree-node.fancytree-expanded { + background-color: #ccc; + } + span.fancytree-node.fancytree-active { + background-color: royalblue; + } +} diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-vista/ui.fancytree.min.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-vista/ui.fancytree.min.css new file mode 100644 index 00000000000..c11c6489c9a --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-vista/ui.fancytree.min.css @@ -0,0 +1,6 @@ +/*! + * Fancytree "Vista" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */.ui-helper-hidden{display:none}ul.fancytree-container{font-family:tahoma,arial,helvetica;font-size:10pt;white-space:nowrap;padding:3px;margin:0;background-color:#fff;border:1px dotted gray;overflow:auto;min-height:0;position:relative}ul.fancytree-container ul{padding:0 0 0 16px;margin:0}ul.fancytree-container li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0}ul.fancytree-container li.fancytree-lastsib,ul.fancytree-no-connector>li{background-image:none}.ui-fancytree-disabled ul.fancytree-container{opacity:.5;background-color:silver}#fancytree-drop-marker,span.fancytree-checkbox,span.fancytree-drag-helper-img,span.fancytree-empty,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio,span.fancytree-vline{width:16px;height:16px;display:inline-block;vertical-align:top;background-repeat:no-repeat;background-image:url(icons.gif);background-position:0 0}span.fancytree-checkbox,span.fancytree-custom-icon,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio{margin-top:0}span.fancytree-custom-icon{display:inline-block;margin-left:3px}img.fancytree-icon{width:16px;height:16px;margin-left:3px;margin-top:0;vertical-align:top;border-style:none}span.fancytree-expander{cursor:pointer}.fancytree-exp-n span.fancytree-expander,.fancytree-exp-nl span.fancytree-expander{background-image:none;cursor:default}.fancytree-exp-n span.fancytree-expander,.fancytree-exp-n span.fancytree-expander:hover{background-position:0 -64px}.fancytree-exp-nl span.fancytree-expander,.fancytree-exp-nl span.fancytree-expander:hover{background-position:-16px -64px}.fancytree-exp-c span.fancytree-expander{background-position:0 -80px}.fancytree-exp-c span.fancytree-expander:hover{background-position:-16px -80px}.fancytree-exp-cl span.fancytree-expander{background-position:0 -96px}.fancytree-exp-cl span.fancytree-expander:hover{background-position:-16px -96px}.fancytree-exp-cd span.fancytree-expander{background-position:-64px -80px}.fancytree-exp-cd span.fancytree-expander:hover{background-position:-80px -80px}.fancytree-exp-cdl span.fancytree-expander{background-position:-64px -96px}.fancytree-exp-cdl span.fancytree-expander:hover{background-position:-80px -96px}.fancytree-exp-e span.fancytree-expander,.fancytree-exp-ed span.fancytree-expander{background-position:-32px -80px}.fancytree-exp-e span.fancytree-expander:hover,.fancytree-exp-ed span.fancytree-expander:hover{background-position:-48px -80px}.fancytree-exp-edl span.fancytree-expander,.fancytree-exp-el span.fancytree-expander{background-position:-32px -96px}.fancytree-exp-edl span.fancytree-expander:hover,.fancytree-exp-el span.fancytree-expander:hover{background-position:-48px -96px}span.fancytree-checkbox{margin-left:3px;background-position:0 -32px}span.fancytree-checkbox:hover{background-position:-16px -32px}.fancytree-partsel span.fancytree-checkbox{background-position:-64px -32px}.fancytree-partsel span.fancytree-checkbox:hover{background-position:-80px -32px}.fancytree-selected span.fancytree-checkbox{background-position:-32px -32px}.fancytree-selected span.fancytree-checkbox:hover{background-position:-48px -32px}.fancytree-unselectable span.fancytree-checkbox{opacity:.4;filter:alpha(opacity=40)}.fancytree-unselectable span.fancytree-checkbox:hover{background-position:0 -32px}.fancytree-unselectable.fancytree-partsel span.fancytree-checkbox:hover{background-position:-64px -32px}.fancytree-unselectable.fancytree-selected span.fancytree-checkbox:hover{background-position:-32px -32px}.fancytree-radio span.fancytree-checkbox{background-position:0 -48px}.fancytree-radio span.fancytree-checkbox:hover{background-position:-16px -48px}.fancytree-radio .fancytree-partsel span.fancytree-checkbox{background-position:-64px -48px}.fancytree-radio .fancytree-partsel span.fancytree-checkbox:hover{background-position:-80px -48px}.fancytree-radio .fancytree-selected span.fancytree-checkbox{background-position:-32px -48px}.fancytree-radio .fancytree-selected span.fancytree-checkbox:hover{background-position:-48px -48px}.fancytree-radio .fancytree-unselectable span.fancytree-checkbox,.fancytree-radio .fancytree-unselectable span.fancytree-checkbox:hover{background-position:0 -48px}span.fancytree-icon{margin-left:3px;background-position:0 0}.fancytree-ico-c span.fancytree-icon:hover{background-position:-16px 0}.fancytree-has-children.fancytree-ico-c span.fancytree-icon{background-position:-32px 0}.fancytree-has-children.fancytree-ico-c span.fancytree-icon:hover{background-position:-48px 0}.fancytree-ico-e span.fancytree-icon{background-position:-64px 0}.fancytree-ico-e span.fancytree-icon:hover{background-position:-80px 0}.fancytree-ico-cf span.fancytree-icon{background-position:0 -16px}.fancytree-ico-cf span.fancytree-icon:hover{background-position:-16px -16px}.fancytree-has-children.fancytree-ico-cf span.fancytree-icon{background-position:-32px -16px}.fancytree-has-children.fancytree-ico-cf span.fancytree-icon:hover{background-position:-48px -16px}.fancytree-ico-ef span.fancytree-icon{background-position:-64px -16px}.fancytree-ico-ef span.fancytree-icon:hover{background-position:-80px -16px}.fancytree-loading span.fancytree-expander,.fancytree-loading span.fancytree-expander:hover,.fancytree-statusnode-wait span.fancytree-icon,.fancytree-statusnode-wait span.fancytree-icon:hover{background-image:url(data:image/gif;base64,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);background-position:0 0}.fancytree-statusnode-error span.fancytree-icon,.fancytree-statusnode-error span.fancytree-icon:hover{background-position:0 -112px}span.fancytree-node{display:inherit;width:100%;margin-top:1px;min-height:16px}span.fancytree-title{color:#000;cursor:pointer;display:inline-block;vertical-align:top;min-height:16px;padding:0 3px;margin:0 0 0 3px;-webkit-border-radius:0;-moz-border-radius:0;-ms-border-radius:0;-o-border-radius:0;border-radius:0}span.fancytree-node.fancytree-error span.fancytree-title{color:red}div.fancytree-drag-helper span.fancytree-childcounter,div.fancytree-drag-helper span.fancytree-dnd-modifier{display:inline-block;color:#fff;background:#337ab7;border:1px solid gray;min-width:10px;height:10px;line-height:1;vertical-align:baseline;border-radius:10px;padding:2px;text-align:center;font-size:9px}div.fancytree-drag-helper span.fancytree-childcounter{position:absolute;top:-6px;right:-6px}div.fancytree-drag-helper span.fancytree-dnd-modifier{background:#5cb85c;border:0;font-weight:bolder}div.fancytree-drag-helper.fancytree-drop-accept span.fancytree-drag-helper-img{background-position:-32px -112px}div.fancytree-drag-helper.fancytree-drop-reject span.fancytree-drag-helper-img{background-position:-16px -112px}#fancytree-drop-marker{width:32px;position:absolute;background-position:0 -128px;margin:0}#fancytree-drop-marker.fancytree-drop-after,#fancytree-drop-marker.fancytree-drop-before{width:64px;background-position:0 -144px}#fancytree-drop-marker.fancytree-drop-copy{background-position:-64px -128px}#fancytree-drop-marker.fancytree-drop-move{background-position:-32px -128px}span.fancytree-drag-source.fancytree-drag-remove{opacity:.15}table.fancytree-ext-table span.fancytree-node{display:inline-block}table.fancytree-ext-columnview tbody tr td{position:relative;border:1px solid gray;vertical-align:top;overflow:auto}table.fancytree-ext-columnview tbody tr td>ul{padding:0}table.fancytree-ext-columnview tbody tr td>ul li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0}table.fancytree-ext-columnview span.fancytree-node{position:relative;display:inline-block}table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right{position:absolute;right:3px;background-position:0 -80px}table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right:hover{background-position:-16px -80px}.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title{color:silver;font-weight:lighter}.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title,.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title{color:#000;font-weight:400}.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title,.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title{color:#000;font-weight:700}.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide,.fancytree-ext-filter-hide tr.fancytree-hide{display:none}.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title,.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title{color:silver;font-weight:lighter}.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title,.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title{color:#000;font-weight:400}.fancytree-ext-childcounter span.fancytree-icon,.fancytree-ext-filter span.fancytree-icon{position:relative}.fancytree-ext-childcounter span.fancytree-childcounter,.fancytree-ext-filter span.fancytree-childcounter{color:#fff;background:#777;border:1px solid gray;position:absolute;top:-6px;right:-6px;min-width:10px;height:10px;line-height:1;vertical-align:baseline;border-radius:10px;padding:2px;text-align:center;font-size:9px}ul.fancytree-ext-wide{position:relative;min-width:100%;z-index:2;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}ul.fancytree-ext-wide span.fancytree-node>span{position:relative;z-index:2}ul.fancytree-ext-wide span.fancytree-node span.fancytree-title{position:absolute;z-index:1;left:0;width:100%;margin-left:0;margin-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}span.fancytree-title{border:1px solid transparent}span.fancytree-title:hover{background-color:#F2F7FD;border-color:#B8D6FB}span.fancytree-focused span.fancytree-title{background-color:#EFEBDE;outline:1px dotted gray}span.fancytree-selected span.fancytree-title{font-style:italic}span.fancytree-active span.fancytree-title{border:1px solid #99DEFD;background-color:#D8F0FA}table.fancytree-ext-table{border-collapse:collapse}table.fancytree-ext-table tbody tr.fancytree-focused{background-color:#99DEFD}table.fancytree-ext-table tbody tr.fancytree-active{background-color:#4169e1}table.fancytree-ext-table tbody tr.fancytree-selected{background-color:#99FDDE}table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded{background-color:#ccc}table.fancytree-ext-columnview span.fancytree-node.fancytree-active{background-color:#4169e1} \ No newline at end of file diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win7/icons.gif b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win7/icons.gif new file mode 100644 index 0000000000000000000000000000000000000000..65719ccc28fb0b78fbed90cb04341280b4cd6ac0 GIT binary patch literal 5492 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 literal 0 HcmV?d00001 diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win7/loading.gif b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win7/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..ef88497ccc2f6c2a3a0c5e41f3cbfc7a18ff5329 GIT binary patch literal 3234 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 RGR}AoOL=)|H48+m{|ju`J$C>A literal 0 HcmV?d00001 diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win7/ui.fancytree.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win7/ui.fancytree.css new file mode 100644 index 00000000000..0ef494ab7d8 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win7/ui.fancytree.css @@ -0,0 +1,630 @@ +/*! + * Fancytree "Win7" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ +/******************************************************************************* + * Common Styles for Fancytree Skins. + * + * This section is automatically generated from the `skin-common.less` template. + ******************************************************************************/ +/*------------------------------------------------------------------------------ + * Helpers + *----------------------------------------------------------------------------*/ +.ui-helper-hidden { + display: none; +} +/*------------------------------------------------------------------------------ + * Container and UL / LI + *----------------------------------------------------------------------------*/ +ul.fancytree-container { + font-family: tahoma, arial, helvetica; + font-size: 10pt; + white-space: nowrap; + padding: 3px; + margin: 0; + background-color: white; + border: 1px dotted gray; + overflow: auto; + min-height: 0%; + position: relative; +} +ul.fancytree-container ul { + padding: 0 0 0 16px; + margin: 0; +} +ul.fancytree-container li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0px 0px; + background-repeat: repeat-y; + background-image: none; + margin: 0; +} +ul.fancytree-container li.fancytree-lastsib { + background-image: none; +} +ul.fancytree-no-connector > li { + background-image: none; +} +.ui-fancytree-disabled ul.fancytree-container { + opacity: 0.5; + background-color: silver; +} +/*------------------------------------------------------------------------------ + * Common icon definitions + *----------------------------------------------------------------------------*/ +span.fancytree-empty, +span.fancytree-vline, +span.fancytree-expander, +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-radio, +span.fancytree-drag-helper-img, +#fancytree-drop-marker { + width: 16px; + height: 16px; + display: inline-block; + vertical-align: top; + background-repeat: no-repeat; + background-position: left; + background-image: url("icons.gif"); + background-position: 0px 0px; +} +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-expander, +span.fancytree-radio, +span.fancytree-custom-icon { + margin-top: 2px; +} +/* Used by iconclass option and iconClass callback: */ +span.fancytree-custom-icon { + display: inline-block; + margin-left: 3px; +} +/* Used by 'icon' node option: */ +img.fancytree-icon { + width: 16px; + height: 16px; + margin-left: 3px; + margin-top: 2px; + vertical-align: top; + border-style: none; +} +/*------------------------------------------------------------------------------ + * Expander icon + * + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-exp- + * 1st character: 'e': expanded, 'c': collapsed, 'n': no children + * 2nd character (optional): 'd': lazy (Delayed) + * 3rd character (optional): 'l': Last sibling + *----------------------------------------------------------------------------*/ +span.fancytree-expander { + cursor: pointer; +} +.fancytree-exp-n span.fancytree-expander, +.fancytree-exp-nl span.fancytree-expander { + background-image: none; + cursor: default; +} +.fancytree-exp-n span.fancytree-expander, +.fancytree-exp-n span.fancytree-expander:hover { + background-position: 0px -64px; +} +.fancytree-exp-nl span.fancytree-expander, +.fancytree-exp-nl span.fancytree-expander:hover { + background-position: -16px -64px; +} +.fancytree-exp-c span.fancytree-expander { + background-position: 0px -80px; +} +.fancytree-exp-c span.fancytree-expander:hover { + background-position: -16px -80px; +} +.fancytree-exp-cl span.fancytree-expander { + background-position: 0px -96px; +} +.fancytree-exp-cl span.fancytree-expander:hover { + background-position: -16px -96px; +} +.fancytree-exp-cd span.fancytree-expander { + background-position: -64px -80px; +} +.fancytree-exp-cd span.fancytree-expander:hover { + background-position: -80px -80px; +} +.fancytree-exp-cdl span.fancytree-expander { + background-position: -64px -96px; +} +.fancytree-exp-cdl span.fancytree-expander:hover { + background-position: -80px -96px; +} +.fancytree-exp-e span.fancytree-expander, +.fancytree-exp-ed span.fancytree-expander { + background-position: -32px -80px; +} +.fancytree-exp-e span.fancytree-expander:hover, +.fancytree-exp-ed span.fancytree-expander:hover { + background-position: -48px -80px; +} +.fancytree-exp-el span.fancytree-expander, +.fancytree-exp-edl span.fancytree-expander { + background-position: -32px -96px; +} +.fancytree-exp-el span.fancytree-expander:hover, +.fancytree-exp-edl span.fancytree-expander:hover { + background-position: -48px -96px; +} +/*------------------------------------------------------------------------------ + * Checkbox icon + *----------------------------------------------------------------------------*/ +span.fancytree-checkbox { + margin-left: 3px; + background-position: 0px -32px; +} +span.fancytree-checkbox:hover { + background-position: -16px -32px; +} +.fancytree-partsel span.fancytree-checkbox { + background-position: -64px -32px; +} +.fancytree-partsel span.fancytree-checkbox:hover { + background-position: -80px -32px; +} +.fancytree-selected span.fancytree-checkbox { + background-position: -32px -32px; +} +.fancytree-selected span.fancytree-checkbox:hover { + background-position: -48px -32px; +} +.fancytree-unselectable span.fancytree-checkbox { + opacity: 0.4; + filter: alpha(opacity=40); +} +.fancytree-unselectable span.fancytree-checkbox:hover { + background-position: 0px -32px; +} +.fancytree-unselectable.fancytree-partsel span.fancytree-checkbox:hover { + background-position: -64px -32px; +} +.fancytree-unselectable.fancytree-selected span.fancytree-checkbox:hover { + background-position: -32px -32px; +} +/*------------------------------------------------------------------------------ + * Radiobutton icon + * This is a customization, that may be activated by overriding the 'checkbox' + * class name as 'fancytree-radio' in the tree options. + *----------------------------------------------------------------------------*/ +.fancytree-radio span.fancytree-checkbox { + background-position: 0px -48px; +} +.fancytree-radio span.fancytree-checkbox:hover { + background-position: -16px -48px; +} +.fancytree-radio .fancytree-partsel span.fancytree-checkbox { + background-position: -64px -48px; +} +.fancytree-radio .fancytree-partsel span.fancytree-checkbox:hover { + background-position: -80px -48px; +} +.fancytree-radio .fancytree-selected span.fancytree-checkbox { + background-position: -32px -48px; +} +.fancytree-radio .fancytree-selected span.fancytree-checkbox:hover { + background-position: -48px -48px; +} +.fancytree-radio .fancytree-unselectable span.fancytree-checkbox, +.fancytree-radio .fancytree-unselectable span.fancytree-checkbox:hover { + background-position: 0px -48px; +} +/*------------------------------------------------------------------------------ + * Node type icon + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-ico- + * 1st character: 'e': expanded, 'c': collapsed + * 2nd character (optional): 'f': folder + *----------------------------------------------------------------------------*/ +span.fancytree-icon { + margin-left: 3px; + background-position: 0px 0px; +} +/* Documents */ +.fancytree-ico-c span.fancytree-icon:hover { + background-position: -16px 0px; +} +.fancytree-has-children.fancytree-ico-c span.fancytree-icon { + background-position: -32px 0px; +} +.fancytree-has-children.fancytree-ico-c span.fancytree-icon:hover { + background-position: -48px 0px; +} +.fancytree-ico-e span.fancytree-icon { + background-position: -64px 0px; +} +.fancytree-ico-e span.fancytree-icon:hover { + background-position: -80px 0px; +} +/* Folders */ +.fancytree-ico-cf span.fancytree-icon { + background-position: 0px -16px; +} +.fancytree-ico-cf span.fancytree-icon:hover { + background-position: -16px -16px; +} +.fancytree-has-children.fancytree-ico-cf span.fancytree-icon { + background-position: -32px -16px; +} +.fancytree-has-children.fancytree-ico-cf span.fancytree-icon:hover { + background-position: -48px -16px; +} +.fancytree-ico-ef span.fancytree-icon { + background-position: -64px -16px; +} +.fancytree-ico-ef span.fancytree-icon:hover { + background-position: -80px -16px; +} +.fancytree-loading span.fancytree-expander, +.fancytree-loading span.fancytree-expander:hover, +.fancytree-statusnode-wait span.fancytree-icon, +.fancytree-statusnode-wait span.fancytree-icon:hover { + background-image: url('data:image/gif;base64,R0lGODlhEAAQAPcAAEai/0+m/1is/12u/2Oy/2u1/3C3/3G4/3W6/3q8/3+//4HA/4XC/4nE/4/H/5LI/5XK/5vN/57O/6DP/6HQ/6TS/6/X/7DX/7HY/7bb/7rd/7ze/8Hg/8fj/8rl/83m/9Dn/9Lp/9bq/9jr/9rt/9/v/+Dv/+Hw/+Xy/+v1/+32//D3//L5//f7//j7//v9/0qk/06m/1Ko/1er/2Cw/2m0/2y2/3u9/32+/4jD/5bK/5jL/5/P/6HP/6PS/6fS/6nU/67X/7Ta/7nc/7zd/8Ph/8bj/8jk/8vl/9Pp/9fr/9rs/9zu/+j0/+72//T6/0ij/1Op/1uu/1yu/2Wy/2q0/2+3/3C4/3m8/3y9/4PB/4vE/4/G/6XS/6jU/67W/7HZ/7Xa/7vd/73e/8Lh/8nk/87m/9Hn/9Ho/9vt/97u/+Lx/+bz/+n0//H4//X6/1Gn/1Go/2Gx/36+/5PJ/5TJ/5nL/57P/7PZ/7TZ/8Xi/9Tq/9zt/+by/+r0/+73//P5//n8/0uk/1Wq/3K4/3e7/4bC/4vF/47G/5fK/77f/9Do/9ns/+Tx/+/3//L4//b6//r9/2Wx/2q1/4bD/6DQ/6fT/9Tp/+Lw/+jz//D4//j8/1qt/2mz/5rM/6bS/8Lg/8jj/97v/+r1/1Cn/1ar/2Cv/3O5/3++/53O/8Th/9Lo/9Xq/+z2/2Kw/2Sx/8Ti/4rF/7DY/1+v/4TB/7fb/+Ty/1+u/2Ox/4zG/6vU/7/f//r8/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/i1NYWRlIGJ5IEtyYXNpbWlyYSBOZWpjaGV2YSAod3d3LmxvYWRpbmZvLm5ldCkAIfkEAQoAMAAsAAAAABAAEAAABptAmFCI6mAsnNNwCUthGomDoYCQoJinyELRgDwUhAFCNFRJGg8P6/VSaQyCgxK2cURMTJioEIA0Jw8geUIZAQMkIhEVLIMwKgMAFx4SGS+NLwwCFR8UGo1CKSgsJBUYLZ9sMCsZF3iDLy2nMCEXGyp5bSqyLBwaHSguQi8sKigqlkIqHb4hJc4lJsdMLSQeHyEhIyXSgy2hxsFLQQAh+QQBCgAAACwAAAAAEAAQAAAHp4AAgoIoH0NCSCiDiwBORDo5Czg3C0BNjCg/Dw46PjwOBwcLS4MrQTs9ICwvL05FODU4igBGPECzi0s4NDyNQT5KjINDAzZMTEBCLMKCTQczQ0lBRcyDODI8SojVAC84MTxMQkVP1SgDMEJPRkS4jB8xM6RKRR/Lwi9HQYJPIB9KTV4MeuHiicBSSkAoYYKiiRMnKw4ucnFiyRKGKJyUq/aChUaDjAIBACH5BAEKAAAALAAAAAAQABAAAAeogACCgm1KZGRmbYOLAG5GXjoPXFsPYIqLbWE7XV1fXjtaWQ9qg25iXmBKby8AKmVcWFyXaBdil4tqWldejWNhpIyCZFZZa2tjZG/BgipYVWRpY2bLg1s0XWpGaNQAL1pTXW1maMrLbVZSYm9oZyrUYVFUpGxoaeWLZzQBOoJvamkm3OCSAsWKiUH+1rBp48bFCxVWaGxb9LBNGxVvVqUBFuzFizculgUCACH5BAEKAAEALAAAAAAQABAAAAi4AAMIFPiHxJEjJPwMXBgAEIg8XijcsUNhzB+GfzjkwYNnSB4KdRzcWTPwzZEhY/i8EfgmhJ0GdhQGIDFGz0WGJuoswBPgzQc9fRgOPDKnQR8/H0K4EErQQQKgIPgwFRioTgE8ffZInRqIztWCfAJN/TOnAAcXJvgAmjpEDgKSf9b4Ectwz5UBd6j68fNnaYBAfvIUEIAgKNU/gN4E+sNgAJw4BvYIfeMiUB8BAAbUMTz1TYU8YRcGBAAh+QQBCgAAACwAAAAAEAAQAAAItAABCBT4qJGIRY0cDVwIAJIIMnnyWABiwYjChY8WGVFExgjELjwsNBroQgSSD40gCXQIJFGXi41AiHjEEECjLg8UNWS06GLND4gSNXrEqESkmgQTGfrgqMRIpAAidVkwpKDPmpF44MgDqVGTo0gdHbqBJJIjR2BrkiG0YCSkRyprMsJBCMhASJEioczbZEihGoaeCtQrgwYOujRoLGBU08IgQYJkzKjBQ/DCSIzy8OgypATDgAAh+QQBCgAAACwAAAAAEAAQAAAIswABCBQIKRMfPmw0DVwIYBObEEiKjBEzJoTChZD4XArB0UyRMBfGtBm4CdOSJW02EeQjxkuYi38wYYLEEEAmDJWMNGyTsKbAS5Us/YHU5o9PgZos7QixSdPFo18eFNkESeXRTV+4FGlo1aemHVvM7ORzFMmCByOXHJgSoiafLTgwCOQjCYqkMCk3/SlCCQvagSEmBRh0gBLcAwe4kF2IaYekKVNoTMLiZWTNTSwtWRqDiWFAACH5BAEKAAIALAAAAAAQABAAAAi5AAUIFOhCBRs2o94MXCjghQpRI/YkQYJkj8KFL0atEcVRVJIOY0KtWKhi1Cg3LwS+YdNhCCg3Kt2oSMlQxZg8IGLSZChA1IU8Khru5PkmjxdRbtgE5TlwCAUknzgxGIoxDw8kQgAMGMVUgJtPnvaQGBAgT1cQDyhwhRCnUxKeazw5GCNwTQFOBsbMfLECyYMGPJYK2INgAAEFDyA0ULDA0xqGbHggKFDgQIIGF7jyfLGmw4ULHdgwDAgAIfkEAQoAAAAsAAAAABAAEAAACLcAAQgcqElTK00uBioUuKlVEzYnlixhk3BhC4MO2SxhtIrVCoWbNrnYNLAhKzMgWggMgqTiwhVIiiwBsKQUKTMLB7IhoqpVHhimmuQU2KJInhOpYtxwmdNMHlapZKAiORRAkSCshpQ61arqijxAJNoYMKTqEh95uvagUWjmQjZAUqkSyAZVDVRFWoXUBKLHjiAfBS5hcOqUg1Q+djh44IPNwiZAFtxAtSCHDiJdh55AkmeIGaEKAwIAIfkEAQoAAAAsAAAAABAAEAAACLcAAQgcGMgFJEiBBioEUEIJAINuRo36k1AhGldXVhSMyAaTCUgDMVWBMiWNQjeY0pRwIVBHAFdoFgKAxOgMG4avooSRKfCPmTOQNEi5MornwzNIRnWZQqkiTyVFSnRxtYWlUTMa0hSpkuWPUUgcNGDClMVKEaMmwohxA6CLFUolZI7ScCEmgFFcsnBB4nVmCTBeNLAVWCKvlh1dvnjRUSlMUYWjwDzYwuWBji6wBss1U6QImscDAwIAIfkEAQoAAQAsAAAAABAAEAAACLMAAwgUyEfWJxYDEw5sBGEAAAGNXkCCpDAAKwNw4AxgoEIii44LCwnolMfPC4EvVPgxKfDOgCusKr7ws0ZFABOF5IipKJAFHz4vOBSYY5NnAD4jVMgqAOGkUT5J/CxtajRAmiRr9CSIVbQiJFZI/DRyMAeJ0awfKMqaQ2dNRRV6xqQR6MdOLDusEAaAtGbMGCR6A6y54wDCpzxiZCnm0FWgijF3INyhcDhJYIV+wH5I0zhAQAAh+QQBCgAAACwAAAAAEAAQAAAItAABCBRYYkiqVLUYuRjIkE2qGjNkxBA0IwhDgYwU0JhVg1YCGjLMLBzYxFCNBEM0uXDBxkyLlQOBEFLA6CKAlZpaAGBjiBAZmwP//HFhJMGhP0AF/mHjopaCVCOBsmGjqZahLlFtsinxx4yhHZqSurDFaGkiREmS/rnESOeQB6nY2NR0CYRcAH+67AByaWSLlkj6DmQTJFWXWmSMkCFCBkRYhn+MBAESpBbitmpLJLlU4vHAgAAh+QQBCgAAACwAAAAAEAAQAAAIvQABCBS4ZpclS0PWDFwIoI0uHFVu3ZIiiY7ChWpyHTiAowGDK4MCVEEzsA0dLAw4OOHFq00YXFBwqREIBkeumQzN3DqQBkCmOgvKMByYpg0vAGZy7XAydCCvFgA45NLVdGCLFrw40PlytCoLJy0u7bAEtSkvJ21aOLF055JXNkYBwKoEJtPQFmvWMAWwIoyuIWrKunCSJo2Jrg2HXAjDwcwlNCDQpCk7kAWIXUN2wTKDZo2Lqk7YpFGTibLAgAA7'); + background-position: 0px 0px; +} +/* Status node icons */ +.fancytree-statusnode-error span.fancytree-icon, +.fancytree-statusnode-error span.fancytree-icon:hover { + background-position: 0px -112px; +} +/*------------------------------------------------------------------------------ + * Node titles and highlighting + *----------------------------------------------------------------------------*/ +span.fancytree-node { + /* See #117 */ + display: inherit; + width: 100%; + margin-top: 1px; + min-height: 20px; +} +span.fancytree-title { + color: #000000; + cursor: pointer; + display: inline-block; + vertical-align: top; + min-height: 20px; + padding: 0 3px 0 3px; + margin: 0px 0 0 3px; + border: 1px solid transparent; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + -ms-border-radius: 3px; + -o-border-radius: 3px; + border-radius: 3px; +} +span.fancytree-node.fancytree-error span.fancytree-title { + color: #ff0000; +} +/*------------------------------------------------------------------------------ + * Drag'n'drop support + *----------------------------------------------------------------------------*/ +div.fancytree-drag-helper span.fancytree-childcounter, +div.fancytree-drag-helper span.fancytree-dnd-modifier { + display: inline-block; + color: #fff; + background: #337ab7; + border: 1px solid gray; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +div.fancytree-drag-helper span.fancytree-childcounter { + position: absolute; + top: -6px; + right: -6px; +} +div.fancytree-drag-helper span.fancytree-dnd-modifier { + background: #5cb85c; + border: none; + font-weight: bolder; +} +div.fancytree-drag-helper.fancytree-drop-accept span.fancytree-drag-helper-img { + background-position: -32px -112px; +} +div.fancytree-drag-helper.fancytree-drop-reject span.fancytree-drag-helper-img { + background-position: -16px -112px; +} +/*** Drop marker icon *********************************************************/ +#fancytree-drop-marker { + width: 32px; + position: absolute; + background-position: 0px -128px; + margin: 0; +} +#fancytree-drop-marker.fancytree-drop-after, +#fancytree-drop-marker.fancytree-drop-before { + width: 64px; + background-position: 0px -144px; +} +#fancytree-drop-marker.fancytree-drop-copy { + background-position: -64px -128px; +} +#fancytree-drop-marker.fancytree-drop-move { + background-position: -32px -128px; +} +/*** Source node while dragging ***********************************************/ +span.fancytree-drag-source.fancytree-drag-remove { + opacity: 0.15; +} +/*** Target node while dragging cursor is over it *****************************/ +/*------------------------------------------------------------------------------ + * 'table' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-table { + border-collapse: collapse; +} +table.fancytree-ext-table span.fancytree-node { + display: inline-block; +} +/*------------------------------------------------------------------------------ + * 'columnview' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-columnview tbody tr td { + position: relative; + border: 1px solid gray; + vertical-align: top; + overflow: auto; +} +table.fancytree-ext-columnview tbody tr td > ul { + padding: 0; +} +table.fancytree-ext-columnview tbody tr td > ul li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0px 0px; + background-repeat: repeat-y; + background-image: none; + /* no v-lines */ + margin: 0; +} +table.fancytree-ext-columnview span.fancytree-node { + position: relative; + /* allow positioning of embedded spans */ + display: inline-block; +} +table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded { + background-color: #CBE8F6; +} +table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right { + position: absolute; + right: 3px; + background-position: 0px -80px; +} +table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right:hover { + background-position: -16px -80px; +} +/*------------------------------------------------------------------------------ + * 'filter' extension + *----------------------------------------------------------------------------*/ +.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title { + color: #c0c0c0; + font-weight: lighter; +} +.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: bold; +} +.fancytree-ext-filter-hide tr.fancytree-hide, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide { + display: none; +} +.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title { + color: #c0c0c0; + font-weight: lighter; +} +.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-childcounter span.fancytree-icon, +.fancytree-ext-filter span.fancytree-icon { + position: relative; +} +.fancytree-ext-childcounter span.fancytree-childcounter, +.fancytree-ext-filter span.fancytree-childcounter { + color: #fff; + background: #777; + border: 1px solid gray; + position: absolute; + top: -6px; + right: -6px; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +/*------------------------------------------------------------------------------ + * 'wide' extension + *----------------------------------------------------------------------------*/ +ul.fancytree-ext-wide { + position: relative; + min-width: 100%; + z-index: 2; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +ul.fancytree-ext-wide span.fancytree-node > span { + position: relative; + z-index: 2; +} +ul.fancytree-ext-wide span.fancytree-node span.fancytree-title { + position: absolute; + z-index: 1; + left: 0px; + width: 100%; + margin-left: 0; + margin-right: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +/******************************************************************************* + * Styles specific to this skin. + * + * This section is automatically generated from the `ui-fancytree.less` template. + ******************************************************************************/ +/******************************************************************************* + * Node titles + */ +span.fancytree-active .fancytree-title, +span.fancytree-selected .fancytree-title { + border-color: #d9d9d9; + background: #e5e5e5; + color: inherit; + background: -moz-linear-gradient(top, #fafafb 0%, #e5e5e5 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fafafb), color-stop(100%, #e5e5e5)); + background: -webkit-linear-gradient(top, #fafafb 0%, #e5e5e5 100%); + background: -o-linear-gradient(top, #fafafb 0%, #e5e5e5 100%); + background: -ms-linear-gradient(top, #fafafb 0%, #e5e5e5 100%); + background: linear-gradient(to bottom, #fafafb 0%, #e5e5e5 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fafafb', endColorstr='#e5e5e5', GradientType=0); +} +span.fancytree-selected .fancytree-title { + font-style: italic; +} +.fancytree-treefocus span.fancytree-active .fancytree-title, +.fancytree-treefocus span.fancytree-selected .fancytree-title { + border-color: #99defd; + background: #f6fbfd; + color: inherit; + background: -moz-linear-gradient(top, #f6fbfd 0%, #d5effc 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f6fbfd), color-stop(100%, #d5effc)); + background: -webkit-linear-gradient(top, #f6fbfd 0%, #d5effc 100%); + background: -o-linear-gradient(top, #f6fbfd 0%, #d5effc 100%); + background: -ms-linear-gradient(top, #f6fbfd 0%, #d5effc 100%); + background: linear-gradient(to bottom, #f6fbfd 0%, #d5effc 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f6fbfd', endColorstr='#d5effc', GradientType=0); +} +.fancytree-treefocus span.fancytree-focused span.fancytree-title { + border: 1px solid #719acb; +} +span.fancytree-title:hover { + border-color: #d8f0fa; + background: #f8fcfe; + color: inherit; + background: -moz-linear-gradient(top, #f8fcfe 0%, #eff9fe 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8fcfe), color-stop(100%, #eff9fe)); + background: -webkit-linear-gradient(top, #f8fcfe 0%, #eff9fe 100%); + background: -o-linear-gradient(top, #f8fcfe 0%, #eff9fe 100%); + background: -ms-linear-gradient(top, #f8fcfe 0%, #eff9fe 100%); + background: linear-gradient(to bottom, #f8fcfe 0%, #eff9fe 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8fcfe', endColorstr='#eff9fe', GradientType=0); +} +span.fancytree-active .fancytree-title:hover, +span.fancytree-selected .fancytree-title:hover { + border-color: #719acb; + background: #f2f9fd; + color: inherit; + background: -moz-linear-gradient(top, #f2f9fd 0%, #c4e8fa 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f2f9fd), color-stop(100%, #c4e8fa)); + background: -webkit-linear-gradient(top, #f2f9fd 0%, #c4e8fa 100%); + background: -o-linear-gradient(top, #f2f9fd 0%, #c4e8fa 100%); + background: -ms-linear-gradient(top, #f2f9fd 0%, #c4e8fa 100%); + background: linear-gradient(to bottom, #f2f9fd 0%, #c4e8fa 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f2f9fd', endColorstr='#c4e8fa', GradientType=0); +} +/******************************************************************************* + * 'table' extension + */ +table.fancytree-ext-table tbody tr td { + border: 1px solid #ededed; +} +table.fancytree-ext-table tbody tr:hover { + border-color: inherit; + background: #f8fcfe; + color: inherit; + background: -moz-linear-gradient(top, #f8fcfe 0%, #eff9fe 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8fcfe), color-stop(100%, #eff9fe)); + background: -webkit-linear-gradient(top, #f8fcfe 0%, #eff9fe 100%); + background: -o-linear-gradient(top, #f8fcfe 0%, #eff9fe 100%); + background: -ms-linear-gradient(top, #f8fcfe 0%, #eff9fe 100%); + background: linear-gradient(to bottom, #f8fcfe 0%, #eff9fe 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8fcfe', endColorstr='#eff9fe', GradientType=0); + outline: 1px solid #d8f0fa; +} +table.fancytree-ext-table tbody tr.fancytree-focused { + outline: 1px dotted #090402; +} +table.fancytree-ext-table tbody span.fancytree-focused span.fancytree-title { + outline: solid dotted black; +} +table.fancytree-ext-table tbody span.fancytree-title:hover { + border: 1px solid transparent; + background: inherit; + background: transparent; + background: none; + filter: none; +} +table.fancytree-ext-table tbody tr.fancytree-active:hover, +table.fancytree-ext-table tbody tr.fancytree-selected:hover { + border-color: inherit; + background: #f2f9fd; + color: inherit; + background: -moz-linear-gradient(top, #f2f9fd 0%, #c4e8fa 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f2f9fd), color-stop(100%, #c4e8fa)); + background: -webkit-linear-gradient(top, #f2f9fd 0%, #c4e8fa 100%); + background: -o-linear-gradient(top, #f2f9fd 0%, #c4e8fa 100%); + background: -ms-linear-gradient(top, #f2f9fd 0%, #c4e8fa 100%); + background: linear-gradient(to bottom, #f2f9fd 0%, #c4e8fa 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f2f9fd', endColorstr='#c4e8fa', GradientType=0); + outline: 1px solid #B6E6FB; +} +table.fancytree-ext-table tbody tr.fancytree-active, +table.fancytree-ext-table tbody tr.fancytree-selected { + border-color: inherit; + background: #f6fbfd; + color: inherit; + background: -moz-linear-gradient(top, #f6fbfd 0%, #d5effc 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f6fbfd), color-stop(100%, #d5effc)); + background: -webkit-linear-gradient(top, #f6fbfd 0%, #d5effc 100%); + background: -o-linear-gradient(top, #f6fbfd 0%, #d5effc 100%); + background: -ms-linear-gradient(top, #f6fbfd 0%, #d5effc 100%); + background: linear-gradient(to bottom, #f6fbfd 0%, #d5effc 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f6fbfd', endColorstr='#d5effc', GradientType=0); + outline: 1px solid #99DEFD; +} diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win7/ui.fancytree.less b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win7/ui.fancytree.less new file mode 100644 index 00000000000..24c8414760e --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win7/ui.fancytree.less @@ -0,0 +1,152 @@ +/*! + * Fancytree "Win7" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ + +// Fancytree Win7 styles + +// both: +// unselected background: #FCFCFC 'nearly white', no border +// +// hover bar (unselected, inactive): #fcfdfe..#EFF9FE (border: #b8d6fb) 'very light blue' +// background: #f8fcfe; // +// background: -moz-linear-gradient(top, #f8fcfe 0%, #eff9fe 100%); + +// active node: #F6FBFD..#D5EFFC (border: #719acb) 'light blue' +// background: #f6fbfd; +// background: -moz-linear-gradient(top, #f6fbfd 0%, #d5effc 100%); + +// active node with hover: #F2F9FD..#C4E8FA (border: #B6E6FB) +// background: #f2f9fd; +// background: -moz-linear-gradient(top, #f2f9fd 0%, #c4e8fa 100%); + +// Tree view: +// active node, tree inactive: #FAFAFB..#E5E5E5 (border: #D9D9D9) 'light gray, selected, but tree not active' +// background: #fafafb; +// background: -moz-linear-gradient(top, #fafafb 0%, #e5e5e5 100%); + +// List view: +// selected bar: --> active bar +// focus bar: active + border 1px dotted #090402 (inside the blue border) + +// table left/right border: #EDEDED 'light gray' + +// Import common styles +@import "../skin-common.less"; + + +/******************************************************************************* + * Styles specific to this skin. + * + * This section is automatically generated from the `ui-fancytree.less` template. + ******************************************************************************/ + +// Override the variable after the import. +// NOTE: Variables are always resolved as the last definition, even if it is +// after where it is used. +@fancy-use-sprites: true; // false: suppress all background images (i.e. icons) +@fancy-hide-connectors: true; + +@fancy-line-height: 20px; // height of a nodes selection bar including borders +@fancy-node-v-spacing: 1px; // gap between two node borders +@fancy-icon-width: 16px; +@fancy-icon-height: 16px; +@fancy-icon-spacing: 3px; // margin between icon/icon or icon/title +@fancy-icon-ofs-top: 2px; // extra vertical offset for expander, checkbox and icon +@fancy-title-ofs-top: 0px; // extra vertical offset for title +@fancy-node-border-width: 1px; +@fancy-node-border-radius: 3px; +@fancy-node-outline-width: 1px; + +// Use 'data-uri(...)' to embed the image into CSS instead of linking to 'loading.gif': +@fancy-loading-url: data-uri("@{fancy-image-dir}/loading.gif"); +// Set to `true` to use `data-uri(...)` which will embed icons.gif into CSS +// instead of linking to that file: +// @fancy-inline-sprites: true; + + +ul.fancytree-container { + +} + +/******************************************************************************* + * Node titles + */ +span.fancytree-title { +} +// active nodes inside an UN-focused tree are gray instead of blue +span.fancytree-active .fancytree-title, +span.fancytree-selected .fancytree-title { + .spanStyleMixin(inherit, #e5e5e5, #d9d9d9, #fafafb, #e5e5e5); +} +span.fancytree-selected .fancytree-title { + font-style: italic; +} +// Markers inside an active tree +.fancytree-treefocus { + span.fancytree-active .fancytree-title, + span.fancytree-selected .fancytree-title { + .spanStyleMixin(inherit, #f6fbfd, #99defd, #f6fbfd, #d5effc); + } + span.fancytree-focused span.fancytree-title { + border: @fancy-node-border-width solid #719acb; + } +} +// Hover is always colored (even if tree is inactive) +span.fancytree-title:hover { + .spanStyleMixin(inherit, #f8fcfe, #d8f0fa, #f8fcfe, #eff9fe); +} +span.fancytree-active .fancytree-title:hover, +span.fancytree-selected .fancytree-title:hover { + .spanStyleMixin(inherit, #f2f9fd, #719acb, #f2f9fd, #c4e8fa); +} + +/******************************************************************************* + * 'table' extension + */ + +table.fancytree-ext-table tbody { + tr td { + border: 1px solid #ededed; + } + tr:hover { + .spanStyleMixin(inherit, #f8fcfe, inherit, #f8fcfe, #eff9fe); + outline: 1px solid #d8f0fa; + } + // tr:hover td { + // outline: 1px solid #D8F0FA; + // } + tr.fancytree-focused { + // background-color: #99DEFD; + outline: 1px dotted #090402; + } + span.fancytree-focused span.fancytree-title { + outline: solid dotted black; + } + + // Title get's a white background, when hovered. Undo standard node formatting + span.fancytree-title:hover { + border: 1px solid transparent; + background: inherit; + background: transparent; + background: none; + filter: none; + } + + tr.fancytree-active:hover, + tr.fancytree-selected:hover { + .spanStyleMixin(inherit, #f2f9fd, inherit, #f2f9fd, #c4e8fa); + outline: 1px solid #B6E6FB; + } + tr.fancytree-active, + tr.fancytree-selected { + .spanStyleMixin(inherit, #f6fbfd, inherit, #f6fbfd, #d5effc); + outline: 1px solid #99DEFD; + } + // tr.fancytree-selected .fancytree-title { + // font-style: italic; + // } + +} diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win7/ui.fancytree.min.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win7/ui.fancytree.min.css new file mode 100644 index 00000000000..1aaa9e97b58 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win7/ui.fancytree.min.css @@ -0,0 +1,6 @@ +/*! + * Fancytree "Win7" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */.ui-helper-hidden{display:none}ul.fancytree-container{font-family:tahoma,arial,helvetica;font-size:10pt;white-space:nowrap;padding:3px;margin:0;background-color:#fff;border:1px dotted gray;overflow:auto;min-height:0;position:relative}ul.fancytree-container ul{padding:0 0 0 16px;margin:0}ul.fancytree-container li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0}ul.fancytree-container li.fancytree-lastsib,ul.fancytree-no-connector>li{background-image:none}.ui-fancytree-disabled ul.fancytree-container{opacity:.5;background-color:silver}#fancytree-drop-marker,span.fancytree-checkbox,span.fancytree-drag-helper-img,span.fancytree-empty,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio,span.fancytree-vline{width:16px;height:16px;display:inline-block;vertical-align:top;background-repeat:no-repeat;background-image:url(icons.gif);background-position:0 0}span.fancytree-checkbox,span.fancytree-custom-icon,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio{margin-top:2px}span.fancytree-custom-icon{display:inline-block;margin-left:3px}img.fancytree-icon{width:16px;height:16px;margin-left:3px;margin-top:2px;vertical-align:top;border-style:none}span.fancytree-expander{cursor:pointer}.fancytree-exp-n span.fancytree-expander,.fancytree-exp-nl span.fancytree-expander{background-image:none;cursor:default}.fancytree-exp-n span.fancytree-expander,.fancytree-exp-n span.fancytree-expander:hover{background-position:0 -64px}.fancytree-exp-nl span.fancytree-expander,.fancytree-exp-nl span.fancytree-expander:hover{background-position:-16px -64px}.fancytree-exp-c span.fancytree-expander{background-position:0 -80px}.fancytree-exp-c span.fancytree-expander:hover{background-position:-16px -80px}.fancytree-exp-cl span.fancytree-expander{background-position:0 -96px}.fancytree-exp-cl span.fancytree-expander:hover{background-position:-16px -96px}.fancytree-exp-cd span.fancytree-expander{background-position:-64px -80px}.fancytree-exp-cd span.fancytree-expander:hover{background-position:-80px -80px}.fancytree-exp-cdl span.fancytree-expander{background-position:-64px -96px}.fancytree-exp-cdl span.fancytree-expander:hover{background-position:-80px -96px}.fancytree-exp-e span.fancytree-expander,.fancytree-exp-ed span.fancytree-expander{background-position:-32px -80px}.fancytree-exp-e span.fancytree-expander:hover,.fancytree-exp-ed span.fancytree-expander:hover{background-position:-48px -80px}.fancytree-exp-edl span.fancytree-expander,.fancytree-exp-el span.fancytree-expander{background-position:-32px -96px}.fancytree-exp-edl span.fancytree-expander:hover,.fancytree-exp-el span.fancytree-expander:hover{background-position:-48px -96px}span.fancytree-checkbox{margin-left:3px;background-position:0 -32px}span.fancytree-checkbox:hover{background-position:-16px -32px}.fancytree-partsel span.fancytree-checkbox{background-position:-64px -32px}.fancytree-partsel span.fancytree-checkbox:hover{background-position:-80px -32px}.fancytree-selected span.fancytree-checkbox{background-position:-32px -32px}.fancytree-selected span.fancytree-checkbox:hover{background-position:-48px -32px}.fancytree-unselectable span.fancytree-checkbox{opacity:.4;filter:alpha(opacity=40)}.fancytree-unselectable span.fancytree-checkbox:hover{background-position:0 -32px}.fancytree-unselectable.fancytree-partsel span.fancytree-checkbox:hover{background-position:-64px -32px}.fancytree-unselectable.fancytree-selected span.fancytree-checkbox:hover{background-position:-32px -32px}.fancytree-radio span.fancytree-checkbox{background-position:0 -48px}.fancytree-radio span.fancytree-checkbox:hover{background-position:-16px -48px}.fancytree-radio .fancytree-partsel span.fancytree-checkbox{background-position:-64px -48px}.fancytree-radio .fancytree-partsel span.fancytree-checkbox:hover{background-position:-80px -48px}.fancytree-radio .fancytree-selected span.fancytree-checkbox{background-position:-32px -48px}.fancytree-radio .fancytree-selected span.fancytree-checkbox:hover{background-position:-48px -48px}.fancytree-radio .fancytree-unselectable span.fancytree-checkbox,.fancytree-radio .fancytree-unselectable span.fancytree-checkbox:hover{background-position:0 -48px}span.fancytree-icon{margin-left:3px;background-position:0 0}.fancytree-ico-c span.fancytree-icon:hover{background-position:-16px 0}.fancytree-has-children.fancytree-ico-c span.fancytree-icon{background-position:-32px 0}.fancytree-has-children.fancytree-ico-c span.fancytree-icon:hover{background-position:-48px 0}.fancytree-ico-e span.fancytree-icon{background-position:-64px 0}.fancytree-ico-e span.fancytree-icon:hover{background-position:-80px 0}.fancytree-ico-cf span.fancytree-icon{background-position:0 -16px}.fancytree-ico-cf span.fancytree-icon:hover{background-position:-16px -16px}.fancytree-has-children.fancytree-ico-cf span.fancytree-icon{background-position:-32px -16px}.fancytree-has-children.fancytree-ico-cf span.fancytree-icon:hover{background-position:-48px -16px}.fancytree-ico-ef span.fancytree-icon{background-position:-64px -16px}.fancytree-ico-ef span.fancytree-icon:hover{background-position:-80px -16px}.fancytree-loading span.fancytree-expander,.fancytree-loading span.fancytree-expander:hover,.fancytree-statusnode-wait span.fancytree-icon,.fancytree-statusnode-wait span.fancytree-icon:hover{background-image:url(data:image/gif;base64,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);background-position:0 0}.fancytree-statusnode-error span.fancytree-icon,.fancytree-statusnode-error span.fancytree-icon:hover{background-position:0 -112px}span.fancytree-node{display:inherit;width:100%;margin-top:1px;min-height:20px}span.fancytree-title{color:#000;cursor:pointer;display:inline-block;vertical-align:top;min-height:20px;padding:0 3px;margin:0 0 0 3px;border:1px solid transparent;-webkit-border-radius:3px;-moz-border-radius:3px;-ms-border-radius:3px;-o-border-radius:3px;border-radius:3px}span.fancytree-node.fancytree-error span.fancytree-title{color:red}div.fancytree-drag-helper span.fancytree-childcounter,div.fancytree-drag-helper span.fancytree-dnd-modifier{display:inline-block;color:#fff;background:#337ab7;border:1px solid gray;min-width:10px;height:10px;line-height:1;vertical-align:baseline;border-radius:10px;padding:2px;text-align:center;font-size:9px}div.fancytree-drag-helper span.fancytree-childcounter{position:absolute;top:-6px;right:-6px}div.fancytree-drag-helper span.fancytree-dnd-modifier{background:#5cb85c;border:0;font-weight:bolder}div.fancytree-drag-helper.fancytree-drop-accept span.fancytree-drag-helper-img{background-position:-32px -112px}div.fancytree-drag-helper.fancytree-drop-reject span.fancytree-drag-helper-img{background-position:-16px -112px}#fancytree-drop-marker{width:32px;position:absolute;background-position:0 -128px;margin:0}#fancytree-drop-marker.fancytree-drop-after,#fancytree-drop-marker.fancytree-drop-before{width:64px;background-position:0 -144px}#fancytree-drop-marker.fancytree-drop-copy{background-position:-64px -128px}#fancytree-drop-marker.fancytree-drop-move{background-position:-32px -128px}span.fancytree-drag-source.fancytree-drag-remove{opacity:.15}table.fancytree-ext-table{border-collapse:collapse}table.fancytree-ext-table span.fancytree-node{display:inline-block}table.fancytree-ext-columnview tbody tr td{position:relative;border:1px solid gray;vertical-align:top;overflow:auto}table.fancytree-ext-columnview tbody tr td>ul{padding:0}table.fancytree-ext-columnview tbody tr td>ul li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0}table.fancytree-ext-columnview span.fancytree-node{position:relative;display:inline-block}table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded{background-color:#CBE8F6}table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right{position:absolute;right:3px;background-position:0 -80px}table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right:hover{background-position:-16px -80px}.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title{color:silver;font-weight:lighter}.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title,.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title{color:#000;font-weight:400}.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title,.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title{color:#000;font-weight:700}.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide,.fancytree-ext-filter-hide tr.fancytree-hide{display:none}.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title,.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title{color:silver;font-weight:lighter}.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title,.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title{color:#000;font-weight:400}.fancytree-ext-childcounter span.fancytree-icon,.fancytree-ext-filter span.fancytree-icon{position:relative}.fancytree-ext-childcounter span.fancytree-childcounter,.fancytree-ext-filter span.fancytree-childcounter{color:#fff;background:#777;border:1px solid gray;position:absolute;top:-6px;right:-6px;min-width:10px;height:10px;line-height:1;vertical-align:baseline;border-radius:10px;padding:2px;text-align:center;font-size:9px}ul.fancytree-ext-wide{position:relative;min-width:100%;z-index:2;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}ul.fancytree-ext-wide span.fancytree-node>span{position:relative;z-index:2}ul.fancytree-ext-wide span.fancytree-node span.fancytree-title{position:absolute;z-index:1;left:0;width:100%;margin-left:0;margin-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}span.fancytree-active .fancytree-title,span.fancytree-selected .fancytree-title{border-color:#d9d9d9;color:inherit;background:-moz-linear-gradient(top,#fafafb 0,#e5e5e5 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#fafafb),color-stop(100%,#e5e5e5));background:-webkit-linear-gradient(top,#fafafb 0,#e5e5e5 100%);background:-o-linear-gradient(top,#fafafb 0,#e5e5e5 100%);background:-ms-linear-gradient(top,#fafafb 0,#e5e5e5 100%);background:linear-gradient(to bottom,#fafafb 0,#e5e5e5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fafafb', endColorstr='#e5e5e5', GradientType=0)}span.fancytree-selected .fancytree-title{font-style:italic}.fancytree-treefocus span.fancytree-active .fancytree-title,.fancytree-treefocus span.fancytree-selected .fancytree-title{border-color:#99defd;color:inherit;background:-moz-linear-gradient(top,#f6fbfd 0,#d5effc 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#f6fbfd),color-stop(100%,#d5effc));background:-webkit-linear-gradient(top,#f6fbfd 0,#d5effc 100%);background:-o-linear-gradient(top,#f6fbfd 0,#d5effc 100%);background:-ms-linear-gradient(top,#f6fbfd 0,#d5effc 100%);background:linear-gradient(to bottom,#f6fbfd 0,#d5effc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f6fbfd', endColorstr='#d5effc', GradientType=0)}.fancytree-treefocus span.fancytree-focused span.fancytree-title{border:1px solid #719acb}span.fancytree-title:hover{border-color:#d8f0fa;color:inherit;background:-moz-linear-gradient(top,#f8fcfe 0,#eff9fe 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#f8fcfe),color-stop(100%,#eff9fe));background:-webkit-linear-gradient(top,#f8fcfe 0,#eff9fe 100%);background:-o-linear-gradient(top,#f8fcfe 0,#eff9fe 100%);background:-ms-linear-gradient(top,#f8fcfe 0,#eff9fe 100%);background:linear-gradient(to bottom,#f8fcfe 0,#eff9fe 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8fcfe', endColorstr='#eff9fe', GradientType=0)}span.fancytree-active .fancytree-title:hover,span.fancytree-selected .fancytree-title:hover{border-color:#719acb;color:inherit;background:-moz-linear-gradient(top,#f2f9fd 0,#c4e8fa 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#f2f9fd),color-stop(100%,#c4e8fa));background:-webkit-linear-gradient(top,#f2f9fd 0,#c4e8fa 100%);background:-o-linear-gradient(top,#f2f9fd 0,#c4e8fa 100%);background:-ms-linear-gradient(top,#f2f9fd 0,#c4e8fa 100%);background:linear-gradient(to bottom,#f2f9fd 0,#c4e8fa 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f2f9fd', endColorstr='#c4e8fa', GradientType=0)}table.fancytree-ext-table tbody tr td{border:1px solid #ededed}table.fancytree-ext-table tbody tr:hover{border-color:inherit;color:inherit;background:-moz-linear-gradient(top,#f8fcfe 0,#eff9fe 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#f8fcfe),color-stop(100%,#eff9fe));background:-webkit-linear-gradient(top,#f8fcfe 0,#eff9fe 100%);background:-o-linear-gradient(top,#f8fcfe 0,#eff9fe 100%);background:-ms-linear-gradient(top,#f8fcfe 0,#eff9fe 100%);background:linear-gradient(to bottom,#f8fcfe 0,#eff9fe 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8fcfe', endColorstr='#eff9fe', GradientType=0);outline:1px solid #d8f0fa}table.fancytree-ext-table tbody tr.fancytree-focused{outline:1px dotted #090402}table.fancytree-ext-table tbody span.fancytree-focused span.fancytree-title{outline:solid dotted #000}table.fancytree-ext-table tbody span.fancytree-title:hover{border:1px solid transparent;background:inherit;background:0 0;background:0 0;filter:none}table.fancytree-ext-table tbody tr.fancytree-active:hover,table.fancytree-ext-table tbody tr.fancytree-selected:hover{border-color:inherit;color:inherit;background:-moz-linear-gradient(top,#f2f9fd 0,#c4e8fa 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#f2f9fd),color-stop(100%,#c4e8fa));background:-webkit-linear-gradient(top,#f2f9fd 0,#c4e8fa 100%);background:-o-linear-gradient(top,#f2f9fd 0,#c4e8fa 100%);background:-ms-linear-gradient(top,#f2f9fd 0,#c4e8fa 100%);background:linear-gradient(to bottom,#f2f9fd 0,#c4e8fa 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f2f9fd', endColorstr='#c4e8fa', GradientType=0);outline:1px solid #B6E6FB}table.fancytree-ext-table tbody tr.fancytree-active,table.fancytree-ext-table tbody tr.fancytree-selected{border-color:inherit;color:inherit;background:-moz-linear-gradient(top,#f6fbfd 0,#d5effc 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#f6fbfd),color-stop(100%,#d5effc));background:-webkit-linear-gradient(top,#f6fbfd 0,#d5effc 100%);background:-o-linear-gradient(top,#f6fbfd 0,#d5effc 100%);background:-ms-linear-gradient(top,#f6fbfd 0,#d5effc 100%);background:linear-gradient(to bottom,#f6fbfd 0,#d5effc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f6fbfd', endColorstr='#d5effc', GradientType=0);outline:1px solid #99DEFD} \ No newline at end of file diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-n/icons.gif b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-n/icons.gif new file mode 100644 index 0000000000000000000000000000000000000000..813eb8385c40a954a85b0fc8379a6446aec3acd8 GIT binary patch literal 5492 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 literal 0 HcmV?d00001 diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-n/loading.gif b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-n/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..ef88497ccc2f6c2a3a0c5e41f3cbfc7a18ff5329 GIT binary patch literal 3234 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 RGR}AoOL=)|H48+m{|ju`J$C>A literal 0 HcmV?d00001 diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-n/ui.fancytree.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-n/ui.fancytree.css new file mode 100644 index 00000000000..653b54215df --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-n/ui.fancytree.css @@ -0,0 +1,575 @@ +/*! + * Fancytree "win8" skin (highlighting the node span instead of title-only). + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ +/******************************************************************************* + * Common Styles for Fancytree Skins. + * + * This section is automatically generated from the `skin-common.less` template. + ******************************************************************************/ +/*------------------------------------------------------------------------------ + * Helpers + *----------------------------------------------------------------------------*/ +.ui-helper-hidden { + display: none; +} +/*------------------------------------------------------------------------------ + * Container and UL / LI + *----------------------------------------------------------------------------*/ +ul.fancytree-container { + font-family: tahoma, arial, helvetica; + font-size: 10pt; + white-space: nowrap; + padding: 3px; + margin: 0; + background-color: white; + border: 1px dotted gray; + overflow: auto; + min-height: 0%; + position: relative; +} +ul.fancytree-container ul { + padding: 0 0 0 16px; + margin: 0; +} +ul.fancytree-container li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0px 0px; + background-repeat: repeat-y; + background-image: none; + margin: 0; +} +ul.fancytree-container li.fancytree-lastsib { + background-image: none; +} +ul.fancytree-no-connector > li { + background-image: none; +} +.ui-fancytree-disabled ul.fancytree-container { + opacity: 0.5; + background-color: silver; +} +/*------------------------------------------------------------------------------ + * Common icon definitions + *----------------------------------------------------------------------------*/ +span.fancytree-empty, +span.fancytree-vline, +span.fancytree-expander, +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-radio, +span.fancytree-drag-helper-img, +#fancytree-drop-marker { + width: 16px; + height: 16px; + display: inline-block; + vertical-align: top; + background-repeat: no-repeat; + background-position: left; + background-image: url("icons.gif"); + background-position: 0px 0px; +} +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-expander, +span.fancytree-radio, +span.fancytree-custom-icon { + margin-top: 0px; +} +/* Used by iconclass option and iconClass callback: */ +span.fancytree-custom-icon { + display: inline-block; + margin-left: 3px; +} +/* Used by 'icon' node option: */ +img.fancytree-icon { + width: 16px; + height: 16px; + margin-left: 3px; + margin-top: 0px; + vertical-align: top; + border-style: none; +} +/*------------------------------------------------------------------------------ + * Expander icon + * + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-exp- + * 1st character: 'e': expanded, 'c': collapsed, 'n': no children + * 2nd character (optional): 'd': lazy (Delayed) + * 3rd character (optional): 'l': Last sibling + *----------------------------------------------------------------------------*/ +span.fancytree-expander { + cursor: pointer; +} +.fancytree-exp-n span.fancytree-expander, +.fancytree-exp-nl span.fancytree-expander { + background-image: none; + cursor: default; +} +.fancytree-exp-n span.fancytree-expander, +.fancytree-exp-n span.fancytree-expander:hover { + background-position: 0px -64px; +} +.fancytree-exp-nl span.fancytree-expander, +.fancytree-exp-nl span.fancytree-expander:hover { + background-position: -16px -64px; +} +.fancytree-exp-c span.fancytree-expander { + background-position: 0px -80px; +} +.fancytree-exp-c span.fancytree-expander:hover { + background-position: -16px -80px; +} +.fancytree-exp-cl span.fancytree-expander { + background-position: 0px -96px; +} +.fancytree-exp-cl span.fancytree-expander:hover { + background-position: -16px -96px; +} +.fancytree-exp-cd span.fancytree-expander { + background-position: -64px -80px; +} +.fancytree-exp-cd span.fancytree-expander:hover { + background-position: -80px -80px; +} +.fancytree-exp-cdl span.fancytree-expander { + background-position: -64px -96px; +} +.fancytree-exp-cdl span.fancytree-expander:hover { + background-position: -80px -96px; +} +.fancytree-exp-e span.fancytree-expander, +.fancytree-exp-ed span.fancytree-expander { + background-position: -32px -80px; +} +.fancytree-exp-e span.fancytree-expander:hover, +.fancytree-exp-ed span.fancytree-expander:hover { + background-position: -48px -80px; +} +.fancytree-exp-el span.fancytree-expander, +.fancytree-exp-edl span.fancytree-expander { + background-position: -32px -96px; +} +.fancytree-exp-el span.fancytree-expander:hover, +.fancytree-exp-edl span.fancytree-expander:hover { + background-position: -48px -96px; +} +/*------------------------------------------------------------------------------ + * Checkbox icon + *----------------------------------------------------------------------------*/ +span.fancytree-checkbox { + margin-left: 3px; + background-position: 0px -32px; +} +span.fancytree-checkbox:hover { + background-position: -16px -32px; +} +.fancytree-partsel span.fancytree-checkbox { + background-position: -64px -32px; +} +.fancytree-partsel span.fancytree-checkbox:hover { + background-position: -80px -32px; +} +.fancytree-selected span.fancytree-checkbox { + background-position: -32px -32px; +} +.fancytree-selected span.fancytree-checkbox:hover { + background-position: -48px -32px; +} +.fancytree-unselectable span.fancytree-checkbox { + opacity: 0.4; + filter: alpha(opacity=40); +} +.fancytree-unselectable span.fancytree-checkbox:hover { + background-position: 0px -32px; +} +.fancytree-unselectable.fancytree-partsel span.fancytree-checkbox:hover { + background-position: -64px -32px; +} +.fancytree-unselectable.fancytree-selected span.fancytree-checkbox:hover { + background-position: -32px -32px; +} +/*------------------------------------------------------------------------------ + * Radiobutton icon + * This is a customization, that may be activated by overriding the 'checkbox' + * class name as 'fancytree-radio' in the tree options. + *----------------------------------------------------------------------------*/ +.fancytree-radio span.fancytree-checkbox { + background-position: 0px -48px; +} +.fancytree-radio span.fancytree-checkbox:hover { + background-position: -16px -48px; +} +.fancytree-radio .fancytree-partsel span.fancytree-checkbox { + background-position: -64px -48px; +} +.fancytree-radio .fancytree-partsel span.fancytree-checkbox:hover { + background-position: -80px -48px; +} +.fancytree-radio .fancytree-selected span.fancytree-checkbox { + background-position: -32px -48px; +} +.fancytree-radio .fancytree-selected span.fancytree-checkbox:hover { + background-position: -48px -48px; +} +.fancytree-radio .fancytree-unselectable span.fancytree-checkbox, +.fancytree-radio .fancytree-unselectable span.fancytree-checkbox:hover { + background-position: 0px -48px; +} +/*------------------------------------------------------------------------------ + * Node type icon + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-ico- + * 1st character: 'e': expanded, 'c': collapsed + * 2nd character (optional): 'f': folder + *----------------------------------------------------------------------------*/ +span.fancytree-icon { + margin-left: 3px; + background-position: 0px 0px; +} +/* Documents */ +.fancytree-ico-c span.fancytree-icon:hover { + background-position: -16px 0px; +} +.fancytree-has-children.fancytree-ico-c span.fancytree-icon { + background-position: -32px 0px; +} +.fancytree-has-children.fancytree-ico-c span.fancytree-icon:hover { + background-position: -48px 0px; +} +.fancytree-ico-e span.fancytree-icon { + background-position: -64px 0px; +} +.fancytree-ico-e span.fancytree-icon:hover { + background-position: -80px 0px; +} +/* Folders */ +.fancytree-ico-cf span.fancytree-icon { + background-position: 0px -16px; +} +.fancytree-ico-cf span.fancytree-icon:hover { + background-position: -16px -16px; +} +.fancytree-has-children.fancytree-ico-cf span.fancytree-icon { + background-position: -32px -16px; +} +.fancytree-has-children.fancytree-ico-cf span.fancytree-icon:hover { + background-position: -48px -16px; +} +.fancytree-ico-ef span.fancytree-icon { + background-position: -64px -16px; +} +.fancytree-ico-ef span.fancytree-icon:hover { + background-position: -80px -16px; +} +.fancytree-loading span.fancytree-expander, +.fancytree-loading span.fancytree-expander:hover, +.fancytree-statusnode-wait span.fancytree-icon, +.fancytree-statusnode-wait span.fancytree-icon:hover { + background-image: url('data:image/gif;base64,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'); + background-position: 0px 0px; +} +/* Status node icons */ +.fancytree-statusnode-error span.fancytree-icon, +.fancytree-statusnode-error span.fancytree-icon:hover { + background-position: 0px -112px; +} +/*------------------------------------------------------------------------------ + * Node titles and highlighting + *----------------------------------------------------------------------------*/ +span.fancytree-node { + /* See #117 */ + display: inherit; + width: 100%; + margin-top: 1px; + min-height: 16px; +} +span.fancytree-title { + color: #000000; + cursor: pointer; + display: inline-block; + vertical-align: top; + min-height: 16px; + padding: 0 3px 0 3px; + margin: 0px 0 0 3px; + border: 1px solid transparent; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + -ms-border-radius: 0px; + -o-border-radius: 0px; + border-radius: 0px; +} +span.fancytree-node.fancytree-error span.fancytree-title { + color: #ff0000; +} +/*------------------------------------------------------------------------------ + * Drag'n'drop support + *----------------------------------------------------------------------------*/ +div.fancytree-drag-helper span.fancytree-childcounter, +div.fancytree-drag-helper span.fancytree-dnd-modifier { + display: inline-block; + color: #fff; + background: #337ab7; + border: 1px solid gray; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +div.fancytree-drag-helper span.fancytree-childcounter { + position: absolute; + top: -6px; + right: -6px; +} +div.fancytree-drag-helper span.fancytree-dnd-modifier { + background: #5cb85c; + border: none; + font-weight: bolder; +} +div.fancytree-drag-helper.fancytree-drop-accept span.fancytree-drag-helper-img { + background-position: -32px -112px; +} +div.fancytree-drag-helper.fancytree-drop-reject span.fancytree-drag-helper-img { + background-position: -16px -112px; +} +/*** Drop marker icon *********************************************************/ +#fancytree-drop-marker { + width: 32px; + position: absolute; + background-position: 0px -128px; + margin: 0; +} +#fancytree-drop-marker.fancytree-drop-after, +#fancytree-drop-marker.fancytree-drop-before { + width: 64px; + background-position: 0px -144px; +} +#fancytree-drop-marker.fancytree-drop-copy { + background-position: -64px -128px; +} +#fancytree-drop-marker.fancytree-drop-move { + background-position: -32px -128px; +} +/*** Source node while dragging ***********************************************/ +span.fancytree-drag-source.fancytree-drag-remove { + opacity: 0.15; +} +/*** Target node while dragging cursor is over it *****************************/ +/*------------------------------------------------------------------------------ + * 'table' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-table { + border-collapse: collapse; +} +table.fancytree-ext-table span.fancytree-node { + display: inline-block; +} +/*------------------------------------------------------------------------------ + * 'columnview' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-columnview tbody tr td { + position: relative; + border: 1px solid gray; + vertical-align: top; + overflow: auto; +} +table.fancytree-ext-columnview tbody tr td > ul { + padding: 0; +} +table.fancytree-ext-columnview tbody tr td > ul li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0px 0px; + background-repeat: repeat-y; + background-image: none; + /* no v-lines */ + margin: 0; +} +table.fancytree-ext-columnview span.fancytree-node { + position: relative; + /* allow positioning of embedded spans */ + display: inline-block; +} +table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded { + background-color: #CBE8F6; +} +table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right { + position: absolute; + right: 3px; + background-position: 0px -80px; +} +table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right:hover { + background-position: -16px -80px; +} +/*------------------------------------------------------------------------------ + * 'filter' extension + *----------------------------------------------------------------------------*/ +.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title { + color: #c0c0c0; + font-weight: lighter; +} +.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: bold; +} +.fancytree-ext-filter-hide tr.fancytree-hide, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide { + display: none; +} +.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title { + color: #c0c0c0; + font-weight: lighter; +} +.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-childcounter span.fancytree-icon, +.fancytree-ext-filter span.fancytree-icon { + position: relative; +} +.fancytree-ext-childcounter span.fancytree-childcounter, +.fancytree-ext-filter span.fancytree-childcounter { + color: #fff; + background: #777; + border: 1px solid gray; + position: absolute; + top: -6px; + right: -6px; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +/*------------------------------------------------------------------------------ + * 'wide' extension + *----------------------------------------------------------------------------*/ +ul.fancytree-ext-wide { + position: relative; + min-width: 100%; + z-index: 2; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +ul.fancytree-ext-wide span.fancytree-node > span { + position: relative; + z-index: 2; +} +ul.fancytree-ext-wide span.fancytree-node span.fancytree-title { + position: absolute; + z-index: 1; + left: 0px; + width: 100%; + margin-left: 0; + margin-right: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +/******************************************************************************* + * Styles specific to this skin. + * + * This section is automatically generated from the `ui-fancytree.less` template. + ******************************************************************************/ +/******************************************************************************* + * Node titles + */ +.fancytree-plain span.fancytree-node { + border: 1px solid transparent; +} +.fancytree-plain span.fancytree-node:hover { + background-color: #E5F3FB; + border-color: #70C0E7; +} +.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-focused { + border-color: #3399FF; +} +.fancytree-plain span.fancytree-node.fancytree-active, +.fancytree-plain span.fancytree-node.fancytree-selected { + background-color: #F7F7F7; + border-color: #DEDEDE; +} +.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-active, +.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-selected, +.fancytree-plain span.fancytree-node.fancytree-active:hover, +.fancytree-plain span.fancytree-node.fancytree-selected:hover { + background-color: #CBE8F6; + border-color: #26A0DA; +} +.fancytree-plain .fancytree-node.fancytree-selected { + font-style: italic; +} +/******************************************************************************* + * 'table' extension + */ +table.fancytree-ext-table tbody tr td { + border: 1px solid #EDEDED; +} +table.fancytree-ext-table tbody span.fancytree-node, +table.fancytree-ext-table tbody span.fancytree-node:hover { + border: none; + background: none; +} +table.fancytree-ext-table tbody tr:hover { + background-color: #E5F3FB; + outline: 1px solid #70C0E7; +} +table.fancytree-ext-table tbody tr.fancytree-focused span.fancytree-title { + outline: 1px dotted black; +} +table.fancytree-ext-table tbody tr.fancytree-active:hover, +table.fancytree-ext-table tbody tr.fancytree-selected:hover { + background-color: #CBE8F6; + outline: 1px solid #26A0DA; +} +table.fancytree-ext-table tbody tr.fancytree-active { + background-color: #F7F7F7; + outline: 1px solid #DEDEDE; +} +table.fancytree-ext-table tbody tr.fancytree-selected { + background-color: #F7F7F7; +} +table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-active { + background-color: #CBE8F6; + outline: 1px solid #26A0DA; +} +table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-selected { + background-color: #CBE8F6; +} diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-n/ui.fancytree.less b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-n/ui.fancytree.less new file mode 100644 index 00000000000..a016c788d90 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-n/ui.fancytree.less @@ -0,0 +1,143 @@ +/*! + * Fancytree "win8" skin (highlighting the node span instead of title-only). + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ + +// Import common styles +@import "../skin-common.less"; + + +/******************************************************************************* + * Styles specific to this skin. + * + * This section is automatically generated from the `ui-fancytree.less` template. + ******************************************************************************/ + +// Borders have NO radius and NO gradients are used! + +// both: +// unselected background: white +// hover bar (unselected, inactive): #E5F3FB (border: #70C0E7) 'very light blue' +// active node: #CBE8F6 (border: #26A0DA) 'light blue' +// active node with hover: wie active node + +// Tree view: +// active node, tree inactive: #F7F7F7 (border: #DEDEDE) 'light gray, selected, but tree not active' + +// List view: +// selected bar: --> active bar +// focus bar: transparent(white) + border 1px solid #3399FF () + +// table left/right border: #EDEDED 'light gray' + +// Override the variable after the import. +// NOTE: Variables are always resolved as the last definition, even if it is +// after where it is used. +@fancy-use-sprites: true; // false: suppress all background images (i.e. icons) +// Set to `true` to inline icon sprite into CSS: +// @fancy-inline-sprites: true; +@fancy-hide-connectors: true; +@fancy-icon-width: 16px; +@fancy-icon-height: 16px; +@fancy-line-height: 16px; +@fancy-icon-spacing: 3px; + +// Use 'data-uri(...)' to embed the image into CSS instead of linking to 'loading.gif': +@fancy-loading-url: data-uri("@{fancy-image-dir}/loading.gif"); +// Set to `true` to use `data-uri(...)` which will embed icons.gif into CSS +// instead of linking to that file: +// @fancy-inline-sprites: true; + + +/******************************************************************************* + * Node titles + */ +.fancytree-plain { + span.fancytree-node { + border: @fancy-node-border-width solid transparent; // avoid jumping, when a border is added on hover + } + span.fancytree-node:hover { + background-color: #E5F3FB; + border-color: #70C0E7; + } + &.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-focused { + border-color: #3399FF; + // outline: 1px solid #3399FF; + } + span.fancytree-node.fancytree-active, + span.fancytree-node.fancytree-selected { // active/selcted nodes inside inactive tree + background-color: #F7F7F7; + border-color: #DEDEDE; + } + &.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-active, + &.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-selected, + span.fancytree-node.fancytree-active:hover, + span.fancytree-node.fancytree-selected:hover { + background-color: #CBE8F6; + border-color: #26A0DA; + } + .fancytree-node.fancytree-selected { + font-style: italic; + } +} + +/******************************************************************************* + * 'table' extension + */ +table.fancytree-ext-table tbody { + tr td { + border: 1px solid #EDEDED; + } + span.fancytree-node, + span.fancytree-node:hover { // undo standard tree css + border: none; + background: none; + } + // Title get's a white background, when hovered. Undo standard node formatting + // span.fancytree-title:hover { + // border: none; //1px solid transparent; + // background: inherit; + // background: transparent; + // background: none; + // filter: none; + // } + tr:hover { + background-color: #E5F3FB; + outline: 1px solid #70C0E7; + } + // tr:hover td { + // outline: 1px solid #D8F0FA; + // } + // tr.fancytree-focused { + // border-color: #3399FF; + // outline: 1px dotted black; + // } + tr.fancytree-focused span.fancytree-title { + outline: 1px dotted black; + } + + tr.fancytree-active:hover, + tr.fancytree-selected:hover { + background-color: #CBE8F6; + outline: 1px solid #26A0DA; + } + tr.fancytree-active { // dimmed, if inside inactive tree + background-color: #F7F7F7; + outline: 1px solid #DEDEDE; + } + tr.fancytree-selected { // dimmed, if inside inactive tree + background-color: #F7F7F7; + } +} + +table.fancytree-ext-table.fancytree-treefocus tbody { + tr.fancytree-active { + background-color: #CBE8F6; + outline: 1px solid #26A0DA; + } + tr.fancytree-selected { + background-color: #CBE8F6; + } +} diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-n/ui.fancytree.min.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-n/ui.fancytree.min.css new file mode 100644 index 00000000000..7b0dffc67e9 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-n/ui.fancytree.min.css @@ -0,0 +1,6 @@ +/*! + * Fancytree "win8" skin (highlighting the node span instead of title-only). + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */.ui-helper-hidden{display:none}ul.fancytree-container{font-family:tahoma,arial,helvetica;font-size:10pt;white-space:nowrap;padding:3px;margin:0;background-color:#fff;border:1px dotted gray;overflow:auto;min-height:0;position:relative}ul.fancytree-container ul{padding:0 0 0 16px;margin:0}ul.fancytree-container li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0}ul.fancytree-container li.fancytree-lastsib,ul.fancytree-no-connector>li{background-image:none}.ui-fancytree-disabled ul.fancytree-container{opacity:.5;background-color:silver}#fancytree-drop-marker,span.fancytree-checkbox,span.fancytree-drag-helper-img,span.fancytree-empty,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio,span.fancytree-vline{width:16px;height:16px;display:inline-block;vertical-align:top;background-repeat:no-repeat;background-image:url(icons.gif);background-position:0 0}span.fancytree-checkbox,span.fancytree-custom-icon,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio{margin-top:0}span.fancytree-custom-icon{display:inline-block;margin-left:3px}img.fancytree-icon{width:16px;height:16px;margin-left:3px;margin-top:0;vertical-align:top;border-style:none}span.fancytree-expander{cursor:pointer}.fancytree-exp-n span.fancytree-expander,.fancytree-exp-nl span.fancytree-expander{background-image:none;cursor:default}.fancytree-exp-n span.fancytree-expander,.fancytree-exp-n span.fancytree-expander:hover{background-position:0 -64px}.fancytree-exp-nl span.fancytree-expander,.fancytree-exp-nl span.fancytree-expander:hover{background-position:-16px -64px}.fancytree-exp-c span.fancytree-expander{background-position:0 -80px}.fancytree-exp-c span.fancytree-expander:hover{background-position:-16px -80px}.fancytree-exp-cl span.fancytree-expander{background-position:0 -96px}.fancytree-exp-cl span.fancytree-expander:hover{background-position:-16px -96px}.fancytree-exp-cd span.fancytree-expander{background-position:-64px -80px}.fancytree-exp-cd span.fancytree-expander:hover{background-position:-80px -80px}.fancytree-exp-cdl span.fancytree-expander{background-position:-64px -96px}.fancytree-exp-cdl span.fancytree-expander:hover{background-position:-80px -96px}.fancytree-exp-e span.fancytree-expander,.fancytree-exp-ed span.fancytree-expander{background-position:-32px -80px}.fancytree-exp-e span.fancytree-expander:hover,.fancytree-exp-ed span.fancytree-expander:hover{background-position:-48px -80px}.fancytree-exp-edl span.fancytree-expander,.fancytree-exp-el span.fancytree-expander{background-position:-32px -96px}.fancytree-exp-edl span.fancytree-expander:hover,.fancytree-exp-el span.fancytree-expander:hover{background-position:-48px -96px}span.fancytree-checkbox{margin-left:3px;background-position:0 -32px}span.fancytree-checkbox:hover{background-position:-16px -32px}.fancytree-partsel span.fancytree-checkbox{background-position:-64px -32px}.fancytree-partsel span.fancytree-checkbox:hover{background-position:-80px -32px}.fancytree-selected span.fancytree-checkbox{background-position:-32px -32px}.fancytree-selected span.fancytree-checkbox:hover{background-position:-48px -32px}.fancytree-unselectable span.fancytree-checkbox{opacity:.4;filter:alpha(opacity=40)}.fancytree-unselectable span.fancytree-checkbox:hover{background-position:0 -32px}.fancytree-unselectable.fancytree-partsel span.fancytree-checkbox:hover{background-position:-64px -32px}.fancytree-unselectable.fancytree-selected span.fancytree-checkbox:hover{background-position:-32px -32px}.fancytree-radio span.fancytree-checkbox{background-position:0 -48px}.fancytree-radio span.fancytree-checkbox:hover{background-position:-16px -48px}.fancytree-radio .fancytree-partsel span.fancytree-checkbox{background-position:-64px -48px}.fancytree-radio .fancytree-partsel span.fancytree-checkbox:hover{background-position:-80px -48px}.fancytree-radio .fancytree-selected span.fancytree-checkbox{background-position:-32px -48px}.fancytree-radio .fancytree-selected span.fancytree-checkbox:hover{background-position:-48px -48px}.fancytree-radio .fancytree-unselectable span.fancytree-checkbox,.fancytree-radio .fancytree-unselectable span.fancytree-checkbox:hover{background-position:0 -48px}span.fancytree-icon{margin-left:3px;background-position:0 0}.fancytree-ico-c span.fancytree-icon:hover{background-position:-16px 0}.fancytree-has-children.fancytree-ico-c span.fancytree-icon{background-position:-32px 0}.fancytree-has-children.fancytree-ico-c span.fancytree-icon:hover{background-position:-48px 0}.fancytree-ico-e span.fancytree-icon{background-position:-64px 0}.fancytree-ico-e span.fancytree-icon:hover{background-position:-80px 0}.fancytree-ico-cf span.fancytree-icon{background-position:0 -16px}.fancytree-ico-cf span.fancytree-icon:hover{background-position:-16px -16px}.fancytree-has-children.fancytree-ico-cf span.fancytree-icon{background-position:-32px -16px}.fancytree-has-children.fancytree-ico-cf span.fancytree-icon:hover{background-position:-48px -16px}.fancytree-ico-ef span.fancytree-icon{background-position:-64px -16px}.fancytree-ico-ef span.fancytree-icon:hover{background-position:-80px -16px}.fancytree-loading span.fancytree-expander,.fancytree-loading span.fancytree-expander:hover,.fancytree-statusnode-wait span.fancytree-icon,.fancytree-statusnode-wait span.fancytree-icon:hover{background-image:url(data:image/gif;base64,R0lGODlhEAAQAPcAAEai/0+m/1is/12u/2Oy/2u1/3C3/3G4/3W6/3q8/3+//4HA/4XC/4nE/4/H/5LI/5XK/5vN/57O/6DP/6HQ/6TS/6/X/7DX/7HY/7bb/7rd/7ze/8Hg/8fj/8rl/83m/9Dn/9Lp/9bq/9jr/9rt/9/v/+Dv/+Hw/+Xy/+v1/+32//D3//L5//f7//j7//v9/0qk/06m/1Ko/1er/2Cw/2m0/2y2/3u9/32+/4jD/5bK/5jL/5/P/6HP/6PS/6fS/6nU/67X/7Ta/7nc/7zd/8Ph/8bj/8jk/8vl/9Pp/9fr/9rs/9zu/+j0/+72//T6/0ij/1Op/1uu/1yu/2Wy/2q0/2+3/3C4/3m8/3y9/4PB/4vE/4/G/6XS/6jU/67W/7HZ/7Xa/7vd/73e/8Lh/8nk/87m/9Hn/9Ho/9vt/97u/+Lx/+bz/+n0//H4//X6/1Gn/1Go/2Gx/36+/5PJ/5TJ/5nL/57P/7PZ/7TZ/8Xi/9Tq/9zt/+by/+r0/+73//P5//n8/0uk/1Wq/3K4/3e7/4bC/4vF/47G/5fK/77f/9Do/9ns/+Tx/+/3//L4//b6//r9/2Wx/2q1/4bD/6DQ/6fT/9Tp/+Lw/+jz//D4//j8/1qt/2mz/5rM/6bS/8Lg/8jj/97v/+r1/1Cn/1ar/2Cv/3O5/3++/53O/8Th/9Lo/9Xq/+z2/2Kw/2Sx/8Ti/4rF/7DY/1+v/4TB/7fb/+Ty/1+u/2Ox/4zG/6vU/7/f//r8/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/i1NYWRlIGJ5IEtyYXNpbWlyYSBOZWpjaGV2YSAod3d3LmxvYWRpbmZvLm5ldCkAIfkEAQoAMAAsAAAAABAAEAAABptAmFCI6mAsnNNwCUthGomDoYCQoJinyELRgDwUhAFCNFRJGg8P6/VSaQyCgxK2cURMTJioEIA0Jw8geUIZAQMkIhEVLIMwKgMAFx4SGS+NLwwCFR8UGo1CKSgsJBUYLZ9sMCsZF3iDLy2nMCEXGyp5bSqyLBwaHSguQi8sKigqlkIqHb4hJc4lJsdMLSQeHyEhIyXSgy2hxsFLQQAh+QQBCgAAACwAAAAAEAAQAAAHp4AAgoIoH0NCSCiDiwBORDo5Czg3C0BNjCg/Dw46PjwOBwcLS4MrQTs9ICwvL05FODU4igBGPECzi0s4NDyNQT5KjINDAzZMTEBCLMKCTQczQ0lBRcyDODI8SojVAC84MTxMQkVP1SgDMEJPRkS4jB8xM6RKRR/Lwi9HQYJPIB9KTV4MeuHiicBSSkAoYYKiiRMnKw4ucnFiyRKGKJyUq/aChUaDjAIBACH5BAEKAAAALAAAAAAQABAAAAeogACCgm1KZGRmbYOLAG5GXjoPXFsPYIqLbWE7XV1fXjtaWQ9qg25iXmBKby8AKmVcWFyXaBdil4tqWldejWNhpIyCZFZZa2tjZG/BgipYVWRpY2bLg1s0XWpGaNQAL1pTXW1maMrLbVZSYm9oZyrUYVFUpGxoaeWLZzQBOoJvamkm3OCSAsWKiUH+1rBp48bFCxVWaGxb9LBNGxVvVqUBFuzFizculgUCACH5BAEKAAEALAAAAAAQABAAAAi4AAMIFPiHxJEjJPwMXBgAEIg8XijcsUNhzB+GfzjkwYNnSB4KdRzcWTPwzZEhY/i8EfgmhJ0GdhQGIDFGz0WGJuoswBPgzQc9fRgOPDKnQR8/H0K4EErQQQKgIPgwFRioTgE8ffZInRqIztWCfAJN/TOnAAcXJvgAmjpEDgKSf9b4Ectwz5UBd6j68fNnaYBAfvIUEIAgKNU/gN4E+sNgAJw4BvYIfeMiUB8BAAbUMTz1TYU8YRcGBAAh+QQBCgAAACwAAAAAEAAQAAAItAABCBT4qJGIRY0cDVwIAJIIMnnyWABiwYjChY8WGVFExgjELjwsNBroQgSSD40gCXQIJFGXi41AiHjEEECjLg8UNWS06GLND4gSNXrEqESkmgQTGfrgqMRIpAAidVkwpKDPmpF44MgDqVGTo0gdHbqBJJIjR2BrkiG0YCSkRyprMsJBCMhASJEioczbZEihGoaeCtQrgwYOujRoLGBU08IgQYJkzKjBQ/DCSIzy8OgypATDgAAh+QQBCgAAACwAAAAAEAAQAAAIswABCBQIKRMfPmw0DVwIYBObEEiKjBEzJoTChZD4XArB0UyRMBfGtBm4CdOSJW02EeQjxkuYi38wYYLEEEAmDJWMNGyTsKbAS5Us/YHU5o9PgZos7QixSdPFo18eFNkESeXRTV+4FGlo1aemHVvM7ORzFMmCByOXHJgSoiafLTgwCOQjCYqkMCk3/SlCCQvagSEmBRh0gBLcAwe4kF2IaYekKVNoTMLiZWTNTSwtWRqDiWFAACH5BAEKAAIALAAAAAAQABAAAAi5AAUIFOhCBRs2o94MXCjghQpRI/YkQYJkj8KFL0atEcVRVJIOY0KtWKhi1Cg3LwS+YdNhCCg3Kt2oSMlQxZg8IGLSZChA1IU8Khru5PkmjxdRbtgE5TlwCAUknzgxGIoxDw8kQgAMGMVUgJtPnvaQGBAgT1cQDyhwhRCnUxKeazw5GCNwTQFOBsbMfLECyYMGPJYK2INgAAEFDyA0ULDA0xqGbHggKFDgQIIGF7jyfLGmw4ULHdgwDAgAIfkEAQoAAAAsAAAAABAAEAAACLcAAQgcqElTK00uBioUuKlVEzYnlixhk3BhC4MO2SxhtIrVCoWbNrnYNLAhKzMgWggMgqTiwhVIiiwBsKQUKTMLB7IhoqpVHhimmuQU2KJInhOpYtxwmdNMHlapZKAiORRAkSCshpQ61arqijxAJNoYMKTqEh95uvagUWjmQjZAUqkSyAZVDVRFWoXUBKLHjiAfBS5hcOqUg1Q+djh44IPNwiZAFtxAtSCHDiJdh55AkmeIGaEKAwIAIfkEAQoAAAAsAAAAABAAEAAACLcAAQgcGMgFJEiBBioEUEIJAINuRo36k1AhGldXVhSMyAaTCUgDMVWBMiWNQjeY0pRwIVBHAFdoFgKAxOgMG4avooSRKfCPmTOQNEi5MornwzNIRnWZQqkiTyVFSnRxtYWlUTMa0hSpkuWPUUgcNGDClMVKEaMmwohxA6CLFUolZI7ScCEmgFFcsnBB4nVmCTBeNLAVWCKvlh1dvnjRUSlMUYWjwDzYwuWBji6wBss1U6QImscDAwIAIfkEAQoAAQAsAAAAABAAEAAACLMAAwgUyEfWJxYDEw5sBGEAAAGNXkCCpDAAKwNw4AxgoEIii44LCwnolMfPC4EvVPgxKfDOgCusKr7ws0ZFABOF5IipKJAFHz4vOBSYY5NnAD4jVMgqAOGkUT5J/CxtajRAmiRr9CSIVbQiJFZI/DRyMAeJ0awfKMqaQ2dNRRV6xqQR6MdOLDusEAaAtGbMGCR6A6y54wDCpzxiZCnm0FWgijF3INyhcDhJYIV+wH5I0zhAQAAh+QQBCgAAACwAAAAAEAAQAAAItAABCBRYYkiqVLUYuRjIkE2qGjNkxBA0IwhDgYwU0JhVg1YCGjLMLBzYxFCNBEM0uXDBxkyLlQOBEFLA6CKAlZpaAGBjiBAZmwP//HFhJMGhP0AF/mHjopaCVCOBsmGjqZahLlFtsinxx4yhHZqSurDFaGkiREmS/rnESOeQB6nY2NR0CYRcAH+67AByaWSLlkj6DmQTJFWXWmSMkCFCBkRYhn+MBAESpBbitmpLJLlU4vHAgAAh+QQBCgAAACwAAAAAEAAQAAAIvQABCBS4ZpclS0PWDFwIoI0uHFVu3ZIiiY7ChWpyHTiAowGDK4MCVEEzsA0dLAw4OOHFq00YXFBwqREIBkeumQzN3DqQBkCmOgvKMByYpg0vAGZy7XAydCCvFgA45NLVdGCLFrw40PlytCoLJy0u7bAEtSkvJ21aOLF055JXNkYBwKoEJtPQFmvWMAWwIoyuIWrKunCSJo2Jrg2HXAjDwcwlNCDQpCk7kAWIXUN2wTKDZo2Lqk7YpFGTibLAgAA7);background-position:0 0}.fancytree-statusnode-error span.fancytree-icon,.fancytree-statusnode-error span.fancytree-icon:hover{background-position:0 -112px}span.fancytree-node{display:inherit;width:100%;margin-top:1px;min-height:16px}span.fancytree-title{color:#000;cursor:pointer;display:inline-block;vertical-align:top;min-height:16px;padding:0 3px;margin:0 0 0 3px;border:1px solid transparent;-webkit-border-radius:0;-moz-border-radius:0;-ms-border-radius:0;-o-border-radius:0;border-radius:0}span.fancytree-node.fancytree-error span.fancytree-title{color:red}div.fancytree-drag-helper span.fancytree-childcounter,div.fancytree-drag-helper span.fancytree-dnd-modifier{display:inline-block;color:#fff;background:#337ab7;border:1px solid gray;min-width:10px;height:10px;line-height:1;vertical-align:baseline;border-radius:10px;padding:2px;text-align:center;font-size:9px}div.fancytree-drag-helper span.fancytree-childcounter{position:absolute;top:-6px;right:-6px}div.fancytree-drag-helper span.fancytree-dnd-modifier{background:#5cb85c;border:0;font-weight:bolder}div.fancytree-drag-helper.fancytree-drop-accept span.fancytree-drag-helper-img{background-position:-32px -112px}div.fancytree-drag-helper.fancytree-drop-reject span.fancytree-drag-helper-img{background-position:-16px -112px}#fancytree-drop-marker{width:32px;position:absolute;background-position:0 -128px;margin:0}#fancytree-drop-marker.fancytree-drop-after,#fancytree-drop-marker.fancytree-drop-before{width:64px;background-position:0 -144px}#fancytree-drop-marker.fancytree-drop-copy{background-position:-64px -128px}#fancytree-drop-marker.fancytree-drop-move{background-position:-32px -128px}span.fancytree-drag-source.fancytree-drag-remove{opacity:.15}table.fancytree-ext-table{border-collapse:collapse}table.fancytree-ext-table span.fancytree-node{display:inline-block}table.fancytree-ext-columnview tbody tr td{position:relative;border:1px solid gray;vertical-align:top;overflow:auto}table.fancytree-ext-columnview tbody tr td>ul{padding:0}table.fancytree-ext-columnview tbody tr td>ul li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0}table.fancytree-ext-columnview span.fancytree-node{position:relative;display:inline-block}table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded{background-color:#CBE8F6}table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right{position:absolute;right:3px;background-position:0 -80px}table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right:hover{background-position:-16px -80px}.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title{color:silver;font-weight:lighter}.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title,.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title{color:#000;font-weight:400}.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title,.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title{color:#000;font-weight:700}.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide,.fancytree-ext-filter-hide tr.fancytree-hide{display:none}.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title,.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title{color:silver;font-weight:lighter}.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title,.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title{color:#000;font-weight:400}.fancytree-ext-childcounter span.fancytree-icon,.fancytree-ext-filter span.fancytree-icon{position:relative}.fancytree-ext-childcounter span.fancytree-childcounter,.fancytree-ext-filter span.fancytree-childcounter{color:#fff;background:#777;border:1px solid gray;position:absolute;top:-6px;right:-6px;min-width:10px;height:10px;line-height:1;vertical-align:baseline;border-radius:10px;padding:2px;text-align:center;font-size:9px}ul.fancytree-ext-wide{position:relative;min-width:100%;z-index:2;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}ul.fancytree-ext-wide span.fancytree-node>span{position:relative;z-index:2}ul.fancytree-ext-wide span.fancytree-node span.fancytree-title{position:absolute;z-index:1;left:0;width:100%;margin-left:0;margin-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.fancytree-plain span.fancytree-node{border:1px solid transparent}.fancytree-plain span.fancytree-node:hover{background-color:#E5F3FB;border-color:#70C0E7}.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-focused{border-color:#39F}.fancytree-plain span.fancytree-node.fancytree-active,.fancytree-plain span.fancytree-node.fancytree-selected{background-color:#F7F7F7;border-color:#DEDEDE}.fancytree-plain span.fancytree-node.fancytree-active:hover,.fancytree-plain span.fancytree-node.fancytree-selected:hover,.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-active,.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-node.fancytree-selected{background-color:#CBE8F6;border-color:#26A0DA}.fancytree-plain .fancytree-node.fancytree-selected{font-style:italic}table.fancytree-ext-table tbody tr td{border:1px solid #EDEDED}table.fancytree-ext-table tbody span.fancytree-node,table.fancytree-ext-table tbody span.fancytree-node:hover{border:0;background:0 0}table.fancytree-ext-table tbody tr:hover{background-color:#E5F3FB;outline:1px solid #70C0E7}table.fancytree-ext-table tbody tr.fancytree-focused span.fancytree-title{outline:1px dotted #000}table.fancytree-ext-table tbody tr.fancytree-active:hover,table.fancytree-ext-table tbody tr.fancytree-selected:hover{background-color:#CBE8F6;outline:1px solid #26A0DA}table.fancytree-ext-table tbody tr.fancytree-active{background-color:#F7F7F7;outline:1px solid #DEDEDE}table.fancytree-ext-table tbody tr.fancytree-selected{background-color:#F7F7F7}table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-active{background-color:#CBE8F6;outline:1px solid #26A0DA}table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-selected{background-color:#CBE8F6} \ No newline at end of file diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-xxl/icons.gif b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-xxl/icons.gif new file mode 100644 index 0000000000000000000000000000000000000000..4dd72bbe0b93c71eceeb75abe2763bebcd2c64d1 GIT binary patch literal 20860 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℞7R= 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 literal 0 HcmV?d00001 diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-xxl/loading.gif b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-xxl/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..8031e4407ac35ba3f2e75668042a2a6a2069a70f GIT binary patch literal 6243 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 literal 0 HcmV?d00001 diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-xxl/ui.fancytree.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-xxl/ui.fancytree.css new file mode 100644 index 00000000000..6b999dd7781 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-xxl/ui.fancytree.css @@ -0,0 +1,583 @@ +/*! + * Fancytree "Win8" 32x32 skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ +/******************************************************************************* + * Common Styles for Fancytree Skins. + * + * This section is automatically generated from the `skin-common.less` template. + ******************************************************************************/ +/*------------------------------------------------------------------------------ + * Helpers + *----------------------------------------------------------------------------*/ +.ui-helper-hidden { + display: none; +} +/*------------------------------------------------------------------------------ + * Container and UL / LI + *----------------------------------------------------------------------------*/ +ul.fancytree-container { + font-family: tahoma, arial, helvetica; + font-size: 10pt; + white-space: nowrap; + padding: 3px; + margin: 0; + background-color: white; + border: 1px dotted gray; + overflow: auto; + min-height: 0%; + position: relative; +} +ul.fancytree-container ul { + padding: 0 0 0 32px; + margin: 0; +} +ul.fancytree-container li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0px 0px; + background-repeat: repeat-y; + background-image: none; + margin: 0; +} +ul.fancytree-container li.fancytree-lastsib { + background-image: none; +} +ul.fancytree-no-connector > li { + background-image: none; +} +.ui-fancytree-disabled ul.fancytree-container { + opacity: 0.5; + background-color: silver; +} +/*------------------------------------------------------------------------------ + * Common icon definitions + *----------------------------------------------------------------------------*/ +span.fancytree-empty, +span.fancytree-vline, +span.fancytree-expander, +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-radio, +span.fancytree-drag-helper-img, +#fancytree-drop-marker { + width: 32px; + height: 32px; + display: inline-block; + vertical-align: top; + background-repeat: no-repeat; + background-position: left; + background-image: url("icons.gif"); + background-position: 0px 0px; +} +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-expander, +span.fancytree-radio, +span.fancytree-custom-icon { + margin-top: 0px; +} +/* Used by iconclass option and iconClass callback: */ +span.fancytree-custom-icon { + display: inline-block; + margin-left: 6px; +} +/* Used by 'icon' node option: */ +img.fancytree-icon { + width: 32px; + height: 32px; + margin-left: 6px; + margin-top: 0px; + vertical-align: top; + border-style: none; +} +/*------------------------------------------------------------------------------ + * Expander icon + * + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-exp- + * 1st character: 'e': expanded, 'c': collapsed, 'n': no children + * 2nd character (optional): 'd': lazy (Delayed) + * 3rd character (optional): 'l': Last sibling + *----------------------------------------------------------------------------*/ +span.fancytree-expander { + cursor: pointer; +} +.fancytree-exp-n span.fancytree-expander, +.fancytree-exp-nl span.fancytree-expander { + background-image: none; + cursor: default; +} +.fancytree-exp-n span.fancytree-expander, +.fancytree-exp-n span.fancytree-expander:hover { + background-position: 0px -128px; +} +.fancytree-exp-nl span.fancytree-expander, +.fancytree-exp-nl span.fancytree-expander:hover { + background-position: -32px -128px; +} +.fancytree-exp-c span.fancytree-expander { + background-position: 0px -160px; +} +.fancytree-exp-c span.fancytree-expander:hover { + background-position: -32px -160px; +} +.fancytree-exp-cl span.fancytree-expander { + background-position: 0px -192px; +} +.fancytree-exp-cl span.fancytree-expander:hover { + background-position: -32px -192px; +} +.fancytree-exp-cd span.fancytree-expander { + background-position: -128px -160px; +} +.fancytree-exp-cd span.fancytree-expander:hover { + background-position: -160px -160px; +} +.fancytree-exp-cdl span.fancytree-expander { + background-position: -128px -192px; +} +.fancytree-exp-cdl span.fancytree-expander:hover { + background-position: -160px -192px; +} +.fancytree-exp-e span.fancytree-expander, +.fancytree-exp-ed span.fancytree-expander { + background-position: -64px -160px; +} +.fancytree-exp-e span.fancytree-expander:hover, +.fancytree-exp-ed span.fancytree-expander:hover { + background-position: -96px -160px; +} +.fancytree-exp-el span.fancytree-expander, +.fancytree-exp-edl span.fancytree-expander { + background-position: -64px -192px; +} +.fancytree-exp-el span.fancytree-expander:hover, +.fancytree-exp-edl span.fancytree-expander:hover { + background-position: -96px -192px; +} +/*------------------------------------------------------------------------------ + * Checkbox icon + *----------------------------------------------------------------------------*/ +span.fancytree-checkbox { + margin-left: 6px; + background-position: 0px -64px; +} +span.fancytree-checkbox:hover { + background-position: -32px -64px; +} +.fancytree-partsel span.fancytree-checkbox { + background-position: -128px -64px; +} +.fancytree-partsel span.fancytree-checkbox:hover { + background-position: -160px -64px; +} +.fancytree-selected span.fancytree-checkbox { + background-position: -64px -64px; +} +.fancytree-selected span.fancytree-checkbox:hover { + background-position: -96px -64px; +} +.fancytree-unselectable span.fancytree-checkbox { + opacity: 0.4; + filter: alpha(opacity=40); +} +.fancytree-unselectable span.fancytree-checkbox:hover { + background-position: 0px -64px; +} +.fancytree-unselectable.fancytree-partsel span.fancytree-checkbox:hover { + background-position: -128px -64px; +} +.fancytree-unselectable.fancytree-selected span.fancytree-checkbox:hover { + background-position: -64px -64px; +} +/*------------------------------------------------------------------------------ + * Radiobutton icon + * This is a customization, that may be activated by overriding the 'checkbox' + * class name as 'fancytree-radio' in the tree options. + *----------------------------------------------------------------------------*/ +.fancytree-radio span.fancytree-checkbox { + background-position: 0px -96px; +} +.fancytree-radio span.fancytree-checkbox:hover { + background-position: -32px -96px; +} +.fancytree-radio .fancytree-partsel span.fancytree-checkbox { + background-position: -128px -96px; +} +.fancytree-radio .fancytree-partsel span.fancytree-checkbox:hover { + background-position: -160px -96px; +} +.fancytree-radio .fancytree-selected span.fancytree-checkbox { + background-position: -64px -96px; +} +.fancytree-radio .fancytree-selected span.fancytree-checkbox:hover { + background-position: -96px -96px; +} +.fancytree-radio .fancytree-unselectable span.fancytree-checkbox, +.fancytree-radio .fancytree-unselectable span.fancytree-checkbox:hover { + background-position: 0px -96px; +} +/*------------------------------------------------------------------------------ + * Node type icon + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-ico- + * 1st character: 'e': expanded, 'c': collapsed + * 2nd character (optional): 'f': folder + *----------------------------------------------------------------------------*/ +span.fancytree-icon { + margin-left: 6px; + background-position: 0px 0px; +} +/* Documents */ +.fancytree-ico-c span.fancytree-icon:hover { + background-position: -32px 0px; +} +.fancytree-has-children.fancytree-ico-c span.fancytree-icon { + background-position: -64px 0px; +} +.fancytree-has-children.fancytree-ico-c span.fancytree-icon:hover { + background-position: -96px 0px; +} +.fancytree-ico-e span.fancytree-icon { + background-position: -128px 0px; +} +.fancytree-ico-e span.fancytree-icon:hover { + background-position: -160px 0px; +} +/* Folders */ +.fancytree-ico-cf span.fancytree-icon { + background-position: 0px -32px; +} +.fancytree-ico-cf span.fancytree-icon:hover { + background-position: -32px -32px; +} +.fancytree-has-children.fancytree-ico-cf span.fancytree-icon { + background-position: -64px -32px; +} +.fancytree-has-children.fancytree-ico-cf span.fancytree-icon:hover { + background-position: -96px -32px; +} +.fancytree-ico-ef span.fancytree-icon { + background-position: -128px -32px; +} +.fancytree-ico-ef span.fancytree-icon:hover { + background-position: -160px -32px; +} +.fancytree-loading span.fancytree-expander, +.fancytree-loading span.fancytree-expander:hover, +.fancytree-statusnode-wait span.fancytree-icon, +.fancytree-statusnode-wait span.fancytree-icon:hover { + background-image: url('data:image/gif;base64,R0lGODdhIAAgAOYAAAAAACue/zGf/yqg/yWh/0Ol/zum/02m/1Cn/1Wp/02q/0Sr/1ut/2Gv/1ew/16w/2Sy/2y1/3G3/265/3S6/3y9/4G//4i//37C/4TC/4zF/5HH/47J/5TJ/8zM/5zN/6HP/57R/6TS/6zV/7HX/6zY/7TZ/6Xa/7zd/8Hf/77h/8Ti/7Tj/8zl/9Hm/8Lp/87p/9Tq/9vt/+Lu/83y/97y/+Ty/9P1/+z1//P2/9z4/+76//X7/+T8/3///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkKAEAALAAAAAAgACAAAAf/gECCg4Q4PzIrKCaLKjE8OISRkoQrMTUrJiMimyMoNS4ok6I/NiuaIh0aFhWsFhodHx0oMzyigzY2PDQnGRS+FBMRERAPDhMcKjsyMrY4MiklHxkVvxjWwBAMDxAVHSMuNpM2Mj0l0xkcHyKLKIojHxoUDwoLGTctzISk0B3THSo6dvwYOJBHj10UFCiIkGFEjB2FfpjIkKGDCBIrZPAgSBBHDBPwICgwoKFHPkEtbojQoKGEyRi2gKxImaFAAQosTAwCxaKDRRQyIMUEgqPFhwkJEmDQQAIIDxkmQmj48KIFzKGCTIWAUCCBhhY2fuwwkWpEj3BYB8GAUUFAAAsw/3bYiDHCJwoetdIKwtFDw4AAEUZUMgVrxUC9gn7w+GAgQIMPI2CsEKEOxmHEA0csIOBVRIvJ61oYQgzkBw4UHy5sMDHTlIgXjUjvJefi4Y8Yrl+gcCFb0EbFG2W00FRixWjZBPEShbrJ8g/kHBPzMCX4EWmOl3nYaIGiUw0ZaLFy3JgXiPAbjMCWt1UQL3lCNnaYMmEZR/hJvx/h+B0RxqJKMcxgyHODtIeXfQMSmJhHkrXTQg8D5SDUfgTJZcN+/BViSAyKoGDVOOCBF599uORCEH7OxPDZCjM9hNcO3y1zIV6XTYJDDorVIFkLVskQw48y/lbjKNr56OOPSMo44xSQQ11oWoklCmRdbwXhQKKVGYoSCAAh+QQJCgBAACwAAAAAIAAgAAAH/4BAgoOENjYxLSgoJiYtLYaEkZKRMjItK4wjJigrMTGToEA4NisoIh8dGhoZrKyqIiQ1NqGDNjKLqKqtFhW9GR8jMTK0tiYjqB3JHR/MH6oU0BUaHS3DkzIxIyLKHyAiI+DHHb3RGistkqO4zCLnNjjwPKO3JhkVERQZHTKzg6PG7Ea0iIGDx4+DP+AlWhUhQoUMLqwJuiSiYjCJoS7ZgxAhhAhCpSya4EdLkCUNFiBAWCboX4lvLVyUjERCRASOFar903ZxJqFFN/FVqwRu0zuftWLcYwBhE7aiKAoibSnDQgSmmhAxQtHC4FQgCTVQSMDggwitJs55nRq2AtllnscYnfsqKOxYBsuwLZpLV57YtyL0pm0hdeohCgwOJBBhosYtFCkI8/g6w8XVAwxGoJB3iROkqS1SQEiQAEInzqVWyJjxNcaKqw0iVBPkacU5gpNLHpSnwkRFQpUuDYQ3EyEPRIsIwUPkqNK7g4QQ/uBBvTqPHISoe4IBQ5gh6tGlV5eeDgc2T5WcG4KXI8d1gwhBwavkSZj6d/Dyw4ce6rqt9JXIYgh+1PFHC3U2zACgDALiVxB8X1Wn33g/0DXIbvI8WGCFoQQCACH5BAkKAEAALAAAAAAgACAAAAf/gECCg4Q4NjIxK4orLTE2OISRkpEziC0omCiMMjKTnkA5OC0rJCMiHx8dqqqoIyaPn4OGKyimqasbGrodIiacsYYpKKcixSIjpqcdGcwZHyIxnZOHKCStyCbZ2ae6FhYaH42SobTIro04ODk8PIYytB0aFRkdIDKQsjbC2CjR6z8Af6QblapCBQ0dYswgFCNGNkwybMQSFKOFBgsUKiAj1KLFwxWwJiJaRoHCM0HkUJjoJ23iIJUVKHxzlI4WxIUuB9GKOS/aIZsr1OUcdCgDhQgUNP3U1GLdUEGG5CFdyYlWIx4/ngIRuAxChGOIFF3N+lTghwxen3Ea1VGrIK4V1SBAeFapYwsXbrfikCf3wwgbNiq6iMFOKw4ZGSI8gDAChaEYLgY7fRq4guIIK3nkaDg4ndZaEBhAoNBCBruGDT0/NcUgAdLSggA35FR4oosVFCAkYKBhAyHZ0WTkyOEyhYkIrRl0+EBI8yFOgNUBJPSDx4wWuQ8cgFBB3CB2MypBx8GO7NsfNlogP5CAQoZo49zNiJ5uOFaAhy0zwLzCE3jA9KVTHkA82CBPRivg9Qk76TSYzg7slMdDRW1NhJ+DD0aIFQ+c/FJWQBoOmNd5BIY43SeBAAAh+QQJCgBAACwAAAAAIAAgAAAH/4BAgoOEODgyMi2KLYiGhI+QjzY2MTErlyuViJGcQDw4MS0oKCYjIqeoIyMoKzY4nYOGoSalpqgfuCImKDI2sIYtK6S0xLSmuB0dHyIjvZw4NsLEoygpKaOqyMoiMTKQPDmK1CrdhjznnzbBHx0aGh8jroQ5OMGjl4jnP/s/4KEiH9x1AOFsECJMLSbBEhTqw4YMGnYRqoTQ0UIZMUB8yJBBlSB/wRjNWPhImAaIHXp9CqVIHslBwU5m6BDDFSVFMc69jCUjYIUMKFpAC9VN504g0HwCbUWpmwweP456whGQAoURJiZpehr16A8cIDRYxarVqVRBX8OOzdp009lPAcslXDVhCFG+rjuhaagQgcKuT3ZnGN1pQ8bevqzOFUaUg4dUUhEgULBQlMeMGb1w5JBKQkRkChlqCjI0yRzeTpYyUIAAQVkhaK5wDO4kjC+ECCFEEDpnqLdsqF37QUMxogKFBw8iVHDhbZBw3/r2jT4UYwSI1QwgVNBQcDePHTsa61NcNQIDBgkSKGfFad9vdP122Nh7Pv35n5lg7YMvPMYEBgcckN1MLcRA0n7RrXRcen0t091L/AgHEDMruGCRVBF+YsouMQh2GiGBAAAh+QQJCgBAACwAAAAAIAAgAAAH/4BAgoOEOTk2NjIxi4g4OISQkZCOM4ouLS0yMoiSnUA8OYotKyilJqeoKCstjp6DOTiKpCiopyO3JqqcnrCLoysrKsDAtCQjIsi5m52OMZjDq5ijpbfIIyYxMpE8PJrSmTM43OPNLccfH9c2j4Pcoi2MNtw/9D+giiYj6CIj64SIi7K1cgVE0bEOH1QRmjFjkSYcOQgCSURCRIcOuQS5UxRjoERBwC5+ALFp4yKIHwc5+yAyxgwesTTJ45FSEA4bIDpo6LAiBixNJX/UBALLogYNq2AimmGD3tAfO/Rl0JBLKaKmQmtCHQEiQ4ZcsBqxexr1g9droMQO1YhDagYSJtG4XcXhtOahDxoqZEDRQm6juiljdcigd5U9mOIAfyRVgUIFDS7piZuXNSWtxhk2xLChcRxliTJaaMjg+IMIQp551JM4irDjW6jH1eMRwwVT1fZu0tJgIUIEC5C1DaKHOzcwF5sdxYphQkTjCBQ0fFgGCXe3FREgQD96lLBvCBAer+o0uwWKBgkYQHBMgYKE7OAj7Mzkyh4KERASHDiAIEF6BupF0IEIyElk3wgSQMCAf/+B55gIJFAnkSOjHIRQOibA49FH9iiCQkXWKCNPZZAEAgAh+QQJCgBAACwAAAAAIAAgAAAH/4BAgoOEPDw4NjKKMjY4joSQkZA5OTaJizONOJKcQIaIMaEtK6SlpDAxj52Chpaio6QosrItMY2rhjOKobwxLb8rKSgmxKS3kjw5u73Mo7LEKCuMka2Xio2G2Z8yMbIjIygpqqw8NrqL2Dw/6z+Giiso3yYox4KO5paUq4K6JiMiIla0IHTPkg1D+4BYGgYwGrmC4xIC+QVwhIl0jjLmkDgoFEARIzA62qGOoz0bJER8EFHrkyN1P0wCyYHDhMoPLV3ClPljh78OH6K1y5ZjHU8e8Tp0EKqNh0xWOJIuXZFt6FNPNUcojVbVkFGTlVRq6CBQXVOnJhGB6DC2FrtDiLxkyBylIYOGD4zWuZPxSya8ukBlbALCTUOFCBRWxEjI7cOGDBlAEuJ7mAEEEysSumjBFjKxyS0oQDhwIEIFcOlctkDBtkKFu7ZAH05wgEEEECNiMMqYaFhd1x1ACI4ET3SCBJYrZFD6ga3hChQotF0sKcaKDBQYaLdNQTlk19G7B9e9ajPbCBDSq4cQAXGFD7nl7tM14kMFCejVI6Zg12K9fY744g8IH6xEggkuCDYYR7nI4E1F0TBSkiSBAAAh+QQJCgBAACwAAAAAIAAgAAAH/4BAgoOEPDw4ODaKNoiGhI+Qj4aIi4qIOJGZQD8/lDYyMjGioy0tojk8moM/h4mgo6KlpS4xiKqcnjWgu68uLSvALS62kayelZWhpSsqKy2MkJOX04bVk5+/KCjOODmFPDvT3Tmc5aw8iqXa28SC1Zc8P6qCiisoJiii3zyoOJzzQBLZM2GilDtr8eQBHBSKID5GCBMuHPTJIQqI5spNFJQDBwoSI0zIsFEt40Ygh+6NGBFDBj94/zayWmFChIhSikSNjDlxZk0RzkiIoEBBwwd/J1nds+lsxAcIDCpoQCqTB4oRTFvUTHCAAQUZmDZ2rPnhZoyrXBlEiGHjZCKsZchpxVgRgUECBiNQnIzR4kOHDyNGymhBAcJdECNO/vKLGBoQDRkSJIhQYUUMgJ9E+O2Aj5BfuxAobAMoCkSH06MH8S3MAEKFDCZWMDLX8ReIDxqMihhJyEaMDIUfRKAQcuS0T/Y65NYgYoRjQvYqSIAAYXjuDyCy+82dIUMHEC0z8dVQIQJ1ylI1bODePYMGxLw1xYBhmmiE+0QpVHjNXKQMzDIIBVkF+e3X3V8PhQUQIqJos1Jz27TUzkKcYEMTCSTE9gwO8WQSCAAh+QQJCgBAACwAAAAAIAAgAAAH/4BAgoOEPIaGOIk4h4SNjo2HipKGj5VAPz+IkjY2MzKfMjaLPJaDmJmKopyeoJyUlpiHOZI4nDagMjExn4mVp4Y5O7S1rLm6Mb2QmTzLh6exiLfHuq+CODvOmdrPy4m5Li0tyKSDJijizJil1jjhKy2fhCIiKCs4OerriTEtKyu6gmS0iNAAQoR/6xrdWlGvhagYKyAkSABhhYuEhDgxTLFCFIoRDA4wiBDDBsZBPNqlQIEiFAkRCQ40oCADx0lBhvqZ+ySiA4MEFDLYIHcyEz9zuj74BKph0c1LPI6aSLq0QlOiGDPpnBqj50+rQ59qRWHChIsYJkZAYCAhQw2bN8ZnkR0xYhfZtREqhHpaCwWJEVNztaAQwaC5p7lGiCCBQpTAChIMLn7KT7E5UYKUQoBgFV7CW2nnoUhBSHFhChbeJUw8T4TqQbk0VIgQIcOGeqIO8ZhVWcSHD4AxD7rVIQPhChl2ikplo5/v35fhEuqnwQIFCsg7fBBBV7HvDuC5x3uU64PsCtg1aND+G7x74Cb2Wkr8IUOF+xYy6FevXflnGx91oIF+BPK3HUfCJTRLLgz9VdY7odwj1g+3hFMWS+Lk9kMlgQAAIfkECQoAQAAsAAAAACAAIAAAB/+AQIKDhDw/hz88ioqHhI6PjoyHi5SQlkAymTI4i4k8OTihooaXgy2nLaGMiqCiODuKpS4rFRQVGjaSrKI2vb2xkCsmEQ0RFZuGnq04vTO9OTmPMzEZFAkHDBEtuYiTiswzmb88hDEtFBAHBxAULTLJiLu9mrnkgx8dDAnZJimlgp8yxYhhAwehDRr0RaCwwsU/IIoExnAmSMY5CPtEjHhIKFQMFwMjtpDQgAGEESg4DvLookWMHDxQDHtgjKBKgDnMtXBR0MQICDQzbLoJkcfHUwVHfIAAoUIHTkQTyYixwp0NEUshZHj6IyqPqStWZMIaQesHqDcTmUOhIoaMESLYIkTYilal2hYoUGSSScEYLoM3P7VIkVfGjBUo+t4aehMUYrYybEzNUKsCihVEJee9HGqahsomUt6cKpNzNCAgPlCgoKGD24fMEJswcYoQ3FoZNLh8qHm2iYGEbMTo8Hnrh6qqKPHoPWJE6IIda4DokMFC68u9XIWa6rO56UfmiFuwruGDRt8+RYAQISJ0ZEtTU2eYb3x9c/YfzItAkQL6pUwmiECcBhps0MGB+bGHHWClMCNTagdGmB8IziF32kM87CBZC4/lVVVkwNj1AzPmhBWWSwWRAkkgACH5BAkKAEAALAAAAAAgACAAAAf/gECCg4QyMSYjIyQ4PI0/P4SRkpEtKyIiHyM2jo2TnkA2Mh8aFBEJCQ8UMYyPjTyPn4MxLR0ZEAwHBwwTq62unZ+zGRUMDKfFFRoyOL6uzJCTLSgVpgnFERQaH5uPP405OKySNjEaFbcQEZkxy6zd3uHxsIMyLRYSD6kVIyg2z76P4sV7RUhEiAjpKqBYEUsQPBw2/OEg9KEDBAgUMrSI0RBIQIgSBRkalm6EiY6EwIWSMeOVDBgZKGA0kQLlIB45ZOhs+WMFilLJZNiwKaiRTp3hUJgAqsEfUSCNZhwNh4hCtg/MnnqTGiOGPxMirG4QkZXoVkNecYAVSxaaTW860rtGrJoNRNm3POJ6teFzmIYOTokanZVW2rAMHZY9xdm1RQt/M2KMyqBhRYunER1vzMEjVMUMGRY+1bnCcgzOgkaIAN0BhNCO4SqVZkfIhAkNGTZ8oN0wc+kVOgl57qCBwwcRLZb9chWqtIrSLcIRgjjiA4e/H1akZbQjHmkUCzcykmQIU4cOH0CYBF9aqW3bCwOPk6G6IvpLJt+XyG/CsvxJoSiFyQcfhHAJfraJN1FDEFVS33EHJgIeO+OhhFMoLshmWlrAvPUDRIZollw7BE0SCAAh+QQJCgBAACwAAAAAIAAgAAAH/4BAgoOEMjIoJiIfHyImKDEyPDyElJWDLS0mIx2cHSIjKy04OJaWNjIiHRUUEBAMr7AQFCMoPD+lhTEfHRGurwnABwcJECK1t7gyLR0Zva0QERWrEq4JDSgukj/IlS0rGRWtEdEVGxsaGRS9ESuR29yDpx8aEhEUFY0yNjajpzErK3Bo+2ELnowYGyyMy6DBEY4ckiThsOEiRo5tBbcRIjFiVYUMoXANshUxIiFFqxi2kCFSUMmSgk510HDPUUtKEXfsEMjDBsJ0FVCsuElI0k4cO2x5A5ehgwxSRF3yOCrwxwoU4DR84BdV6k5+khBlaCpCYFcgBCfyE2jCxNgPI8zMdk27b21bDRpAxJ0094dafjsQ4dUrN+q2v6O84fVkI8dZSfsMjYqxTEMHEFy7Qj71dIc8Th9axDg76qAhyDJA7OoQsutkSJH4miDB6ZO+m6Vj6N5HCAWKXYwg4cahezfUmDVGKIJrYuXLiBN1Y3IRm9BETYs+ieZZcuJBTKKrUzKkScQnWqHAewMIcPtxSjZqIDL/qa1Q9r7v6x4lct9VTSOMYF9+KawAyUPDudACIm0N6Fsop/F1k0T+KBjeUzydhZF3xUEClkaWBAIAIfkECQoAQAAsAAAAACAAIAAAB/+AQIKDhDYyKygjIiIjJigyNjw8hJSVgzExKCYiHx8gjS0xODiWljg2JCIaGRQUEa8QrxQVHyKQpYQyMSMfGRWwEMEPD7EZHaG4QLofHRWtsxUZ0hUSEQwMCQwUGSsupTEtHazQGhod5xu+ENgJEBQmK5U4MpwV0RqOkKOjuiMg1gcSRKjQQkYhGR802DOHYsWoHxB5nErk6sABdwUJmTAhzRyyZEBSmLA2MOMgRdI6fIhhEGSLFNQqaGApyBCzDBpQpABJqUVBGZIk2UynYUULnrlsjOIB8Qe4Dhw6gJBBCqmgoE0htljRQUMtpVavZv3BFNE5ESZwTArblGlTsx3N0KoNC6StJIiImI1AkeMH3YhBy6LQm9YvW7I5lvIA10nuWqsR90mK4YKTCBJz2UqU/OOUokWY6Erap7azDROffdLdpxQHREEpUCxyZMMGT6G1WxPauqiRjBm3eeTWPWgi6r0rfgcOzE+Gc0iSCI2KPaIRCpZql29+DimS4YOaNqJoGIqlLkzoned4TOkUoo2OyLdw4QJTfUzK2cuz4WLreJ0rBDhffdDpZ4lEmASoggoBGnVfDLVFh9RotXHXXWB//ZBYhc7NoJRb31ESCAA7'); + background-position: 0px 0px; +} +/* Status node icons */ +.fancytree-statusnode-error span.fancytree-icon, +.fancytree-statusnode-error span.fancytree-icon:hover { + background-position: 0px -224px; +} +/*------------------------------------------------------------------------------ + * Node titles and highlighting + *----------------------------------------------------------------------------*/ +span.fancytree-node { + /* See #117 */ + display: inherit; + width: 100%; + margin-top: 1px; + min-height: 32px; +} +span.fancytree-title { + color: #000000; + cursor: pointer; + display: inline-block; + vertical-align: top; + min-height: 32px; + padding: 0 3px 0 3px; + margin: 0px 0 0 6px; + border: 1px solid transparent; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + -ms-border-radius: 0px; + -o-border-radius: 0px; + border-radius: 0px; +} +span.fancytree-node.fancytree-error span.fancytree-title { + color: #ff0000; +} +/*------------------------------------------------------------------------------ + * Drag'n'drop support + *----------------------------------------------------------------------------*/ +div.fancytree-drag-helper span.fancytree-childcounter, +div.fancytree-drag-helper span.fancytree-dnd-modifier { + display: inline-block; + color: #fff; + background: #337ab7; + border: 1px solid gray; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +div.fancytree-drag-helper span.fancytree-childcounter { + position: absolute; + top: -6px; + right: -6px; +} +div.fancytree-drag-helper span.fancytree-dnd-modifier { + background: #5cb85c; + border: none; + font-weight: bolder; +} +div.fancytree-drag-helper.fancytree-drop-accept span.fancytree-drag-helper-img { + background-position: -64px -224px; +} +div.fancytree-drag-helper.fancytree-drop-reject span.fancytree-drag-helper-img { + background-position: -32px -224px; +} +/*** Drop marker icon *********************************************************/ +#fancytree-drop-marker { + width: 64px; + position: absolute; + background-position: 0px -256px; + margin: 0; +} +#fancytree-drop-marker.fancytree-drop-after, +#fancytree-drop-marker.fancytree-drop-before { + width: 128px; + background-position: 0px -288px; +} +#fancytree-drop-marker.fancytree-drop-copy { + background-position: -128px -256px; +} +#fancytree-drop-marker.fancytree-drop-move { + background-position: -64px -256px; +} +/*** Source node while dragging ***********************************************/ +span.fancytree-drag-source.fancytree-drag-remove { + opacity: 0.15; +} +/*** Target node while dragging cursor is over it *****************************/ +/*------------------------------------------------------------------------------ + * 'table' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-table { + border-collapse: collapse; +} +table.fancytree-ext-table span.fancytree-node { + display: inline-block; +} +/*------------------------------------------------------------------------------ + * 'columnview' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-columnview tbody tr td { + position: relative; + border: 1px solid gray; + vertical-align: top; + overflow: auto; +} +table.fancytree-ext-columnview tbody tr td > ul { + padding: 0; +} +table.fancytree-ext-columnview tbody tr td > ul li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0px 0px; + background-repeat: repeat-y; + background-image: none; + /* no v-lines */ + margin: 0; +} +table.fancytree-ext-columnview span.fancytree-node { + position: relative; + /* allow positioning of embedded spans */ + display: inline-block; +} +table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded { + background-color: #CBE8F6; +} +table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right { + position: absolute; + right: 3px; + background-position: 0px -160px; +} +table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right:hover { + background-position: -32px -160px; +} +/*------------------------------------------------------------------------------ + * 'filter' extension + *----------------------------------------------------------------------------*/ +.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title { + color: #c0c0c0; + font-weight: lighter; +} +.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: bold; +} +.fancytree-ext-filter-hide tr.fancytree-hide, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide { + display: none; +} +.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title { + color: #c0c0c0; + font-weight: lighter; +} +.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-childcounter span.fancytree-icon, +.fancytree-ext-filter span.fancytree-icon { + position: relative; +} +.fancytree-ext-childcounter span.fancytree-childcounter, +.fancytree-ext-filter span.fancytree-childcounter { + color: #fff; + background: #777; + border: 1px solid gray; + position: absolute; + top: -6px; + right: -6px; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +/*------------------------------------------------------------------------------ + * 'wide' extension + *----------------------------------------------------------------------------*/ +ul.fancytree-ext-wide { + position: relative; + min-width: 100%; + z-index: 2; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +ul.fancytree-ext-wide span.fancytree-node > span { + position: relative; + z-index: 2; +} +ul.fancytree-ext-wide span.fancytree-node span.fancytree-title { + position: absolute; + z-index: 1; + left: 0px; + width: 100%; + margin-left: 0; + margin-right: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +/*! + * Fancytree "Win8" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ +/******************************************************************************* + * Styles specific to this skin. + * + * This section is automatically generated from the `ui-fancytree.less` template. + ******************************************************************************/ +/******************************************************************************* + * Node titles + */ +.fancytree-plain span.fancytree-title { + border: 1px solid transparent; +} +.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-focused span.fancytree-title { + border-color: #3399ff; +} +.fancytree-plain span.fancytree-active span.fancytree-title, +.fancytree-plain span.fancytree-selected span.fancytree-title { + background-color: #f7f7f7; + border-color: #dedede; +} +.fancytree-plain span.fancytree-node span.fancytree-selected span.fancytree-title { + font-style: italic; +} +.fancytree-plain span.fancytree-node:hover span.fancytree-title { + background-color: #eff9fe; + border-color: #70c0e7; +} +.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-active span.fancytree-title, +.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-selected span.fancytree-title { + background-color: #cbe8f6; + border-color: #26a0da; +} +/******************************************************************************* + * 'table' extension + */ +table.fancytree-ext-table tbody tr td { + border: 1px solid #EDEDED; +} +table.fancytree-ext-table tbody span.fancytree-node, +table.fancytree-ext-table tbody span.fancytree-node:hover { + border: none; + background: none; +} +table.fancytree-ext-table tbody tr:hover { + background-color: #E5F3FB; + outline: 1px solid #70C0E7; +} +table.fancytree-ext-table tbody tr.fancytree-focused span.fancytree-title { + outline: 1px dotted black; +} +table.fancytree-ext-table tbody tr.fancytree-active:hover, +table.fancytree-ext-table tbody tr.fancytree-selected:hover { + background-color: #CBE8F6; + outline: 1px solid #26A0DA; +} +table.fancytree-ext-table tbody tr.fancytree-active { + background-color: #F7F7F7; + outline: 1px solid #DEDEDE; +} +table.fancytree-ext-table tbody tr.fancytree-selected { + background-color: #F7F7F7; +} +table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-active { + background-color: #CBE8F6; + outline: 1px solid #26A0DA; +} +table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-selected { + background-color: #CBE8F6; +} +ul.fancytree-container { + font-size: 20pt; + padding: 6px; +} diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-xxl/ui.fancytree.less b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-xxl/ui.fancytree.less new file mode 100644 index 00000000000..139d9314897 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-xxl/ui.fancytree.less @@ -0,0 +1,37 @@ +/*! + * Fancytree "Win8" 32x32 skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ + +// Import common styles +@import "../skin-common.less"; + +// Import standard win8 +@import "../skin-win8/ui.fancytree.less"; + + +// Override the variable after the import. +// NOTE: Variables are always resolved as the last definition, even if it is +// after where it is used. +@fancy-use-sprites: true; // false: suppress all background images (i.e. icons) +@fancy-hide-connectors: true; + +@fancy-level-indent: 32px; +@fancy-line-height: 32px; // height of a nodes selection bar including borders +@fancy-node-v-spacing: 1px; // gap between two node borders +@fancy-icon-width: 32px; +@fancy-icon-height: 32px; +@fancy-icon-spacing: 6px; // margin between icon/icon or icon/title +@fancy-icon-ofs-top: 0px; // extra vertical offset for expander, checkbox and icon +@fancy-title-ofs-top: 0px; // extra vertical offset for title +@fancy-node-border-width: 1px; +@fancy-node-border-radius: 0px; +@fancy-node-outline-width: 1px; + +ul.fancytree-container { +// font-family: tahoma, arial, helvetica; + font-size: 20pt; + padding: 6px; +} \ No newline at end of file diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-xxl/ui.fancytree.min.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-xxl/ui.fancytree.min.css new file mode 100644 index 00000000000..57542b7cbe0 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8-xxl/ui.fancytree.min.css @@ -0,0 +1,11 @@ +/*! + * Fancytree "Win8" 32x32 skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */.ui-helper-hidden{display:none}ul.fancytree-container{font-family:tahoma,arial,helvetica;white-space:nowrap;margin:0;background-color:#fff;border:1px dotted gray;overflow:auto;min-height:0;position:relative}ul.fancytree-container ul{padding:0 0 0 32px;margin:0}ul.fancytree-container li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0}ul.fancytree-container li.fancytree-lastsib,ul.fancytree-no-connector>li{background-image:none}.ui-fancytree-disabled ul.fancytree-container{opacity:.5;background-color:silver}#fancytree-drop-marker,span.fancytree-checkbox,span.fancytree-drag-helper-img,span.fancytree-empty,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio,span.fancytree-vline{width:32px;height:32px;display:inline-block;vertical-align:top;background-repeat:no-repeat;background-image:url(icons.gif);background-position:0 0}span.fancytree-checkbox,span.fancytree-custom-icon,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio{margin-top:0}span.fancytree-custom-icon{display:inline-block;margin-left:6px}img.fancytree-icon{width:32px;height:32px;margin-left:6px;margin-top:0;vertical-align:top;border-style:none}span.fancytree-expander{cursor:pointer}.fancytree-exp-n span.fancytree-expander,.fancytree-exp-nl span.fancytree-expander{background-image:none;cursor:default}.fancytree-exp-n span.fancytree-expander,.fancytree-exp-n span.fancytree-expander:hover{background-position:0 -128px}.fancytree-exp-nl span.fancytree-expander,.fancytree-exp-nl span.fancytree-expander:hover{background-position:-32px -128px}.fancytree-exp-c span.fancytree-expander{background-position:0 -160px}.fancytree-exp-c span.fancytree-expander:hover{background-position:-32px -160px}.fancytree-exp-cl span.fancytree-expander{background-position:0 -192px}.fancytree-exp-cl span.fancytree-expander:hover{background-position:-32px -192px}.fancytree-exp-cd span.fancytree-expander{background-position:-128px -160px}.fancytree-exp-cd span.fancytree-expander:hover{background-position:-160px -160px}.fancytree-exp-cdl span.fancytree-expander{background-position:-128px -192px}.fancytree-exp-cdl span.fancytree-expander:hover{background-position:-160px -192px}.fancytree-exp-e span.fancytree-expander,.fancytree-exp-ed span.fancytree-expander{background-position:-64px -160px}.fancytree-exp-e span.fancytree-expander:hover,.fancytree-exp-ed span.fancytree-expander:hover{background-position:-96px -160px}.fancytree-exp-edl span.fancytree-expander,.fancytree-exp-el span.fancytree-expander{background-position:-64px -192px}.fancytree-exp-edl span.fancytree-expander:hover,.fancytree-exp-el span.fancytree-expander:hover{background-position:-96px -192px}span.fancytree-checkbox{margin-left:6px;background-position:0 -64px}span.fancytree-checkbox:hover{background-position:-32px -64px}.fancytree-partsel span.fancytree-checkbox{background-position:-128px -64px}.fancytree-partsel span.fancytree-checkbox:hover{background-position:-160px -64px}.fancytree-selected span.fancytree-checkbox{background-position:-64px -64px}.fancytree-selected span.fancytree-checkbox:hover{background-position:-96px -64px}.fancytree-unselectable span.fancytree-checkbox{opacity:.4;filter:alpha(opacity=40)}.fancytree-unselectable span.fancytree-checkbox:hover{background-position:0 -64px}.fancytree-unselectable.fancytree-partsel span.fancytree-checkbox:hover{background-position:-128px -64px}.fancytree-unselectable.fancytree-selected span.fancytree-checkbox:hover{background-position:-64px -64px}.fancytree-radio span.fancytree-checkbox{background-position:0 -96px}.fancytree-radio span.fancytree-checkbox:hover{background-position:-32px -96px}.fancytree-radio .fancytree-partsel span.fancytree-checkbox{background-position:-128px -96px}.fancytree-radio .fancytree-partsel span.fancytree-checkbox:hover{background-position:-160px -96px}.fancytree-radio .fancytree-selected span.fancytree-checkbox{background-position:-64px -96px}.fancytree-radio .fancytree-selected span.fancytree-checkbox:hover{background-position:-96px -96px}.fancytree-radio .fancytree-unselectable span.fancytree-checkbox,.fancytree-radio .fancytree-unselectable span.fancytree-checkbox:hover{background-position:0 -96px}span.fancytree-icon{margin-left:6px;background-position:0 0}.fancytree-ico-c span.fancytree-icon:hover{background-position:-32px 0}.fancytree-has-children.fancytree-ico-c span.fancytree-icon{background-position:-64px 0}.fancytree-has-children.fancytree-ico-c span.fancytree-icon:hover{background-position:-96px 0}.fancytree-ico-e span.fancytree-icon{background-position:-128px 0}.fancytree-ico-e span.fancytree-icon:hover{background-position:-160px 0}.fancytree-ico-cf span.fancytree-icon{background-position:0 -32px}.fancytree-ico-cf span.fancytree-icon:hover{background-position:-32px -32px}.fancytree-has-children.fancytree-ico-cf span.fancytree-icon{background-position:-64px -32px}.fancytree-has-children.fancytree-ico-cf span.fancytree-icon:hover{background-position:-96px -32px}.fancytree-ico-ef span.fancytree-icon{background-position:-128px -32px}.fancytree-ico-ef span.fancytree-icon:hover{background-position:-160px -32px}.fancytree-loading span.fancytree-expander,.fancytree-loading span.fancytree-expander:hover,.fancytree-statusnode-wait span.fancytree-icon,.fancytree-statusnode-wait span.fancytree-icon:hover{background-image:url(data:image/gif;base64,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);background-position:0 0}.fancytree-statusnode-error span.fancytree-icon,.fancytree-statusnode-error span.fancytree-icon:hover{background-position:0 -224px}span.fancytree-node{display:inherit;width:100%;margin-top:1px;min-height:32px}span.fancytree-title{color:#000;cursor:pointer;display:inline-block;vertical-align:top;min-height:32px;padding:0 3px;margin:0 0 0 6px;border:1px solid transparent;-webkit-border-radius:0;-moz-border-radius:0;-ms-border-radius:0;-o-border-radius:0;border-radius:0}span.fancytree-node.fancytree-error span.fancytree-title{color:red}div.fancytree-drag-helper span.fancytree-childcounter,div.fancytree-drag-helper span.fancytree-dnd-modifier{display:inline-block;color:#fff;background:#337ab7;border:1px solid gray;min-width:10px;height:10px;line-height:1;vertical-align:baseline;border-radius:10px;padding:2px;text-align:center;font-size:9px}div.fancytree-drag-helper span.fancytree-childcounter{position:absolute;top:-6px;right:-6px}div.fancytree-drag-helper span.fancytree-dnd-modifier{background:#5cb85c;border:0;font-weight:bolder}div.fancytree-drag-helper.fancytree-drop-accept span.fancytree-drag-helper-img{background-position:-64px -224px}div.fancytree-drag-helper.fancytree-drop-reject span.fancytree-drag-helper-img{background-position:-32px -224px}#fancytree-drop-marker{width:64px;position:absolute;background-position:0 -256px;margin:0}#fancytree-drop-marker.fancytree-drop-after,#fancytree-drop-marker.fancytree-drop-before{width:128px;background-position:0 -288px}#fancytree-drop-marker.fancytree-drop-copy{background-position:-128px -256px}#fancytree-drop-marker.fancytree-drop-move{background-position:-64px -256px}span.fancytree-drag-source.fancytree-drag-remove{opacity:.15}table.fancytree-ext-table{border-collapse:collapse}table.fancytree-ext-table span.fancytree-node{display:inline-block}table.fancytree-ext-columnview tbody tr td{position:relative;border:1px solid gray;vertical-align:top;overflow:auto}table.fancytree-ext-columnview tbody tr td>ul{padding:0}table.fancytree-ext-columnview tbody tr td>ul li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0}table.fancytree-ext-columnview span.fancytree-node{position:relative;display:inline-block}table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded{background-color:#CBE8F6}table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right{position:absolute;right:3px;background-position:0 -160px}table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right:hover{background-position:-32px -160px}.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title{color:silver;font-weight:lighter}.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title,.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title{color:#000;font-weight:400}.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title,.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title{color:#000;font-weight:700}.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide,.fancytree-ext-filter-hide tr.fancytree-hide{display:none}.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title,.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title{color:silver;font-weight:lighter}.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title,.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title{color:#000;font-weight:400}.fancytree-ext-childcounter span.fancytree-icon,.fancytree-ext-filter span.fancytree-icon{position:relative}.fancytree-ext-childcounter span.fancytree-childcounter,.fancytree-ext-filter span.fancytree-childcounter{color:#fff;background:#777;border:1px solid gray;position:absolute;top:-6px;right:-6px;min-width:10px;height:10px;line-height:1;vertical-align:baseline;border-radius:10px;padding:2px;text-align:center;font-size:9px}ul.fancytree-ext-wide{position:relative;min-width:100%;z-index:2;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}ul.fancytree-ext-wide span.fancytree-node>span{position:relative;z-index:2}ul.fancytree-ext-wide span.fancytree-node span.fancytree-title{position:absolute;z-index:1;left:0;width:100%;margin-left:0;margin-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}/*! + * Fancytree "Win8" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */.fancytree-plain span.fancytree-title{border:1px solid transparent}.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-focused span.fancytree-title{border-color:#39f}.fancytree-plain span.fancytree-active span.fancytree-title,.fancytree-plain span.fancytree-selected span.fancytree-title{background-color:#f7f7f7;border-color:#dedede}.fancytree-plain span.fancytree-node span.fancytree-selected span.fancytree-title{font-style:italic}.fancytree-plain span.fancytree-node:hover span.fancytree-title{background-color:#eff9fe;border-color:#70c0e7}.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-active span.fancytree-title,.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-selected span.fancytree-title{background-color:#cbe8f6;border-color:#26a0da}table.fancytree-ext-table tbody tr td{border:1px solid #EDEDED}table.fancytree-ext-table tbody span.fancytree-node,table.fancytree-ext-table tbody span.fancytree-node:hover{border:0;background:0 0}table.fancytree-ext-table tbody tr:hover{background-color:#E5F3FB;outline:1px solid #70C0E7}table.fancytree-ext-table tbody tr.fancytree-focused span.fancytree-title{outline:1px dotted #000}table.fancytree-ext-table tbody tr.fancytree-active:hover,table.fancytree-ext-table tbody tr.fancytree-selected:hover{background-color:#CBE8F6;outline:1px solid #26A0DA}table.fancytree-ext-table tbody tr.fancytree-active{background-color:#F7F7F7;outline:1px solid #DEDEDE}table.fancytree-ext-table tbody tr.fancytree-selected{background-color:#F7F7F7}table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-active{background-color:#CBE8F6;outline:1px solid #26A0DA}table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-selected{background-color:#CBE8F6}ul.fancytree-container{font-size:20pt;padding:6px} \ No newline at end of file diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8/icons.gif b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8/icons.gif new file mode 100644 index 0000000000000000000000000000000000000000..813eb8385c40a954a85b0fc8379a6446aec3acd8 GIT binary patch literal 5492 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 literal 0 HcmV?d00001 diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8/loading.gif b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..ef88497ccc2f6c2a3a0c5e41f3cbfc7a18ff5329 GIT binary patch literal 3234 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 RGR}AoOL=)|H48+m{|ju`J$C>A literal 0 HcmV?d00001 diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8/ui.fancytree.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8/ui.fancytree.css new file mode 100644 index 00000000000..e14b5c29f17 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8/ui.fancytree.css @@ -0,0 +1,573 @@ +/*! + * Fancytree "Win8" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ +/******************************************************************************* + * Common Styles for Fancytree Skins. + * + * This section is automatically generated from the `skin-common.less` template. + ******************************************************************************/ +/*------------------------------------------------------------------------------ + * Helpers + *----------------------------------------------------------------------------*/ +.ui-helper-hidden { + display: none; +} +/*------------------------------------------------------------------------------ + * Container and UL / LI + *----------------------------------------------------------------------------*/ +ul.fancytree-container { + font-family: tahoma, arial, helvetica; + font-size: 10pt; + white-space: nowrap; + padding: 3px; + margin: 0; + background-color: white; + border: 1px dotted gray; + overflow: auto; + min-height: 0%; + position: relative; +} +ul.fancytree-container ul { + padding: 0 0 0 16px; + margin: 0; +} +ul.fancytree-container li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0px 0px; + background-repeat: repeat-y; + background-image: none; + margin: 0; +} +ul.fancytree-container li.fancytree-lastsib { + background-image: none; +} +ul.fancytree-no-connector > li { + background-image: none; +} +.ui-fancytree-disabled ul.fancytree-container { + opacity: 0.5; + background-color: silver; +} +/*------------------------------------------------------------------------------ + * Common icon definitions + *----------------------------------------------------------------------------*/ +span.fancytree-empty, +span.fancytree-vline, +span.fancytree-expander, +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-radio, +span.fancytree-drag-helper-img, +#fancytree-drop-marker { + width: 16px; + height: 16px; + display: inline-block; + vertical-align: top; + background-repeat: no-repeat; + background-position: left; + background-image: url("icons.gif"); + background-position: 0px 0px; +} +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-expander, +span.fancytree-radio, +span.fancytree-custom-icon { + margin-top: 2px; +} +/* Used by iconclass option and iconClass callback: */ +span.fancytree-custom-icon { + display: inline-block; + margin-left: 3px; +} +/* Used by 'icon' node option: */ +img.fancytree-icon { + width: 16px; + height: 16px; + margin-left: 3px; + margin-top: 2px; + vertical-align: top; + border-style: none; +} +/*------------------------------------------------------------------------------ + * Expander icon + * + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-exp- + * 1st character: 'e': expanded, 'c': collapsed, 'n': no children + * 2nd character (optional): 'd': lazy (Delayed) + * 3rd character (optional): 'l': Last sibling + *----------------------------------------------------------------------------*/ +span.fancytree-expander { + cursor: pointer; +} +.fancytree-exp-n span.fancytree-expander, +.fancytree-exp-nl span.fancytree-expander { + background-image: none; + cursor: default; +} +.fancytree-exp-n span.fancytree-expander, +.fancytree-exp-n span.fancytree-expander:hover { + background-position: 0px -64px; +} +.fancytree-exp-nl span.fancytree-expander, +.fancytree-exp-nl span.fancytree-expander:hover { + background-position: -16px -64px; +} +.fancytree-exp-c span.fancytree-expander { + background-position: 0px -80px; +} +.fancytree-exp-c span.fancytree-expander:hover { + background-position: -16px -80px; +} +.fancytree-exp-cl span.fancytree-expander { + background-position: 0px -96px; +} +.fancytree-exp-cl span.fancytree-expander:hover { + background-position: -16px -96px; +} +.fancytree-exp-cd span.fancytree-expander { + background-position: -64px -80px; +} +.fancytree-exp-cd span.fancytree-expander:hover { + background-position: -80px -80px; +} +.fancytree-exp-cdl span.fancytree-expander { + background-position: -64px -96px; +} +.fancytree-exp-cdl span.fancytree-expander:hover { + background-position: -80px -96px; +} +.fancytree-exp-e span.fancytree-expander, +.fancytree-exp-ed span.fancytree-expander { + background-position: -32px -80px; +} +.fancytree-exp-e span.fancytree-expander:hover, +.fancytree-exp-ed span.fancytree-expander:hover { + background-position: -48px -80px; +} +.fancytree-exp-el span.fancytree-expander, +.fancytree-exp-edl span.fancytree-expander { + background-position: -32px -96px; +} +.fancytree-exp-el span.fancytree-expander:hover, +.fancytree-exp-edl span.fancytree-expander:hover { + background-position: -48px -96px; +} +/*------------------------------------------------------------------------------ + * Checkbox icon + *----------------------------------------------------------------------------*/ +span.fancytree-checkbox { + margin-left: 3px; + background-position: 0px -32px; +} +span.fancytree-checkbox:hover { + background-position: -16px -32px; +} +.fancytree-partsel span.fancytree-checkbox { + background-position: -64px -32px; +} +.fancytree-partsel span.fancytree-checkbox:hover { + background-position: -80px -32px; +} +.fancytree-selected span.fancytree-checkbox { + background-position: -32px -32px; +} +.fancytree-selected span.fancytree-checkbox:hover { + background-position: -48px -32px; +} +.fancytree-unselectable span.fancytree-checkbox { + opacity: 0.4; + filter: alpha(opacity=40); +} +.fancytree-unselectable span.fancytree-checkbox:hover { + background-position: 0px -32px; +} +.fancytree-unselectable.fancytree-partsel span.fancytree-checkbox:hover { + background-position: -64px -32px; +} +.fancytree-unselectable.fancytree-selected span.fancytree-checkbox:hover { + background-position: -32px -32px; +} +/*------------------------------------------------------------------------------ + * Radiobutton icon + * This is a customization, that may be activated by overriding the 'checkbox' + * class name as 'fancytree-radio' in the tree options. + *----------------------------------------------------------------------------*/ +.fancytree-radio span.fancytree-checkbox { + background-position: 0px -48px; +} +.fancytree-radio span.fancytree-checkbox:hover { + background-position: -16px -48px; +} +.fancytree-radio .fancytree-partsel span.fancytree-checkbox { + background-position: -64px -48px; +} +.fancytree-radio .fancytree-partsel span.fancytree-checkbox:hover { + background-position: -80px -48px; +} +.fancytree-radio .fancytree-selected span.fancytree-checkbox { + background-position: -32px -48px; +} +.fancytree-radio .fancytree-selected span.fancytree-checkbox:hover { + background-position: -48px -48px; +} +.fancytree-radio .fancytree-unselectable span.fancytree-checkbox, +.fancytree-radio .fancytree-unselectable span.fancytree-checkbox:hover { + background-position: 0px -48px; +} +/*------------------------------------------------------------------------------ + * Node type icon + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-ico- + * 1st character: 'e': expanded, 'c': collapsed + * 2nd character (optional): 'f': folder + *----------------------------------------------------------------------------*/ +span.fancytree-icon { + margin-left: 3px; + background-position: 0px 0px; +} +/* Documents */ +.fancytree-ico-c span.fancytree-icon:hover { + background-position: -16px 0px; +} +.fancytree-has-children.fancytree-ico-c span.fancytree-icon { + background-position: -32px 0px; +} +.fancytree-has-children.fancytree-ico-c span.fancytree-icon:hover { + background-position: -48px 0px; +} +.fancytree-ico-e span.fancytree-icon { + background-position: -64px 0px; +} +.fancytree-ico-e span.fancytree-icon:hover { + background-position: -80px 0px; +} +/* Folders */ +.fancytree-ico-cf span.fancytree-icon { + background-position: 0px -16px; +} +.fancytree-ico-cf span.fancytree-icon:hover { + background-position: -16px -16px; +} +.fancytree-has-children.fancytree-ico-cf span.fancytree-icon { + background-position: -32px -16px; +} +.fancytree-has-children.fancytree-ico-cf span.fancytree-icon:hover { + background-position: -48px -16px; +} +.fancytree-ico-ef span.fancytree-icon { + background-position: -64px -16px; +} +.fancytree-ico-ef span.fancytree-icon:hover { + background-position: -80px -16px; +} +.fancytree-loading span.fancytree-expander, +.fancytree-loading span.fancytree-expander:hover, +.fancytree-statusnode-wait span.fancytree-icon, +.fancytree-statusnode-wait span.fancytree-icon:hover { + background-image: url('data:image/gif;base64,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'); + background-position: 0px 0px; +} +/* Status node icons */ +.fancytree-statusnode-error span.fancytree-icon, +.fancytree-statusnode-error span.fancytree-icon:hover { + background-position: 0px -112px; +} +/*------------------------------------------------------------------------------ + * Node titles and highlighting + *----------------------------------------------------------------------------*/ +span.fancytree-node { + /* See #117 */ + display: inherit; + width: 100%; + margin-top: 0px; + min-height: 20px; +} +span.fancytree-title { + color: #000000; + cursor: pointer; + display: inline-block; + vertical-align: top; + min-height: 20px; + padding: 0 3px 0 3px; + margin: 0px 0 0 3px; + border: 1px solid transparent; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + -ms-border-radius: 0px; + -o-border-radius: 0px; + border-radius: 0px; +} +span.fancytree-node.fancytree-error span.fancytree-title { + color: #ff0000; +} +/*------------------------------------------------------------------------------ + * Drag'n'drop support + *----------------------------------------------------------------------------*/ +div.fancytree-drag-helper span.fancytree-childcounter, +div.fancytree-drag-helper span.fancytree-dnd-modifier { + display: inline-block; + color: #fff; + background: #337ab7; + border: 1px solid gray; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +div.fancytree-drag-helper span.fancytree-childcounter { + position: absolute; + top: -6px; + right: -6px; +} +div.fancytree-drag-helper span.fancytree-dnd-modifier { + background: #5cb85c; + border: none; + font-weight: bolder; +} +div.fancytree-drag-helper.fancytree-drop-accept span.fancytree-drag-helper-img { + background-position: -32px -112px; +} +div.fancytree-drag-helper.fancytree-drop-reject span.fancytree-drag-helper-img { + background-position: -16px -112px; +} +/*** Drop marker icon *********************************************************/ +#fancytree-drop-marker { + width: 32px; + position: absolute; + background-position: 0px -128px; + margin: 0; +} +#fancytree-drop-marker.fancytree-drop-after, +#fancytree-drop-marker.fancytree-drop-before { + width: 64px; + background-position: 0px -144px; +} +#fancytree-drop-marker.fancytree-drop-copy { + background-position: -64px -128px; +} +#fancytree-drop-marker.fancytree-drop-move { + background-position: -32px -128px; +} +/*** Source node while dragging ***********************************************/ +span.fancytree-drag-source.fancytree-drag-remove { + opacity: 0.15; +} +/*** Target node while dragging cursor is over it *****************************/ +/*------------------------------------------------------------------------------ + * 'table' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-table { + border-collapse: collapse; +} +table.fancytree-ext-table span.fancytree-node { + display: inline-block; +} +/*------------------------------------------------------------------------------ + * 'columnview' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-columnview tbody tr td { + position: relative; + border: 1px solid gray; + vertical-align: top; + overflow: auto; +} +table.fancytree-ext-columnview tbody tr td > ul { + padding: 0; +} +table.fancytree-ext-columnview tbody tr td > ul li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0px 0px; + background-repeat: repeat-y; + background-image: none; + /* no v-lines */ + margin: 0; +} +table.fancytree-ext-columnview span.fancytree-node { + position: relative; + /* allow positioning of embedded spans */ + display: inline-block; +} +table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded { + background-color: #CBE8F6; +} +table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right { + position: absolute; + right: 3px; + background-position: 0px -80px; +} +table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right:hover { + background-position: -16px -80px; +} +/*------------------------------------------------------------------------------ + * 'filter' extension + *----------------------------------------------------------------------------*/ +.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title { + color: #c0c0c0; + font-weight: lighter; +} +.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: bold; +} +.fancytree-ext-filter-hide tr.fancytree-hide, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide { + display: none; +} +.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title { + color: #c0c0c0; + font-weight: lighter; +} +.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-childcounter span.fancytree-icon, +.fancytree-ext-filter span.fancytree-icon { + position: relative; +} +.fancytree-ext-childcounter span.fancytree-childcounter, +.fancytree-ext-filter span.fancytree-childcounter { + color: #fff; + background: #777; + border: 1px solid gray; + position: absolute; + top: -6px; + right: -6px; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +/*------------------------------------------------------------------------------ + * 'wide' extension + *----------------------------------------------------------------------------*/ +ul.fancytree-ext-wide { + position: relative; + min-width: 100%; + z-index: 2; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +ul.fancytree-ext-wide span.fancytree-node > span { + position: relative; + z-index: 2; +} +ul.fancytree-ext-wide span.fancytree-node span.fancytree-title { + position: absolute; + z-index: 1; + left: 0px; + width: 100%; + margin-left: 0; + margin-right: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +/******************************************************************************* + * Styles specific to this skin. + * + * This section is automatically generated from the `ui-fancytree.less` template. + ******************************************************************************/ +/******************************************************************************* + * Node titles + */ +.fancytree-plain span.fancytree-title { + border: 1px solid transparent; +} +.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-focused span.fancytree-title { + border-color: #3399ff; +} +.fancytree-plain span.fancytree-active span.fancytree-title, +.fancytree-plain span.fancytree-selected span.fancytree-title { + background-color: #f7f7f7; + border-color: #dedede; +} +.fancytree-plain span.fancytree-node span.fancytree-selected span.fancytree-title { + font-style: italic; +} +.fancytree-plain span.fancytree-node:hover span.fancytree-title { + background-color: #eff9fe; + border-color: #70c0e7; +} +.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-active span.fancytree-title, +.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-selected span.fancytree-title { + background-color: #cbe8f6; + border-color: #26a0da; +} +/******************************************************************************* + * 'table' extension + */ +table.fancytree-ext-table tbody tr td { + border: 1px solid #EDEDED; +} +table.fancytree-ext-table tbody span.fancytree-node, +table.fancytree-ext-table tbody span.fancytree-node:hover { + border: none; + background: none; +} +table.fancytree-ext-table tbody tr:hover { + background-color: #E5F3FB; + outline: 1px solid #70C0E7; +} +table.fancytree-ext-table tbody tr.fancytree-focused span.fancytree-title { + outline: 1px dotted black; +} +table.fancytree-ext-table tbody tr.fancytree-active:hover, +table.fancytree-ext-table tbody tr.fancytree-selected:hover { + background-color: #CBE8F6; + outline: 1px solid #26A0DA; +} +table.fancytree-ext-table tbody tr.fancytree-active { + background-color: #F7F7F7; + outline: 1px solid #DEDEDE; +} +table.fancytree-ext-table tbody tr.fancytree-selected { + background-color: #F7F7F7; +} +table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-active { + background-color: #CBE8F6; + outline: 1px solid #26A0DA; +} +table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-selected { + background-color: #CBE8F6; +} diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8/ui.fancytree.less b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8/ui.fancytree.less new file mode 100644 index 00000000000..acdf2ee3263 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8/ui.fancytree.less @@ -0,0 +1,153 @@ +/*! + * Fancytree "Win8" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ + +// Import common styles +@import "../skin-common.less"; + + +/******************************************************************************* + * Styles specific to this skin. + * + * This section is automatically generated from the `ui-fancytree.less` template. + ******************************************************************************/ + +// Borders have NO radius and NO gradients are used! + +// both: +// unselected background: white +// hover bar (unselected, inactive): #E5F3FB (border: #70C0E7) 'very light blue' +// active node: #CBE8F6 (border: #26A0DA) 'light blue' +// active node with hover: wie active node + +// Tree view: +// active node, tree inactive: #F7F7F7 (border: #DEDEDE) 'light gray, selected, but tree not active' + +// List view: +// selected bar: --> active bar +// focus bar: transparent(white) + border 1px solid #3399FF () + +// table left/right border: #EDEDED 'light gray' + +// Override the variable after the import. +// NOTE: Variables are always resolved as the last definition, even if it is +// after where it is used. +@fancy-use-sprites: true; // false: suppress all background images (i.e. icons) + +@fancy-hide-connectors: true; + +@fancy-line-height: 20px; // height of a nodes selection bar including borders +@fancy-node-v-spacing: 0px; // gap between two node borders +@fancy-icon-width: 16px; +@fancy-icon-height: 16px; +@fancy-icon-spacing: 3px; // margin between icon/icon or icon/title +@fancy-icon-ofs-top: 2px; // extra vertical offset for expander, checkbox and icon +@fancy-title-ofs-top: 0px; // extra vertical offset for title +@fancy-node-border-width: 1px; +@fancy-node-border-radius: 0px; +@fancy-node-outline-width: 1px; + + +// @fancy-icon-width: 16px; +// @fancy-icon-height: 16px; +// @fancy-line-height: 16px; +// @fancy-icon-spacing: 3px; + +// Use 'data-uri(...)' to embed the image into CSS instead of linking to 'loading.gif': +@fancy-loading-url: data-uri("@{fancy-image-dir}/loading.gif"); +// Set to `true` to use `data-uri(...)` which will embed icons.gif into CSS +// instead of linking to that file: +// @fancy-inline-sprites: true; + +/******************************************************************************* + * Node titles + */ +.fancytree-plain { + span.fancytree-title { + border: @fancy-node-border-width solid transparent; // avoid jumping, when a border is added on hover + } + &.fancytree-container.fancytree-treefocus span.fancytree-focused span.fancytree-title { + border-color: #3399ff; + } + span.fancytree-active span.fancytree-title, + span.fancytree-selected span.fancytree-title { // active/selcted nodes inside inactive tree + background-color: #f7f7f7; + border-color: #dedede; + } + span.fancytree-node span.fancytree-selected span.fancytree-title { + font-style: italic; + } + span.fancytree-node:hover span.fancytree-title { + background-color: #eff9fe; // hover is always colored, even if tree is unfocused + border-color: #70c0e7; + } + &.fancytree-container.fancytree-treefocus { + span.fancytree-active span.fancytree-title, + span.fancytree-selected span.fancytree-title { + background-color: #cbe8f6; + border-color: #26a0da; + } + } +} + +/******************************************************************************* + * 'table' extension + */ +table.fancytree-ext-table tbody { + tr td { + border: 1px solid #EDEDED; + } + span.fancytree-node, + span.fancytree-node:hover { // undo standard tree css + border: none; + background: none; + } + // Title get's a white background, when hovered. Undo standard node formatting + // span.fancytree-title:hover { + // border: none; //1px solid transparent; + // background: inherit; + // background: transparent; + // background: none; + // filter: none; + // } + tr:hover { + background-color: #E5F3FB; + outline: 1px solid #70C0E7; + } + // tr:hover td { + // outline: 1px solid #D8F0FA; + // } + // tr.fancytree-focused { + // border-color: #3399FF; + // outline: 1px dotted black; + // } + tr.fancytree-focused span.fancytree-title { + outline: 1px dotted black; + } + + tr.fancytree-active:hover, + tr.fancytree-selected:hover { + background-color: #CBE8F6; + outline: 1px solid #26A0DA; + } + tr.fancytree-active { // dimmed, if inside inactive tree + background-color: #F7F7F7; + outline: 1px solid #DEDEDE; + } + tr.fancytree-selected { // dimmed, if inside inactive tree + background-color: #F7F7F7; + } +} + +table.fancytree-ext-table.fancytree-treefocus tbody { + tr.fancytree-active { + background-color: #CBE8F6; + outline: 1px solid #26A0DA; + } + tr.fancytree-selected { + background-color: #CBE8F6; + } +} diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8/ui.fancytree.min.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8/ui.fancytree.min.css new file mode 100644 index 00000000000..b6b298bdd0b --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-win8/ui.fancytree.min.css @@ -0,0 +1,6 @@ +/*! + * Fancytree "Win8" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */.ui-helper-hidden{display:none}ul.fancytree-container{font-family:tahoma,arial,helvetica;font-size:10pt;white-space:nowrap;padding:3px;margin:0;background-color:#fff;border:1px dotted gray;overflow:auto;min-height:0;position:relative}ul.fancytree-container ul{padding:0 0 0 16px;margin:0}ul.fancytree-container li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0}ul.fancytree-container li.fancytree-lastsib,ul.fancytree-no-connector>li{background-image:none}.ui-fancytree-disabled ul.fancytree-container{opacity:.5;background-color:silver}#fancytree-drop-marker,span.fancytree-checkbox,span.fancytree-drag-helper-img,span.fancytree-empty,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio,span.fancytree-vline{width:16px;height:16px;display:inline-block;vertical-align:top;background-repeat:no-repeat;background-image:url(icons.gif);background-position:0 0}span.fancytree-checkbox,span.fancytree-custom-icon,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio{margin-top:2px}span.fancytree-custom-icon{display:inline-block;margin-left:3px}img.fancytree-icon{width:16px;height:16px;margin-left:3px;margin-top:2px;vertical-align:top;border-style:none}span.fancytree-expander{cursor:pointer}.fancytree-exp-n span.fancytree-expander,.fancytree-exp-nl span.fancytree-expander{background-image:none;cursor:default}.fancytree-exp-n span.fancytree-expander,.fancytree-exp-n span.fancytree-expander:hover{background-position:0 -64px}.fancytree-exp-nl span.fancytree-expander,.fancytree-exp-nl span.fancytree-expander:hover{background-position:-16px -64px}.fancytree-exp-c span.fancytree-expander{background-position:0 -80px}.fancytree-exp-c span.fancytree-expander:hover{background-position:-16px -80px}.fancytree-exp-cl span.fancytree-expander{background-position:0 -96px}.fancytree-exp-cl span.fancytree-expander:hover{background-position:-16px -96px}.fancytree-exp-cd span.fancytree-expander{background-position:-64px -80px}.fancytree-exp-cd span.fancytree-expander:hover{background-position:-80px -80px}.fancytree-exp-cdl span.fancytree-expander{background-position:-64px -96px}.fancytree-exp-cdl span.fancytree-expander:hover{background-position:-80px -96px}.fancytree-exp-e span.fancytree-expander,.fancytree-exp-ed span.fancytree-expander{background-position:-32px -80px}.fancytree-exp-e span.fancytree-expander:hover,.fancytree-exp-ed span.fancytree-expander:hover{background-position:-48px -80px}.fancytree-exp-edl span.fancytree-expander,.fancytree-exp-el span.fancytree-expander{background-position:-32px -96px}.fancytree-exp-edl span.fancytree-expander:hover,.fancytree-exp-el span.fancytree-expander:hover{background-position:-48px -96px}span.fancytree-checkbox{margin-left:3px;background-position:0 -32px}span.fancytree-checkbox:hover{background-position:-16px -32px}.fancytree-partsel span.fancytree-checkbox{background-position:-64px -32px}.fancytree-partsel span.fancytree-checkbox:hover{background-position:-80px -32px}.fancytree-selected span.fancytree-checkbox{background-position:-32px -32px}.fancytree-selected span.fancytree-checkbox:hover{background-position:-48px -32px}.fancytree-unselectable span.fancytree-checkbox{opacity:.4;filter:alpha(opacity=40)}.fancytree-unselectable span.fancytree-checkbox:hover{background-position:0 -32px}.fancytree-unselectable.fancytree-partsel span.fancytree-checkbox:hover{background-position:-64px -32px}.fancytree-unselectable.fancytree-selected span.fancytree-checkbox:hover{background-position:-32px -32px}.fancytree-radio span.fancytree-checkbox{background-position:0 -48px}.fancytree-radio span.fancytree-checkbox:hover{background-position:-16px -48px}.fancytree-radio .fancytree-partsel span.fancytree-checkbox{background-position:-64px -48px}.fancytree-radio .fancytree-partsel span.fancytree-checkbox:hover{background-position:-80px -48px}.fancytree-radio .fancytree-selected span.fancytree-checkbox{background-position:-32px -48px}.fancytree-radio .fancytree-selected span.fancytree-checkbox:hover{background-position:-48px -48px}.fancytree-radio .fancytree-unselectable span.fancytree-checkbox,.fancytree-radio .fancytree-unselectable span.fancytree-checkbox:hover{background-position:0 -48px}span.fancytree-icon{margin-left:3px;background-position:0 0}.fancytree-ico-c span.fancytree-icon:hover{background-position:-16px 0}.fancytree-has-children.fancytree-ico-c span.fancytree-icon{background-position:-32px 0}.fancytree-has-children.fancytree-ico-c span.fancytree-icon:hover{background-position:-48px 0}.fancytree-ico-e span.fancytree-icon{background-position:-64px 0}.fancytree-ico-e span.fancytree-icon:hover{background-position:-80px 0}.fancytree-ico-cf span.fancytree-icon{background-position:0 -16px}.fancytree-ico-cf span.fancytree-icon:hover{background-position:-16px -16px}.fancytree-has-children.fancytree-ico-cf span.fancytree-icon{background-position:-32px -16px}.fancytree-has-children.fancytree-ico-cf span.fancytree-icon:hover{background-position:-48px -16px}.fancytree-ico-ef span.fancytree-icon{background-position:-64px -16px}.fancytree-ico-ef span.fancytree-icon:hover{background-position:-80px -16px}.fancytree-loading span.fancytree-expander,.fancytree-loading span.fancytree-expander:hover,.fancytree-statusnode-wait span.fancytree-icon,.fancytree-statusnode-wait span.fancytree-icon:hover{background-image:url(data:image/gif;base64,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);background-position:0 0}.fancytree-statusnode-error span.fancytree-icon,.fancytree-statusnode-error span.fancytree-icon:hover{background-position:0 -112px}span.fancytree-node{display:inherit;width:100%;margin-top:0;min-height:20px}span.fancytree-title{color:#000;cursor:pointer;display:inline-block;vertical-align:top;min-height:20px;padding:0 3px;margin:0 0 0 3px;border:1px solid transparent;-webkit-border-radius:0;-moz-border-radius:0;-ms-border-radius:0;-o-border-radius:0;border-radius:0}span.fancytree-node.fancytree-error span.fancytree-title{color:red}div.fancytree-drag-helper span.fancytree-childcounter,div.fancytree-drag-helper span.fancytree-dnd-modifier{display:inline-block;color:#fff;background:#337ab7;border:1px solid gray;min-width:10px;height:10px;line-height:1;vertical-align:baseline;border-radius:10px;padding:2px;text-align:center;font-size:9px}div.fancytree-drag-helper span.fancytree-childcounter{position:absolute;top:-6px;right:-6px}div.fancytree-drag-helper span.fancytree-dnd-modifier{background:#5cb85c;border:0;font-weight:bolder}div.fancytree-drag-helper.fancytree-drop-accept span.fancytree-drag-helper-img{background-position:-32px -112px}div.fancytree-drag-helper.fancytree-drop-reject span.fancytree-drag-helper-img{background-position:-16px -112px}#fancytree-drop-marker{width:32px;position:absolute;background-position:0 -128px;margin:0}#fancytree-drop-marker.fancytree-drop-after,#fancytree-drop-marker.fancytree-drop-before{width:64px;background-position:0 -144px}#fancytree-drop-marker.fancytree-drop-copy{background-position:-64px -128px}#fancytree-drop-marker.fancytree-drop-move{background-position:-32px -128px}span.fancytree-drag-source.fancytree-drag-remove{opacity:.15}table.fancytree-ext-table{border-collapse:collapse}table.fancytree-ext-table span.fancytree-node{display:inline-block}table.fancytree-ext-columnview tbody tr td{position:relative;border:1px solid gray;vertical-align:top;overflow:auto}table.fancytree-ext-columnview tbody tr td>ul{padding:0}table.fancytree-ext-columnview tbody tr td>ul li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0}table.fancytree-ext-columnview span.fancytree-node{position:relative;display:inline-block}table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded{background-color:#CBE8F6}table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right{position:absolute;right:3px;background-position:0 -80px}table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right:hover{background-position:-16px -80px}.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title{color:silver;font-weight:lighter}.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title,.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title{color:#000;font-weight:400}.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title,.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title{color:#000;font-weight:700}.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide,.fancytree-ext-filter-hide tr.fancytree-hide{display:none}.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title,.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title{color:silver;font-weight:lighter}.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title,.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title{color:#000;font-weight:400}.fancytree-ext-childcounter span.fancytree-icon,.fancytree-ext-filter span.fancytree-icon{position:relative}.fancytree-ext-childcounter span.fancytree-childcounter,.fancytree-ext-filter span.fancytree-childcounter{color:#fff;background:#777;border:1px solid gray;position:absolute;top:-6px;right:-6px;min-width:10px;height:10px;line-height:1;vertical-align:baseline;border-radius:10px;padding:2px;text-align:center;font-size:9px}ul.fancytree-ext-wide{position:relative;min-width:100%;z-index:2;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}ul.fancytree-ext-wide span.fancytree-node>span{position:relative;z-index:2}ul.fancytree-ext-wide span.fancytree-node span.fancytree-title{position:absolute;z-index:1;left:0;width:100%;margin-left:0;margin-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.fancytree-plain span.fancytree-title{border:1px solid transparent}.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-focused span.fancytree-title{border-color:#39f}.fancytree-plain span.fancytree-active span.fancytree-title,.fancytree-plain span.fancytree-selected span.fancytree-title{background-color:#f7f7f7;border-color:#dedede}.fancytree-plain span.fancytree-node span.fancytree-selected span.fancytree-title{font-style:italic}.fancytree-plain span.fancytree-node:hover span.fancytree-title{background-color:#eff9fe;border-color:#70c0e7}.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-active span.fancytree-title,.fancytree-plain.fancytree-container.fancytree-treefocus span.fancytree-selected span.fancytree-title{background-color:#cbe8f6;border-color:#26a0da}table.fancytree-ext-table tbody tr td{border:1px solid #EDEDED}table.fancytree-ext-table tbody span.fancytree-node,table.fancytree-ext-table tbody span.fancytree-node:hover{border:0;background:0 0}table.fancytree-ext-table tbody tr:hover{background-color:#E5F3FB;outline:1px solid #70C0E7}table.fancytree-ext-table tbody tr.fancytree-focused span.fancytree-title{outline:1px dotted #000}table.fancytree-ext-table tbody tr.fancytree-active:hover,table.fancytree-ext-table tbody tr.fancytree-selected:hover{background-color:#CBE8F6;outline:1px solid #26A0DA}table.fancytree-ext-table tbody tr.fancytree-active{background-color:#F7F7F7;outline:1px solid #DEDEDE}table.fancytree-ext-table tbody tr.fancytree-selected{background-color:#F7F7F7}table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-active{background-color:#CBE8F6;outline:1px solid #26A0DA}table.fancytree-ext-table.fancytree-treefocus tbody tr.fancytree-selected{background-color:#CBE8F6} \ No newline at end of file diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/icons-rtl.gif b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/icons-rtl.gif new file mode 100644 index 0000000000000000000000000000000000000000..a29b5fbc967378b8665df3513f4d8cf648f73809 GIT binary patch literal 4046 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 literal 0 HcmV?d00001 diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/icons.gif b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/icons.gif new file mode 100644 index 0000000000000000000000000000000000000000..a58eb93f12a2c63382d6b47f070fa03ffec7fd5f GIT binary patch literal 4041 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 literal 0 HcmV?d00001 diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/loading.gif b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..251df0544cd63db56160b5a53c9e203999a561e6 GIT binary patch literal 570 zcmZ?wbhEHb6krfwSj5Tz21}is{<pOJKX&XGgbySY|8x7fh6Fo12DlpO889<~gnqKH zaxt(n=ztV~v@<YkMeMq>PSHlpTQ%ic>s*20?KO#JbB`J<SafRE3uUX~K;!MauT|%p z?~hPsL}+JZU}E5AU<Ya!iO>oX<Xg8aNpf*k>-PVwjtvhv)DQ}p7#JCNfEF?^3rDO{ z`kg!_%&DO$()C1j*!N6FCWJZ`pgL{_4xl=*2&=_$Eh1qp1s`u759OHqxi!UnQaqAU zcA!#rpkkoi9wBF<l1;?Yg%2g2j(iYr&YI|qWH%Skk*q-5!3x*>Np|>|CHN@uv{OZ# zV43`6q`+WjU;$bUHZfwA%kH-)E!nmfb1nSIbx^$N(G(<wEMSWv-rnVX<ibJE(-K!7 z3Cs}S4)3@>2}vOn0~gfWLK1;@d|WKqXXYeZXu6yfzU<41@HNCEU|$23t=045OkcT; z;~__8v>{Kcdao~%ubF^ug!o!mBJj*D13gJ?VWlK%w>PYgE=fr0KrsXHv~Yyf!lUbT TUrrHtcg?o#wX~xJP@OdZ_UVjb literal 0 HcmV?d00001 diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/ui.fancytree.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/ui.fancytree.css new file mode 100644 index 00000000000..e582778282c --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/ui.fancytree.css @@ -0,0 +1,562 @@ +/*! + * Fancytree "XP" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ +/******************************************************************************* + * Common Styles for Fancytree Skins. + * + * This section is automatically generated from the `skin-common.less` template. + ******************************************************************************/ +/*------------------------------------------------------------------------------ + * Helpers + *----------------------------------------------------------------------------*/ +.ui-helper-hidden { + display: none; +} +/*------------------------------------------------------------------------------ + * Container and UL / LI + *----------------------------------------------------------------------------*/ +ul.fancytree-container { + font-family: tahoma, arial, helvetica; + font-size: 10pt; + white-space: nowrap; + padding: 3px; + margin: 0; + background-color: white; + border: 1px dotted gray; + overflow: auto; + min-height: 0%; + position: relative; +} +ul.fancytree-container ul { + padding: 0 0 0 16px; + margin: 0; +} +ul.fancytree-container li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0px 0px; + background-repeat: repeat-y; + background-image: none; + margin: 0; +} +ul.fancytree-container li.fancytree-lastsib { + background-image: none; +} +ul.fancytree-no-connector > li { + background-image: none; +} +.ui-fancytree-disabled ul.fancytree-container { + opacity: 0.5; + background-color: silver; +} +/*------------------------------------------------------------------------------ + * Common icon definitions + *----------------------------------------------------------------------------*/ +span.fancytree-empty, +span.fancytree-vline, +span.fancytree-expander, +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-radio, +span.fancytree-drag-helper-img, +#fancytree-drop-marker { + width: 16px; + height: 16px; + display: inline-block; + vertical-align: top; + background-repeat: no-repeat; + background-position: left; + background-image: url("icons.gif"); + background-position: 0px 0px; +} +span.fancytree-icon, +span.fancytree-checkbox, +span.fancytree-expander, +span.fancytree-radio, +span.fancytree-custom-icon { + margin-top: 0px; +} +/* Used by iconclass option and iconClass callback: */ +span.fancytree-custom-icon { + display: inline-block; + margin-left: 3px; +} +/* Used by 'icon' node option: */ +img.fancytree-icon { + width: 16px; + height: 16px; + margin-left: 3px; + margin-top: 0px; + vertical-align: top; + border-style: none; +} +/*------------------------------------------------------------------------------ + * Expander icon + * + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-exp- + * 1st character: 'e': expanded, 'c': collapsed, 'n': no children + * 2nd character (optional): 'd': lazy (Delayed) + * 3rd character (optional): 'l': Last sibling + *----------------------------------------------------------------------------*/ +span.fancytree-expander { + cursor: pointer; +} +.fancytree-exp-n span.fancytree-expander, +.fancytree-exp-nl span.fancytree-expander { + cursor: default; +} +.fancytree-exp-n span.fancytree-expander, +.fancytree-exp-n span.fancytree-expander:hover { + background-position: 0px -64px; +} +.fancytree-exp-nl span.fancytree-expander, +.fancytree-exp-nl span.fancytree-expander:hover { + background-position: -16px -64px; +} +.fancytree-exp-c span.fancytree-expander { + background-position: 0px -80px; +} +.fancytree-exp-c span.fancytree-expander:hover { + background-position: -16px -80px; +} +.fancytree-exp-cl span.fancytree-expander { + background-position: 0px -96px; +} +.fancytree-exp-cl span.fancytree-expander:hover { + background-position: -16px -96px; +} +.fancytree-exp-cd span.fancytree-expander { + background-position: -64px -80px; +} +.fancytree-exp-cd span.fancytree-expander:hover { + background-position: -80px -80px; +} +.fancytree-exp-cdl span.fancytree-expander { + background-position: -64px -96px; +} +.fancytree-exp-cdl span.fancytree-expander:hover { + background-position: -80px -96px; +} +.fancytree-exp-e span.fancytree-expander, +.fancytree-exp-ed span.fancytree-expander { + background-position: -32px -80px; +} +.fancytree-exp-e span.fancytree-expander:hover, +.fancytree-exp-ed span.fancytree-expander:hover { + background-position: -48px -80px; +} +.fancytree-exp-el span.fancytree-expander, +.fancytree-exp-edl span.fancytree-expander { + background-position: -32px -96px; +} +.fancytree-exp-el span.fancytree-expander:hover, +.fancytree-exp-edl span.fancytree-expander:hover { + background-position: -48px -96px; +} +/*------------------------------------------------------------------------------ + * Checkbox icon + *----------------------------------------------------------------------------*/ +span.fancytree-checkbox { + margin-left: 3px; + background-position: 0px -32px; +} +span.fancytree-checkbox:hover { + background-position: -16px -32px; +} +.fancytree-partsel span.fancytree-checkbox { + background-position: -64px -32px; +} +.fancytree-partsel span.fancytree-checkbox:hover { + background-position: -80px -32px; +} +.fancytree-selected span.fancytree-checkbox { + background-position: -32px -32px; +} +.fancytree-selected span.fancytree-checkbox:hover { + background-position: -48px -32px; +} +.fancytree-unselectable span.fancytree-checkbox { + opacity: 0.4; + filter: alpha(opacity=40); +} +.fancytree-unselectable span.fancytree-checkbox:hover { + background-position: 0px -32px; +} +.fancytree-unselectable.fancytree-partsel span.fancytree-checkbox:hover { + background-position: -64px -32px; +} +.fancytree-unselectable.fancytree-selected span.fancytree-checkbox:hover { + background-position: -32px -32px; +} +/*------------------------------------------------------------------------------ + * Radiobutton icon + * This is a customization, that may be activated by overriding the 'checkbox' + * class name as 'fancytree-radio' in the tree options. + *----------------------------------------------------------------------------*/ +.fancytree-radio span.fancytree-checkbox { + background-position: 0px -48px; +} +.fancytree-radio span.fancytree-checkbox:hover { + background-position: -16px -48px; +} +.fancytree-radio .fancytree-partsel span.fancytree-checkbox { + background-position: -64px -48px; +} +.fancytree-radio .fancytree-partsel span.fancytree-checkbox:hover { + background-position: -80px -48px; +} +.fancytree-radio .fancytree-selected span.fancytree-checkbox { + background-position: -32px -48px; +} +.fancytree-radio .fancytree-selected span.fancytree-checkbox:hover { + background-position: -48px -48px; +} +.fancytree-radio .fancytree-unselectable span.fancytree-checkbox, +.fancytree-radio .fancytree-unselectable span.fancytree-checkbox:hover { + background-position: 0px -48px; +} +/*------------------------------------------------------------------------------ + * Node type icon + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: fancytree-ico- + * 1st character: 'e': expanded, 'c': collapsed + * 2nd character (optional): 'f': folder + *----------------------------------------------------------------------------*/ +span.fancytree-icon { + margin-left: 3px; + background-position: 0px 0px; +} +/* Documents */ +.fancytree-ico-c span.fancytree-icon:hover { + background-position: -16px 0px; +} +.fancytree-has-children.fancytree-ico-c span.fancytree-icon { + background-position: -32px 0px; +} +.fancytree-has-children.fancytree-ico-c span.fancytree-icon:hover { + background-position: -48px 0px; +} +.fancytree-ico-e span.fancytree-icon { + background-position: -64px 0px; +} +.fancytree-ico-e span.fancytree-icon:hover { + background-position: -80px 0px; +} +/* Folders */ +.fancytree-ico-cf span.fancytree-icon { + background-position: 0px -16px; +} +.fancytree-ico-cf span.fancytree-icon:hover { + background-position: -16px -16px; +} +.fancytree-has-children.fancytree-ico-cf span.fancytree-icon { + background-position: -32px -16px; +} +.fancytree-has-children.fancytree-ico-cf span.fancytree-icon:hover { + background-position: -48px -16px; +} +.fancytree-ico-ef span.fancytree-icon { + background-position: -64px -16px; +} +.fancytree-ico-ef span.fancytree-icon:hover { + background-position: -80px -16px; +} +.fancytree-loading span.fancytree-expander, +.fancytree-loading span.fancytree-expander:hover, +.fancytree-statusnode-wait span.fancytree-icon, +.fancytree-statusnode-wait span.fancytree-icon:hover { + background-image: url('data:image/gif;base64,R0lGODlhEAAQAKIFAAAAAAAApUJC/4SE/8bGxgAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgAFACwAAAAAEAAQAAADKli63K4hPBZLJWTWhZ0QU7d8YTadxTCgosqa6CM6c1Eztw3rJZ83v1gjAQAh+QQFCgAFACwBAAIACwAHAAADFFgqUhEOrqZiGaNqhbf/BUGA4QgmACH5BAUKAAUALAIAAQAMAAUAAAMTWKoi+2OUVkKAcllFyHtW92lBAgAh+QQFCgAFACwEAAEACwAIAAADFlg6o16EFFaEcPHZx1UInfOFZDeSXwIAIfkEBQoABQAsBwABAAcACwAAAxRIVMxaYzQWZxPCYstZ4F83BWFDJgAh+QQFCgAFACwKAAIABQAMAAADFEhUrPxjQPlqEeJhy0J4XhF2H5MAACH5BAUKAAUALAcABAAIAAsAAAMUWKpEu+3JOQa1cwqh+QrBF4LilAAAIfkEBQoABQAsBAAHAAsABwAAAxRYukvE0MFJyxjV4hCYEAtXiN+SAAAh+QQFCgAFACwCAAoADAAFAAADEhhR3ExEOQeZbGM4KUTJE9NNCQAh+QQFCgAFACwBAAcACwAIAAADFhhR3K0uSglnqbYI4QhpWzEMhSeNTQIAIfkEBQoABQAsAgAEAAcACwAAAxMYUczaMC4ZKxMiYjtG7AVBRGICACH5BAUKAAUALAEAAgAFAAwAAAMTWBqhxa8t6ZQQ7tY9husbQThiAgA7'); + background-position: 0px 0px; +} +/* Status node icons */ +.fancytree-statusnode-error span.fancytree-icon, +.fancytree-statusnode-error span.fancytree-icon:hover { + background-position: 0px -112px; +} +/*------------------------------------------------------------------------------ + * Node titles and highlighting + *----------------------------------------------------------------------------*/ +span.fancytree-node { + /* See #117 */ + display: inherit; + width: 100%; + margin-top: 1px; + min-height: 16px; +} +span.fancytree-title { + color: #000000; + cursor: pointer; + display: inline-block; + vertical-align: top; + min-height: 16px; + padding: 0 3px 0 3px; + margin: 0px 0 0 3px; + border: 0 solid transparent; + -webkit-border-radius: 0px; + -moz-border-radius: 0px; + -ms-border-radius: 0px; + -o-border-radius: 0px; + border-radius: 0px; +} +span.fancytree-node.fancytree-error span.fancytree-title { + color: #ff0000; +} +/*------------------------------------------------------------------------------ + * Drag'n'drop support + *----------------------------------------------------------------------------*/ +div.fancytree-drag-helper span.fancytree-childcounter, +div.fancytree-drag-helper span.fancytree-dnd-modifier { + display: inline-block; + color: #fff; + background: #337ab7; + border: 1px solid gray; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +div.fancytree-drag-helper span.fancytree-childcounter { + position: absolute; + top: -6px; + right: -6px; +} +div.fancytree-drag-helper span.fancytree-dnd-modifier { + background: #5cb85c; + border: none; + font-weight: bolder; +} +div.fancytree-drag-helper.fancytree-drop-accept span.fancytree-drag-helper-img { + background-position: -32px -112px; +} +div.fancytree-drag-helper.fancytree-drop-reject span.fancytree-drag-helper-img { + background-position: -16px -112px; +} +/*** Drop marker icon *********************************************************/ +#fancytree-drop-marker { + width: 32px; + position: absolute; + background-position: 0px -128px; + margin: 0; +} +#fancytree-drop-marker.fancytree-drop-after, +#fancytree-drop-marker.fancytree-drop-before { + width: 64px; + background-position: 0px -144px; +} +#fancytree-drop-marker.fancytree-drop-copy { + background-position: -64px -128px; +} +#fancytree-drop-marker.fancytree-drop-move { + background-position: -32px -128px; +} +/*** Source node while dragging ***********************************************/ +span.fancytree-drag-source.fancytree-drag-remove { + opacity: 0.15; +} +/*** Target node while dragging cursor is over it *****************************/ +/*------------------------------------------------------------------------------ + * 'table' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-table { + border-collapse: collapse; +} +table.fancytree-ext-table span.fancytree-node { + display: inline-block; +} +/*------------------------------------------------------------------------------ + * 'columnview' extension + *----------------------------------------------------------------------------*/ +table.fancytree-ext-columnview tbody tr td { + position: relative; + border: 1px solid gray; + vertical-align: top; + overflow: auto; +} +table.fancytree-ext-columnview tbody tr td > ul { + padding: 0; +} +table.fancytree-ext-columnview tbody tr td > ul li { + list-style-image: none; + list-style-position: outside; + list-style-type: none; + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background-attachment: scroll; + background-color: transparent; + background-position: 0px 0px; + background-repeat: repeat-y; + background-image: none; + /* no v-lines */ + margin: 0; +} +table.fancytree-ext-columnview span.fancytree-node { + position: relative; + /* allow positioning of embedded spans */ + display: inline-block; +} +table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded { + background-color: #CBE8F6; +} +table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right { + position: absolute; + right: 3px; + background-position: 0px -80px; +} +table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right:hover { + background-position: -16px -80px; +} +/*------------------------------------------------------------------------------ + * 'filter' extension + *----------------------------------------------------------------------------*/ +.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title { + color: #c0c0c0; + font-weight: lighter; +} +.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: bold; +} +.fancytree-ext-filter-hide tr.fancytree-hide, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide { + display: none; +} +.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title { + color: #c0c0c0; + font-weight: lighter; +} +.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title, +.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title { + color: black; + font-weight: normal; +} +.fancytree-ext-childcounter span.fancytree-icon, +.fancytree-ext-filter span.fancytree-icon { + position: relative; +} +.fancytree-ext-childcounter span.fancytree-childcounter, +.fancytree-ext-filter span.fancytree-childcounter { + color: #fff; + background: #777; + border: 1px solid gray; + position: absolute; + top: -6px; + right: -6px; + min-width: 10px; + height: 10px; + line-height: 1; + vertical-align: baseline; + border-radius: 10px; + padding: 2px; + text-align: center; + font-size: 9px; +} +/*------------------------------------------------------------------------------ + * 'wide' extension + *----------------------------------------------------------------------------*/ +ul.fancytree-ext-wide { + position: relative; + min-width: 100%; + z-index: 2; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +ul.fancytree-ext-wide span.fancytree-node > span { + position: relative; + z-index: 2; +} +ul.fancytree-ext-wide span.fancytree-node span.fancytree-title { + position: absolute; + z-index: 1; + left: 0px; + width: 100%; + margin-left: 0; + margin-right: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +/******************************************************************************* + * Styles specific to this skin. + * + * This section is automatically generated from the `ui-fancytree.less` template. + ******************************************************************************/ +/******************************************************************************* + * Tree container + */ +ul.fancytree-container li { + background-image: url("vline.gif"); + background-position: 0 0; +} +ul.fancytree-container li.fancytree-lastsib { + background-image: none; +} +ul.fancytree-no-connector > li { + background-image: none; +} +/******************************************************************************* + * Node titles + */ +span.fancytree-title { + border: 0 solid transparent; +} +span.fancytree-title:hover { + background-color: #F2F7FD; + border-color: #B8D6FB; +} +span.fancytree-focused span.fancytree-title { + outline: 1px dotted black; + background-color: #EFEBDE; +} +.fancytree-folder span.fancytree-title { + font-weight: bold; +} +.fancytree-selected span.fancytree-title { + color: green; + font-style: italic; +} +.fancytree-active span.fancytree-title { + background-color: #3169C6 !important; + color: white !important; +} +/******************************************************************************* + * 'table' extension + */ +table.fancytree-ext-table { + border-collapse: collapse; +} +table.fancytree-ext-table tbody tr.fancytree-focused { + background-color: #99DEFD; +} +table.fancytree-ext-table tbody tr.fancytree-active { + background-color: royalblue; +} +table.fancytree-ext-table tbody tr.fancytree-selected { + background-color: #99FDDE; +} diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/ui.fancytree.less b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/ui.fancytree.less new file mode 100644 index 00000000000..71aab080514 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/ui.fancytree.less @@ -0,0 +1,96 @@ +/*! + * Fancytree "XP" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */ + +// Import common styles +@import "../skin-common.less"; + + +/******************************************************************************* + * Styles specific to this skin. + * + * This section is automatically generated from the `ui-fancytree.less` template. + ******************************************************************************/ + +// Override the variable after the import. +// NOTE: Variables are always resolved as the last definition, even if it is +// after where it is used. +@fancy-use-sprites: true; // false: suppress all background images (i.e. icons) +@fancy-hide-connectors: false; // true: show vertical connector lines + +@fancy-icon-width: 16px; +@fancy-icon-height: 16px; +@fancy-icon-spacing: 3px; +@fancy-node-border-width: 0; + +// Use 'data-uri(...)' to embed the image into CSS instead of linking to 'loading.gif': +@fancy-loading-url: data-uri("@{fancy-image-dir}/loading.gif"); +// Set to `true` to use `data-uri(...)` which will embed icons.gif into CSS +// instead of linking to that file: +// @fancy-inline-sprites: true; + + +/******************************************************************************* + * Tree container + */ +ul.fancytree-container { + li { + background-image: url("vline.gif"); + background-position: 0 0; + } + // Suppress lines for last child node + li.fancytree-lastsib { + background-image: none; + } +} +// Suppress lines if level is fixed expanded (option minExpandLevel) +ul.fancytree-no-connector > li { + background-image: none; +} + +/******************************************************************************* + * Node titles + */ + +span.fancytree-title { + border: @fancy-node-border-width solid transparent; // avoid jumping, when a border is added on hover +} +span.fancytree-title:hover { + background-color: #F2F7FD; // light blue + border-color: #B8D6FB; // darker light blue +} +span.fancytree-focused span.fancytree-title { + outline: 1px dotted black; + background-color: #EFEBDE; // gray +} +.fancytree-folder span.fancytree-title { + font-weight: bold; +} +.fancytree-selected span.fancytree-title { + color: green; + font-style: italic; +} +.fancytree-active span.fancytree-title { + background-color: #3169C6 !important; + color: white !important; // @ IE6 +} + +/******************************************************************************* + * 'table' extension + */ +table.fancytree-ext-table { + border-collapse: collapse; + tbody tr.fancytree-focused { + background-color: #99DEFD; + } + tbody tr.fancytree-active { + background-color: royalblue; + } + tbody tr.fancytree-selected { + background-color: #99FDDE; + } +} + diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/ui.fancytree.min.css b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/ui.fancytree.min.css new file mode 100644 index 00000000000..3b24c0a784f --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/ui.fancytree.min.css @@ -0,0 +1,6 @@ +/*! + * Fancytree "XP" skin. + * + * DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from + * the LESS templates. + */.ui-helper-hidden{display:none}ul.fancytree-container{font-family:tahoma,arial,helvetica;font-size:10pt;white-space:nowrap;padding:3px;margin:0;background-color:#fff;border:1px dotted gray;overflow:auto;min-height:0;position:relative}ul.fancytree-container ul{padding:0 0 0 16px;margin:0}ul.fancytree-container li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-repeat:repeat-y;margin:0}.ui-fancytree-disabled ul.fancytree-container{opacity:.5;background-color:silver}#fancytree-drop-marker,span.fancytree-checkbox,span.fancytree-drag-helper-img,span.fancytree-empty,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio,span.fancytree-vline{width:16px;height:16px;display:inline-block;vertical-align:top;background-repeat:no-repeat;background-image:url(icons.gif);background-position:0 0}span.fancytree-checkbox,span.fancytree-custom-icon,span.fancytree-expander,span.fancytree-icon,span.fancytree-radio{margin-top:0}span.fancytree-custom-icon{display:inline-block;margin-left:3px}img.fancytree-icon{width:16px;height:16px;margin-left:3px;margin-top:0;vertical-align:top;border-style:none}span.fancytree-expander{cursor:pointer}.fancytree-exp-n span.fancytree-expander,.fancytree-exp-nl span.fancytree-expander{cursor:default}.fancytree-exp-n span.fancytree-expander,.fancytree-exp-n span.fancytree-expander:hover{background-position:0 -64px}.fancytree-exp-nl span.fancytree-expander,.fancytree-exp-nl span.fancytree-expander:hover{background-position:-16px -64px}.fancytree-exp-c span.fancytree-expander{background-position:0 -80px}.fancytree-exp-c span.fancytree-expander:hover{background-position:-16px -80px}.fancytree-exp-cl span.fancytree-expander{background-position:0 -96px}.fancytree-exp-cl span.fancytree-expander:hover{background-position:-16px -96px}.fancytree-exp-cd span.fancytree-expander{background-position:-64px -80px}.fancytree-exp-cd span.fancytree-expander:hover{background-position:-80px -80px}.fancytree-exp-cdl span.fancytree-expander{background-position:-64px -96px}.fancytree-exp-cdl span.fancytree-expander:hover{background-position:-80px -96px}.fancytree-exp-e span.fancytree-expander,.fancytree-exp-ed span.fancytree-expander{background-position:-32px -80px}.fancytree-exp-e span.fancytree-expander:hover,.fancytree-exp-ed span.fancytree-expander:hover{background-position:-48px -80px}.fancytree-exp-edl span.fancytree-expander,.fancytree-exp-el span.fancytree-expander{background-position:-32px -96px}.fancytree-exp-edl span.fancytree-expander:hover,.fancytree-exp-el span.fancytree-expander:hover{background-position:-48px -96px}span.fancytree-checkbox{margin-left:3px;background-position:0 -32px}span.fancytree-checkbox:hover{background-position:-16px -32px}.fancytree-partsel span.fancytree-checkbox{background-position:-64px -32px}.fancytree-partsel span.fancytree-checkbox:hover{background-position:-80px -32px}.fancytree-selected span.fancytree-checkbox{background-position:-32px -32px}.fancytree-selected span.fancytree-checkbox:hover{background-position:-48px -32px}.fancytree-unselectable span.fancytree-checkbox{opacity:.4;filter:alpha(opacity=40)}.fancytree-unselectable span.fancytree-checkbox:hover{background-position:0 -32px}.fancytree-unselectable.fancytree-partsel span.fancytree-checkbox:hover{background-position:-64px -32px}.fancytree-unselectable.fancytree-selected span.fancytree-checkbox:hover{background-position:-32px -32px}.fancytree-radio span.fancytree-checkbox{background-position:0 -48px}.fancytree-radio span.fancytree-checkbox:hover{background-position:-16px -48px}.fancytree-radio .fancytree-partsel span.fancytree-checkbox{background-position:-64px -48px}.fancytree-radio .fancytree-partsel span.fancytree-checkbox:hover{background-position:-80px -48px}.fancytree-radio .fancytree-selected span.fancytree-checkbox{background-position:-32px -48px}.fancytree-radio .fancytree-selected span.fancytree-checkbox:hover{background-position:-48px -48px}.fancytree-radio .fancytree-unselectable span.fancytree-checkbox,.fancytree-radio .fancytree-unselectable span.fancytree-checkbox:hover{background-position:0 -48px}span.fancytree-icon{margin-left:3px;background-position:0 0}.fancytree-ico-c span.fancytree-icon:hover{background-position:-16px 0}.fancytree-has-children.fancytree-ico-c span.fancytree-icon{background-position:-32px 0}.fancytree-has-children.fancytree-ico-c span.fancytree-icon:hover{background-position:-48px 0}.fancytree-ico-e span.fancytree-icon{background-position:-64px 0}.fancytree-ico-e span.fancytree-icon:hover{background-position:-80px 0}.fancytree-ico-cf span.fancytree-icon{background-position:0 -16px}.fancytree-ico-cf span.fancytree-icon:hover{background-position:-16px -16px}.fancytree-has-children.fancytree-ico-cf span.fancytree-icon{background-position:-32px -16px}.fancytree-has-children.fancytree-ico-cf span.fancytree-icon:hover{background-position:-48px -16px}.fancytree-ico-ef span.fancytree-icon{background-position:-64px -16px}.fancytree-ico-ef span.fancytree-icon:hover{background-position:-80px -16px}.fancytree-loading span.fancytree-expander,.fancytree-loading span.fancytree-expander:hover,.fancytree-statusnode-wait span.fancytree-icon,.fancytree-statusnode-wait span.fancytree-icon:hover{background-image:url(data:image/gif;base64,R0lGODlhEAAQAKIFAAAAAAAApUJC/4SE/8bGxgAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgAFACwAAAAAEAAQAAADKli63K4hPBZLJWTWhZ0QU7d8YTadxTCgosqa6CM6c1Eztw3rJZ83v1gjAQAh+QQFCgAFACwBAAIACwAHAAADFFgqUhEOrqZiGaNqhbf/BUGA4QgmACH5BAUKAAUALAIAAQAMAAUAAAMTWKoi+2OUVkKAcllFyHtW92lBAgAh+QQFCgAFACwEAAEACwAIAAADFlg6o16EFFaEcPHZx1UInfOFZDeSXwIAIfkEBQoABQAsBwABAAcACwAAAxRIVMxaYzQWZxPCYstZ4F83BWFDJgAh+QQFCgAFACwKAAIABQAMAAADFEhUrPxjQPlqEeJhy0J4XhF2H5MAACH5BAUKAAUALAcABAAIAAsAAAMUWKpEu+3JOQa1cwqh+QrBF4LilAAAIfkEBQoABQAsBAAHAAsABwAAAxRYukvE0MFJyxjV4hCYEAtXiN+SAAAh+QQFCgAFACwCAAoADAAFAAADEhhR3ExEOQeZbGM4KUTJE9NNCQAh+QQFCgAFACwBAAcACwAIAAADFhhR3K0uSglnqbYI4QhpWzEMhSeNTQIAIfkEBQoABQAsAgAEAAcACwAAAxMYUczaMC4ZKxMiYjtG7AVBRGICACH5BAUKAAUALAEAAgAFAAwAAAMTWBqhxa8t6ZQQ7tY9husbQThiAgA7);background-position:0 0}.fancytree-statusnode-error span.fancytree-icon,.fancytree-statusnode-error span.fancytree-icon:hover{background-position:0 -112px}span.fancytree-node{display:inherit;width:100%;margin-top:1px;min-height:16px}span.fancytree-title{color:#000;cursor:pointer;display:inline-block;vertical-align:top;min-height:16px;padding:0 3px;margin:0 0 0 3px;-webkit-border-radius:0;-moz-border-radius:0;-ms-border-radius:0;-o-border-radius:0;border-radius:0}span.fancytree-node.fancytree-error span.fancytree-title{color:red}div.fancytree-drag-helper span.fancytree-childcounter,div.fancytree-drag-helper span.fancytree-dnd-modifier{display:inline-block;color:#fff;background:#337ab7;border:1px solid gray;min-width:10px;height:10px;line-height:1;vertical-align:baseline;border-radius:10px;padding:2px;text-align:center;font-size:9px}div.fancytree-drag-helper span.fancytree-childcounter{position:absolute;top:-6px;right:-6px}div.fancytree-drag-helper span.fancytree-dnd-modifier{background:#5cb85c;border:0;font-weight:bolder}div.fancytree-drag-helper.fancytree-drop-accept span.fancytree-drag-helper-img{background-position:-32px -112px}div.fancytree-drag-helper.fancytree-drop-reject span.fancytree-drag-helper-img{background-position:-16px -112px}#fancytree-drop-marker{width:32px;position:absolute;background-position:0 -128px;margin:0}#fancytree-drop-marker.fancytree-drop-after,#fancytree-drop-marker.fancytree-drop-before{width:64px;background-position:0 -144px}#fancytree-drop-marker.fancytree-drop-copy{background-position:-64px -128px}#fancytree-drop-marker.fancytree-drop-move{background-position:-32px -128px}span.fancytree-drag-source.fancytree-drag-remove{opacity:.15}table.fancytree-ext-table span.fancytree-node{display:inline-block}table.fancytree-ext-columnview tbody tr td{position:relative;border:1px solid gray;vertical-align:top;overflow:auto}table.fancytree-ext-columnview tbody tr td>ul{padding:0}table.fancytree-ext-columnview tbody tr td>ul li{list-style-image:none;list-style-position:outside;list-style-type:none;-moz-background-clip:border;-moz-background-inline-policy:continuous;-moz-background-origin:padding;background-attachment:scroll;background-color:transparent;background-position:0 0;background-repeat:repeat-y;background-image:none;margin:0}table.fancytree-ext-columnview span.fancytree-node{position:relative;display:inline-block}table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded{background-color:#CBE8F6}table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right{position:absolute;right:3px;background-position:0 -80px}table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right:hover{background-position:-16px -80px}.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title{color:silver;font-weight:lighter}.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title,.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title{color:#000;font-weight:400}.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title,.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title{color:#000;font-weight:700}.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide,.fancytree-ext-filter-hide tr.fancytree-hide{display:none}.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title,.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title{color:silver;font-weight:lighter}.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title,.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title{color:#000;font-weight:400}.fancytree-ext-childcounter span.fancytree-icon,.fancytree-ext-filter span.fancytree-icon{position:relative}.fancytree-ext-childcounter span.fancytree-childcounter,.fancytree-ext-filter span.fancytree-childcounter{color:#fff;background:#777;border:1px solid gray;position:absolute;top:-6px;right:-6px;min-width:10px;height:10px;line-height:1;vertical-align:baseline;border-radius:10px;padding:2px;text-align:center;font-size:9px}ul.fancytree-ext-wide{position:relative;min-width:100%;z-index:2;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}ul.fancytree-ext-wide span.fancytree-node>span{position:relative;z-index:2}ul.fancytree-ext-wide span.fancytree-node span.fancytree-title{position:absolute;z-index:1;left:0;width:100%;margin-left:0;margin-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}ul.fancytree-container li{background-image:url(vline.gif);background-position:0 0}ul.fancytree-container li.fancytree-lastsib,ul.fancytree-no-connector>li{background-image:none}span.fancytree-title{border:0 solid transparent}span.fancytree-title:hover{background-color:#F2F7FD;border-color:#B8D6FB}span.fancytree-focused span.fancytree-title{outline:1px dotted #000;background-color:#EFEBDE}.fancytree-folder span.fancytree-title{font-weight:700}.fancytree-selected span.fancytree-title{color:green;font-style:italic}.fancytree-active span.fancytree-title{background-color:#3169C6!important;color:#fff!important}table.fancytree-ext-table{border-collapse:collapse}table.fancytree-ext-table tbody tr.fancytree-focused{background-color:#99DEFD}table.fancytree-ext-table tbody tr.fancytree-active{background-color:#4169e1}table.fancytree-ext-table tbody tr.fancytree-selected{background-color:#99FDDE} \ No newline at end of file diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/vline-rtl.gif b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/vline-rtl.gif new file mode 100644 index 0000000000000000000000000000000000000000..0400cb3eeace6abda62ae41957f3e41907a3aa6b GIT binary patch literal 842 zcmZ?wbhEHb6krfw_|5<V4Pe{=rW$~}hK2(`aOc3XQy>2S|G#wUQXn}BMnhnzhQRL+ z3l=PCXlVEkOy~a@{(~tX4P*g<;!hSv28MqOIzUNaju2pA;817y%PHgWLGEBPhp^U{ h^n!(l+j-@^TqFt?xweTLhn?Y=xcF$VBr_9(H2~DE@*DsF literal 0 HcmV?d00001 diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/vline.gif b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/skin-xp/vline.gif new file mode 100644 index 0000000000000000000000000000000000000000..1b00ae50e0f1538d985811207b0af2a85d1d128b GIT binary patch literal 844 zcmZ?wbhEHb6krfw_|5<V4Pe{=rW$~}hK2(`aOc3XQy>2S|G#wUQXn}BMnhnzhQRL+ z3l=PCXlVEkOy~a@{(~tX4P*g<;!hSv28MqOIzUNaju2pA;Lv3F%PCTkzu;gqhp>{) jiVX`7H}c4P#aL`ybg)BAJ?YGk0_Edva`s$291PX~%%k&- literal 0 HcmV?d00001 diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.childcounter.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.childcounter.js new file mode 100644 index 00000000000..2f2e0e04b9e --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.childcounter.js @@ -0,0 +1,208 @@ +// Extending Fancytree +// =================== +// +// See also the [live demo](http://wwwendt.de/tech/fancytree/demo/sample-ext-childcounter.html) of this code. +// +// Every extension should have a comment header containing some information +// about the author, copyright and licensing. Also a pointer to the latest +// source code. +// Prefix with `/*!` so the comment is not removed by the minifier. + +/*! + * jquery.fancytree.childcounter.js + * + * Add a child counter bubble to tree nodes. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +// To keep the global namespace clean, we wrap everything in a closure + +;(function($, undefined) { + +// Consider to use [strict mode](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) +"use strict"; + +// The [coding guidelines](http://contribute.jquery.org/style-guide/js/) +// require jshint compliance. +// But for this sample, we want to allow unused variables for demonstration purpose. + +/*jshint unused:false */ + + +// Adding methods +// -------------- + +// New member functions can be added to the `Fancytree` class. +// This function will be available for every tree instance: +// +// var tree = $("#tree").fancytree("getTree"); +// tree.countSelected(false); + +$.ui.fancytree._FancytreeClass.prototype.countSelected = function(topOnly){ + var tree = this, + treeOptions = tree.options; + + return tree.getSelectedNodes(topOnly).length; +}; + + +// The `FancytreeNode` class can also be easily extended. This would be called +// like +// node.updateCounters(); +// +// It is also good practice to add a docstring comment. +/** + * [ext-childcounter] Update counter badges for `node` and its parents. + * May be called in the `loadChildren` event, to update parents of lazy loaded + * nodes. + * @alias FancytreeNode#updateCounters + * @requires jquery.fancytree.childcounters.js + */ +$.ui.fancytree._FancytreeNodeClass.prototype.updateCounters = function(){ + var node = this, + $badge = $("span.fancytree-childcounter", node.span), + extOpts = node.tree.options.childcounter, + count = node.countChildren(extOpts.deep); + + node.data.childCounter = count; + if( (count || !extOpts.hideZeros) && (!node.isExpanded() || !extOpts.hideExpanded) ) { + if( !$badge.length ) { + $badge = $("<span class='fancytree-childcounter'/>").appendTo($("span.fancytree-icon", node.span)); + } + $badge.text(count); + } else { + $badge.remove(); + } + if( extOpts.deep && !node.isTopLevel() && !node.isRoot() ) { + node.parent.updateCounters(); + } +}; + + +// Finally, we can extend the widget API and create functions that are called +// like so: +// +// $("#tree").fancytree("widgetMethod1", "abc"); + +$.ui.fancytree.prototype.widgetMethod1 = function(arg1){ + var tree = this.tree; + return arg1; +}; + + +// Register a Fancytree extension +// ------------------------------ +// A full blown extension, extension is available for all trees and can be +// enabled like so (see also the [live demo](http://wwwendt.de/tech/fancytree/demo/sample-ext-childcounter.html)): +// +// <script src="../src/jquery.fancytree.js" type="text/javascript"></script> +// <script src="../src/jquery.fancytree.childcounter.js" type="text/javascript"></script> +// ... +// +// $("#tree").fancytree({ +// extensions: ["childcounter"], +// childcounter: { +// hideExpanded: true +// }, +// ... +// }); +// + + +/* 'childcounter' extension */ +$.ui.fancytree.registerExtension({ +// Every extension must be registered by a unique name. + name: "childcounter", +// Version information should be compliant with [semver](http://semver.org) + version: "1.0.0", + +// Extension specific options and their defaults. +// This options will be available as `tree.options.childcounter.hideExpanded` + + options: { + deep: true, + hideZeros: true, + hideExpanded: false + }, + +// Attributes other than `options` (or functions) can be defined here, and +// will be added to the tree.ext.EXTNAME namespace, in this case `tree.ext.childcounter.foo`. +// They can also be accessed as `this._local.foo` from within the extension +// methods. + foo: 42, + +// Local functions are prefixed with an underscore '_'. +// Callable as `this._local._appendCounter()`. + + _appendCounter: function(bar){ + var tree = this; + }, + +// **Override virtual methods for this extension.** +// +// Fancytree implements a number of 'hook methods', prefixed by 'node...' or 'tree...'. +// with a `ctx` argument (see [EventData](http://www.wwwendt.de/tech/fancytree/doc/jsdoc/global.html#EventData) +// for details) and an extended calling context:<br> +// `this` : the Fancytree instance<br> +// `this._local`: the namespace that contains extension attributes and private methods (same as this.ext.EXTNAME)<br> +// `this._super`: the virtual function that was overridden (member of previous extension or Fancytree) +// +// See also the [complete list of available hook functions](http://www.wwwendt.de/tech/fancytree/doc/jsdoc/Fancytree_Hooks.html). + + /* Init */ +// `treeInit` is triggered when a tree is initalized. We can set up classes or +// bind event handlers here... + treeInit: function(ctx){ + var tree = this, // same as ctx.tree, + opts = ctx.options, + extOpts = ctx.options.childcounter; +// Optionally check for dependencies with other extensions + /* this._requireExtension("glyph", false, false); */ +// Call the base implementation + this._superApply(arguments); +// Add a class to the tree container + this.$container.addClass("fancytree-ext-childcounter"); + }, + +// Destroy this tree instance (we only call the default implementation, so +// this method could as well be omitted). + + treeDestroy: function(ctx){ + this._superApply(arguments); + }, + +// Overload the `renderTitle` hook, to append a counter badge + nodeRenderTitle: function(ctx, title) { + var node = ctx.node, + extOpts = ctx.options.childcounter, + count = (node.data.childCounter == null) ? node.countChildren(extOpts.deep) : +node.data.childCounter; +// Let the base implementation render the title + this._superApply(arguments); +// Append a counter badge + if( (count || ! extOpts.hideZeros) && (!node.isExpanded() || !extOpts.hideExpanded) ){ + $("span.fancytree-icon", node.span).append($("<span class='fancytree-childcounter'/>").text(count)); + } + }, +// Overload the `setExpanded` hook, so the counters are updated + nodeSetExpanded: function(ctx, flag, opts) { + var tree = ctx.tree, + node = ctx.node; +// Let the base implementation expand/collapse the node, then redraw the title +// after the animation has finished + return this._superApply(arguments).always(function(){ + tree.nodeRenderTitle(ctx); + }); + } + +// End of extension definition +}); +// End of namespace closure +}(jQuery)); diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.clones.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.clones.js new file mode 100644 index 00000000000..fcf31916dcf --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.clones.js @@ -0,0 +1,451 @@ +/*! + * + * jquery.fancytree.clones.js + * Support faster lookup of nodes by key and shared ref-ids. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + +/******************************************************************************* + * Private functions and variables + */ +function _assert(cond, msg){ + // TODO: see qunit.js extractStacktrace() + if(!cond){ + msg = msg ? ": " + msg : ""; + $.error("Assertion failed" + msg); + } +} + + +/* Return first occurrence of member from array. */ +function _removeArrayMember(arr, elem) { + // TODO: use Array.indexOf for IE >= 9 + var i; + for (i = arr.length - 1; i >= 0; i--) { + if (arr[i] === elem) { + arr.splice(i, 1); + return true; + } + } + return false; +} + + +// /** +// * Calculate a 32 bit FNV-1a hash +// * Found here: https://gist.github.com/vaiorabbit/5657561 +// * Ref.: http://isthe.com/chongo/tech/comp/fnv/ +// * +// * @param {string} str the input value +// * @param {boolean} [asString=false] set to true to return the hash value as +// * 8-digit hex string instead of an integer +// * @param {integer} [seed] optionally pass the hash of the previous chunk +// * @returns {integer | string} +// */ +// function hashFnv32a(str, asString, seed) { +// /*jshint bitwise:false */ +// var i, l, +// hval = (seed === undefined) ? 0x811c9dc5 : seed; + +// for (i = 0, l = str.length; i < l; i++) { +// hval ^= str.charCodeAt(i); +// hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24); +// } +// if( asString ){ +// // Convert to 8 digit hex string +// return ("0000000" + (hval >>> 0).toString(16)).substr(-8); +// } +// return hval >>> 0; +// } + + +/** + * JS Implementation of MurmurHash3 (r136) (as of May 20, 2011) + * + * @author <a href="mailto:gary.court@gmail.com">Gary Court</a> + * @see http://github.com/garycourt/murmurhash-js + * @author <a href="mailto:aappleby@gmail.com">Austin Appleby</a> + * @see http://sites.google.com/site/murmurhash/ + * + * @param {string} key ASCII only + * @param {boolean} [asString=false] + * @param {number} seed Positive integer only + * @return {number} 32-bit positive integer hash + */ +function hashMurmur3(key, asString, seed) { + /*jshint bitwise:false */ + var h1b, k1, + remainder = key.length & 3, + bytes = key.length - remainder, + h1 = seed, + c1 = 0xcc9e2d51, + c2 = 0x1b873593, + i = 0; + + while (i < bytes) { + k1 = + ((key.charCodeAt(i) & 0xff)) | + ((key.charCodeAt(++i) & 0xff) << 8) | + ((key.charCodeAt(++i) & 0xff) << 16) | + ((key.charCodeAt(++i) & 0xff) << 24); + ++i; + + k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff; + k1 = (k1 << 15) | (k1 >>> 17); + k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff; + + h1 ^= k1; + h1 = (h1 << 13) | (h1 >>> 19); + h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff; + h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16)); + } + + k1 = 0; + + switch (remainder) { + /*jshint -W086:true */ + case 3: k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16; + case 2: k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8; + case 1: k1 ^= (key.charCodeAt(i) & 0xff); + + k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff; + k1 = (k1 << 15) | (k1 >>> 17); + k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff; + h1 ^= k1; + } + + h1 ^= key.length; + + h1 ^= h1 >>> 16; + h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff; + h1 ^= h1 >>> 13; + h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff; + h1 ^= h1 >>> 16; + + if( asString ){ + // Convert to 8 digit hex string + return ("0000000" + (h1 >>> 0).toString(16)).substr(-8); + } + return h1 >>> 0; +} + +// console.info(hashMurmur3("costarring")); +// console.info(hashMurmur3("costarring", true)); +// console.info(hashMurmur3("liquid")); +// console.info(hashMurmur3("liquid", true)); + + +/* + * Return a unique key for node by calculationg the hash of the parents refKey-list + */ +function calcUniqueKey(node) { + var key, + path = $.map(node.getParentList(false, true), function(e){ return e.refKey || e.key; }); + path = path.join("/"); + key = "id_" + hashMurmur3(path, true); + // node.debug(path + " -> " + key); + return key; +} + + +/** + * [ext-clones] Return a list of clone-nodes or null. + * @param {boolean} [includeSelf=false] + * @returns {FancytreeNode[] | null} + * + * @alias FancytreeNode#getCloneList + * @requires jquery.fancytree.clones.js + */ +$.ui.fancytree._FancytreeNodeClass.prototype.getCloneList = function(includeSelf){ + var key, + tree = this.tree, + refList = tree.refMap[this.refKey] || null, + keyMap = tree.keyMap; + + if( refList ) { + key = this.key; + // Convert key list to node list + if( includeSelf ) { + refList = $.map(refList, function(val){ return keyMap[val]; }); + } else { + refList = $.map(refList, function(val){ return val === key ? null : keyMap[val]; }); + if( refList.length < 1 ) { + refList = null; + } + } + } + return refList; +}; + + +/** + * [ext-clones] Return true if this node has at least another clone with same refKey. + * @returns {boolean} + * + * @alias FancytreeNode#isClone + * @requires jquery.fancytree.clones.js + */ +$.ui.fancytree._FancytreeNodeClass.prototype.isClone = function(){ + var refKey = this.refKey || null, + refList = refKey && this.tree.refMap[refKey] || null; + return !!(refList && refList.length > 1); +}; + + +/** + * [ext-clones] Update key and/or refKey for an existing node. + * @param {string} key + * @param {string} refKey + * @returns {boolean} + * + * @alias FancytreeNode#reRegister + * @requires jquery.fancytree.clones.js + */ +$.ui.fancytree._FancytreeNodeClass.prototype.reRegister = function(key, refKey){ + key = (key == null) ? null : "" + key; + refKey = (refKey == null) ? null : "" + refKey; + // this.debug("reRegister", key, refKey); + + var tree = this.tree, + prevKey = this.key, + prevRefKey = this.refKey, + keyMap = tree.keyMap, + refMap = tree.refMap, + refList = refMap[prevRefKey] || null, +// curCloneKeys = refList ? node.getCloneList(true), + modified = false; + + // Key has changed: update all references + if( key != null && key !== this.key ) { + if( keyMap[key] ) { + $.error("[ext-clones] reRegister(" + key + "): already exists: " + this); + } + // Update keyMap + delete keyMap[prevKey]; + keyMap[key] = this; + // Update refMap + if( refList ) { + refMap[prevRefKey] = $.map(refList, function(e){ + return e === prevKey ? key : e; + }); + } + this.key = key; + modified = true; + } + + // refKey has changed + if( refKey != null && refKey !== this.refKey ) { + // Remove previous refKeys + if( refList ){ + if( refList.length === 1 ){ + delete refMap[prevRefKey]; + }else{ + refMap[prevRefKey] = $.map(refList, function(e){ + return e === prevKey ? null : e; + }); + } + } + // Add refKey + if( refMap[refKey] ) { + refMap[refKey].append(key); + }else{ + refMap[refKey] = [ this.key ]; + } + this.refKey = refKey; + modified = true; + } + return modified; +}; + + +/** + * [ext-clones] Return all nodes with a given refKey (null if not found). + * @param {string} refKey + * @param {FancytreeNode} [rootNode] optionally restrict results to descendants of this node + * @returns {FancytreeNode[] | null} + * @alias Fancytree#getNodesByRef + * @requires jquery.fancytree.clones.js + */ +$.ui.fancytree._FancytreeClass.prototype.getNodesByRef = function(refKey, rootNode){ + var keyMap = this.keyMap, + refList = this.refMap[refKey] || null; + + if( refList ) { + // Convert key list to node list + if( rootNode ) { + refList = $.map(refList, function(val){ + var node = keyMap[val]; + return node.isDescendantOf(rootNode) ? node : null; + }); + }else{ + refList = $.map(refList, function(val){ return keyMap[val]; }); + } + if( refList.length < 1 ) { + refList = null; + } + } + return refList; +}; + + +/** + * [ext-clones] Replace a refKey with a new one. + * @param {string} oldRefKey + * @param {string} newRefKey + * @alias Fancytree#changeRefKey + * @requires jquery.fancytree.clones.js + */ +$.ui.fancytree._FancytreeClass.prototype.changeRefKey = function(oldRefKey, newRefKey) { + var i, node, + keyMap = this.keyMap, + refList = this.refMap[oldRefKey] || null; + + if (refList) { + for (i = 0; i < refList.length; i++) { + node = keyMap[refList[i]]; + node.refKey = newRefKey; + } + delete this.refMap[oldRefKey]; + this.refMap[newRefKey] = refList; + } +}; + + +/******************************************************************************* + * Extension code + */ +$.ui.fancytree.registerExtension({ + name: "clones", + version: "0.0.3", + // Default options for this extension. + options: { + highlightActiveClones: true, // set 'fancytree-active-clone' on active clones and all peers + highlightClones: false // set 'fancytree-clone' class on any node that has at least one clone + }, + + treeCreate: function(ctx){ + this._superApply(arguments); + ctx.tree.refMap = {}; + ctx.tree.keyMap = {}; + }, + treeInit: function(ctx){ + this.$container.addClass("fancytree-ext-clones"); + _assert(ctx.options.defaultKey == null); + // Generate unique / reproducible default keys + ctx.options.defaultKey = function(node){ + return calcUniqueKey(node); + }; + // The default implementation loads initial data + this._superApply(arguments); + }, + treeClear: function(ctx){ + ctx.tree.refMap = {}; + ctx.tree.keyMap = {}; + return this._superApply(arguments); + }, + treeRegisterNode: function(ctx, add, node) { + var refList, len, + tree = ctx.tree, + keyMap = tree.keyMap, + refMap = tree.refMap, + key = node.key, + refKey = (node && node.refKey != null) ? "" + node.refKey : null; + +// ctx.tree.debug("clones.treeRegisterNode", add, node); + + if( key === "_statusNode" ){ + return this._superApply(arguments); + } + + if( add ) { + if( keyMap[node.key] != null ) { + $.error("clones.treeRegisterNode: node.key already exists: " + node); + } + keyMap[key] = node; + if( refKey ) { + refList = refMap[refKey]; + if( refList ) { + refList.push(key); + if( refList.length === 2 && ctx.options.clones.highlightClones ) { + // Mark peer node, if it just became a clone (no need to + // mark current node, since it will be rendered later anyway) + keyMap[refList[0]].renderStatus(); + } + } else { + refMap[refKey] = [key]; + } + // node.debug("clones.treeRegisterNode: add clone =>", refMap[refKey]); + } + }else { + if( keyMap[key] == null ) { + $.error("clones.treeRegisterNode: node.key not registered: " + node.key); + } + delete keyMap[key]; + if( refKey ) { + refList = refMap[refKey]; + // node.debug("clones.treeRegisterNode: remove clone BEFORE =>", refMap[refKey]); + if( refList ) { + len = refList.length; + if( len <= 1 ){ + _assert(len === 1); + _assert(refList[0] === key); + delete refMap[refKey]; + }else{ + _removeArrayMember(refList, key); + // Unmark peer node, if this was the only clone + if( len === 2 && ctx.options.clones.highlightClones ) { +// node.debug("clones.treeRegisterNode: last =>", node.getCloneList()); + keyMap[refList[0]].renderStatus(); + } + } + // node.debug("clones.treeRegisterNode: remove clone =>", refMap[refKey]); + } + } + } + return this._superApply(arguments); + }, + nodeRenderStatus: function(ctx) { + var $span, res, + node = ctx.node; + + res = this._superApply(arguments); + + if( ctx.options.clones.highlightClones ) { + $span = $(node[ctx.tree.statusClassPropName]); + // Only if span already exists + if( $span.length && node.isClone() ){ +// node.debug("clones.nodeRenderStatus: ", ctx.options.clones.highlightClones); + $span.addClass("fancytree-clone"); + } + } + return res; + }, + nodeSetActive: function(ctx, flag) { + var res, + scpn = ctx.tree.statusClassPropName, + node = ctx.node; + + res = this._superApply(arguments); + + if( ctx.options.clones.highlightActiveClones && node.isClone() ) { + $.each(node.getCloneList(true), function(idx, n){ + // n.debug("clones.nodeSetActive: ", flag !== false); + $(n[scpn]).toggleClass("fancytree-active-clone", flag !== false); + }); + } + return res; + } +}); +}(jQuery, window, document)); diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.columnview.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.columnview.js new file mode 100644 index 00000000000..c64b59d59b0 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.columnview.js @@ -0,0 +1,150 @@ +/*! + * jquery.fancytree.columnview.js + * + * Render tree like a Mac Finder's column view. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + +// prevent duplicate loading +// if ( $.ui.fancytree && $.ui.fancytree.version ) { +// $.ui.fancytree.warn("Fancytree: duplicate include"); +// return; +// } + + +/******************************************************************************* + * Private functions and variables + */ +/* +function _assert(cond, msg){ + msg = msg || ""; + if(!cond){ + $.error("Assertion failed " + msg); + } +} +*/ + +/******************************************************************************* + * Private functions and variables + */ +$.ui.fancytree.registerExtension({ + name: "columnview", + version: "0.0.1", + // Default options for this extension. + options: { + }, + // Overide virtual methods for this extension. + // `this` : is this extension object + // `this._base` : the Fancytree instance + // `this._super`: the virtual function that was overriden (member of prev. extension or Fancytree) + treeInit: function(ctx){ + var $tdFirst, $ul, + tree = ctx.tree, + $table = tree.widget.element; + + tree.tr = $("tbody tr", $table)[0]; + tree.columnCount = $(">td", tree.tr).length; + // Perform default behavior + this._superApply(arguments); + // Standard Fancytree created a root <ul>. Now move this into first table cell + $ul = $(tree.rootNode.ul); + $tdFirst = $(">td", tree.tr).eq(0); + + $ul.removeClass("fancytree-container"); + $ul.removeAttr("tabindex"); + tree.$container = $table; + $table.addClass("fancytree-container fancytree-ext-columnview"); + $table.attr("tabindex", "0"); + + $tdFirst.empty(); + $ul.detach().appendTo($tdFirst); + + // Force some required options + tree.widget.options.autoCollapse = true; +// tree.widget.options.autoActivate = true; + tree.widget.options.toggleEffect = false; + tree.widget.options.clickFolderMode = 1; + + // Make sure that only active path is expanded when a node is activated: + $table.bind("fancytreeactivate", function(event, data){ + var i, tdList, + node = data.node, + tree = data.tree, + level = node.getLevel(); + + tree._callHook("nodeCollapseSiblings", node); + // Clear right neighbours + if(level <= tree.columnCount){ + tdList = $(">td", tree.tr); + for(i=level; i<tree.columnCount; i++){ + tdList.eq(i).empty(); + } + } + // Expand nodes on activate, so we populate the right neighbor cell + if(!node.expanded && (node.children || node.lazy)) { + node.setExpanded(); + } + // Adjust keyboard behaviour: + }).bind("fancytreekeydown", function(event, data){ + var next = null, + node = data.node || data.tree.getFirstChild(); + switch(event.which){ + case $.ui.keyCode.DOWN: + next = node.getNextSibling(); + if( next ){ + next.setFocus(); + } + return false; + case $.ui.keyCode.LEFT: + next = node.getParent(); + if( next ){ + next.setFocus(); + } + return false; + case $.ui.keyCode.UP: + next = node.getPrevSibling(); + if( next ){ + next.setFocus(); + } + return false; + } + }); + }, + nodeRender: function(ctx, force, deep, collapsed, _recursive) { + // Render standard nested <ul> - <li> hierarchy + this._superApply(arguments); + // Remove expander and add a trailing triangle instead + var level, $tdChild, $ul, + tree = ctx.tree, + node = ctx.node, + $span = $(node.span); + + $span.find("span.fancytree-expander").remove(); + if(node.hasChildren() !== false && !$span.find("span.fancytree-cv-right").length){ + $span.append($("<span class='fancytree-icon fancytree-cv-right'>")); + } + // Move <ul> with children into the appropriate <td> + if(node.ul){ + node.ul.style.display = ""; // might be hidden if RIGHT was pressed + level = node.getLevel(); + if(level < tree.columnCount){ + $tdChild = $(">td", tree.tr).eq(level); + $ul = $(node.ul).detach(); + $tdChild.empty().append($ul); + } + } + } +}); +}(jQuery, window, document)); diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.debug.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.debug.js new file mode 100644 index 00000000000..778fe0eef05 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.debug.js @@ -0,0 +1,142 @@ +/*! + * jquery.fancytree.debug.js + * + * Miscellaneous debug extensions. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + +// prevent duplicate loading +// if ( $.ui.fancytree && $.ui.fancytree.version ) { +// $.ui.fancytree.warn("Fancytree: duplicate include"); +// return; +// } + + +/* ***************************************************************************** + * Private functions and variables + */ +var i, + HOOK_NAMES = "nodeClick nodeCollapseSiblings".split(" "), + EVENT_NAMES = "activate beforeActivate".split(" "), + HOOK_NAME_MAP = {}, + EVENT_NAME_MAP = {}; + +for(i=0; i<HOOK_NAMES.length; i++){ HOOK_NAME_MAP[HOOK_NAMES[i]] = true; } +for(i=0; i<EVENT_NAMES.length; i++){ EVENT_NAME_MAP[EVENT_NAMES[i]] = true; } + +/* ***************************************************************************** + * Extension code + */ +$.ui.fancytree.registerExtension({ + name: "tracecalls", + version: "0.0.1", + // Default options for this extension. + options: { + logTarget: null, // optional redirect logging to this <div> tag + traceEvents: false, // `true`or list of hook names + traceHooks: false // `true`or list of event names + }, + // Overide virtual methods for this extension. + // `this` : is this Fancytree object + // `this._super`: the virtual function that was overridden (member of prev. extension or Fancytree) + treeInit: function(ctx){ + var tree = ctx.tree; + + // Bind init-handler to apply cookie state + tree.$div.bind("fancytreeinit", function(event){ + tree.debug("COOKIE " + document.cookie); + }); + // Init the tree + this._superApply(arguments); + }, + nodeClick: function(ctx) { + if(this.options.tracecalls.traceHooks){ + this.debug(); + } + }, + nodeCollapseSiblings: function(ctx) { + }, + nodeDblclick: function(ctx) { + }, + nodeKeydown: function(ctx) { + }, + nodeLoadChildren: function(ctx, source) { + }, + nodeOnFocusInOut: function(ctx) { + }, + nodeRemoveChildMarkup: function(ctx) { + }, + nodeRemoveMarkup: function(ctx) { + }, + nodeRender: function(ctx, force, deep, collapsed, _recursive) { + }, + nodeRenderStatus: function(ctx) { + }, + nodeRenderTitle: function(ctx, title) { + }, + nodeSetActive: function(ctx, flag, opts) { + }, + nodeSetExpanded: function(ctx, flag, opts) { + }, + nodeSetFocus: function(ctx) { + }, + nodeSetSelected: function(ctx, flag) { + }, + nodeSetStatus: function(ctx, status, message, details) { + }, + nodeToggleExpanded: function(ctx) { + }, + nodeToggleSelected: function(ctx) { + }, + treeClear: function(ctx) { + }, + treeCreate: function(ctx) { + }, + treeDestroy: function(ctx) { + }, +// treeInit: function(ctx) { +// }, + treeLoad: function(ctx, source) { + }, + treeSetFocus: function(ctx, flag) { + } +}); + +}(jQuery, window, document)); + + + +/* ***************************************************************************** + * Fancytree extension: profiler + */ +;(function($, window, document, undefined) { + $.ui.fancytree.registerExtension({ + name: "profiler", + version: "0.0.1", + // Default options for this extension + options: { + prefix: "" + }, + // Overide virtual methods for this extension + nodeRender: function(ctx, force, deep, collapsed){ + // ctx.tree.debug("**** PROFILER nodeRender"); + var s = this.options.prefix + "render '" + ctx.node + "'"; + /*jshint expr:true */ + window.console && window.console.time && window.console.time(s); + this._superApply(arguments); + window.console && window.console.timeEnd && window.console.timeEnd(s); + } + }); +}(jQuery, window, document)); diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.dnd.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.dnd.js new file mode 100644 index 00000000000..41a9e7f6725 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.dnd.js @@ -0,0 +1,553 @@ +/*! + * jquery.fancytree.dnd.js + * + * Drag-and-drop support. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + +/* ***************************************************************************** + * Private functions and variables + */ +var didRegisterDnd = false, + classDropAccept = "fancytree-drop-accept", + classDropAfter = "fancytree-drop-after", + classDropBefore = "fancytree-drop-before", + classDropOver = "fancytree-drop-over", + classDropReject = "fancytree-drop-reject", + classDropTarget = "fancytree-drop-target"; + +/* Convert number to string and prepend +/-; return empty string for 0.*/ +function offsetString(n){ + return n === 0 ? "" : (( n > 0 ) ? ("+" + n) : ("" + n)); +} + +/* ***************************************************************************** + * Drag and drop support + */ +function _initDragAndDrop(tree) { + var dnd = tree.options.dnd || null, + glyph = tree.options.glyph || null; + + // Register 'connectToFancytree' option with ui.draggable + if( dnd ) { + _registerDnd(); + } + // Attach ui.draggable to this Fancytree instance + if(dnd && dnd.dragStart ) { + tree.widget.element.draggable($.extend({ + addClasses: false, + // DT issue 244: helper should be child of scrollParent: + appendTo: tree.$container, +// appendTo: "body", + containment: false, +// containment: "parent", + delay: 0, + distance: 4, + revert: false, + scroll: true, // to disable, also set css 'position: inherit' on ul.fancytree-container + scrollSpeed: 7, + scrollSensitivity: 10, + // Delegate draggable.start, drag, and stop events to our handler + connectToFancytree: true, + // Let source tree create the helper element + helper: function(event) { + var $helper, $nodeTag, opts, + sourceNode = $.ui.fancytree.getNode(event.target); + + if(!sourceNode){ + // #405, DT issue 211: might happen, if dragging a table *header* + return "<div>ERROR?: helper requested but sourceNode not found</div>"; + } + opts = sourceNode.tree.options.dnd; + $nodeTag = $(sourceNode.span); + // Only event and node argument is available + $helper = $("<div class='fancytree-drag-helper'><span class='fancytree-drag-helper-img' /></div>") + .css({zIndex: 3, position: "relative"}) // so it appears above ext-wide selection bar + .append($nodeTag.find("span.fancytree-title").clone()); + + // Attach node reference to helper object + $helper.data("ftSourceNode", sourceNode); + + // Support glyph symbols instead of icons + if( glyph ) { + $helper.find(".fancytree-drag-helper-img") + .addClass(glyph.map.dragHelper); + } + // Allow to modify the helper, e.g. to add multi-node-drag feedback + if( opts.initHelper ) { + opts.initHelper.call(sourceNode.tree, sourceNode, { + node: sourceNode, + tree: sourceNode.tree, + originalEvent: event, + ui: { helper: $helper } + }); + } + // We return an unconnected element, so `draggable` will add this + // to the parent specified as `appendTo` option + return $helper; + }, + start: function(event, ui) { + var sourceNode = ui.helper.data("ftSourceNode"); + return !!sourceNode; // Abort dragging if no node could be found + } + }, tree.options.dnd.draggable)); + } + // Attach ui.droppable to this Fancytree instance + if(dnd && dnd.dragDrop) { + tree.widget.element.droppable($.extend({ + addClasses: false, + tolerance: "intersect", + greedy: false +/* + activate: function(event, ui) { + tree.debug("droppable - activate", event, ui, this); + }, + create: function(event, ui) { + tree.debug("droppable - create", event, ui); + }, + deactivate: function(event, ui) { + tree.debug("droppable - deactivate", event, ui); + }, + drop: function(event, ui) { + tree.debug("droppable - drop", event, ui); + }, + out: function(event, ui) { + tree.debug("droppable - out", event, ui); + }, + over: function(event, ui) { + tree.debug("droppable - over", event, ui); + } +*/ + }, tree.options.dnd.droppable)); + } +} + +//--- Extend ui.draggable event handling -------------------------------------- + +function _registerDnd() { + if(didRegisterDnd){ + return; + } + + // Register proxy-functions for draggable.start/drag/stop + + $.ui.plugin.add("draggable", "connectToFancytree", { + start: function(event, ui) { + // 'draggable' was renamed to 'ui-draggable' since jQueryUI 1.10 + var draggable = $(this).data("ui-draggable") || $(this).data("draggable"), + sourceNode = ui.helper.data("ftSourceNode") || null; + + if(sourceNode) { + // Adjust helper offset, so cursor is slightly outside top/left corner + draggable.offset.click.top = -2; + draggable.offset.click.left = + 16; + // Trigger dragStart event + // TODO: when called as connectTo..., the return value is ignored(?) + return sourceNode.tree.ext.dnd._onDragEvent("start", sourceNode, null, event, ui, draggable); + } + }, + drag: function(event, ui) { + var ctx, isHelper, logObject, + // 'draggable' was renamed to 'ui-draggable' since jQueryUI 1.10 + draggable = $(this).data("ui-draggable") || $(this).data("draggable"), + sourceNode = ui.helper.data("ftSourceNode") || null, + prevTargetNode = ui.helper.data("ftTargetNode") || null, + targetNode = $.ui.fancytree.getNode(event.target), + dndOpts = sourceNode && sourceNode.tree.options.dnd; + + // logObject = sourceNode || prevTargetNode || $.ui.fancytree; + // logObject.debug("Drag event:", event, event.shiftKey); + if(event.target && !targetNode){ + // We got a drag event, but the targetNode could not be found + // at the event location. This may happen, + // 1. if the mouse jumped over the drag helper, + // 2. or if a non-fancytree element is dragged + // We ignore it: + isHelper = $(event.target).closest("div.fancytree-drag-helper,#fancytree-drop-marker").length > 0; + if(isHelper){ + logObject = sourceNode || prevTargetNode || $.ui.fancytree; + logObject.debug("Drag event over helper: ignored."); + return; + } + } + ui.helper.data("ftTargetNode", targetNode); + + if( dndOpts && dndOpts.updateHelper ) { + ctx = sourceNode.tree._makeHookContext(sourceNode, event, { + otherNode: targetNode, + ui: ui, + draggable: draggable, + dropMarker: $("#fancytree-drop-marker") + }); + dndOpts.updateHelper.call(sourceNode.tree, sourceNode, ctx); + } + + // Leaving a tree node + if(prevTargetNode && prevTargetNode !== targetNode ) { + prevTargetNode.tree.ext.dnd._onDragEvent("leave", prevTargetNode, sourceNode, event, ui, draggable); + } + if(targetNode){ + if(!targetNode.tree.options.dnd.dragDrop) { + // not enabled as drop target + } else if(targetNode === prevTargetNode) { + // Moving over same node + targetNode.tree.ext.dnd._onDragEvent("over", targetNode, sourceNode, event, ui, draggable); + }else{ + // Entering this node first time + targetNode.tree.ext.dnd._onDragEvent("enter", targetNode, sourceNode, event, ui, draggable); + } + } + // else go ahead with standard event handling + }, + stop: function(event, ui) { + var logObject, + // 'draggable' was renamed to 'ui-draggable' since jQueryUI 1.10: + draggable = $(this).data("ui-draggable") || $(this).data("draggable"), + sourceNode = ui.helper.data("ftSourceNode") || null, + targetNode = ui.helper.data("ftTargetNode") || null, + dropped = (event.type === "mouseup" && event.which === 1); + + if(!dropped){ + logObject = sourceNode || targetNode || $.ui.fancytree; + logObject.debug("Drag was cancelled"); + } + if(targetNode) { + if(dropped){ + targetNode.tree.ext.dnd._onDragEvent("drop", targetNode, sourceNode, event, ui, draggable); + } + targetNode.tree.ext.dnd._onDragEvent("leave", targetNode, sourceNode, event, ui, draggable); + } + if(sourceNode){ + sourceNode.tree.ext.dnd._onDragEvent("stop", sourceNode, null, event, ui, draggable); + } + } + }); + + didRegisterDnd = true; +} + + +/* ***************************************************************************** + * + */ + +$.ui.fancytree.registerExtension({ + name: "dnd", + version: "0.2.0", + // Default options for this extension. + options: { + // Make tree nodes accept draggables + autoExpandMS: 1000, // Expand nodes after n milliseconds of hovering. + draggable: null, // Additional options passed to jQuery draggable + droppable: null, // Additional options passed to jQuery droppable + focusOnClick: false, // Focus, although draggable cancels mousedown event (#270) + preventVoidMoves: true, // Prevent dropping nodes 'before self', etc. + preventRecursiveMoves: true, // Prevent dropping nodes on own descendants + smartRevert: true, // set draggable.revert = true if drop was rejected + // Events (drag support) + dragStart: null, // Callback(sourceNode, data), return true, to enable dnd + dragStop: null, // Callback(sourceNode, data) + initHelper: null, // Callback(sourceNode, data) + updateHelper: null, // Callback(sourceNode, data) + // Events (drop support) + dragEnter: null, // Callback(targetNode, data) + dragOver: null, // Callback(targetNode, data) + dragDrop: null, // Callback(targetNode, data) + dragLeave: null // Callback(targetNode, data) + }, + + treeInit: function(ctx){ + var tree = ctx.tree; + this._superApply(arguments); + // issue #270: draggable eats mousedown events + if( tree.options.dnd.dragStart ){ + tree.$container.on("mousedown", function(event){ +// if( !tree.hasFocus() && ctx.options.dnd.focusOnClick ) { + if( ctx.options.dnd.focusOnClick ) { // #270 + var node = $.ui.fancytree.getNode(event); + if (node){ + node.debug("Re-enable focus that was prevented by jQuery UI draggable."); + // node.setFocus(); + // $(node.span).closest(":tabbable").focus(); + // $(event.target).trigger("focus"); + // $(event.target).closest(":tabbable").trigger("focus"); + } + setTimeout(function() { // #300 + $(event.target).closest(":tabbable").focus(); + }, 10); + } + }); + } + _initDragAndDrop(tree); + }, + /* Display drop marker according to hitMode ('after', 'before', 'over'). */ + _setDndStatus: function(sourceNode, targetNode, helper, hitMode, accept) { + var markerOffsetX = 0, + markerAt = "center", + instData = this._local, + glyph = this.options.glyph || null, + $source = sourceNode ? $(sourceNode.span) : null, + $target = $(targetNode.span); + + if( !instData.$dropMarker ) { + instData.$dropMarker = $("<div id='fancytree-drop-marker'></div>") + .hide() + .css({"z-index": 1000}) + .prependTo($(this.$div).parent()); +// .prependTo("body"); + + if( glyph ) { + // instData.$dropMarker.addClass(glyph.map.dragHelper); + instData.$dropMarker + .addClass(glyph.map.dropMarker); + } + } + if( hitMode === "after" || hitMode === "before" || hitMode === "over" ){ + switch(hitMode){ + case "before": + markerAt = "top"; + break; + case "after": + markerAt = "bottom"; + break; + default: + markerOffsetX = 8; + } + + instData.$dropMarker + .toggleClass(classDropAfter, hitMode === "after") + .toggleClass(classDropOver, hitMode === "over") + .toggleClass(classDropBefore, hitMode === "before") + .show() + .position($.ui.fancytree.fixPositionOptions({ + my: "left" + offsetString(markerOffsetX) + " center", + at: "left " + markerAt, + of: $target + })); + } else { + instData.$dropMarker.hide(); + } + if( $source ){ + $source + .toggleClass(classDropAccept, accept === true) + .toggleClass(classDropReject, accept === false); + } + $target + .toggleClass(classDropTarget, hitMode === "after" || hitMode === "before" || hitMode === "over") + .toggleClass(classDropAfter, hitMode === "after") + .toggleClass(classDropBefore, hitMode === "before") + .toggleClass(classDropAccept, accept === true) + .toggleClass(classDropReject, accept === false); + + helper + .toggleClass(classDropAccept, accept === true) + .toggleClass(classDropReject, accept === false); + }, + + /* + * Handles drag'n'drop functionality. + * + * A standard jQuery drag-and-drop process may generate these calls: + * + * start: + * _onDragEvent("start", sourceNode, null, event, ui, draggable); + * drag: + * _onDragEvent("leave", prevTargetNode, sourceNode, event, ui, draggable); + * _onDragEvent("over", targetNode, sourceNode, event, ui, draggable); + * _onDragEvent("enter", targetNode, sourceNode, event, ui, draggable); + * stop: + * _onDragEvent("drop", targetNode, sourceNode, event, ui, draggable); + * _onDragEvent("leave", targetNode, sourceNode, event, ui, draggable); + * _onDragEvent("stop", sourceNode, null, event, ui, draggable); + */ + _onDragEvent: function(eventName, node, otherNode, event, ui, draggable) { + if(eventName !== "over"){ + this.debug("tree.ext.dnd._onDragEvent(%s, %o, %o) - %o", eventName, node, otherNode, this); + } + var accept, nodeOfs, relPos, relPos2, + enterResponse, hitMode, r, + opts = this.options, + dnd = opts.dnd, + ctx = this._makeHookContext(node, event, {otherNode: otherNode, ui: ui, draggable: draggable}), + res = null, + that = this, + $nodeTag = $(node.span); + + if( dnd.smartRevert ) { + draggable.options.revert = "invalid"; + } + + switch (eventName) { + + case "start": + if( node.isStatusNode() ) { + res = false; + } else if(dnd.dragStart) { + res = dnd.dragStart(node, ctx); + } + if(res === false) { + this.debug("tree.dragStart() cancelled"); + //draggable._clear(); + // NOTE: the return value seems to be ignored (drag is not canceled, when false is returned) + // TODO: call this._cancelDrag()? + ui.helper.trigger("mouseup") + .hide(); + } else { + $nodeTag.addClass("fancytree-drag-source"); + // Register global handlers to allow cancel + $(document) + .on("keydown.fancytree-dnd,mousedown.fancytree-dnd", function(event){ + // node.tree.debug("dnd global event", event.type, event.which); + if( event.type === "keydown" && event.which === $.ui.keyCode.ESCAPE ) { + that.ext.dnd._cancelDrag(); + } else if( event.type === "mousedown" ) { + that.ext.dnd._cancelDrag(); + } + }); + } + break; + + case "enter": + if(dnd.preventRecursiveMoves && node.isDescendantOf(otherNode)){ + r = false; + }else{ + r = dnd.dragEnter ? dnd.dragEnter(node, ctx) : null; + } + if(!r){ + // convert null, undefined, false to false + res = false; + }else if ( $.isArray(r) ) { + // TODO: also accept passing an object of this format directly + res = { + over: ($.inArray("over", r) >= 0), + before: ($.inArray("before", r) >= 0), + after: ($.inArray("after", r) >= 0) + }; + }else{ + res = { + over: ((r === true) || (r === "over")), + before: ((r === true) || (r === "before")), + after: ((r === true) || (r === "after")) + }; + } + ui.helper.data("enterResponse", res); + this.debug("helper.enterResponse: %o", res); + break; + + case "over": + enterResponse = ui.helper.data("enterResponse"); + hitMode = null; + if(enterResponse === false){ + // Don't call dragOver if onEnter returned false. +// break; + } else if(typeof enterResponse === "string") { + // Use hitMode from onEnter if provided. + hitMode = enterResponse; + } else { + // Calculate hitMode from relative cursor position. + nodeOfs = $nodeTag.offset(); + relPos = { x: event.pageX - nodeOfs.left, + y: event.pageY - nodeOfs.top }; + relPos2 = { x: relPos.x / $nodeTag.width(), + y: relPos.y / $nodeTag.height() }; + + if( enterResponse.after && relPos2.y > 0.75 ){ + hitMode = "after"; + } else if(!enterResponse.over && enterResponse.after && relPos2.y > 0.5 ){ + hitMode = "after"; + } else if(enterResponse.before && relPos2.y <= 0.25) { + hitMode = "before"; + } else if(!enterResponse.over && enterResponse.before && relPos2.y <= 0.5) { + hitMode = "before"; + } else if(enterResponse.over) { + hitMode = "over"; + } + // Prevent no-ops like 'before source node' + // TODO: these are no-ops when moving nodes, but not in copy mode + if( dnd.preventVoidMoves ){ + if(node === otherNode){ + this.debug(" drop over source node prevented"); + hitMode = null; + }else if(hitMode === "before" && otherNode && node === otherNode.getNextSibling()){ + this.debug(" drop after source node prevented"); + hitMode = null; + }else if(hitMode === "after" && otherNode && node === otherNode.getPrevSibling()){ + this.debug(" drop before source node prevented"); + hitMode = null; + }else if(hitMode === "over" && otherNode && otherNode.parent === node && otherNode.isLastSibling() ){ + this.debug(" drop last child over own parent prevented"); + hitMode = null; + } + } +// this.debug("hitMode: %s - %s - %s", hitMode, (node.parent === otherNode), node.isLastSibling()); + ui.helper.data("hitMode", hitMode); + } + // Auto-expand node (only when 'over' the node, not 'before', or 'after') + if(hitMode === "over" && dnd.autoExpandMS && node.hasChildren() !== false && !node.expanded) { + node.scheduleAction("expand", dnd.autoExpandMS); + } + if(hitMode && dnd.dragOver){ + // TODO: http://code.google.com/p/dynatree/source/detail?r=625 + ctx.hitMode = hitMode; + res = dnd.dragOver(node, ctx); + } + accept = (res !== false && hitMode !== null); + if( dnd.smartRevert ) { + draggable.options.revert = !accept; + } + this._local._setDndStatus(otherNode, node, ui.helper, hitMode, accept); + break; + + case "drop": + hitMode = ui.helper.data("hitMode"); + if(hitMode && dnd.dragDrop){ + ctx.hitMode = hitMode; + dnd.dragDrop(node, ctx); + } + break; + + case "leave": + // Cancel pending expand request + node.scheduleAction("cancel"); + ui.helper.data("enterResponse", null); + ui.helper.data("hitMode", null); + this._local._setDndStatus(otherNode, node, ui.helper, "out", undefined); + if(dnd.dragLeave){ + dnd.dragLeave(node, ctx); + } + break; + + case "stop": + $nodeTag.removeClass("fancytree-drag-source"); + $(document).off(".fancytree-dnd"); + if(dnd.dragStop){ + dnd.dragStop(node, ctx); + } + break; + + default: + $.error("Unsupported drag event: " + eventName); + } + return res; + }, + + _cancelDrag: function() { + var dd = $.ui.ddmanager.current; + if(dd){ + dd.cancel(); + } + } +}); +}(jQuery, window, document)); diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.edit.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.edit.js new file mode 100644 index 00000000000..dd498b6a5c3 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.edit.js @@ -0,0 +1,309 @@ +/*! + * jquery.fancytree.edit.js + * + * Make node titles editable. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + + +/******************************************************************************* + * Private functions and variables + */ + +var isMac = /Mac/.test(navigator.platform), + escapeHtml = $.ui.fancytree.escapeHtml, + unescapeHtml = $.ui.fancytree.unescapeHtml; + +/** + * [ext-edit] Start inline editing of current node title. + * + * @alias FancytreeNode#editStart + * @requires Fancytree + */ +$.ui.fancytree._FancytreeNodeClass.prototype.editStart = function(){ + var $input, + node = this, + tree = this.tree, + local = tree.ext.edit, + instOpts = tree.options.edit, + $title = $(".fancytree-title", node.span), + eventData = { + node: node, + tree: tree, + options: tree.options, + isNew: $(node[tree.statusClassPropName]).hasClass("fancytree-edit-new"), + orgTitle: node.title, + input: null, + dirty: false + }; + + // beforeEdit may want to modify the title before editing + if( instOpts.beforeEdit.call(node, {type: "beforeEdit"}, eventData) === false ) { + return false; + } + $.ui.fancytree.assert(!local.currentNode, "recursive edit"); + local.currentNode = this; + local.eventData = eventData; + + // Disable standard Fancytree mouse- and key handling + tree.widget._unbind(); + // #116: ext-dnd prevents the blur event, so we have to catch outer clicks + $(document).on("mousedown.fancytree-edit", function(event){ + if( ! $(event.target).hasClass("fancytree-edit-input") ){ + node.editEnd(true, event); + } + }); + + // Replace node with <input> + $input = $("<input />", { + "class": "fancytree-edit-input", + type: "text", + value: unescapeHtml(eventData.orgTitle) + }); + local.eventData.input = $input; + if ( instOpts.adjustWidthOfs != null ) { + $input.width($title.width() + instOpts.adjustWidthOfs); + } + if ( instOpts.inputCss != null ) { + $input.css(instOpts.inputCss); + } + + $title.html($input); + + // Focus <input> and bind keyboard handler + $input + .focus() + .change(function(event){ + $input.addClass("fancytree-edit-dirty"); + }).keydown(function(event){ + switch( event.which ) { + case $.ui.keyCode.ESCAPE: + node.editEnd(false, event); + break; + case $.ui.keyCode.ENTER: + node.editEnd(true, event); + return false; // so we don't start editmode on Mac + } + event.stopPropagation(); + }).blur(function(event){ + return node.editEnd(true, event); + }); + + instOpts.edit.call(node, {type: "edit"}, eventData); +}; + + +/** + * [ext-edit] Stop inline editing. + * @param {Boolean} [applyChanges=false] false: cancel edit, true: save (if modified) + * @alias FancytreeNode#editEnd + * @requires jquery.fancytree.edit.js + */ +$.ui.fancytree._FancytreeNodeClass.prototype.editEnd = function(applyChanges, _event){ + var newVal, + node = this, + tree = this.tree, + local = tree.ext.edit, + eventData = local.eventData, + instOpts = tree.options.edit, + $title = $(".fancytree-title", node.span), + $input = $title.find("input.fancytree-edit-input"); + + // eventData.isNew = $(node[tree.statusClassPropName]).hasClass("fancytree-edit-new"); + + if( instOpts.trim ) { + $input.val($.trim($input.val())); + } + newVal = $input.val(); + // eventData.dirty = $input.hasClass("fancytree-edit-dirty") || ; + eventData.dirty = ( newVal !== node.title ); + + // Find out, if saving is required + if( applyChanges === false ) { + // If true/false was passed, honor this (except in rename mode, if unchanged) + eventData.save = false; + } else if( eventData.isNew ) { + // In create mode, we save everyting, except for empty text + eventData.save = (newVal !== ""); + } else { + // In rename mode, we save everyting, except for empty or unchanged text + eventData.save = eventData.dirty && (newVal !== ""); + } + // Allow to break (keep editor open), modify input, or re-define data.save + if( instOpts.beforeClose.call(node, {type: "beforeClose"}, eventData) === false){ + return false; + } + if( eventData.save && instOpts.save.call(node, {type: "save"}, eventData) === false){ + return false; + } + $input + .removeClass("fancytree-edit-dirty") + .unbind(); + // Unbind outer-click handler + $(document).off(".fancytree-edit"); + + if( eventData.save ) { + node.setTitle( escapeHtml(newVal) ); + // $(node[tree.statusClassPropName]).removeClass("fancytree-edit-new"); + node.setFocus(); + }else{ + if( eventData.isNew ) { + node.remove(); + node = eventData.node = null; + local.relatedNode.setFocus(); + } else { + node.renderTitle(); + node.setFocus(); + } + } + local.eventData = null; + local.currentNode = null; + local.relatedNode = null; + // Re-enable mouse and keyboard handling + tree.widget._bind(); + // Set keyboard focus, even if setFocus() claims 'nothing to do' + $(tree.$container).focus(); + eventData.input = null; + instOpts.close.call(node, {type: "close"}, eventData); + return true; +}; + + +/** +* [ext-edit] Create a new child or sibling node and start edit mode. +* +* @param {String} [mode='child'] 'before', 'after', or 'child' +* @param {Object} [init] NodeData (or simple title string) +* @alias FancytreeNode#editCreateNode +* @requires jquery.fancytree.edit.js +* @since 2.4 +*/ +$.ui.fancytree._FancytreeNodeClass.prototype.editCreateNode = function(mode, init){ + var newNode, + tree = this.tree, + self = this; + + mode = mode || "child"; + if( init == null ) { + init = { title: "" }; + } else if( typeof init === "string" ) { + init = { title: init }; + } else { + $.ui.fancytree.assert($.isPlainObject(init)); + } + // Make sure node is expanded (and loaded) in 'child' mode + if( mode === "child" && !this.isExpanded() && this.hasChildren() !== false ) { + this.setExpanded().done(function(){ + self.editCreateNode(mode, init); + }); + return; + } + newNode = this.addNode(init, mode); + newNode.makeVisible(/*{noAnimation: true}*/).done(function(){ + $(newNode[tree.statusClassPropName]).addClass("fancytree-edit-new"); + self.tree.ext.edit.relatedNode = self; + newNode.editStart(); + }); +}; + + +/** + * [ext-edit] Check if any node in this tree in edit mode. + * + * @returns {FancytreeNode | null} + * @alias Fancytree#isEditing + * @requires jquery.fancytree.edit.js + */ +$.ui.fancytree._FancytreeClass.prototype.isEditing = function(){ + return this.ext.edit.currentNode; +}; + + +/** + * [ext-edit] Check if this node is in edit mode. + * @returns {Boolean} true if node is currently beeing edited + * @alias FancytreeNode#isEditing + * @requires jquery.fancytree.edit.js + */ +$.ui.fancytree._FancytreeNodeClass.prototype.isEditing = function(){ + return this.tree.ext.edit.currentNode === this; +}; + + +/******************************************************************************* + * Extension code + */ +$.ui.fancytree.registerExtension({ + name: "edit", + version: "0.2.0", + // Default options for this extension. + options: { + adjustWidthOfs: 4, // null: don't adjust input size to content + allowEmpty: false, // Prevent empty input + inputCss: {minWidth: "3em"}, + triggerCancel: ["esc", "tab", "click"], + // triggerStart: ["f2", "dblclick", "shift+click", "mac+enter"], + triggerStart: ["f2", "shift+click", "mac+enter"], + trim: true, // Trim whitespace before save + // Events: + beforeClose: $.noop, // Return false to prevent cancel/save (data.input is available) + beforeEdit: $.noop, // Return false to prevent edit mode + close: $.noop, // Editor was removed + edit: $.noop, // Editor was opened (available as data.input) +// keypress: $.noop, // Not yet implemented + save: $.noop // Save data.input.val() or return false to keep editor open + }, + // Local attributes + currentNode: null, + + treeInit: function(ctx){ + this._superApply(arguments); + this.$container.addClass("fancytree-ext-edit"); + }, + nodeClick: function(ctx) { + if( $.inArray("shift+click", ctx.options.edit.triggerStart) >= 0 ){ + if( ctx.originalEvent.shiftKey ){ + ctx.node.editStart(); + return false; + } + } + return this._superApply(arguments); + }, + nodeDblclick: function(ctx) { + if( $.inArray("dblclick", ctx.options.edit.triggerStart) >= 0 ){ + ctx.node.editStart(); + return false; + } + return this._superApply(arguments); + }, + nodeKeydown: function(ctx) { + switch( ctx.originalEvent.which ) { + case 113: // [F2] + if( $.inArray("f2", ctx.options.edit.triggerStart) >= 0 ){ + ctx.node.editStart(); + return false; + } + break; + case $.ui.keyCode.ENTER: + if( $.inArray("mac+enter", ctx.options.edit.triggerStart) >= 0 && isMac ){ + ctx.node.editStart(); + return false; + } + break; + } + return this._superApply(arguments); + } +}); +}(jQuery, window, document)); diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.filter.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.filter.js new file mode 100644 index 00000000000..a1a88f00d18 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.filter.js @@ -0,0 +1,283 @@ +/*! + * jquery.fancytree.filter.js + * + * Remove or highlight tree nodes, based on a filter. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + + +/******************************************************************************* + * Private functions and variables + */ + +function _escapeRegex(str){ + /*jshint regexdash:true */ + return (str + "").replace(/([.?*+\^\$\[\]\\(){}|-])/g, "\\$1"); +} + +$.ui.fancytree._FancytreeClass.prototype._applyFilterImpl = function(filter, branchMode, opts){ + var leavesOnly, match, re, re2, + count = 0, + filterOpts = this.options.filter, + hideMode = filterOpts.mode === "hide"; + + opts = opts || {}; + leavesOnly = !!opts.leavesOnly && !branchMode; + + // Default to 'match title substring (not case sensitive)' + if(typeof filter === "string"){ + // console.log("rex", filter.split('').join('\\w*').replace(/\W/, "")) + if( filterOpts.fuzzy ) { + // See https://codereview.stackexchange.com/questions/23899/faster-javascript-fuzzy-string-matching-function/23905#23905 + // and http://www.quora.com/How-is-the-fuzzy-search-algorithm-in-Sublime-Text-designed + // and http://www.dustindiaz.com/autocomplete-fuzzy-matching + match = filter.split("").reduce(function(a, b) { + return a + "[^" + b + "]*" + b; + }); + } else { + match = _escapeRegex(filter); // make sure a '.' is treated literally + } + re = new RegExp(".*" + match + ".*", "i"); + re2 = new RegExp(filter, "gi"); + filter = function(node){ + var res = !!re.test(node.title); + // node.debug("filter res", res, filterOpts.highlight) + if( res && filterOpts.highlight ) { + node.titleWithHighlight = node.title.replace(re2, function(s){ + return "<mark>" + s + "</mark>"; + }); + // } else { + // delete node.titleWithHighlight; + } + return res; + }; + } + + this.enableFilter = true; + this.lastFilterArgs = arguments; + + this.$div.addClass("fancytree-ext-filter"); + if( hideMode ){ + this.$div.addClass("fancytree-ext-filter-hide"); + } else { + this.$div.addClass("fancytree-ext-filter-dimm"); + } + // Reset current filter + this.visit(function(node){ + delete node.match; + delete node.titleWithHighlight; + node.subMatchCount = 0; + }); + // Adjust node.hide, .match, and .subMatchCount properties + this.visit(function(node){ + if ((!leavesOnly || node.children == null) && filter(node)) { + count++; + node.match = true; + node.visitParents(function(p){ + p.subMatchCount += 1; + if( opts.autoExpand && !p.expanded ) { + p.setExpanded(true, {noAnimation: true, noEvents: true, scrollIntoView: false}); + p._filterAutoExpanded = true; + } + }); + if( branchMode ) { + node.visit(function(p){ + p.match = true; + }); + return "skip"; + } + } + }); + // Redraw whole tree + this.render(); + return count; +}; + +/** + * [ext-filter] Dimm or hide nodes. + * + * @param {function | string} filter + * @param {boolean} [opts={autoExpand: false, leavesOnly: false}] + * @returns {integer} count + * @alias Fancytree#filterNodes + * @requires jquery.fancytree.filter.js + */ +$.ui.fancytree._FancytreeClass.prototype.filterNodes = function(filter, opts) { + if( typeof opts === "boolean" ) { + opts = { leavesOnly: opts }; + this.warn("Fancytree.filterNodes() leavesOnly option is deprecated since 2.9.0 / 2015-04-19."); + } + return this._applyFilterImpl(filter, false, opts); +}; + +/** + * @deprecated + */ +$.ui.fancytree._FancytreeClass.prototype.applyFilter = function(filter){ + this.warn("Fancytree.applyFilter() is deprecated since 2.1.0 / 2014-05-29. Use .filterNodes() instead."); + return this.filterNodes.apply(this, arguments); +}; + +/** + * [ext-filter] Dimm or hide whole branches. + * + * @param {function | string} filter + * @param {boolean} [opts={autoExpand: false}] + * @returns {integer} count + * @alias Fancytree#filterBranches + * @requires jquery.fancytree.filter.js + */ +$.ui.fancytree._FancytreeClass.prototype.filterBranches = function(filter, opts){ + return this._applyFilterImpl(filter, true, opts); +}; + + +/** + * [ext-filter] Reset the filter. + * + * @alias Fancytree#clearFilter + * @requires jquery.fancytree.filter.js + */ +$.ui.fancytree._FancytreeClass.prototype.clearFilter = function(){ + this.visit(function(node){ + if( node.match ) { // #491 + $(">span.fancytree-title", node.span).html(node.title); + } + delete node.match; + delete node.subMatchCount; + delete node.titleWithHighlight; + if ( node.$subMatchBadge ) { + node.$subMatchBadge.remove(); + delete node.$subMatchBadge; + } + if( node._filterAutoExpanded && node.expanded ) { + node.setExpanded(false, {noAnimation: true, noEvents: true, scrollIntoView: false}); + } + delete node._filterAutoExpanded; + }); + this.enableFilter = false; + this.lastFilterArgs = null; + this.$div.removeClass("fancytree-ext-filter fancytree-ext-filter-dimm fancytree-ext-filter-hide"); + this.render(); +}; + + +/** + * [ext-filter] Return true if a filter is currently applied. + * + * @returns {Boolean} + * @alias Fancytree#isFilterActive + * @requires jquery.fancytree.filter.js + * @since 2.13 + */ +$.ui.fancytree._FancytreeClass.prototype.isFilterActive = function(){ + return !!this.enableFilter; +}; + + +/** + * [ext-filter] Return true if this node is matched by current filter (or no filter is active). + * + * @returns {Boolean} + * @alias FancytreeNode#isMatched + * @requires jquery.fancytree.filter.js + * @since 2.13 + */ +$.ui.fancytree._FancytreeNodeClass.prototype.isMatched = function(){ + return !(this.tree.enableFilter && !this.match); +}; + + +/******************************************************************************* + * Extension code + */ +$.ui.fancytree.registerExtension({ + name: "filter", + version: "0.7.0", + // Default options for this extension. + options: { + autoApply: true, // Re-apply last filter if lazy data is loaded + counter: true, // Show a badge with number of matching child nodes near parent icons + fuzzy: false, // Match single characters in order, e.g. 'fb' will match 'FooBar' + hideExpandedCounter: true, // Hide counter badge, when parent is expanded + highlight: true, // Highlight matches by wrapping inside <mark> tags + mode: "dimm" // Grayout unmatched nodes (pass "hide" to remove unmatched node instead) + }, + // treeCreate: function(ctx){ + // this._superApply(arguments); + // console.log("create") + // ctx.tree.options.renderTitle = function(event, data) { + // var node = data.node; + // console.log("create n", node.titleWithHighlight, data.tree.enableFilter) + // if( node.titleWithHighlight && node.tree.enableFilter ) { + // return node.titleWithHighlight; + // } + // } + // }, + // treeInit: function(ctx){ + // this._superApply(arguments); + // }, + nodeLoadChildren: function(ctx, source) { + return this._superApply(arguments).done(function() { + if( ctx.tree.enableFilter && ctx.tree.lastFilterArgs && ctx.options.filter.autoApply ) { + ctx.tree._applyFilterImpl.apply(ctx.tree, ctx.tree.lastFilterArgs); + } + }); + }, + nodeSetExpanded: function(ctx, flag, callOpts) { + delete ctx.node._filterAutoExpanded; + // Make sure counter badge is displayed again, when node is beeing collapsed + if( !flag && ctx.options.filter.hideExpandedCounter && ctx.node.$subMatchBadge ) { + ctx.node.$subMatchBadge.show(); + } + return this._superApply(arguments); + }, + nodeRenderStatus: function(ctx) { + // Set classes for current status + var res, + node = ctx.node, + tree = ctx.tree, + opts = ctx.options.filter, + $span = $(node[tree.statusClassPropName]); + + res = this._superApply(arguments); + // nothing to do, if node was not yet rendered + if( !$span.length || !tree.enableFilter ) { + return res; + } + $span + .toggleClass("fancytree-match", !!node.match) + .toggleClass("fancytree-submatch", !!node.subMatchCount) + .toggleClass("fancytree-hide", !(node.match || node.subMatchCount)); + // Add/update counter badge + if( opts.counter && node.subMatchCount && (!node.isExpanded() || !opts.hideExpandedCounter) ) { + if( !node.$subMatchBadge ) { + node.$subMatchBadge = $("<span class='fancytree-childcounter'/>"); + $("span.fancytree-icon", node.span).append(node.$subMatchBadge); + } + node.$subMatchBadge.show().text(node.subMatchCount); + } else if ( node.$subMatchBadge ) { + node.$subMatchBadge.hide(); + } + // node.debug("nodeRenderStatus", node.titleWithHighlight, node.title) + if( node.titleWithHighlight ) { + $("span.fancytree-title", node.span).html(node.titleWithHighlight); + } else { + $("span.fancytree-title", node.span).html(node.title); + } + return res; + } +}); +}(jQuery, window, document)); diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.glyph.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.glyph.js new file mode 100644 index 00000000000..e8aa3aaa84e --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.glyph.js @@ -0,0 +1,139 @@ +/*! + * jquery.fancytree.glyph.js + * + * Use glyph fonts as instead of icon sprites. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + +/* ***************************************************************************** + * Private functions and variables + */ + +function _getIcon(opts, type){ + return opts.map[type]; +} + +$.ui.fancytree.registerExtension({ + name: "glyph", + version: "0.3.0", + // Default options for this extension. + options: { + map: { + // Samples from Font Awesome 3.2 + // http://fortawesome.github.io/Font-Awesome/3.2.1/icons/ + // See here for alternatives: + // http://fortawesome.github.io/Font-Awesome/icons/ + // http://getbootstrap.com/components/ + checkbox: "icon-check-empty", + checkboxSelected: "icon-check", + checkboxUnknown: "icon-check icon-muted", + error: "icon-exclamation-sign", + expanderClosed: "icon-caret-right", + expanderLazy: "icon-angle-right", + expanderOpen: "icon-caret-down", + noExpander: "", + dragHelper: "icon-caret-right", + dropMarker: "icon-caret-right", + // Default node icons. + // (Use tree.options.iconClass callback to define custom icons + // based on node data) + doc: "icon-file-alt", + docOpen: "icon-file-alt", + loading: "icon-refresh icon-spin", + folder: "icon-folder-close-alt", + folderOpen: "icon-folder-open-alt" + } + }, + + treeInit: function(ctx){ + var tree = ctx.tree; + this._superApply(arguments); + tree.$container.addClass("fancytree-ext-glyph"); + }, + nodeRenderStatus: function(ctx) { + var icon, span, + node = ctx.node, + $span = $(node.span), + opts = ctx.options.glyph, + // callback = opts.icon, + map = opts.map + // $span = $(node.span) + ; + + this._superApply(arguments); + + if( node.isRoot() ){ + return; + } + span = $span.children("span.fancytree-expander").get(0); + if( span ){ + if( node.isLoading() ){ + icon = "loading"; + }else if( node.expanded ){ + icon = "expanderOpen"; + }else if( node.isUndefined() ){ + icon = "expanderLazy"; + }else if( node.hasChildren() ){ + icon = "expanderClosed"; + }else{ + icon = "noExpander"; + } + span.className = "fancytree-expander " + map[icon]; + } + + if( node.tr ){ + span = $("td", node.tr).find("span.fancytree-checkbox").get(0); + }else{ + span = $span.children("span.fancytree-checkbox").get(0); + } + if( span ){ + icon = node.selected ? "checkboxSelected" : (node.partsel ? "checkboxUnknown" : "checkbox"); + span.className = "fancytree-checkbox " + map[icon]; + } + + // Icon (note that this does not match .fancytree-custom-icon, that might + // be set by opts.iconClass) + span = $span.children("span.fancytree-icon").get(0); + if( span ){ + if( node.folder ){ + icon = node.expanded ? _getIcon(opts, "folderOpen") : _getIcon(opts, "folder"); + }else{ + icon = node.expanded ? _getIcon(opts, "docOpen") : _getIcon(opts, "doc"); + } + span.className = "fancytree-icon " + icon; + } + }, + nodeSetStatus: function(ctx, status, message, details) { + var span, + opts = ctx.options.glyph, + node = ctx.node; + + this._superApply(arguments); + + if(node.parent){ + span = $("span.fancytree-expander", node.span).get(0); + }else{ + span = $(".fancytree-statusnode-wait, .fancytree-statusnode-error", node[this.nodeContainerAttrName]) + .find("span.fancytree-expander").get(0); + } + if( status === "loading"){ + // $("span.fancytree-expander", ctx.node.span).addClass(_getIcon(opts, "loading")); + span.className = "fancytree-expander " + _getIcon(opts, "loading"); + }else if( status === "error"){ + span.className = "fancytree-expander " + _getIcon(opts, "error"); + } + } +}); +}(jQuery, window, document)); diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.gridnav.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.gridnav.js new file mode 100644 index 00000000000..d700c2a54d2 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.gridnav.js @@ -0,0 +1,199 @@ +/*! + * jquery.fancytree.gridnav.js + * + * Support keyboard navigation for trees with embedded input controls. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + + +/******************************************************************************* + * Private functions and variables + */ + +// Allow these navigation keys even when input controls are focused + +var KC = $.ui.keyCode, + // which keys are *not* handled by embedded control, but passed to tree + // navigation handler: + NAV_KEYS = { + "text": [KC.UP, KC.DOWN], + "checkbox": [KC.UP, KC.DOWN, KC.LEFT, KC.RIGHT], + "radiobutton": [KC.UP, KC.DOWN, KC.LEFT, KC.RIGHT], + "select-one": [KC.LEFT, KC.RIGHT], + "select-multiple": [KC.LEFT, KC.RIGHT] + }; + + +/* Calculate TD column index (considering colspans).*/ +function getColIdx($tr, $td) { + var colspan, + td = $td.get(0), + idx = 0; + + $tr.children().each(function () { + if( this === td ) { + return false; + } + colspan = $(this).prop("colspan"); + idx += colspan ? colspan : 1; + }); + return idx; +} + + +/* Find TD at given column index (considering colspans).*/ +function findTdAtColIdx($tr, colIdx) { + var colspan, + res = null, + idx = 0; + + $tr.children().each(function () { + if( idx >= colIdx ) { + res = $(this); + return false; + } + colspan = $(this).prop("colspan"); + idx += colspan ? colspan : 1; + }); + return res; +} + + +/* Find adjacent cell for a given direction. Skip empty cells and consider merged cells */ +function findNeighbourTd($target, keyCode){ + var $tr, colIdx, + $td = $target.closest("td"), + $tdNext = null; + + switch( keyCode ){ + case KC.LEFT: + $tdNext = $td.prev(); + break; + case KC.RIGHT: + $tdNext = $td.next(); + break; + case KC.UP: + case KC.DOWN: + $tr = $td.parent(); + colIdx = getColIdx($tr, $td); + while( true ) { + $tr = (keyCode === KC.UP) ? $tr.prev() : $tr.next(); + if( !$tr.length ) { + break; + } + // Skip hidden rows + if( $tr.is(":hidden") ) { + continue; + } + // Find adjacent cell in the same column + $tdNext = findTdAtColIdx($tr, colIdx); + // Skip cells that don't conatain a focusable element + if( $tdNext && $tdNext.find(":input").length ) { + break; + } + } + break; + } + return $tdNext; +} + + +/******************************************************************************* + * Extension code + */ +$.ui.fancytree.registerExtension({ + name: "gridnav", + version: "0.0.1", + // Default options for this extension. + options: { + autofocusInput: false, // Focus first embedded input if node gets activated + handleCursorKeys: true // Allow UP/DOWN in inputs to move to prev/next node + }, + + treeInit: function(ctx){ + // gridnav requires the table extension to be loaded before itself + this._requireExtension("table", true, true); + this._superApply(arguments); + + this.$container.addClass("fancytree-ext-gridnav"); + + // Activate node if embedded input gets focus (due to a click) + this.$container.on("focusin", function(event){ + var ctx2, + node = $.ui.fancytree.getNode(event.target); + + if( node && !node.isActive() ){ + // Call node.setActive(), but also pass the event + ctx2 = ctx.tree._makeHookContext(node, event); + ctx.tree._callHook("nodeSetActive", ctx2, true); + } + }); + }, + nodeSetActive: function(ctx, flag) { + var $outer, + opts = ctx.options.gridnav, + node = ctx.node, + event = ctx.originalEvent || {}, + triggeredByInput = $(event.target).is(":input"); + + flag = (flag !== false); + + this._superApply(arguments); + + if( flag ){ + if( ctx.options.titlesTabbable ){ + if( !triggeredByInput ) { + $(node.span).find("span.fancytree-title").focus(); + node.setFocus(); + } + // If one node is tabbable, the container no longer needs to be + ctx.tree.$container.attr("tabindex", "-1"); + // ctx.tree.$container.removeAttr("tabindex"); + } else if( opts.autofocusInput && !triggeredByInput ){ + // Set focus to input sub input (if node was clicked, but not + // when TAB was pressed ) + $outer = $(node.tr || node.span); + $outer.find(":input:enabled:first").focus(); + } + } + }, + nodeKeydown: function(ctx) { + var inputType, handleKeys, $td, + opts = ctx.options.gridnav, + event = ctx.originalEvent, + $target = $(event.target); + + // jQuery + inputType = $target.is(":input:enabled") ? $target.prop("type") : null; +// ctx.tree.debug("ext-gridnav nodeKeydown", event, inputType); + + if( inputType && opts.handleCursorKeys ){ + handleKeys = NAV_KEYS[inputType]; + if( handleKeys && $.inArray(event.which, handleKeys) >= 0 ){ + $td = findNeighbourTd($target, event.which); + // ctx.node.debug("ignore keydown in input", event.which, handleKeys); + if( $td && $td.length ) { + $td.find(":input:enabled").focus(); + // Prevent Fancytree default navigation + return false; + } + } + return true; + } + // ctx.tree.debug("ext-gridnav NOT HANDLED", event, inputType); + return this._superApply(arguments); + } +}); +}(jQuery, window, document)); diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.js new file mode 100644 index 00000000000..95de0d3735c --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.js @@ -0,0 +1,4515 @@ +/*! + * jquery.fancytree.js + * Tree view control with support for lazy loading and much more. + * https://github.com/mar10/fancytree/ + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +/** Core Fancytree module. + */ + + +// Start of local namespace +;(function($, window, document, undefined) { +"use strict"; + +// prevent duplicate loading +if ( $.ui && $.ui.fancytree ) { + $.ui.fancytree.warn("Fancytree: ignored duplicate include"); + return; +} + + +/* ***************************************************************************** + * Private functions and variables + */ + +function _assert(cond, msg){ + // TODO: see qunit.js extractStacktrace() + if(!cond){ + msg = msg ? ": " + msg : ""; + // consoleApply("assert", [!!cond, msg]); + $.error("Fancytree assertion failed" + msg); + } +} + +_assert($.ui, "Fancytree requires jQuery UI (http://jqueryui.com)"); + +function consoleApply(method, args){ + var i, s, + fn = window.console ? window.console[method] : null; + + if(fn){ + try{ + fn.apply(window.console, args); + } catch(e) { + // IE 8? + s = ""; + for( i=0; i<args.length; i++){ + s += args[i]; + } + fn(s); + } + } +} + +/*Return true if x is a FancytreeNode.*/ +function _isNode(x){ + return !!(x.tree && x.statusNodeType !== undefined); +} + +/** Return true if dotted version string is equal or higher than requested version. + * + * See http://jsfiddle.net/mar10/FjSAN/ + */ +function isVersionAtLeast(dottedVersion, major, minor, patch){ + var i, v, t, + verParts = $.map($.trim(dottedVersion).split("."), function(e){ return parseInt(e, 10); }), + testParts = $.map(Array.prototype.slice.call(arguments, 1), function(e){ return parseInt(e, 10); }); + + for( i = 0; i < testParts.length; i++ ){ + v = verParts[i] || 0; + t = testParts[i] || 0; + if( v !== t ){ + return ( v > t ); + } + } + return true; +} + +/** Return a wrapper that calls sub.methodName() and exposes + * this : tree + * this._local : tree.ext.EXTNAME + * this._super : base.methodName() + */ +function _makeVirtualFunction(methodName, tree, base, extension, extName){ + // $.ui.fancytree.debug("_makeVirtualFunction", methodName, tree, base, extension, extName); + // if(rexTestSuper && !rexTestSuper.test(func)){ + // // extension.methodName() doesn't call _super(), so no wrapper required + // return func; + // } + // Use an immediate function as closure + var proxy = (function(){ + var prevFunc = tree[methodName], // org. tree method or prev. proxy + baseFunc = extension[methodName], // + _local = tree.ext[extName], + _super = function(){ + return prevFunc.apply(tree, arguments); + }, + _superApply = function(args){ + return prevFunc.apply(tree, args); + }; + + // Return the wrapper function + return function(){ + var prevLocal = tree._local, + prevSuper = tree._super, + prevSuperApply = tree._superApply; + + try{ + tree._local = _local; + tree._super = _super; + tree._superApply = _superApply; + return baseFunc.apply(tree, arguments); + }finally{ + tree._local = prevLocal; + tree._super = prevSuper; + tree._superApply = prevSuperApply; + } + }; + })(); // end of Immediate Function + return proxy; +} + +/** + * Subclass `base` by creating proxy functions + */ +function _subclassObject(tree, base, extension, extName){ + // $.ui.fancytree.debug("_subclassObject", tree, base, extension, extName); + for(var attrName in extension){ + if(typeof extension[attrName] === "function"){ + if(typeof tree[attrName] === "function"){ + // override existing method + tree[attrName] = _makeVirtualFunction(attrName, tree, base, extension, extName); + }else if(attrName.charAt(0) === "_"){ + // Create private methods in tree.ext.EXTENSION namespace + tree.ext[extName][attrName] = _makeVirtualFunction(attrName, tree, base, extension, extName); + }else{ + $.error("Could not override tree." + attrName + ". Use prefix '_' to create tree." + extName + "._" + attrName); + } + }else{ + // Create member variables in tree.ext.EXTENSION namespace + if(attrName !== "options"){ + tree.ext[extName][attrName] = extension[attrName]; + } + } + } +} + + +function _getResolvedPromise(context, argArray){ + if(context === undefined){ + return $.Deferred(function(){this.resolve();}).promise(); + }else{ + return $.Deferred(function(){this.resolveWith(context, argArray);}).promise(); + } +} + + +function _getRejectedPromise(context, argArray){ + if(context === undefined){ + return $.Deferred(function(){this.reject();}).promise(); + }else{ + return $.Deferred(function(){this.rejectWith(context, argArray);}).promise(); + } +} + + +function _makeResolveFunc(deferred, context){ + return function(){ + deferred.resolveWith(context); + }; +} + + +function _getElementDataAsDict($el){ + // Evaluate 'data-NAME' attributes with special treatment for 'data-json'. + var d = $.extend({}, $el.data()), + json = d.json; + + delete d.fancytree; // added to container by widget factory (old jQuery UI) + delete d.uiFancytree; // added to container by widget factory + + if( json ) { + delete d.json; + // <li data-json='...'> is already returned as object (http://api.jquery.com/data/#data-html5) + d = $.extend(d, json); + } + return d; +} + + +// TODO: use currying +function _makeNodeTitleMatcher(s){ + s = s.toLowerCase(); + return function(node){ + return node.title.toLowerCase().indexOf(s) >= 0; + }; +} + + +function _makeNodeTitleStartMatcher(s){ + var reMatch = new RegExp("^" + s, "i"); + return function(node){ + return reMatch.test(node.title); + }; +} + +var i, attr, + FT = null, // initialized below + ENTITY_MAP = {"&": "&", "<": "<", ">": ">", "\"": """, "'": "'", "/": "/"}, + IGNORE_KEYCODES = { 16: true, 17: true, 18: true }, + SPECIAL_KEYCODES = { + 8: "backspace", 9: "tab", 10: "return", 13: "return", + // 16: null, 17: null, 18: null, // ignore shift, ctrl, alt + 19: "pause", 20: "capslock", 27: "esc", 32: "space", 33: "pageup", + 34: "pagedown", 35: "end", 36: "home", 37: "left", 38: "up", + 39: "right", 40: "down", 45: "insert", 46: "del", 59: ";", 61: "=", + 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", + 103: "7", 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", + 111: "/", 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: "scroll", 173: "-", 186: ";", 187: "=", + 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", + 221: "]", 222: "'"}, + MOUSE_BUTTONS = { 0: "", 1: "left", 2: "middle", 3: "right" }, + //boolean attributes that can be set with equivalent class names in the LI tags + CLASS_ATTRS = "active expanded focus folder hideCheckbox lazy selected unselectable".split(" "), + CLASS_ATTR_MAP = {}, + // Top-level Fancytree node attributes, that can be set by dict + NODE_ATTRS = "expanded extraClasses folder hideCheckbox key lazy refKey selected title tooltip unselectable".split(" "), + NODE_ATTR_MAP = {}, + // Mapping of lowercase -> real name (because HTML5 data-... attribute only supports lowercase) + NODE_ATTR_LOWERCASE_MAP = {}, + // Attribute names that should NOT be added to node.data + NONE_NODE_DATA_MAP = {"active": true, "children": true, "data": true, "focus": true}; + +for(i=0; i<CLASS_ATTRS.length; i++){ CLASS_ATTR_MAP[CLASS_ATTRS[i]] = true; } +for(i=0; i<NODE_ATTRS.length; i++) { + attr = NODE_ATTRS[i]; + NODE_ATTR_MAP[attr] = true; + if( attr !== attr.toLowerCase() ) { + NODE_ATTR_LOWERCASE_MAP[attr.toLowerCase()] = attr; + } +} + + +/* ***************************************************************************** + * FancytreeNode + */ + + +/** + * Creates a new FancytreeNode + * + * @class FancytreeNode + * @classdesc A FancytreeNode represents the hierarchical data model and operations. + * + * @param {FancytreeNode} parent + * @param {NodeData} obj + * + * @property {Fancytree} tree The tree instance + * @property {FancytreeNode} parent The parent node + * @property {string} key Node id (must be unique inside the tree) + * @property {string} title Display name (may contain HTML) + * @property {object} data Contains all extra data that was passed on node creation + * @property {FancytreeNode[] | null | undefined} children Array of child nodes.<br> + * For lazy nodes, null or undefined means 'not yet loaded'. Use an empty array + * to define a node that has no children. + * @property {boolean} expanded Use isExpanded(), setExpanded() to access this property. + * @property {string} extraClasses Addtional CSS classes, added to the node's `<span>` + * @property {boolean} folder Folder nodes have different default icons and click behavior.<br> + * Note: Also non-folders may have children. + * @property {string} statusNodeType null or type of temporarily generated system node like 'loading', or 'error'. + * @property {boolean} lazy True if this node is loaded on demand, i.e. on first expansion. + * @property {boolean} selected Use isSelected(), setSelected() to access this property. + * @property {string} tooltip Alternative description used as hover banner + */ +function FancytreeNode(parent, obj){ + var i, l, name, cl; + + this.parent = parent; + this.tree = parent.tree; + this.ul = null; + this.li = null; // <li id='key' ftnode=this> tag + this.statusNodeType = null; // if this is a temp. node to display the status of its parent + this._isLoading = false; // if this node itself is loading + this._error = null; // {message: '...'} if a load error occurred + this.data = {}; + + // TODO: merge this code with node.toDict() + // copy attributes from obj object + for(i=0, l=NODE_ATTRS.length; i<l; i++){ + name = NODE_ATTRS[i]; + this[name] = obj[name]; + } + // node.data += obj.data + if(obj.data){ + $.extend(this.data, obj.data); + } + // copy all other attributes to this.data.NAME + for(name in obj){ + if(!NODE_ATTR_MAP[name] && !$.isFunction(obj[name]) && !NONE_NODE_DATA_MAP[name]){ + // node.data.NAME = obj.NAME + this.data[name] = obj[name]; + } + } + + // Fix missing key + if( this.key == null ){ // test for null OR undefined + if( this.tree.options.defaultKey ) { + this.key = this.tree.options.defaultKey(this); + _assert(this.key, "defaultKey() must return a unique key"); + } else { + this.key = "_" + (FT._nextNodeKey++); + } + } else { + this.key = "" + this.key; // Convert to string (#217) + } + + // Fix tree.activeNode + // TODO: not elegant: we use obj.active as marker to set tree.activeNode + // when loading from a dictionary. + if(obj.active){ + _assert(this.tree.activeNode === null, "only one active node allowed"); + this.tree.activeNode = this; + } + if( obj.selected ){ // #186 + this.tree.lastSelectedNode = this; + } + // TODO: handle obj.focus = true + // Create child nodes + cl = obj.children; + if( cl ){ + if( cl.length ){ + this._setChildren(cl); + } else { + // if an empty array was passed for a lazy node, keep it, in order to mark it 'loaded' + this.children = this.lazy ? [] : null; + } + } else { + this.children = null; + } + // Add to key/ref map (except for root node) +// if( parent ) { + this.tree._callHook("treeRegisterNode", this.tree, true, this); +// } +} + + +FancytreeNode.prototype = /** @lends FancytreeNode# */{ + /* Return the direct child FancytreeNode with a given key, index. */ + _findDirectChild: function(ptr){ + var i, l, + cl = this.children; + + if(cl){ + if(typeof ptr === "string"){ + for(i=0, l=cl.length; i<l; i++){ + if(cl[i].key === ptr){ + return cl[i]; + } + } + }else if(typeof ptr === "number"){ + return this.children[ptr]; + }else if(ptr.parent === this){ + return ptr; + } + } + return null; + }, + // TODO: activate() + // TODO: activateSilently() + /* Internal helper called in recursive addChildren sequence.*/ + _setChildren: function(children){ + _assert(children && (!this.children || this.children.length === 0), "only init supported"); + this.children = []; + for(var i=0, l=children.length; i<l; i++){ + this.children.push(new FancytreeNode(this, children[i])); + } + }, + /** + * Append (or insert) a list of child nodes. + * + * @param {NodeData[]} children array of child node definitions (also single child accepted) + * @param {FancytreeNode | string | Integer} [insertBefore] child node (or key or index of such). + * If omitted, the new children are appended. + * @returns {FancytreeNode} first child added + * + * @see FancytreeNode#applyPatch + */ + addChildren: function(children, insertBefore){ + var i, l, pos, + firstNode = null, + nodeList = []; + + if($.isPlainObject(children) ){ + children = [children]; + } + if(!this.children){ + this.children = []; + } + for(i=0, l=children.length; i<l; i++){ + nodeList.push(new FancytreeNode(this, children[i])); + } + firstNode = nodeList[0]; + if(insertBefore == null){ + this.children = this.children.concat(nodeList); + }else{ + insertBefore = this._findDirectChild(insertBefore); + pos = $.inArray(insertBefore, this.children); + _assert(pos >= 0, "insertBefore must be an existing child"); + // insert nodeList after children[pos] + this.children.splice.apply(this.children, [pos, 0].concat(nodeList)); + } + if( !this.parent || this.parent.ul || this.tr ){ + // render if the parent was rendered (or this is a root node) + this.render(); + } + if( this.tree.options.selectMode === 3 ){ + this.fixSelection3FromEndNodes(); + } + return firstNode; + }, + /** + * Append or prepend a node, or append a child node. + * + * This a convenience function that calls addChildren() + * + * @param {NodeData} node node definition + * @param {string} [mode=child] 'before', 'after', 'firstChild', or 'child' ('over' is a synonym for 'child') + * @returns {FancytreeNode} new node + */ + addNode: function(node, mode){ + if(mode === undefined || mode === "over"){ + mode = "child"; + } + switch(mode){ + case "after": + return this.getParent().addChildren(node, this.getNextSibling()); + case "before": + return this.getParent().addChildren(node, this); + case "firstChild": + // Insert before the first child if any + var insertBefore = (this.children ? this.children[0] : null); + return this.addChildren(node, insertBefore); + case "child": + case "over": + return this.addChildren(node); + } + _assert(false, "Invalid mode: " + mode); + }, + /** + * Append new node after this. + * + * This a convenience function that calls addNode(node, 'after') + * + * @param {NodeData} node node definition + * @returns {FancytreeNode} new node + */ + appendSibling: function(node){ + return this.addNode(node, "after"); + }, + /** + * Modify existing child nodes. + * + * @param {NodePatch} patch + * @returns {$.Promise} + * @see FancytreeNode#addChildren + */ + applyPatch: function(patch) { + // patch [key, null] means 'remove' + if(patch === null){ + this.remove(); + return _getResolvedPromise(this); + } + // TODO: make sure that root node is not collapsed or modified + // copy (most) attributes to node.ATTR or node.data.ATTR + var name, promise, v, + IGNORE_MAP = { children: true, expanded: true, parent: true }; // TODO: should be global + + for(name in patch){ + v = patch[name]; + if( !IGNORE_MAP[name] && !$.isFunction(v)){ + if(NODE_ATTR_MAP[name]){ + this[name] = v; + }else{ + this.data[name] = v; + } + } + } + // Remove and/or create children + if(patch.hasOwnProperty("children")){ + this.removeChildren(); + if(patch.children){ // only if not null and not empty list + // TODO: addChildren instead? + this._setChildren(patch.children); + } + // TODO: how can we APPEND or INSERT child nodes? + } + if(this.isVisible()){ + this.renderTitle(); + this.renderStatus(); + } + // Expand collapse (final step, since this may be async) + if(patch.hasOwnProperty("expanded")){ + promise = this.setExpanded(patch.expanded); + }else{ + promise = _getResolvedPromise(this); + } + return promise; + }, + /** Collapse all sibling nodes. + * @returns {$.Promise} + */ + collapseSiblings: function() { + return this.tree._callHook("nodeCollapseSiblings", this); + }, + /** Copy this node as sibling or child of `node`. + * + * @param {FancytreeNode} node source node + * @param {string} [mode=child] 'before' | 'after' | 'child' + * @param {Function} [map] callback function(NodeData) that could modify the new node + * @returns {FancytreeNode} new + */ + copyTo: function(node, mode, map) { + return node.addNode(this.toDict(true, map), mode); + }, + /** Count direct and indirect children. + * + * @param {boolean} [deep=true] pass 'false' to only count direct children + * @returns {int} number of child nodes + */ + countChildren: function(deep) { + var cl = this.children, i, l, n; + if( !cl ){ + return 0; + } + n = cl.length; + if(deep !== false){ + for(i=0, l=n; i<l; i++){ + n += cl[i].countChildren(); + } + } + return n; + }, + // TODO: deactivate() + /** Write to browser console if debugLevel >= 2 (prepending node info) + * + * @param {*} msg string or object or array of such + */ + debug: function(msg){ + if( this.tree.options.debugLevel >= 2 ) { + Array.prototype.unshift.call(arguments, this.toString()); + consoleApply("log", arguments); + } + }, + /** Deprecated. + * @deprecated since 2014-02-16. Use resetLazy() instead. + */ + discard: function(){ + this.warn("FancytreeNode.discard() is deprecated since 2014-02-16. Use .resetLazy() instead."); + return this.resetLazy(); + }, + + // TODO: expand(flag) + + /**Find all nodes that match condition (excluding self). + * + * @param {string | function(node)} match title string to search for, or a + * callback function that returns `true` if a node is matched. + * @returns {FancytreeNode[]} array of nodes (may be empty) + */ + findAll: function(match) { + match = $.isFunction(match) ? match : _makeNodeTitleMatcher(match); + var res = []; + this.visit(function(n){ + if(match(n)){ + res.push(n); + } + }); + return res; + }, + /**Find first node that matches condition (excluding self). + * + * @param {string | function(node)} match title string to search for, or a + * callback function that returns `true` if a node is matched. + * @returns {FancytreeNode} matching node or null + * @see FancytreeNode#findAll + */ + findFirst: function(match) { + match = $.isFunction(match) ? match : _makeNodeTitleMatcher(match); + var res = null; + this.visit(function(n){ + if(match(n)){ + res = n; + return false; + } + }); + return res; + }, + /* Apply selection state (internal use only) */ + _changeSelectStatusAttrs: function (state) { + var changed = false; + + switch(state){ + case false: + changed = ( this.selected || this.partsel ); + this.selected = false; + this.partsel = false; + break; + case true: + changed = ( !this.selected || !this.partsel ); + this.selected = true; + this.partsel = true; + break; + case undefined: + changed = ( this.selected || !this.partsel ); + this.selected = false; + this.partsel = true; + break; + default: + _assert(false, "invalid state: " + state); + } + // this.debug("fixSelection3AfterLoad() _changeSelectStatusAttrs()", state, changed); + if( changed ){ + this.renderStatus(); + } + return changed; + }, + /** + * Fix selection status, after this node was (de)selected in multi-hier mode. + * This includes (de)selecting all children. + */ + fixSelection3AfterClick: function() { + var flag = this.isSelected(); + +// this.debug("fixSelection3AfterClick()"); + + this.visit(function(node){ + node._changeSelectStatusAttrs(flag); + }); + this.fixSelection3FromEndNodes(); + }, + /** + * Fix selection status for multi-hier mode. + * Only end-nodes are considered to update the descendants branch and parents. + * Should be called after this node has loaded new children or after + * children have been modified using the API. + */ + fixSelection3FromEndNodes: function() { +// this.debug("fixSelection3FromEndNodes()"); + _assert(this.tree.options.selectMode === 3, "expected selectMode 3"); + + // Visit all end nodes and adjust their parent's `selected` and `partsel` + // attributes. Return selection state true, false, or undefined. + function _walk(node){ + var i, l, child, s, state, allSelected,someSelected, + children = node.children; + + if( children && children.length ){ + // check all children recursively + allSelected = true; + someSelected = false; + + for( i=0, l=children.length; i<l; i++ ){ + child = children[i]; + // the selection state of a node is not relevant; we need the end-nodes + s = _walk(child); + if( s !== false ) { + someSelected = true; + } + if( s !== true ) { + allSelected = false; + } + } + state = allSelected ? true : (someSelected ? undefined : false); + }else{ + // This is an end-node: simply report the status +// state = ( node.unselectable ) ? undefined : !!node.selected; + state = !!node.selected; + } + node._changeSelectStatusAttrs(state); + return state; + } + _walk(this); + + // Update parent's state + this.visitParents(function(node){ + var i, l, child, state, + children = node.children, + allSelected = true, + someSelected = false; + + for( i=0, l=children.length; i<l; i++ ){ + child = children[i]; + // When fixing the parents, we trust the sibling status (i.e. + // we don't recurse) + if( child.selected || child.partsel ) { + someSelected = true; + } + if( !child.unselectable && !child.selected ) { + allSelected = false; + } + } + state = allSelected ? true : (someSelected ? undefined : false); + node._changeSelectStatusAttrs(state); + }); + }, + // TODO: focus() + /** + * Update node data. If dict contains 'children', then also replace + * the hole sub tree. + * @param {NodeData} dict + * + * @see FancytreeNode#addChildren + * @see FancytreeNode#applyPatch + */ + fromDict: function(dict) { + // copy all other attributes to this.data.xxx + for(var name in dict){ + if(NODE_ATTR_MAP[name]){ + // node.NAME = dict.NAME + this[name] = dict[name]; + }else if(name === "data"){ + // node.data += dict.data + $.extend(this.data, dict.data); + }else if(!$.isFunction(dict[name]) && !NONE_NODE_DATA_MAP[name]){ + // node.data.NAME = dict.NAME + this.data[name] = dict[name]; + } + } + if(dict.children){ + // recursively set children and render + this.removeChildren(); + this.addChildren(dict.children); + } + this.renderTitle(); +/* + var children = dict.children; + if(children === undefined){ + this.data = $.extend(this.data, dict); + this.render(); + return; + } + dict = $.extend({}, dict); + dict.children = undefined; + this.data = $.extend(this.data, dict); + this.removeChildren(); + this.addChild(children); +*/ + }, + /** Return the list of child nodes (undefined for unexpanded lazy nodes). + * @returns {FancytreeNode[] | undefined} + */ + getChildren: function() { + if(this.hasChildren() === undefined){ // TODO: only required for lazy nodes? + return undefined; // Lazy node: unloaded, currently loading, or load error + } + return this.children; + }, + /** Return the first child node or null. + * @returns {FancytreeNode | null} + */ + getFirstChild: function() { + return this.children ? this.children[0] : null; + }, + /** Return the 0-based child index. + * @returns {int} + */ + getIndex: function() { +// return this.parent.children.indexOf(this); + return $.inArray(this, this.parent.children); // indexOf doesn't work in IE7 + }, + /** Return the hierarchical child index (1-based, e.g. '3.2.4'). + * @returns {string} + */ + getIndexHier: function(separator) { + separator = separator || "."; + var res = []; + $.each(this.getParentList(false, true), function(i, o){ + res.push(o.getIndex() + 1); + }); + return res.join(separator); + }, + /** Return the parent keys separated by options.keyPathSeparator, e.g. "id_1/id_17/id_32". + * @param {boolean} [excludeSelf=false] + * @returns {string} + */ + getKeyPath: function(excludeSelf) { + var path = [], + sep = this.tree.options.keyPathSeparator; + this.visitParents(function(n){ + if(n.parent){ + path.unshift(n.key); + } + }, !excludeSelf); + return sep + path.join(sep); + }, + /** Return the last child of this node or null. + * @returns {FancytreeNode | null} + */ + getLastChild: function() { + return this.children ? this.children[this.children.length - 1] : null; + }, + /** Return node depth. 0: System root node, 1: visible top-level node, 2: first sub-level, ... . + * @returns {int} + */ + getLevel: function() { + var level = 0, + dtn = this.parent; + while( dtn ) { + level++; + dtn = dtn.parent; + } + return level; + }, + /** Return the successor node (under the same parent) or null. + * @returns {FancytreeNode | null} + */ + getNextSibling: function() { + // TODO: use indexOf, if available: (not in IE6) + if( this.parent ){ + var i, l, + ac = this.parent.children; + + for(i=0, l=ac.length-1; i<l; i++){ // up to length-2, so next(last) = null + if( ac[i] === this ){ + return ac[i+1]; + } + } + } + return null; + }, + /** Return the parent node (null for the system root node). + * @returns {FancytreeNode | null} + */ + getParent: function() { + // TODO: return null for top-level nodes? + return this.parent; + }, + /** Return an array of all parent nodes (top-down). + * @param {boolean} [includeRoot=false] Include the invisible system root node. + * @param {boolean} [includeSelf=false] Include the node itself. + * @returns {FancytreeNode[]} + */ + getParentList: function(includeRoot, includeSelf) { + var l = [], + dtn = includeSelf ? this : this.parent; + while( dtn ) { + if( includeRoot || dtn.parent ){ + l.unshift(dtn); + } + dtn = dtn.parent; + } + return l; + }, + /** Return the predecessor node (under the same parent) or null. + * @returns {FancytreeNode | null} + */ + getPrevSibling: function() { + if( this.parent ){ + var i, l, + ac = this.parent.children; + + for(i=1, l=ac.length; i<l; i++){ // start with 1, so prev(first) = null + if( ac[i] === this ){ + return ac[i-1]; + } + } + } + return null; + }, + /** Return true if node has children. Return undefined if not sure, i.e. the node is lazy and not yet loaded). + * @returns {boolean | undefined} + */ + hasChildren: function() { + if(this.lazy){ + if(this.children == null ){ + // null or undefined: Not yet loaded + return undefined; + }else if(this.children.length === 0){ + // Loaded, but response was empty + return false; + }else if(this.children.length === 1 && this.children[0].isStatusNode() ){ + // Currently loading or load error + return undefined; + } + return true; + } + return !!( this.children && this.children.length ); + }, + /** Return true if node has keyboard focus. + * @returns {boolean} + */ + hasFocus: function() { + return (this.tree.hasFocus() && this.tree.focusNode === this); + }, + /** Write to browser console if debugLevel >= 1 (prepending node info) + * + * @param {*} msg string or object or array of such + */ + info: function(msg){ + if( this.tree.options.debugLevel >= 1 ) { + Array.prototype.unshift.call(arguments, this.toString()); + consoleApply("info", arguments); + } + }, + /** Return true if node is active (see also FancytreeNode#isSelected). + * @returns {boolean} + */ + isActive: function() { + return (this.tree.activeNode === this); + }, + /** Return true if node is a direct child of otherNode. + * @param {FancytreeNode} otherNode + * @returns {boolean} + */ + isChildOf: function(otherNode) { + return (this.parent && this.parent === otherNode); + }, + /** Return true, if node is a direct or indirect sub node of otherNode. + * @param {FancytreeNode} otherNode + * @returns {boolean} + */ + isDescendantOf: function(otherNode) { + if(!otherNode || otherNode.tree !== this.tree){ + return false; + } + var p = this.parent; + while( p ) { + if( p === otherNode ){ + return true; + } + p = p.parent; + } + return false; + }, + /** Return true if node is expanded. + * @returns {boolean} + */ + isExpanded: function() { + return !!this.expanded; + }, + /** Return true if node is the first node of its parent's children. + * @returns {boolean} + */ + isFirstSibling: function() { + var p = this.parent; + return !p || p.children[0] === this; + }, + /** Return true if node is a folder, i.e. has the node.folder attribute set. + * @returns {boolean} + */ + isFolder: function() { + return !!this.folder; + }, + /** Return true if node is the last node of its parent's children. + * @returns {boolean} + */ + isLastSibling: function() { + var p = this.parent; + return !p || p.children[p.children.length-1] === this; + }, + /** Return true if node is lazy (even if data was already loaded) + * @returns {boolean} + */ + isLazy: function() { + return !!this.lazy; + }, + /** Return true if node is lazy and loaded. For non-lazy nodes always return true. + * @returns {boolean} + */ + isLoaded: function() { + return !this.lazy || this.hasChildren() !== undefined; // Also checks if the only child is a status node + }, + /** Return true if children are currently beeing loaded, i.e. a Ajax request is pending. + * @returns {boolean} + */ + isLoading: function() { + return !!this._isLoading; + }, + /* + * @deprecated since v2.4.0: Use isRootNode() instead + */ + isRoot: function() { + return this.isRootNode(); + }, + /** Return true if this is the (invisible) system root node. + * @returns {boolean} + * @since 2.4 + */ + isRootNode: function() { + return (this.tree.rootNode === this); + }, + /** Return true if node is selected, i.e. has a checkmark set (see also FancytreeNode#isActive). + * @returns {boolean} + */ + isSelected: function() { + return !!this.selected; + }, + /** Return true if this node is a temporarily generated system node like + * 'loading', or 'error' (node.statusNodeType contains the type). + * @returns {boolean} + */ + isStatusNode: function() { + return !!this.statusNodeType; + }, + /** Return true if this a top level node, i.e. a direct child of the (invisible) system root node. + * @returns {boolean} + * @since 2.4 + */ + isTopLevel: function() { + return (this.tree.rootNode === this.parent); + }, + /** Return true if node is lazy and not yet loaded. For non-lazy nodes always return false. + * @returns {boolean} + */ + isUndefined: function() { + return this.hasChildren() === undefined; // also checks if the only child is a status node + }, + /** Return true if all parent nodes are expanded. Note: this does not check + * whether the node is scrolled into the visible part of the screen. + * @returns {boolean} + */ + isVisible: function() { + var i, l, + parents = this.getParentList(false, false); + + for(i=0, l=parents.length; i<l; i++){ + if( ! parents[i].expanded ){ return false; } + } + return true; + }, + /** Deprecated. + * @deprecated since 2014-02-16: use load() instead. + */ + lazyLoad: function(discard) { + this.warn("FancytreeNode.lazyLoad() is deprecated since 2014-02-16. Use .load() instead."); + return this.load(discard); + }, + /** + * Load all children of a lazy node if neccessary. The *expanded* state is maintained. + * @param {boolean} [forceReload=false] Pass true to discard any existing nodes before. + * @returns {$.Promise} + */ + load: function(forceReload) { + var res, source, + that = this; + + _assert( this.isLazy(), "load() requires a lazy node" ); + // _assert( forceReload || this.isUndefined(), "Pass forceReload=true to re-load a lazy node" ); + if( !forceReload && !this.isUndefined() ) { + return _getResolvedPromise(this); + } + if( this.isLoaded() ){ + this.resetLazy(); // also collapses + } + // This method is also called by setExpanded() and loadKeyPath(), so we + // have to avoid recursion. + source = this.tree._triggerNodeEvent("lazyLoad", this); + if( source === false ) { // #69 + return _getResolvedPromise(this); + } + _assert(typeof source !== "boolean", "lazyLoad event must return source in data.result"); + res = this.tree._callHook("nodeLoadChildren", this, source); + if( this.expanded ) { + res.always(function(){ + that.render(); + }); + } + return res; + }, + /** Expand all parents and optionally scroll into visible area as neccessary. + * Promise is resolved, when lazy loading and animations are done. + * @param {object} [opts] passed to `setExpanded()`. + * Defaults to {noAnimation: false, noEvents: false, scrollIntoView: true} + * @returns {$.Promise} + */ + makeVisible: function(opts) { + var i, + that = this, + deferreds = [], + dfd = new $.Deferred(), + parents = this.getParentList(false, false), + len = parents.length, + effects = !(opts && opts.noAnimation === true), + scroll = !(opts && opts.scrollIntoView === false); + + // Expand bottom-up, so only the top node is animated + for(i = len - 1; i >= 0; i--){ + // that.debug("pushexpand" + parents[i]); + deferreds.push(parents[i].setExpanded(true, opts)); + } + $.when.apply($, deferreds).done(function(){ + // All expands have finished + // that.debug("expand DONE", scroll); + if( scroll ){ + that.scrollIntoView(effects).done(function(){ + // that.debug("scroll DONE"); + dfd.resolve(); + }); + } else { + dfd.resolve(); + } + }); + return dfd.promise(); + }, + /** Move this node to targetNode. + * @param {FancytreeNode} targetNode + * @param {string} mode <pre> + * 'child': append this node as last child of targetNode. + * This is the default. To be compatble with the D'n'd + * hitMode, we also accept 'over'. + * 'before': add this node as sibling before targetNode. + * 'after': add this node as sibling after targetNode.</pre> + * @param {function} [map] optional callback(FancytreeNode) to allow modifcations + */ + moveTo: function(targetNode, mode, map) { + if(mode === undefined || mode === "over"){ + mode = "child"; + } + var pos, + prevParent = this.parent, + targetParent = (mode === "child") ? targetNode : targetNode.parent; + + if(this === targetNode){ + return; + }else if( !this.parent ){ + throw "Cannot move system root"; + }else if( targetParent.isDescendantOf(this) ){ + throw "Cannot move a node to its own descendant"; + } + // Unlink this node from current parent + if( this.parent.children.length === 1 ) { + if( this.parent === targetParent ){ + return; // #258 + } + this.parent.children = this.parent.lazy ? [] : null; + this.parent.expanded = false; + } else { + pos = $.inArray(this, this.parent.children); + _assert(pos >= 0, "invalid source parent"); + this.parent.children.splice(pos, 1); + } + // Remove from source DOM parent +// if(this.parent.ul){ +// this.parent.ul.removeChild(this.li); +// } + + // Insert this node to target parent's child list + this.parent = targetParent; + if( targetParent.hasChildren() ) { + switch(mode) { + case "child": + // Append to existing target children + targetParent.children.push(this); + break; + case "before": + // Insert this node before target node + pos = $.inArray(targetNode, targetParent.children); + _assert(pos >= 0, "invalid target parent"); + targetParent.children.splice(pos, 0, this); + break; + case "after": + // Insert this node after target node + pos = $.inArray(targetNode, targetParent.children); + _assert(pos >= 0, "invalid target parent"); + targetParent.children.splice(pos+1, 0, this); + break; + default: + throw "Invalid mode " + mode; + } + } else { + targetParent.children = [ this ]; + } + // Parent has no <ul> tag yet: +// if( !targetParent.ul ) { +// // This is the parent's first child: create UL tag +// // (Hidden, because it will be +// targetParent.ul = document.createElement("ul"); +// targetParent.ul.style.display = "none"; +// targetParent.li.appendChild(targetParent.ul); +// } +// // Issue 319: Add to target DOM parent (only if node was already rendered(expanded)) +// if(this.li){ +// targetParent.ul.appendChild(this.li); +// }^ + + // Let caller modify the nodes + if( map ){ + targetNode.visit(map, true); + } + // Handle cross-tree moves + if( this.tree !== targetNode.tree ) { + // Fix node.tree for all source nodes +// _assert(false, "Cross-tree move is not yet implemented."); + this.warn("Cross-tree moveTo is experimantal!"); + this.visit(function(n){ + // TODO: fix selection state and activation, ... + n.tree = targetNode.tree; + }, true); + } + + // A collaposed node won't re-render children, so we have to remove it manually + // if( !targetParent.expanded ){ + // prevParent.ul.removeChild(this.li); + // } + + // Update HTML markup + if( !prevParent.isDescendantOf(targetParent)) { + prevParent.render(); + } + if( !targetParent.isDescendantOf(prevParent) && targetParent !== prevParent) { + targetParent.render(); + } + // TODO: fix selection state + // TODO: fix active state + +/* + var tree = this.tree; + var opts = tree.options; + var pers = tree.persistence; + + + // Always expand, if it's below minExpandLevel +// tree.logDebug ("%s._addChildNode(%o), l=%o", this, ftnode, ftnode.getLevel()); + if ( opts.minExpandLevel >= ftnode.getLevel() ) { +// tree.logDebug ("Force expand for %o", ftnode); + this.bExpanded = true; + } + + // In multi-hier mode, update the parents selection state + // DT issue #82: only if not initializing, because the children may not exist yet +// if( !ftnode.data.isStatusNode() && opts.selectMode==3 && !isInitializing ) +// ftnode._fixSelectionState(); + + // In multi-hier mode, update the parents selection state + if( ftnode.bSelected && opts.selectMode==3 ) { + var p = this; + while( p ) { + if( !p.hasSubSel ) + p._setSubSel(true); + p = p.parent; + } + } + // render this node and the new child + if ( tree.bEnableUpdate ) + this.render(); + + return ftnode; + +*/ + }, + /** Set focus relative to this node and optionally activate. + * + * @param {number} where The keyCode that would normally trigger this move, + * e.g. `$.ui.keyCode.LEFT` would collapse the node if it + * is expanded or move to the parent oterwise. + * @param {boolean} [activate=true] + * @returns {$.Promise} + */ + // navigate: function(where, activate) { + // console.time("navigate") + // this._navigate(where, activate) + // console.timeEnd("navigate") + // }, + navigate: function(where, activate) { + var i, parents, + handled = true, + KC = $.ui.keyCode, + sib = null; + + // Navigate to node + function _goto(n){ + if( n ){ + try { n.makeVisible(); } catch(e) {} // #272 + // Node may still be hidden by a filter + if( ! $(n.span).is(":visible") ) { + n.debug("Navigate: skipping hidden node"); + n.navigate(where, activate); + return; + } + return activate === false ? n.setFocus() : n.setActive(); + } + } + + switch( where ) { + case KC.BACKSPACE: + if( this.parent && this.parent.parent ) { + _goto(this.parent); + } + break; + case KC.LEFT: + if( this.expanded ) { + this.setExpanded(false); + _goto(this); + } else if( this.parent && this.parent.parent ) { + _goto(this.parent); + } + break; + case KC.RIGHT: + if( !this.expanded && (this.children || this.lazy) ) { + this.setExpanded(); + _goto(this); + } else if( this.children && this.children.length ) { + _goto(this.children[0]); + } + break; + case KC.UP: + sib = this.getPrevSibling(); + // #359: skip hidden sibling nodes, preventing a _goto() recursion + while( sib && !$(sib.span).is(":visible") ) { + sib = sib.getPrevSibling(); + } + while( sib && sib.expanded && sib.children && sib.children.length ) { + sib = sib.children[sib.children.length - 1]; + } + if( !sib && this.parent && this.parent.parent ){ + sib = this.parent; + } + _goto(sib); + break; + case KC.DOWN: + if( this.expanded && this.children && this.children.length ) { + sib = this.children[0]; + } else { + parents = this.getParentList(false, true); + for(i=parents.length-1; i>=0; i--) { + sib = parents[i].getNextSibling(); + // #359: skip hidden sibling nodes, preventing a _goto() recursion + while( sib && !$(sib.span).is(":visible") ) { + sib = sib.getNextSibling(); + } + if( sib ){ break; } + } + } + _goto(sib); + break; + default: + handled = false; + } + }, + /** + * Remove this node (not allowed for system root). + */ + remove: function() { + return this.parent.removeChild(this); + }, + /** + * Remove childNode from list of direct children. + * @param {FancytreeNode} childNode + */ + removeChild: function(childNode) { + return this.tree._callHook("nodeRemoveChild", this, childNode); + }, + /** + * Remove all child nodes and descendents. This converts the node into a leaf.<br> + * If this was a lazy node, it is still considered 'loaded'; call node.resetLazy() + * in order to trigger lazyLoad on next expand. + */ + removeChildren: function() { + return this.tree._callHook("nodeRemoveChildren", this); + }, + /** + * This method renders and updates all HTML markup that is required + * to display this node in its current state.<br> + * Note: + * <ul> + * <li>It should only be neccessary to call this method after the node object + * was modified by direct access to its properties, because the common + * API methods (node.setTitle(), moveTo(), addChildren(), remove(), ...) + * already handle this. + * <li> {@link FancytreeNode#renderTitle} and {@link FancytreeNode#renderStatus} + * are implied. If changes are more local, calling only renderTitle() or + * renderStatus() may be sufficient and faster. + * <li>If a node was created/removed, node.render() must be called <i>on the parent</i>. + * </ul> + * + * @param {boolean} [force=false] re-render, even if html markup was already created + * @param {boolean} [deep=false] also render all descendants, even if parent is collapsed + */ + render: function(force, deep) { + return this.tree._callHook("nodeRender", this, force, deep); + }, + /** Create HTML markup for the node's outer <span> (expander, checkbox, icon, and title). + * Implies {@link FancytreeNode#renderStatus}. + * @see Fancytree_Hooks#nodeRenderTitle + */ + renderTitle: function() { + return this.tree._callHook("nodeRenderTitle", this); + }, + /** Update element's CSS classes according to node state. + * @see Fancytree_Hooks#nodeRenderStatus + */ + renderStatus: function() { + return this.tree._callHook("nodeRenderStatus", this); + }, + /** + * Remove all children, collapse, and set the lazy-flag, so that the lazyLoad + * event is triggered on next expand. + */ + resetLazy: function() { + this.removeChildren(); + this.expanded = false; + this.lazy = true; + this.children = undefined; + this.renderStatus(); + }, + /** Schedule activity for delayed execution (cancel any pending request). + * scheduleAction('cancel') will only cancel a pending request (if any). + * @param {string} mode + * @param {number} ms + */ + scheduleAction: function(mode, ms) { + if( this.tree.timer ) { + clearTimeout(this.tree.timer); +// this.tree.debug("clearTimeout(%o)", this.tree.timer); + } + this.tree.timer = null; + var self = this; // required for closures + switch (mode) { + case "cancel": + // Simply made sure that timer was cleared + break; + case "expand": + this.tree.timer = setTimeout(function(){ + self.tree.debug("setTimeout: trigger expand"); + self.setExpanded(true); + }, ms); + break; + case "activate": + this.tree.timer = setTimeout(function(){ + self.tree.debug("setTimeout: trigger activate"); + self.setActive(true); + }, ms); + break; + default: + throw "Invalid mode " + mode; + } +// this.tree.debug("setTimeout(%s, %s): %s", mode, ms, this.tree.timer); + }, + /** + * + * @param {boolean | PlainObject} [effects=false] animation options. + * @param {object} [options=null] {topNode: null, effects: ..., parent: ...} this node will remain visible in + * any case, even if `this` is outside the scroll pane. + * @returns {$.Promise} + */ + scrollIntoView: function(effects, options) { + if( options !== undefined && _isNode(options) ) { + this.warn("scrollIntoView() with 'topNode' option is deprecated since 2014-05-08. Use 'options.topNode' instead."); + options = {topNode: options}; + } + // this.$scrollParent = (this.options.scrollParent === "auto") ? $ul.scrollParent() : $(this.options.scrollParent); + // this.$scrollParent = this.$scrollParent.length ? this.$scrollParent || this.$container; + + var topNodeY, nodeY, horzScrollbarHeight, containerOffsetTop, + opts = $.extend({ + effects: (effects === true) ? {duration: 200, queue: false} : effects, + scrollOfs: this.tree.options.scrollOfs, + scrollParent: this.tree.options.scrollParent || this.tree.$container, + topNode: null + }, options), + dfd = new $.Deferred(), + that = this, + nodeHeight = $(this.span).height(), + $container = $(opts.scrollParent), + topOfs = opts.scrollOfs.top || 0, + bottomOfs = opts.scrollOfs.bottom || 0, + containerHeight = $container.height(),// - topOfs - bottomOfs, + scrollTop = $container.scrollTop(), + $animateTarget = $container, + isParentWindow = $container[0] === window, + topNode = opts.topNode || null, + newScrollTop = null; + + // this.debug("scrollIntoView(), scrollTop=", scrollTop, opts.scrollOfs); +// _assert($(this.span).is(":visible"), "scrollIntoView node is invisible"); // otherwise we cannot calc offsets + if( !$(this.span).is(":visible") ) { + // We cannot calc offsets for hidden elements + this.warn("scrollIntoView(): node is invisible."); + return _getResolvedPromise(); + } + if( isParentWindow ) { + nodeY = $(this.span).offset().top; + topNodeY = (topNode && topNode.span) ? $(topNode.span).offset().top : 0; + $animateTarget = $("html,body"); + + } else { + _assert($container[0] !== document && $container[0] !== document.body, "scrollParent should be an simple element or `window`, not document or body."); + + containerOffsetTop = $container.offset().top, + nodeY = $(this.span).offset().top - containerOffsetTop + scrollTop; // relative to scroll parent + topNodeY = topNode ? $(topNode.span).offset().top - containerOffsetTop + scrollTop : 0; + horzScrollbarHeight = Math.max(0, ($container.innerHeight() - $container[0].clientHeight)); + containerHeight -= horzScrollbarHeight; + } + + // this.debug(" scrollIntoView(), nodeY=", nodeY, "containerHeight=", containerHeight); + if( nodeY < (scrollTop + topOfs) ){ + // Node is above visible container area + newScrollTop = nodeY - topOfs; + // this.debug(" scrollIntoView(), UPPER newScrollTop=", newScrollTop); + + }else if((nodeY + nodeHeight) > (scrollTop + containerHeight - bottomOfs)){ + newScrollTop = nodeY + nodeHeight - containerHeight + bottomOfs; + // this.debug(" scrollIntoView(), LOWER newScrollTop=", newScrollTop); + // If a topNode was passed, make sure that it is never scrolled + // outside the upper border + if(topNode){ + _assert(topNode.isRootNode() || $(topNode.span).is(":visible"), "topNode must be visible"); + if( topNodeY < newScrollTop ){ + newScrollTop = topNodeY - topOfs; + // this.debug(" scrollIntoView(), TOP newScrollTop=", newScrollTop); + } + } + } + + if(newScrollTop !== null){ + // this.debug(" scrollIntoView(), SET newScrollTop=", newScrollTop); + if(opts.effects){ + opts.effects.complete = function(){ + dfd.resolveWith(that); + }; + $animateTarget.stop(true).animate({ + scrollTop: newScrollTop + }, opts.effects); + }else{ + $animateTarget[0].scrollTop = newScrollTop; + dfd.resolveWith(this); + } + }else{ + dfd.resolveWith(this); + } + return dfd.promise(); + }, + + /**Activate this node. + * @param {boolean} [flag=true] pass false to deactivate + * @param {object} [opts] additional options. Defaults to {noEvents: false} + * @returns {$.Promise} + */ + setActive: function(flag, opts){ + return this.tree._callHook("nodeSetActive", this, flag, opts); + }, + /**Expand or collapse this node. Promise is resolved, when lazy loading and animations are done. + * @param {boolean} [flag=true] pass false to collapse + * @param {object} [opts] additional options. Defaults to {noAnimation: false, noEvents: false} + * @returns {$.Promise} + */ + setExpanded: function(flag, opts){ + return this.tree._callHook("nodeSetExpanded", this, flag, opts); + }, + /**Set keyboard focus to this node. + * @param {boolean} [flag=true] pass false to blur + * @see Fancytree#setFocus + */ + setFocus: function(flag){ + return this.tree._callHook("nodeSetFocus", this, flag); + }, + /**Select this node, i.e. check the checkbox. + * @param {boolean} [flag=true] pass false to deselect + */ + setSelected: function(flag){ + return this.tree._callHook("nodeSetSelected", this, flag); + }, + /**Mark a lazy node as 'error', 'loading', or 'ok'. + * @param {string} status 'error', 'ok' + * @param {string} [message] + * @param {string} [details] + */ + setStatus: function(status, message, details){ + return this.tree._callHook("nodeSetStatus", this, status, message, details); + }, + /**Rename this node. + * @param {string} title + */ + setTitle: function(title){ + this.title = title; + this.renderTitle(); + }, + /**Sort child list by title. + * @param {function} [cmp] custom compare function(a, b) that returns -1, 0, or 1 (defaults to sort by title). + * @param {boolean} [deep=false] pass true to sort all descendant nodes + */ + sortChildren: function(cmp, deep) { + var i,l, + cl = this.children; + + if( !cl ){ + return; + } + cmp = cmp || function(a, b) { + var x = a.title.toLowerCase(), + y = b.title.toLowerCase(); + return x === y ? 0 : x > y ? 1 : -1; + }; + cl.sort(cmp); + if( deep ){ + for(i=0, l=cl.length; i<l; i++){ + if( cl[i].children ){ + cl[i].sortChildren(cmp, "$norender$"); + } + } + } + if( deep !== "$norender$" ){ + this.render(); + } + }, + /** Convert node (or whole branch) into a plain object. + * + * The result is compatible with node.addChildren(). + * + * @param {boolean} [recursive=false] include child nodes + * @param {function} [callback] callback(dict, node) is called for every node, in order to allow modifications + * @returns {NodeData} + */ + toDict: function(recursive, callback) { + var i, l, node, + dict = {}, + self = this; + + $.each(NODE_ATTRS, function(i, a){ + if(self[a] || self[a] === false){ + dict[a] = self[a]; + } + }); + if(!$.isEmptyObject(this.data)){ + dict.data = $.extend({}, this.data); + if($.isEmptyObject(dict.data)){ + delete dict.data; + } + } + if( callback ){ + callback(dict, self); + } + if( recursive ) { + if(this.hasChildren()){ + dict.children = []; + for(i=0, l=this.children.length; i<l; i++ ){ + node = this.children[i]; + if( !node.isStatusNode() ){ + dict.children.push(node.toDict(true, callback)); + } + } + }else{ +// dict.children = null; + } + } + return dict; + }, + /** Flip expanded status. */ + toggleExpanded: function(){ + return this.tree._callHook("nodeToggleExpanded", this); + }, + /** Flip selection status. */ + toggleSelected: function(){ + return this.tree._callHook("nodeToggleSelected", this); + }, + toString: function() { + return "<FancytreeNode(#" + this.key + ", '" + this.title + "')>"; + }, + /** Call fn(node) for all child nodes.<br> + * Stop iteration, if fn() returns false. Skip current branch, if fn() returns "skip".<br> + * Return false if iteration was stopped. + * + * @param {function} fn the callback function. + * Return false to stop iteration, return "skip" to skip this node and + * its children only. + * @param {boolean} [includeSelf=false] + * @returns {boolean} + */ + visit: function(fn, includeSelf) { + var i, l, + res = true, + children = this.children; + + if( includeSelf === true ) { + res = fn(this); + if( res === false || res === "skip" ){ + return res; + } + } + if(children){ + for(i=0, l=children.length; i<l; i++){ + res = children[i].visit(fn, true); + if( res === false ){ + break; + } + } + } + return res; + }, + /** Call fn(node) for all child nodes and recursively load lazy children.<br> + * <b>Note:</b> If you need this method, you probably should consider to review + * your architecture! Recursivley loading nodes is a perfect way for lazy + * programmers to flood the server with requests ;-) + * + * @param {function} [fn] optional callback function. + * Return false to stop iteration, return "skip" to skip this node and + * its children only. + * @param {boolean} [includeSelf=false] + * @returns {$.Promise} + * @since 2.4 + */ + visitAndLoad: function(fn, includeSelf, _recursion) { + var dfd, res, loaders, + node = this; + + // node.debug("visitAndLoad"); + if( fn && includeSelf === true ) { + res = fn(node); + if( res === false || res === "skip" ) { + return _recursion ? res : _getResolvedPromise(); + } + } + if( !node.children && !node.lazy ) { + return _getResolvedPromise(); + } + dfd = new $.Deferred(); + loaders = []; + // node.debug("load()..."); + node.load().done(function(){ + // node.debug("load()... done."); + for(var i=0, l=node.children.length; i<l; i++){ + res = node.children[i].visitAndLoad(fn, true, true); + if( res === false ) { + dfd.reject(); + break; + } else if ( res !== "skip" ) { + loaders.push(res); // Add promise to the list + } + } + $.when.apply(this, loaders).then(function(){ + dfd.resolve(); + }); + }); + return dfd.promise(); + }, + /** Call fn(node) for all parent nodes, bottom-up, including invisible system root.<br> + * Stop iteration, if fn() returns false.<br> + * Return false if iteration was stopped. + * + * @param {function} fn the callback function. + * Return false to stop iteration, return "skip" to skip this node and children only. + * @param {boolean} [includeSelf=false] + * @returns {boolean} + */ + visitParents: function(fn, includeSelf) { + // Visit parent nodes (bottom up) + if(includeSelf && fn(this) === false){ + return false; + } + var p = this.parent; + while( p ) { + if(fn(p) === false){ + return false; + } + p = p.parent; + } + return true; + }, + /** Write warning to browser console (prepending node info) + * + * @param {*} msg string or object or array of such + */ + warn: function(msg){ + Array.prototype.unshift.call(arguments, this.toString()); + consoleApply("warn", arguments); + } +}; + + +/* ***************************************************************************** + * Fancytree + */ +/** + * Construct a new tree object. + * + * @class Fancytree + * @classdesc The controller behind a fancytree. + * This class also contains 'hook methods': see {@link Fancytree_Hooks}. + * + * @param {Widget} widget + * + * @property {string} _id Automatically generated unique tree instance ID, e.g. "1". + * @property {string} _ns Automatically generated unique tree namespace, e.g. ".fancytree-1". + * @property {FancytreeNode} activeNode Currently active node or null. + * @property {string} ariaPropName Property name of FancytreeNode that contains the element which will receive the aria attributes. + * Typically "li", but "tr" for table extension. + * @property {jQueryObject} $container Outer <ul> element (or <table> element for ext-table). + * @property {jQueryObject} $div A jQuery object containing the element used to instantiate the tree widget (`widget.element`) + * @property {object} data Metadata, i.e. properties that may be passed to `source` in addition to a children array. + * @property {object} ext Hash of all active plugin instances. + * @property {FancytreeNode} focusNode Currently focused node or null. + * @property {FancytreeNode} lastSelectedNode Used to implement selectMode 1 (single select) + * @property {string} nodeContainerAttrName Property name of FancytreeNode that contains the outer element of single nodes. + * Typically "li", but "tr" for table extension. + * @property {FancytreeOptions} options Current options, i.e. default options + options passed to constructor. + * @property {FancytreeNode} rootNode Invisible system root node. + * @property {string} statusClassPropName Property name of FancytreeNode that contains the element which will receive the status classes. + * Typically "span", but "tr" for table extension. + * @property {object} widget Base widget instance. + */ +function Fancytree(widget) { + this.widget = widget; + this.$div = widget.element; + this.options = widget.options; + if( this.options ) { + if( $.isFunction(this.options.lazyload ) && !$.isFunction(this.options.lazyLoad) ) { + this.options.lazyLoad = function() { + FT.warn("The 'lazyload' event is deprecated since 2014-02-25. Use 'lazyLoad' (with uppercase L) instead."); + return widget.options.lazyload.apply(this, arguments); + }; + } + if( $.isFunction(this.options.loaderror) ) { + $.error("The 'loaderror' event was renamed since 2014-07-03. Use 'loadError' (with uppercase E) instead."); + } + if( this.options.fx !== undefined ) { + FT.warn("The 'fx' options was replaced by 'toggleEffect' since 2014-11-30."); + } + } + this.ext = {}; // Active extension instances + // allow to init tree.data.foo from <div data-foo=''> + this.data = _getElementDataAsDict(this.$div); + // TODO: use widget.uuid instead? + this._id = $.ui.fancytree._nextId++; + // TODO: use widget.eventNamespace instead? + this._ns = ".fancytree-" + this._id; // append for namespaced events + this.activeNode = null; + this.focusNode = null; + this._hasFocus = null; + this.lastSelectedNode = null; + this.systemFocusElement = null; + this.lastQuicksearchTerm = ""; + this.lastQuicksearchTime = 0; + + this.statusClassPropName = "span"; + this.ariaPropName = "li"; + this.nodeContainerAttrName = "li"; + + // Remove previous markup if any + this.$div.find(">ul.fancytree-container").remove(); + + // Create a node without parent. + var fakeParent = { tree: this }, + $ul; + this.rootNode = new FancytreeNode(fakeParent, { + title: "root", + key: "root_" + this._id, + children: null, + expanded: true + }); + this.rootNode.parent = null; + + // Create root markup + $ul = $("<ul>", { + "class": "ui-fancytree fancytree-container fancytree-plain" + }).appendTo(this.$div); + this.$container = $ul; + this.rootNode.ul = $ul[0]; + + if(this.options.debugLevel == null){ + this.options.debugLevel = FT.debugLevel; + } + // Add container to the TAB chain + // See http://www.w3.org/TR/wai-aria-practices/#focus_activedescendant + this.$container.attr("tabindex", this.options.tabbable ? "0" : "-1"); + if(this.options.aria){ + this.$container + .attr("role", "tree") + .attr("aria-multiselectable", true); + } +} + + +Fancytree.prototype = /** @lends Fancytree# */{ + /* Return a context object that can be re-used for _callHook(). + * @param {Fancytree | FancytreeNode | EventData} obj + * @param {Event} originalEvent + * @param {Object} extra + * @returns {EventData} + */ + _makeHookContext: function(obj, originalEvent, extra) { + var ctx, tree; + if(obj.node !== undefined){ + // obj is already a context object + if(originalEvent && obj.originalEvent !== originalEvent){ + $.error("invalid args"); + } + ctx = obj; + }else if(obj.tree){ + // obj is a FancytreeNode + tree = obj.tree; + ctx = { node: obj, tree: tree, widget: tree.widget, options: tree.widget.options, originalEvent: originalEvent }; + }else if(obj.widget){ + // obj is a Fancytree + ctx = { node: null, tree: obj, widget: obj.widget, options: obj.widget.options, originalEvent: originalEvent }; + }else{ + $.error("invalid args"); + } + if(extra){ + $.extend(ctx, extra); + } + return ctx; + }, + /* Trigger a hook function: funcName(ctx, [...]). + * + * @param {string} funcName + * @param {Fancytree|FancytreeNode|EventData} contextObject + * @param {any} [_extraArgs] optional additional arguments + * @returns {any} + */ + _callHook: function(funcName, contextObject, _extraArgs) { + var ctx = this._makeHookContext(contextObject), + fn = this[funcName], + args = Array.prototype.slice.call(arguments, 2); + if(!$.isFunction(fn)){ + $.error("_callHook('" + funcName + "') is not a function"); + } + args.unshift(ctx); +// this.debug("_hook", funcName, ctx.node && ctx.node.toString() || ctx.tree.toString(), args); + return fn.apply(this, args); + }, + /* Check if current extensions dependencies are met and throw an error if not. + * + * This method may be called inside the `treeInit` hook for custom extensions. + * + * @param {string} extension name of the required extension + * @param {boolean} [required=true] pass `false` if the extension is optional, but we want to check for order if it is present + * @param {boolean} [before] `true` if `name` must be included before this, `false` otherwise (use `null` if order doesn't matter) + * @param {string} [message] optional error message (defaults to a descriptve error message) + */ + _requireExtension: function(name, required, before, message) { + before = !!before; + var thisName = this._local.name, + extList = this.options.extensions, + isBefore = $.inArray(name, extList) < $.inArray(thisName, extList), + isMissing = required && this.ext[name] == null, + badOrder = !isMissing && before != null && (before !== isBefore); + + _assert(thisName && thisName !== name, "invalid or same name"); + + if( isMissing || badOrder ){ + if( !message ){ + if( isMissing || required ){ + message = "'" + thisName + "' extension requires '" + name + "'"; + if( badOrder ){ + message += " to be registered " + (before ? "before" : "after") + " itself"; + } + }else{ + message = "If used together, `" + name + "` must be registered " + (before ? "before" : "after") + " `" + thisName + "`"; + } + } + $.error(message); + return false; + } + return true; + }, + /** Activate node with a given key and fire focus and activate events. + * + * A prevously activated node will be deactivated. + * If activeVisible option is set, all parents will be expanded as necessary. + * Pass key = false, to deactivate the current node only. + * @param {string} key + * @returns {FancytreeNode} activated node (null, if not found) + */ + activateKey: function(key) { + var node = this.getNodeByKey(key); + if(node){ + node.setActive(); + }else if(this.activeNode){ + this.activeNode.setActive(false); + } + return node; + }, + /** (experimental) + * + * @param {Array} patchList array of [key, NodePatch] arrays + * @returns {$.Promise} resolved, when all patches have been applied + * @see TreePatch + */ + applyPatch: function(patchList) { + var dfd, i, p2, key, patch, node, + patchCount = patchList.length, + deferredList = []; + + for(i=0; i<patchCount; i++){ + p2 = patchList[i]; + _assert(p2.length === 2, "patchList must be an array of length-2-arrays"); + key = p2[0]; + patch = p2[1]; + node = (key === null) ? this.rootNode : this.getNodeByKey(key); + if(node){ + dfd = new $.Deferred(); + deferredList.push(dfd); + node.applyPatch(patch).always(_makeResolveFunc(dfd, node)); + }else{ + this.warn("could not find node with key '" + key + "'"); + } + } + // Return a promise that is resolved, when ALL patches were applied + return $.when.apply($, deferredList).promise(); + }, + /* TODO: implement in dnd extension + cancelDrag: function() { + var dd = $.ui.ddmanager.current; + if(dd){ + dd.cancel(); + } + }, + */ + /** Return the number of nodes. + * @returns {integer} + */ + count: function() { + return this.rootNode.countChildren(); + }, + /** Write to browser console if debugLevel >= 2 (prepending tree name) + * + * @param {*} msg string or object or array of such + */ + debug: function(msg){ + if( this.options.debugLevel >= 2 ) { + Array.prototype.unshift.call(arguments, this.toString()); + consoleApply("log", arguments); + } + }, + // TODO: disable() + // TODO: enable() + // TODO: enableUpdate() + + /**Find all nodes that matches condition. + * + * @param {string | function(node)} match title string to search for, or a + * callback function that returns `true` if a node is matched. + * @returns {FancytreeNode[]} array of nodes (may be empty) + * @see FancytreeNode#findAll + * @since 2.12 + */ + findAll: function(match) { + return this.rootNode.findAll(match); + }, + /**Find first node that matches condition. + * + * @param {string | function(node)} match title string to search for, or a + * callback function that returns `true` if a node is matched. + * @returns {FancytreeNode} matching node or null + * @see FancytreeNode#findFirst + * @since 2.12 + */ + findFirst: function(match) { + return this.rootNode.findFirst(match); + }, + /** Find the next visible node that starts with `match`, starting at `startNode` + * and wrap-around at the end. + * + * @param {string|function} match + * @param {FancytreeNode} [startNode] defaults to first node + * @returns {FancytreeNode} matching node or null + */ + findNextNode: function(match, startNode, visibleOnly) { + var stopNode = null, + parentChildren = startNode.parent.children, + matchingNode = null, + walkVisible = function(parent, idx, fn) { + var i, grandParent, + parentChildren = parent.children, + siblingCount = parentChildren.length, + node = parentChildren[idx]; + // visit node itself + if( node && fn(node) === false ) { + return false; + } + // visit descendants + if( node && node.children && node.expanded ) { + if( walkVisible(node, 0, fn) === false ) { + return false; + } + } + // visit subsequent siblings + for( i = idx + 1; i < siblingCount; i++ ) { + if( walkVisible(parent, i, fn) === false ) { + return false; + } + } + // visit parent's subsequent siblings + grandParent = parent.parent; + if( grandParent ) { + return walkVisible(grandParent, grandParent.children.indexOf(parent) + 1, fn); + } else { + // wrap-around: restart with first node + return walkVisible(parent, 0, fn); + } + }; + + match = (typeof match === "string") ? _makeNodeTitleStartMatcher(match) : match; + startNode = startNode || this.getFirstChild(); + + walkVisible(startNode.parent, parentChildren.indexOf(startNode), function(node){ + // Stop iteration if we see the start node a second time + if( node === stopNode ) { + return false; + } + stopNode = stopNode || node; + // Ignore nodes hidden by a filter + if( ! $(node.span).is(":visible") ) { + node.debug("quicksearch: skipping hidden node"); + return; + } + // Test if we found a match, but search for a second match if this + // was the currently active node + if( match(node) ) { + // node.debug("quicksearch match " + node.title, startNode); + matchingNode = node; + if( matchingNode !== startNode ) { + return false; + } + } + }); + return matchingNode; + }, + // TODO: fromDict + /** + * Generate INPUT elements that can be submitted with html forms. + * + * In selectMode 3 only the topmost selected nodes are considered, unless + * `opts.stopOnParents: false` is passed. + * + * @param {boolean | string} [selected=true] Pass false to disable, pass a string to overide the field name (default: 'ft_ID[]') + * @param {boolean | string} [active=true] Pass false to disable, pass a string to overide the field name (default: 'ft_ID_active') + * @param {object} [opts] default { stopOnParents: true } + */ + generateFormElements: function(selected, active, opts) { + // TODO: test case + opts = opts || {}; + + var nodeList, + selectedName = (typeof selected === "string") ? selected : "ft_" + this._id + "[]", + activeName = (typeof active === "string") ? active : "ft_" + this._id + "_active", + id = "fancytree_result_" + this._id, + $result = $("#" + id), + stopOnParents = this.options.selectMode === 3 && opts.stopOnParents !== false; + + if($result.length){ + $result.empty(); + }else{ + $result = $("<div>", { + id: id + }).hide().insertAfter(this.$container); + } + if(selected !== false){ + nodeList = this.getSelectedNodes(stopOnParents); + $.each(nodeList, function(idx, node){ + $result.append($("<input>", { + type: "checkbox", + name: selectedName, + value: node.key, + checked: true + })); + }); + } + if(active !== false && this.activeNode){ + $result.append($("<input>", { + type: "radio", + name: activeName, + value: this.activeNode.key, + checked: true + })); + } + }, + /** + * Return the currently active node or null. + * @returns {FancytreeNode} + */ + getActiveNode: function() { + return this.activeNode; + }, + /** Return the first top level node if any (not the invisible root node). + * @returns {FancytreeNode | null} + */ + getFirstChild: function() { + return this.rootNode.getFirstChild(); + }, + /** + * Return node that has keyboard focus or null. + * @returns {FancytreeNode} + */ + getFocusNode: function() { + return this.focusNode; + }, + /** + * Return node with a given key or null if not found. + * @param {string} key + * @param {FancytreeNode} [searchRoot] only search below this node + * @returns {FancytreeNode | null} + */ + getNodeByKey: function(key, searchRoot) { + // Search the DOM by element ID (assuming this is faster than traversing all nodes). + // $("#...") has problems, if the key contains '.', so we use getElementById() + var el, match; + if(!searchRoot){ + el = document.getElementById(this.options.idPrefix + key); + if( el ){ + return el.ftnode ? el.ftnode : null; + } + } + // Not found in the DOM, but still may be in an unrendered part of tree + // TODO: optimize with specialized loop + // TODO: consider keyMap? + searchRoot = searchRoot || this.rootNode; + match = null; + searchRoot.visit(function(node){ +// window.console.log("getNodeByKey(" + key + "): ", node.key); + if(node.key === key) { + match = node; + return false; + } + }, true); + return match; + }, + /** Return the invisible system root node. + * @returns {FancytreeNode} + */ + getRootNode: function() { + return this.rootNode; + }, + /** + * Return an array of selected nodes. + * @param {boolean} [stopOnParents=false] only return the topmost selected + * node (useful with selectMode 3) + * @returns {FancytreeNode[]} + */ + getSelectedNodes: function(stopOnParents) { + var nodeList = []; + this.rootNode.visit(function(node){ + if( node.selected ) { + nodeList.push(node); + if( stopOnParents === true ){ + return "skip"; // stop processing this branch + } + } + }); + return nodeList; + }, + /** Return true if the tree control has keyboard focus + * @returns {boolean} + */ + hasFocus: function(){ + return !!this._hasFocus; + }, + /** Write to browser console if debugLevel >= 1 (prepending tree name) + * @param {*} msg string or object or array of such + */ + info: function(msg){ + if( this.options.debugLevel >= 1 ) { + Array.prototype.unshift.call(arguments, this.toString()); + consoleApply("info", arguments); + } + }, +/* + TODO: isInitializing: function() { + return ( this.phase=="init" || this.phase=="postInit" ); + }, + TODO: isReloading: function() { + return ( this.phase=="init" || this.phase=="postInit" ) && this.options.persist && this.persistence.cookiesFound; + }, + TODO: isUserEvent: function() { + return ( this.phase=="userEvent" ); + }, +*/ + + /** + * Make sure that a node with a given ID is loaded, by traversing - and + * loading - its parents. This method is ment for lazy hierarchies. + * A callback is executed for every node as we go. + * @example + * tree.loadKeyPath("/_3/_23/_26/_27", function(node, status){ + * if(status === "loaded") { + * console.log("loaded intermiediate node " + node); + * }else if(status === "ok") { + * node.activate(); + * } + * }); + * + * @param {string | string[]} keyPathList one or more key paths (e.g. '/3/2_1/7') + * @param {function} callback callback(node, status) is called for every visited node ('loading', 'loaded', 'ok', 'error') + * @returns {$.Promise} + */ + loadKeyPath: function(keyPathList, callback, _rootNode) { + var deferredList, dfd, i, path, key, loadMap, node, root, segList, + sep = this.options.keyPathSeparator, + self = this; + + if(!$.isArray(keyPathList)){ + keyPathList = [keyPathList]; + } + // Pass 1: handle all path segments for nodes that are already loaded + // Collect distinct top-most lazy nodes in a map + loadMap = {}; + + for(i=0; i<keyPathList.length; i++){ + root = _rootNode || this.rootNode; + path = keyPathList[i]; + // strip leading slash + if(path.charAt(0) === sep){ + path = path.substr(1); + } + // traverse and strip keys, until we hit a lazy, unloaded node + segList = path.split(sep); + while(segList.length){ + key = segList.shift(); +// node = _findDirectChild(root, key); + node = root._findDirectChild(key); + if(!node){ + this.warn("loadKeyPath: key not found: " + key + " (parent: " + root + ")"); + callback.call(this, key, "error"); + break; + }else if(segList.length === 0){ + callback.call(this, node, "ok"); + break; + }else if(!node.lazy || (node.hasChildren() !== undefined )){ + callback.call(this, node, "loaded"); + root = node; + }else{ + callback.call(this, node, "loaded"); +// segList.unshift(key); + if(loadMap[key]){ + loadMap[key].push(segList.join(sep)); + }else{ + loadMap[key] = [segList.join(sep)]; + } + break; + } + } + } +// alert("loadKeyPath: loadMap=" + JSON.stringify(loadMap)); + // Now load all lazy nodes and continue itearation for remaining paths + deferredList = []; + // Avoid jshint warning 'Don't make functions within a loop.': + function __lazyload(key, node, dfd){ + callback.call(self, node, "loading"); + node.load().done(function(){ + self.loadKeyPath.call(self, loadMap[key], callback, node).always(_makeResolveFunc(dfd, self)); + }).fail(function(errMsg){ + self.warn("loadKeyPath: error loading: " + key + " (parent: " + root + ")"); + callback.call(self, node, "error"); + dfd.reject(); + }); + } + for(key in loadMap){ + node = root._findDirectChild(key); +// alert("loadKeyPath: lazy node(" + key + ") = " + node); + dfd = new $.Deferred(); + deferredList.push(dfd); + __lazyload(key, node, dfd); + } + // Return a promise that is resolved, when ALL paths were loaded + return $.when.apply($, deferredList).promise(); + }, + /** Re-fire beforeActivate and activate events. */ + reactivate: function(setFocus) { + var res, + node = this.activeNode; + + if( !node ) { + return _getResolvedPromise(); + } + this.activeNode = null; // Force re-activating + res = node.setActive(); + if( setFocus ){ + node.setFocus(); + } + return res; + }, + /** Reload tree from source and return a promise. + * @param [source] optional new source (defaults to initial source data) + * @returns {$.Promise} + */ + reload: function(source) { + this._callHook("treeClear", this); + return this._callHook("treeLoad", this, source); + }, + /**Render tree (i.e. create DOM elements for all top-level nodes). + * @param {boolean} [force=false] create DOM elemnts, even is parent is collapsed + * @param {boolean} [deep=false] + */ + render: function(force, deep) { + return this.rootNode.render(force, deep); + }, + // TODO: selectKey: function(key, select) + // TODO: serializeArray: function(stopOnParents) + /** + * @param {boolean} [flag=true] + */ + setFocus: function(flag) { + return this._callHook("treeSetFocus", this, flag); + }, + /** + * Return all nodes as nested list of {@link NodeData}. + * + * @param {boolean} [includeRoot=false] Returns the hidden system root node (and its children) + * @param {function} [callback] callback(dict, node) is called for every node, in order to allow modifications + * @returns {Array | object} + * @see FancytreeNode#toDict + */ + toDict: function(includeRoot, callback){ + var res = this.rootNode.toDict(true, callback); + return includeRoot ? res : res.children; + }, + /* Implicitly called for string conversions. + * @returns {string} + */ + toString: function(){ + return "<Fancytree(#" + this._id + ")>"; + }, + /* _trigger a widget event with additional node ctx. + * @see EventData + */ + _triggerNodeEvent: function(type, node, originalEvent, extra) { +// this.debug("_trigger(" + type + "): '" + ctx.node.title + "'", ctx); + var ctx = this._makeHookContext(node, originalEvent, extra), + res = this.widget._trigger(type, originalEvent, ctx); + if(res !== false && ctx.result !== undefined){ + return ctx.result; + } + return res; + }, + /* _trigger a widget event with additional tree data. */ + _triggerTreeEvent: function(type, originalEvent, extra) { +// this.debug("_trigger(" + type + ")", ctx); + var ctx = this._makeHookContext(this, originalEvent, extra), + res = this.widget._trigger(type, originalEvent, ctx); + + if(res !== false && ctx.result !== undefined){ + return ctx.result; + } + return res; + }, + /** Call fn(node) for all nodes. + * + * @param {function} fn the callback function. + * Return false to stop iteration, return "skip" to skip this node and children only. + * @returns {boolean} false, if the iterator was stopped. + */ + visit: function(fn) { + return this.rootNode.visit(fn, false); + }, + /** Write warning to browser console (prepending tree info) + * + * @param {*} msg string or object or array of such + */ + warn: function(msg){ + Array.prototype.unshift.call(arguments, this.toString()); + consoleApply("warn", arguments); + } +}; + +/** + * These additional methods of the {@link Fancytree} class are 'hook functions' + * that can be used and overloaded by extensions. + * (See <a href="https://github.com/mar10/fancytree/wiki/TutorialExtensions">writing extensions</a>.) + * @mixin Fancytree_Hooks + */ +$.extend(Fancytree.prototype, + /** @lends Fancytree_Hooks# */ + { + /** Default handling for mouse click events. + * + * @param {EventData} ctx + */ + nodeClick: function(ctx) { + var activate, expand, + // event = ctx.originalEvent, + targetType = ctx.targetType, + node = ctx.node; + +// this.debug("ftnode.onClick(" + event.type + "): ftnode:" + this + ", button:" + event.button + ", which: " + event.which, ctx); + // TODO: use switch + // TODO: make sure clicks on embedded <input> doesn't steal focus (see table sample) + if( targetType === "expander" ) { + if( node.isLoading() ) { + // #495: we probably got a click event while a lazy load is pending. + // The 'expanded' state is not yet set, so 'toggle' would expand + // and trigger lazyLoad again. + // It would be better to allow to collapse/expand the status node + // while loading (instead of ignoring), but that would require some + // more work. + node.debug("Got 2nd click while loading: ignored"); + return; + } + // Clicking the expander icon always expands/collapses + this._callHook("nodeToggleExpanded", ctx); + + } else if( targetType === "checkbox" ) { + // Clicking the checkbox always (de)selects + this._callHook("nodeToggleSelected", ctx); + if( ctx.options.focusOnSelect ) { // #358 + this._callHook("nodeSetFocus", ctx, true); + } + + } else { + // Honor `clickFolderMode` for + expand = false; + activate = true; + if( node.folder ) { + switch( ctx.options.clickFolderMode ) { + case 2: // expand only + expand = true; + activate = false; + break; + case 3: // expand and activate + activate = true; + expand = true; //!node.isExpanded(); + break; + // else 1 or 4: just activate + } + } + if( activate ) { + this.nodeSetFocus(ctx); + this._callHook("nodeSetActive", ctx, true); + } + if( expand ) { + if(!activate){ +// this._callHook("nodeSetFocus", ctx); + } +// this._callHook("nodeSetExpanded", ctx, true); + this._callHook("nodeToggleExpanded", ctx); + } + } + // Make sure that clicks stop, otherwise <a href='#'> jumps to the top + // if(event.target.localName === "a" && event.target.className === "fancytree-title"){ + // event.preventDefault(); + // } + // TODO: return promise? + }, + /** Collapse all other children of same parent. + * + * @param {EventData} ctx + * @param {object} callOpts + */ + nodeCollapseSiblings: function(ctx, callOpts) { + // TODO: return promise? + var ac, i, l, + node = ctx.node; + + if( node.parent ){ + ac = node.parent.children; + for (i=0, l=ac.length; i<l; i++) { + if ( ac[i] !== node && ac[i].expanded ){ + this._callHook("nodeSetExpanded", ac[i], false, callOpts); + } + } + } + }, + /** Default handling for mouse douleclick events. + * @param {EventData} ctx + */ + nodeDblclick: function(ctx) { + // TODO: return promise? + if( ctx.targetType === "title" && ctx.options.clickFolderMode === 4) { +// this.nodeSetFocus(ctx); +// this._callHook("nodeSetActive", ctx, true); + this._callHook("nodeToggleExpanded", ctx); + } + // TODO: prevent text selection on dblclicks + if( ctx.targetType === "title" ) { + ctx.originalEvent.preventDefault(); + } + }, + /** Default handling for mouse keydown events. + * + * NOTE: this may be called with node == null if tree (but no node) has focus. + * @param {EventData} ctx + */ + nodeKeydown: function(ctx) { + // TODO: return promise? + var matchNode, stamp, res, focusNode, + event = ctx.originalEvent, + node = ctx.node, + tree = ctx.tree, + opts = ctx.options, + which = event.which, + whichChar = String.fromCharCode(which), + clean = !(event.altKey || event.ctrlKey || event.metaKey || event.shiftKey), + $target = $(event.target), + handled = true, + activate = !(event.ctrlKey || !opts.autoActivate ); + +// (node || FT).debug("ftnode.nodeKeydown(" + event.type + "): ftnode:" + this + ", charCode:" + event.charCode + ", keyCode: " + event.keyCode + ", which: " + event.which); +// FT.debug("eventToString", which, '"' + String.fromCharCode(which) + '"', '"' + FT.eventToString(event) + '"'); + + // Set focus to active (or first node) if no other node has the focus yet + if( !node ){ + focusNode = (this.getActiveNode() || this.getFirstChild()); + if (focusNode){ + focusNode.setFocus(); + node = ctx.node = this.focusNode; + node.debug("Keydown force focus on active node"); + } + } + + if( opts.quicksearch && clean && /\w/.test(whichChar) && !$target.is(":input:enabled") ) { + // Allow to search for longer streaks if typed in quickly + stamp = new Date().getTime(); + if( stamp - tree.lastQuicksearchTime > 500 ) { + tree.lastQuicksearchTerm = ""; + } + tree.lastQuicksearchTime = stamp; + tree.lastQuicksearchTerm += whichChar; + // tree.debug("quicksearch find", tree.lastQuicksearchTerm); + matchNode = tree.findNextNode(tree.lastQuicksearchTerm, tree.getActiveNode()); + if( matchNode ) { + matchNode.setActive(); + } + event.preventDefault(); + return; + } + switch( FT.eventToString(event) ) { + case "+": + case "=": // 187: '+' @ Chrome, Safari + tree.nodeSetExpanded(ctx, true); + break; + case "-": + tree.nodeSetExpanded(ctx, false); + break; + case "space": + if(opts.checkbox){ + tree.nodeToggleSelected(ctx); + }else{ + tree.nodeSetActive(ctx, true); + } + break; + case "return": + tree.nodeSetActive(ctx, true); + break; + case "backspace": + case "left": + case "right": + case "up": + case "down": + res = node.navigate(event.which, activate); + break; + default: + handled = false; + } + if(handled){ + event.preventDefault(); + } + }, + + + // /** Default handling for mouse keypress events. */ + // nodeKeypress: function(ctx) { + // var event = ctx.originalEvent; + // }, + + // /** Trigger lazyLoad event (async). */ + // nodeLazyLoad: function(ctx) { + // var node = ctx.node; + // if(this._triggerNodeEvent()) + // }, + /** Load child nodes (async). + * + * @param {EventData} ctx + * @param {object[]|object|string|$.Promise|function} source + * @returns {$.Promise} The deferred will be resolved as soon as the (ajax) + * data was rendered. + */ + nodeLoadChildren: function(ctx, source) { + var ajax, delay, dfd, + tree = ctx.tree, + node = ctx.node; + + if($.isFunction(source)){ + source = source(); + } + // TOTHINK: move to 'ajax' extension? + if(source.url){ + // `source` is an Ajax options object + ajax = $.extend({}, ctx.options.ajax, source); + if(ajax.debugDelay){ + // simulate a slow server + delay = ajax.debugDelay; + if($.isArray(delay)){ // random delay range [min..max] + delay = delay[0] + Math.random() * (delay[1] - delay[0]); + } + + node.debug("nodeLoadChildren waiting debug delay " + Math.round(delay) + "ms"); + ajax.debugDelay = false; + dfd = $.Deferred(function (dfd) { + setTimeout(function () { + $.ajax(ajax) + .done(function () { dfd.resolveWith(this, arguments); }) + .fail(function () { dfd.rejectWith(this, arguments); }); + }, delay); + }); + }else{ + dfd = $.ajax(ajax); + } + + // Defer the deferred: we want to be able to reject, even if ajax + // resolved ok. + source = new $.Deferred(); + dfd.done(function (data, textStatus, jqXHR) { + var errorObj, res; + if(this.dataType === "json" && typeof data === "string"){ + $.error("Ajax request returned a string (did you get the JSON dataType wrong?)."); + } + // postProcess is similar to the standard ajax dataFilter hook, + // but it is also called for JSONP + if( ctx.options.postProcess ){ + res = tree._triggerNodeEvent("postProcess", ctx, ctx.originalEvent, {response: data, error: null, dataType: this.dataType}); + if( res.error ) { + errorObj = $.isPlainObject(res.error) ? res.error : {message: res.error}; + errorObj = tree._makeHookContext(node, null, errorObj); + source.rejectWith(this, [errorObj]); + return; + } + data = $.isArray(res) ? res : data; + + } else if (data && data.hasOwnProperty("d") && ctx.options.enableAspx ) { + // Process ASPX WebMethod JSON object inside "d" property + data = (typeof data.d === "string") ? $.parseJSON(data.d) : data.d; + } + source.resolveWith(this, [data]); + }).fail(function (jqXHR, textStatus, errorThrown) { + var errorObj = tree._makeHookContext(node, null, { + error: jqXHR, + args: Array.prototype.slice.call(arguments), + message: errorThrown, + details: jqXHR.status + ": " + errorThrown + }); + source.rejectWith(this, [errorObj]); + }); + } + // #383: accept and convert ECMAScript 6 Promise + if( $.isFunction(source.then) && $.isFunction(source["catch"]) ) { + dfd = source; + source = new $.Deferred(); + dfd.then(function(value){ + source.resolve(value); + }, function(reason){ + source.reject(reason); + }); + } + if($.isFunction(source.promise)){ + // `source` is a deferred, i.e. ajax request + _assert(!node.isLoading(), "recursive load"); + // node._isLoading = true; + tree.nodeSetStatus(ctx, "loading"); + + source.done(function (children) { + tree.nodeSetStatus(ctx, "ok"); + }).fail(function(error){ + var ctxErr; + if (error.node && error.error && error.message) { + // error is already a context object + ctxErr = error; + } else { + ctxErr = tree._makeHookContext(node, null, { + error: error, // it can be jqXHR or any custom error + args: Array.prototype.slice.call(arguments), + message: error ? (error.message || error.toString()) : "" + }); + } + if( tree._triggerNodeEvent("loadError", ctxErr, null) !== false ) { + tree.nodeSetStatus(ctx, "error", ctxErr.message, ctxErr.details); + } + }); + } + // $.when(source) resolves also for non-deferreds + return $.when(source).done(function(children){ + var metaData; + + if( $.isPlainObject(children) ){ + // We got {foo: 'abc', children: [...]} + // Copy extra properties to tree.data.foo + _assert(node.isRootNode(), "source may only be an object for root nodes (expecting an array of child objects otherwise)"); + _assert($.isArray(children.children), "if an object is passed as source, it must contain a 'children' array (all other properties are added to 'tree.data')"); + metaData = children; + children = children.children; + delete metaData.children; + $.extend(tree.data, metaData); + } + _assert($.isArray(children), "expected array of children"); + node._setChildren(children); + // trigger fancytreeloadchildren + tree._triggerNodeEvent("loadChildren", node); + // }).always(function(){ + // node._isLoading = false; + }); + }, + /** [Not Implemented] */ + nodeLoadKeyPath: function(ctx, keyPathList) { + // TODO: implement and improve + // http://code.google.com/p/dynatree/issues/detail?id=222 + }, + /** + * Remove a single direct child of ctx.node. + * @param {EventData} ctx + * @param {FancytreeNode} childNode dircect child of ctx.node + */ + nodeRemoveChild: function(ctx, childNode) { + var idx, + node = ctx.node, + opts = ctx.options, + subCtx = $.extend({}, ctx, {node: childNode}), + children = node.children; + + // FT.debug("nodeRemoveChild()", node.toString(), childNode.toString()); + + if( children.length === 1 ) { + _assert(childNode === children[0], "invalid single child"); + return this.nodeRemoveChildren(ctx); + } + if( this.activeNode && (childNode === this.activeNode || this.activeNode.isDescendantOf(childNode))){ + this.activeNode.setActive(false); // TODO: don't fire events + } + if( this.focusNode && (childNode === this.focusNode || this.focusNode.isDescendantOf(childNode))){ + this.focusNode = null; + } + // TODO: persist must take care to clear select and expand cookies + this.nodeRemoveMarkup(subCtx); + this.nodeRemoveChildren(subCtx); + idx = $.inArray(childNode, children); + _assert(idx >= 0, "invalid child"); + // Unlink to support GC + childNode.visit(function(n){ + n.parent = null; + }, true); + this._callHook("treeRegisterNode", this, false, childNode); + if ( opts.removeNode ){ + opts.removeNode.call(ctx.tree, {type: "removeNode"}, subCtx); + } + // remove from child list + children.splice(idx, 1); + }, + /**Remove HTML markup for all descendents of ctx.node. + * @param {EventData} ctx + */ + nodeRemoveChildMarkup: function(ctx) { + var node = ctx.node; + + // FT.debug("nodeRemoveChildMarkup()", node.toString()); + // TODO: Unlink attr.ftnode to support GC + if(node.ul){ + if( node.isRootNode() ) { + $(node.ul).empty(); + } else { + $(node.ul).remove(); + node.ul = null; + } + node.visit(function(n){ + n.li = n.ul = null; + }); + } + }, + /**Remove all descendants of ctx.node. + * @param {EventData} ctx + */ + nodeRemoveChildren: function(ctx) { + var subCtx, + tree = ctx.tree, + node = ctx.node, + children = node.children, + opts = ctx.options; + + // FT.debug("nodeRemoveChildren()", node.toString()); + if(!children){ + return; + } + if( this.activeNode && this.activeNode.isDescendantOf(node)){ + this.activeNode.setActive(false); // TODO: don't fire events + } + if( this.focusNode && this.focusNode.isDescendantOf(node)){ + this.focusNode = null; + } + // TODO: persist must take care to clear select and expand cookies + this.nodeRemoveChildMarkup(ctx); + // Unlink children to support GC + // TODO: also delete this.children (not possible using visit()) + subCtx = $.extend({}, ctx); + node.visit(function(n){ + n.parent = null; + tree._callHook("treeRegisterNode", tree, false, n); + if ( opts.removeNode ){ + subCtx.node = n; + opts.removeNode.call(ctx.tree, {type: "removeNode"}, subCtx); + } + }); + if( node.lazy ){ + // 'undefined' would be interpreted as 'not yet loaded' for lazy nodes + node.children = []; + } else{ + node.children = null; + } + if( !node.isRootNode() ) { + node.expanded = false; // #449, #459 + } + this.nodeRenderStatus(ctx); + }, + /**Remove HTML markup for ctx.node and all its descendents. + * @param {EventData} ctx + */ + nodeRemoveMarkup: function(ctx) { + var node = ctx.node; + // FT.debug("nodeRemoveMarkup()", node.toString()); + // TODO: Unlink attr.ftnode to support GC + if(node.li){ + $(node.li).remove(); + node.li = null; + } + this.nodeRemoveChildMarkup(ctx); + }, + /** + * Create `<li><span>..</span> .. </li>` tags for this node. + * + * This method takes care that all HTML markup is created that is required + * to display this node in it's current state. + * + * Call this method to create new nodes, or after the strucuture + * was changed (e.g. after moving this node or adding/removing children) + * nodeRenderTitle() and nodeRenderStatus() are implied. + * + * Note: if a node was created/removed, nodeRender() must be called for the + * parent. + * <code> + * <li id='KEY' ftnode=NODE> + * <span class='fancytree-node fancytree-expanded fancytree-has-children fancytree-lastsib fancytree-exp-el fancytree-ico-e'> + * <span class="fancytree-expander"></span> + * <span class="fancytree-checkbox"></span> // only present in checkbox mode + * <span class="fancytree-icon"></span> + * <a href="#" class="fancytree-title"> Node 1 </a> + * </span> + * <ul> // only present if node has children + * <li id='KEY' ftnode=NODE> child1 ... </li> + * <li id='KEY' ftnode=NODE> child2 ... </li> + * </ul> + * </li> + * </code> + * + * @param {EventData} ctx + * @param {boolean} [force=false] re-render, even if html markup was already created + * @param {boolean} [deep=false] also render all descendants, even if parent is collapsed + * @param {boolean} [collapsed=false] force root node to be collapsed, so we can apply animated expand later + */ + nodeRender: function(ctx, force, deep, collapsed, _recursive) { + /* This method must take care of all cases where the current data mode + * (i.e. node hierarchy) does not match the current markup. + * + * - node was not yet rendered: + * create markup + * - node was rendered: exit fast + * - children have been added + * - children have been removed + */ + var childLI, childNode1, childNode2, i, l, next, subCtx, + node = ctx.node, + tree = ctx.tree, + opts = ctx.options, + aria = opts.aria, + firstTime = false, + parent = node.parent, + isRootNode = !parent, + children = node.children, + successorLi = null; + // FT.debug("nodeRender(" + !!force + ", " + !!deep + ")", node.toString()); + + if( ! isRootNode && ! parent.ul ) { + // Calling node.collapse on a deep, unrendered node + return; + } + _assert(isRootNode || parent.ul, "parent UL must exist"); + + // Render the node + if( !isRootNode ){ + // Discard markup on force-mode, or if it is not linked to parent <ul> + if(node.li && (force || (node.li.parentNode !== node.parent.ul) ) ){ + if( node.li.parentNode === node.parent.ul ){ + // #486: store following node, so we can insert the new markup there later + successorLi = node.li.nextSibling; + }else{ + // May happen, when a top-level node was dropped over another + this.debug("Unlinking " + node + " (must be child of " + node.parent + ")"); + } +// this.debug("nodeRemoveMarkup..."); + this.nodeRemoveMarkup(ctx); + } + // Create <li><span /> </li> +// node.debug("render..."); + if( !node.li ) { +// node.debug("render... really"); + firstTime = true; + node.li = document.createElement("li"); + node.li.ftnode = node; + if(aria){ + // TODO: why doesn't this work: +// node.li.role = "treeitem"; +// $(node.li).attr("role", "treeitem") +// .attr("aria-labelledby", "ftal_" + node.key); + } + if( node.key && opts.generateIds ){ + node.li.id = opts.idPrefix + node.key; + } + node.span = document.createElement("span"); + node.span.className = "fancytree-node"; + if(aria){ + $(node.span).attr("aria-labelledby", "ftal_" + node.key); + } + node.li.appendChild(node.span); + + // Create inner HTML for the <span> (expander, checkbox, icon, and title) + this.nodeRenderTitle(ctx); + + // Allow tweaking and binding, after node was created for the first time + if ( opts.createNode ){ + opts.createNode.call(tree, {type: "createNode"}, ctx); + } + }else{ +// this.nodeRenderTitle(ctx); + this.nodeRenderStatus(ctx); + } + // Allow tweaking after node state was rendered + if ( opts.renderNode ){ + opts.renderNode.call(tree, {type: "renderNode"}, ctx); + } + } + + // Visit child nodes + if( children ){ + if( isRootNode || node.expanded || deep === true ) { + // Create a UL to hold the children + if( !node.ul ){ + node.ul = document.createElement("ul"); + if((collapsed === true && !_recursive) || !node.expanded){ + // hide top UL, so we can use an animation to show it later + node.ul.style.display = "none"; + } + if(aria){ + $(node.ul).attr("role", "group"); + } + if ( node.li ) { // issue #67 + node.li.appendChild(node.ul); + } else { + node.tree.$div.append(node.ul); + } + } + // Add child markup + for(i=0, l=children.length; i<l; i++) { + subCtx = $.extend({}, ctx, {node: children[i]}); + this.nodeRender(subCtx, force, deep, false, true); + } + // Remove <li> if nodes have moved to another parent + childLI = node.ul.firstChild; + while( childLI ){ + childNode2 = childLI.ftnode; + if( childNode2 && childNode2.parent !== node ) { + node.debug("_fixParent: remove missing " + childNode2, childLI); + next = childLI.nextSibling; + childLI.parentNode.removeChild(childLI); + childLI = next; + }else{ + childLI = childLI.nextSibling; + } + } + // Make sure, that <li> order matches node.children order. + childLI = node.ul.firstChild; + for(i=0, l=children.length-1; i<l; i++) { + childNode1 = children[i]; + childNode2 = childLI.ftnode; + if( childNode1 !== childNode2 ) { + // node.debug("_fixOrder: mismatch at index " + i + ": " + childNode1 + " != " + childNode2); + node.ul.insertBefore(childNode1.li, childNode2.li); + } else { + childLI = childLI.nextSibling; + } + } + } + }else{ + // No children: remove markup if any + if( node.ul ){ +// alert("remove child markup for " + node); + this.warn("remove child markup for " + node); + this.nodeRemoveChildMarkup(ctx); + } + } + if( !isRootNode ){ + // Update element classes according to node state + // this.nodeRenderStatus(ctx); + // Finally add the whole structure to the DOM, so the browser can render + if( firstTime ){ + // #486: successorLi is set, if we re-rendered (i.e. discarded) + // existing markup, which we want to insert at the same position. + // (null is equivalent to append) +// parent.ul.appendChild(node.li); + parent.ul.insertBefore(node.li, successorLi); + } + } + }, + /** Create HTML inside the node's outer <span> (i.e. expander, checkbox, + * icon, and title). + * + * nodeRenderStatus() is implied. + * @param {EventData} ctx + * @param {string} [title] optinal new title + */ + nodeRenderTitle: function(ctx, title) { + // set node connector images, links and text + var id, iconSpanClass, nodeTitle, role, tabindex, tooltip, + node = ctx.node, + tree = ctx.tree, + opts = ctx.options, + aria = opts.aria, + level = node.getLevel(), + ares = [], + iconSrc = node.data.icon; + + if(title !== undefined){ + node.title = title; + } + if(!node.span){ + // Silently bail out if node was not rendered yet, assuming + // node.render() will be called as the node becomes visible + return; + } + // connector (expanded, expandable or simple) + // TODO: optimize this if clause + if( level < opts.minExpandLevel ) { + if( !node.lazy ) { + node.expanded = true; + } + if(level > 1){ + if(aria){ + ares.push("<span role='button' class='fancytree-expander fancytree-expander-fixed'></span>"); + }else{ + ares.push("<span class='fancytree-expander fancytree-expander-fixed''></span>"); + } + } + // .. else (i.e. for root level) skip expander/connector alltogether + } else { + if(aria){ + ares.push("<span role='button' class='fancytree-expander'></span>"); + }else{ + ares.push("<span class='fancytree-expander'></span>"); + } + } + // Checkbox mode + if( opts.checkbox && node.hideCheckbox !== true && !node.isStatusNode() ) { + if(aria){ + ares.push("<span role='checkbox' class='fancytree-checkbox'></span>"); + }else{ + ares.push("<span class='fancytree-checkbox'></span>"); + } + } + // folder or doctype icon + role = aria ? " role='img'" : ""; + if( iconSrc === true || (iconSrc !== false && opts.icons !== false) ) { + // opts.icons defines the default behavior, node.icon == true/false can override this + if ( iconSrc && typeof iconSrc === "string" ) { + // node.icon is an image url + iconSrc = (iconSrc.charAt(0) === "/") ? iconSrc : ((opts.imagePath || "") + iconSrc); + ares.push("<img src='" + iconSrc + "' class='fancytree-icon' alt='' />"); + } else { + // See if node.iconclass or opts.iconClass() define a class name + iconSpanClass = (opts.iconClass && opts.iconClass.call(tree, {type: "iconClass"}, ctx)) || node.data.iconclass || null; + if( iconSpanClass ) { + ares.push("<span " + role + " class='fancytree-custom-icon " + iconSpanClass + "'></span>"); + } else { + ares.push("<span " + role + " class='fancytree-icon'></span>"); + } + } + } + + // node title + nodeTitle = ""; + if ( opts.renderTitle ){ + nodeTitle = opts.renderTitle.call(tree, {type: "renderTitle"}, ctx) || ""; + } + if(!nodeTitle){ + tooltip = node.tooltip ? " title='" + FT.escapeHtml(node.tooltip) + "'" : ""; + id = aria ? " id='ftal_" + node.key + "'" : ""; + role = aria ? " role='treeitem'" : ""; + tabindex = opts.titlesTabbable ? " tabindex='0'" : ""; + + nodeTitle = "<span " + role + " class='fancytree-title'" + id + tooltip + tabindex + ">" + node.title + "</span>"; + } + ares.push(nodeTitle); + // Note: this will trigger focusout, if node had the focus + //$(node.span).html(ares.join("")); // it will cleanup the jQuery data currently associated with SPAN (if any), but it executes more slowly + node.span.innerHTML = ares.join(""); + // Update CSS classes + this.nodeRenderStatus(ctx); + }, + /** Update element classes according to node state. + * @param {EventData} ctx + */ + nodeRenderStatus: function(ctx) { + // Set classes for current status + var node = ctx.node, + tree = ctx.tree, + opts = ctx.options, +// nodeContainer = node[tree.nodeContainerAttrName], + hasChildren = node.hasChildren(), + isLastSib = node.isLastSibling(), + aria = opts.aria, +// $ariaElem = aria ? $(node[tree.ariaPropName]) : null, + $ariaElem = $(node.span).find(".fancytree-title"), + cn = opts._classNames, + cnList = [], + statusElem = node[tree.statusClassPropName]; + + if( !statusElem ){ + // if this function is called for an unrendered node, ignore it (will be updated on nect render anyway) + return; + } + // Build a list of class names that we will add to the node <span> + cnList.push(cn.node); + if( tree.activeNode === node ){ + cnList.push(cn.active); +// $(">span.fancytree-title", statusElem).attr("tabindex", "0"); +// tree.$container.removeAttr("tabindex"); + // }else{ +// $(">span.fancytree-title", statusElem).removeAttr("tabindex"); +// tree.$container.attr("tabindex", "0"); + } + if( tree.focusNode === node ){ + cnList.push(cn.focused); + if(aria){ +// $(">span.fancytree-title", statusElem).attr("tabindex", "0"); +// $(">span.fancytree-title", statusElem).attr("tabindex", "-1"); + // TODO: is this the right element for this attribute? + $ariaElem + .attr("aria-activedescendant", true); +// .attr("tabindex", "-1"); + } + }else if(aria){ +// $(">span.fancytree-title", statusElem).attr("tabindex", "-1"); + $ariaElem + .removeAttr("aria-activedescendant"); +// .removeAttr("tabindex"); + } + if( node.expanded ){ + cnList.push(cn.expanded); + if(aria){ + $ariaElem.attr("aria-expanded", true); + } + }else if(aria){ + $ariaElem.removeAttr("aria-expanded"); + } + if( node.folder ){ + cnList.push(cn.folder); + } + if( hasChildren !== false ){ + cnList.push(cn.hasChildren); + } + // TODO: required? + if( isLastSib ){ + cnList.push(cn.lastsib); + } + if( node.lazy && node.children == null ){ + cnList.push(cn.lazy); + } + if( node.partsel ){ + cnList.push(cn.partsel); + } + if( node.unselectable ){ + cnList.push(cn.unselectable); + } + if( node._isLoading ){ + cnList.push(cn.loading); + } + if( node._error ){ + cnList.push(cn.error); + } + if( node.selected ){ + cnList.push(cn.selected); + if(aria){ + $ariaElem.attr("aria-selected", true); + } + }else if(aria){ + $ariaElem.attr("aria-selected", false); + } + if( node.extraClasses ){ + cnList.push(node.extraClasses); + } + // IE6 doesn't correctly evaluate multiple class names, + // so we create combined class names that can be used in the CSS + if( hasChildren === false ){ + cnList.push(cn.combinedExpanderPrefix + "n" + + (isLastSib ? "l" : "") + ); + }else{ + cnList.push(cn.combinedExpanderPrefix + + (node.expanded ? "e" : "c") + + (node.lazy && node.children == null ? "d" : "") + + (isLastSib ? "l" : "") + ); + } + cnList.push(cn.combinedIconPrefix + + (node.expanded ? "e" : "c") + + (node.folder ? "f" : "") + ); +// node.span.className = cnList.join(" "); + statusElem.className = cnList.join(" "); + + // TODO: we should not set this in the <span> tag also, if we set it here: + // Maybe most (all) of the classes should be set in LI instead of SPAN? + if(node.li){ + node.li.className = isLastSib ? cn.lastsib : ""; + } + }, + /** Activate node. + * flag defaults to true. + * If flag is true, the node is activated (must be a synchronous operation) + * If flag is false, the node is deactivated (must be a synchronous operation) + * @param {EventData} ctx + * @param {boolean} [flag=true] + * @param {object} [opts] additional options. Defaults to {noEvents: false, noFocus: false} + * @returns {$.Promise} + */ + nodeSetActive: function(ctx, flag, callOpts) { + // Handle user click / [space] / [enter], according to clickFolderMode. + callOpts = callOpts || {}; + var subCtx, + node = ctx.node, + tree = ctx.tree, + opts = ctx.options, + noEvents = (callOpts.noEvents === true), + noFocus = (callOpts.noFocus === true), + isActive = (node === tree.activeNode); + + // flag defaults to true + flag = (flag !== false); + // node.debug("nodeSetActive", flag); + + if(isActive === flag){ + // Nothing to do + return _getResolvedPromise(node); + }else if(flag && !noEvents && this._triggerNodeEvent("beforeActivate", node, ctx.originalEvent) === false ){ + // Callback returned false + return _getRejectedPromise(node, ["rejected"]); + } + if(flag){ + if(tree.activeNode){ + _assert(tree.activeNode !== node, "node was active (inconsistency)"); + subCtx = $.extend({}, ctx, {node: tree.activeNode}); + tree.nodeSetActive(subCtx, false); + _assert(tree.activeNode === null, "deactivate was out of sync?"); + } + if(opts.activeVisible){ + // tree.nodeMakeVisible(ctx); + node.makeVisible({scrollIntoView: false}); // nodeSetFocus will scroll + } + tree.activeNode = node; + tree.nodeRenderStatus(ctx); + if( !noFocus ) { + tree.nodeSetFocus(ctx); + } + if( !noEvents ) { + tree._triggerNodeEvent("activate", node, ctx.originalEvent); + } + }else{ + _assert(tree.activeNode === node, "node was not active (inconsistency)"); + tree.activeNode = null; + this.nodeRenderStatus(ctx); + if( !noEvents ) { + ctx.tree._triggerNodeEvent("deactivate", node, ctx.originalEvent); + } + } + return _getResolvedPromise(node); + }, + /** Expand or collapse node, return Deferred.promise. + * + * @param {EventData} ctx + * @param {boolean} [flag=true] + * @param {object} [opts] additional options. Defaults to {noAnimation: false, noEvents: false} + * @returns {$.Promise} The deferred will be resolved as soon as the (lazy) + * data was retrieved, rendered, and the expand animation finshed. + */ + nodeSetExpanded: function(ctx, flag, callOpts) { + callOpts = callOpts || {}; + var _afterLoad, dfd, i, l, parents, prevAC, + node = ctx.node, + tree = ctx.tree, + opts = ctx.options, + noAnimation = (callOpts.noAnimation === true), + noEvents = (callOpts.noEvents === true); + + // flag defaults to true + flag = (flag !== false); + + // node.debug("nodeSetExpanded(" + flag + ")"); + + if((node.expanded && flag) || (!node.expanded && !flag)){ + // Nothing to do + // node.debug("nodeSetExpanded(" + flag + "): nothing to do"); + return _getResolvedPromise(node); + }else if(flag && !node.lazy && !node.hasChildren() ){ + // Prevent expanding of empty nodes + // return _getRejectedPromise(node, ["empty"]); + return _getResolvedPromise(node); + }else if( !flag && node.getLevel() < opts.minExpandLevel ) { + // Prevent collapsing locked levels + return _getRejectedPromise(node, ["locked"]); + }else if ( !noEvents && this._triggerNodeEvent("beforeExpand", node, ctx.originalEvent) === false ){ + // Callback returned false + return _getRejectedPromise(node, ["rejected"]); + } + // If this node inside a collpased node, no animation and scrolling is needed + if( !noAnimation && !node.isVisible() ) { + noAnimation = callOpts.noAnimation = true; + } + + dfd = new $.Deferred(); + + // Auto-collapse mode: collapse all siblings + if( flag && !node.expanded && opts.autoCollapse ) { + parents = node.getParentList(false, true); + prevAC = opts.autoCollapse; + try{ + opts.autoCollapse = false; + for(i=0, l=parents.length; i<l; i++){ + // TODO: should return promise? + this._callHook("nodeCollapseSiblings", parents[i], callOpts); + } + }finally{ + opts.autoCollapse = prevAC; + } + } + // Trigger expand/collapse after expanding + dfd.done(function(){ + var lastChild = node.getLastChild(); + if( flag && opts.autoScroll && !noAnimation && lastChild ) { + // Scroll down to last child, but keep current node visible + lastChild.scrollIntoView(true, {topNode: node}).always(function(){ + if( !noEvents ) { + ctx.tree._triggerNodeEvent(flag ? "expand" : "collapse", ctx); + } + }); + } else { + if( !noEvents ) { + ctx.tree._triggerNodeEvent(flag ? "expand" : "collapse", ctx); + } + } + }); + // vvv Code below is executed after loading finished: + _afterLoad = function(callback){ + var isVisible, isExpanded, + effect = opts.toggleEffect; + + node.expanded = flag; + // Create required markup, but make sure the top UL is hidden, so we + // can animate later + tree._callHook("nodeRender", ctx, false, false, true); + + // If the currently active node is now hidden, deactivate it + // if( opts.activeVisible && this.activeNode && ! this.activeNode.isVisible() ) { + // this.activeNode.deactivate(); + // } + + // Expanding a lazy node: set 'loading...' and call callback + // if( bExpand && this.data.isLazy && this.childList === null && !this._isLoading ) { + // this._loadContent(); + // return; + // } + // Hide children, if node is collapsed + if( node.ul ) { + isVisible = (node.ul.style.display !== "none"); + isExpanded = !!node.expanded; + if ( isVisible === isExpanded ) { + node.warn("nodeSetExpanded: UL.style.display already set"); + + } else if ( !effect || noAnimation ) { + node.ul.style.display = ( node.expanded || !parent ) ? "" : "none"; + + } else { + // The UI toggle() effect works with the ext-wide extension, + // while jQuery.animate() has problems when the title span + // has positon: absolute + + // duration = opts.fx.duration || 200; + // easing = opts.fx.easing; + // $(node.ul).animate(opts.fx, duration, easing, function(){ + + // node.debug("nodeSetExpanded: animate start..."); + $(node.ul).toggle(effect.effect, effect.options, effect.duration, function(){ + // node.debug("nodeSetExpanded: animate done"); + callback(); + }); + return; + } + } + callback(); + }; + // ^^^ Code above is executed after loading finshed. + + // Load lazy nodes, if any. Then continue with _afterLoad() + if(flag && node.lazy && node.hasChildren() === undefined){ + // node.debug("nodeSetExpanded: load start..."); + node.load().done(function(){ + // node.debug("nodeSetExpanded: load done"); + if(dfd.notifyWith){ // requires jQuery 1.6+ + dfd.notifyWith(node, ["loaded"]); + } + _afterLoad(function () { dfd.resolveWith(node); }); + }).fail(function(errMsg){ + _afterLoad(function () { dfd.rejectWith(node, ["load failed (" + errMsg + ")"]); }); + }); +/* + var source = tree._triggerNodeEvent("lazyLoad", node, ctx.originalEvent); + _assert(typeof source !== "boolean", "lazyLoad event must return source in data.result"); + node.debug("nodeSetExpanded: load start..."); + this._callHook("nodeLoadChildren", ctx, source).done(function(){ + node.debug("nodeSetExpanded: load done"); + if(dfd.notifyWith){ // requires jQuery 1.6+ + dfd.notifyWith(node, ["loaded"]); + } + _afterLoad.call(tree); + }).fail(function(errMsg){ + dfd.rejectWith(node, ["load failed (" + errMsg + ")"]); + }); +*/ + }else{ + _afterLoad(function () { dfd.resolveWith(node); }); + } + // node.debug("nodeSetExpanded: returns"); + return dfd.promise(); + }, + /** Focus or blur this node. + * @param {EventData} ctx + * @param {boolean} [flag=true] + */ + nodeSetFocus: function(ctx, flag) { + // ctx.node.debug("nodeSetFocus(" + flag + ")"); + var ctx2, + tree = ctx.tree, + node = ctx.node; + + flag = (flag !== false); + + // Blur previous node if any + if(tree.focusNode){ + if(tree.focusNode === node && flag){ + // node.debug("nodeSetFocus(" + flag + "): nothing to do"); + return; + } + ctx2 = $.extend({}, ctx, {node: tree.focusNode}); + tree.focusNode = null; + this._triggerNodeEvent("blur", ctx2); + this._callHook("nodeRenderStatus", ctx2); + } + // Set focus to container and node + if(flag){ + if( !this.hasFocus() ){ + node.debug("nodeSetFocus: forcing container focus"); + this._callHook("treeSetFocus", ctx, true, {calledByNode: true}); + } + node.makeVisible({scrollIntoView: false}); + tree.focusNode = node; +// node.debug("FOCUS..."); +// $(node.span).find(".fancytree-title").focus(); + this._triggerNodeEvent("focus", ctx); +// if(ctx.options.autoActivate){ +// tree.nodeSetActive(ctx, true); +// } + if(ctx.options.autoScroll){ + node.scrollIntoView(); + } + this._callHook("nodeRenderStatus", ctx); + } + }, + /** (De)Select node, return new status (sync). + * + * @param {EventData} ctx + * @param {boolean} [flag=true] + */ + nodeSetSelected: function(ctx, flag) { + var node = ctx.node, + tree = ctx.tree, + opts = ctx.options; + // flag defaults to true + flag = (flag !== false); + + node.debug("nodeSetSelected(" + flag + ")", ctx); + if( node.unselectable){ + return; + } + // TODO: !!node.expanded is nicer, but doesn't pass jshint + // https://github.com/jshint/jshint/issues/455 +// if( !!node.expanded === !!flag){ + if((node.selected && flag) || (!node.selected && !flag)){ + return !!node.selected; + }else if ( this._triggerNodeEvent("beforeSelect", node, ctx.originalEvent) === false ){ + return !!node.selected; + } + if(flag && opts.selectMode === 1){ + // single selection mode + if(tree.lastSelectedNode){ + tree.lastSelectedNode.setSelected(false); + } + }else if(opts.selectMode === 3){ + // multi.hier selection mode + node.selected = flag; +// this._fixSelectionState(node); + node.fixSelection3AfterClick(); + } + node.selected = flag; + this.nodeRenderStatus(ctx); + tree.lastSelectedNode = flag ? node : null; + tree._triggerNodeEvent("select", ctx); + }, + /** Show node status (ok, loading, error) using styles and a dummy child node. + * + * @param {EventData} ctx + * @param status + * @param message + * @param details + * @since 2.3 + */ + nodeSetStatus: function(ctx, status, message, details) { + var node = ctx.node, + tree = ctx.tree; + // cn = ctx.options._classNames; + + function _clearStatusNode() { + // Remove dedicated dummy node, if any + var firstChild = ( node.children ? node.children[0] : null ); + if ( firstChild && firstChild.isStatusNode() ) { + try{ + // I've seen exceptions here with loadKeyPath... + if(node.ul){ + node.ul.removeChild(firstChild.li); + firstChild.li = null; // avoid leaks (DT issue 215) + } + }catch(e){} + if( node.children.length === 1 ){ + node.children = []; + }else{ + node.children.shift(); + } + } + } + function _setStatusNode(data, type) { + // Create/modify the dedicated dummy node for 'loading...' or + // 'error!' status. (only called for direct child of the invisible + // system root) + var firstChild = ( node.children ? node.children[0] : null ); + if ( firstChild && firstChild.isStatusNode() ) { + $.extend(firstChild, data); + // tree._callHook("nodeRender", firstChild); + tree._callHook("nodeRenderTitle", firstChild); + } else { + data.key = "_statusNode"; + node._setChildren([data]); + node.children[0].statusNodeType = type; + tree.render(); + } + return node.children[0]; + } + + switch( status ){ + case "ok": + _clearStatusNode(); + // $(node.span).removeClass(cn.loading).removeClass(cn.error); + node._isLoading = false; + node._error = null; + node.renderStatus(); + break; + case "loading": + // $(node.span).removeClass(cn.error).addClass(cn.loading); + if( !node.parent ) { + _setStatusNode({ + title: tree.options.strings.loading + (message ? " (" + message + ") " : ""), + tooltip: details, + extraClasses: "fancytree-statusnode-wait" + }, status); + } + node._isLoading = true; + node._error = null; + node.renderStatus(); + break; + case "error": + // $(node.span).removeClass(cn.loading).addClass(cn.error); + _setStatusNode({ + title: tree.options.strings.loadError + (message ? " (" + message + ") " : ""), + tooltip: details, + extraClasses: "fancytree-statusnode-error" + }, status); + node._isLoading = false; + node._error = { message: message, details: details }; + node.renderStatus(); + break; + default: + $.error("invalid node status " + status); + } + }, + /** + * + * @param {EventData} ctx + */ + nodeToggleExpanded: function(ctx) { + return this.nodeSetExpanded(ctx, !ctx.node.expanded); + }, + /** + * @param {EventData} ctx + */ + nodeToggleSelected: function(ctx) { + return this.nodeSetSelected(ctx, !ctx.node.selected); + }, + /** Remove all nodes. + * @param {EventData} ctx + */ + treeClear: function(ctx) { + var tree = ctx.tree; + tree.activeNode = null; + tree.focusNode = null; + tree.$div.find(">ul.fancytree-container").empty(); + // TODO: call destructors and remove reference loops + tree.rootNode.children = null; + }, + /** Widget was created (called only once, even it re-initialized). + * @param {EventData} ctx + */ + treeCreate: function(ctx) { + }, + /** Widget was destroyed. + * @param {EventData} ctx + */ + treeDestroy: function(ctx) { + this.$div.find(">ul.fancytree-container").remove(); + this.$source && this.$source.removeClass("ui-helper-hidden"); + }, + /** Widget was (re-)initialized. + * @param {EventData} ctx + */ + treeInit: function(ctx) { + //this.debug("Fancytree.treeInit()"); + this.treeLoad(ctx); + }, + /** Parse Fancytree from source, as configured in the options. + * @param {EventData} ctx + * @param {object} [source] optional new source (use last data otherwise) + */ + treeLoad: function(ctx, source) { + var type, $ul, + tree = ctx.tree, + $container = ctx.widget.element, + dfd, + // calling context for root node + rootCtx = $.extend({}, ctx, {node: this.rootNode}); + + if(tree.rootNode.children){ + this.treeClear(ctx); + } + source = source || this.options.source; + + if(!source){ + type = $container.data("type") || "html"; + switch(type){ + case "html": + $ul = $container.find(">ul:first"); + $ul.addClass("ui-fancytree-source ui-helper-hidden"); + source = $.ui.fancytree.parseHtml($ul); + // allow to init tree.data.foo from <ul data-foo=''> + this.data = $.extend(this.data, _getElementDataAsDict($ul)); + break; + case "json": + // $().addClass("ui-helper-hidden"); + source = $.parseJSON($container.text()); + if(source.children){ + if(source.title){tree.title = source.title;} + source = source.children; + } + break; + default: + $.error("Invalid data-type: " + type); + } + }else if(typeof source === "string"){ + // TODO: source is an element ID + $.error("Not implemented"); + } + + // Trigger fancytreeinit after nodes have been loaded + dfd = this.nodeLoadChildren(rootCtx, source).done(function(){ + tree.render(); + if( ctx.options.selectMode === 3 ){ + tree.rootNode.fixSelection3FromEndNodes(); + } + if( tree.activeNode && tree.options.activeVisible ) { + tree.activeNode.makeVisible(); + } + tree._triggerTreeEvent("init", null, { status: true }); + }).fail(function(){ + tree.render(); + tree._triggerTreeEvent("init", null, { status: false }); + }); + return dfd; + }, + /** Node was inserted into or removed from the tree. + * @param {EventData} ctx + * @param {boolean} add + * @param {FancytreeNode} node + */ + treeRegisterNode: function(ctx, add, node) { + }, + /** Widget got focus. + * @param {EventData} ctx + * @param {boolean} [flag=true] + */ + treeSetFocus: function(ctx, flag, callOpts) { + flag = (flag !== false); + + // this.debug("treeSetFocus(" + flag + "), callOpts: " + callOpts, this.hasFocus()); + // this.debug(" focusNode: " + this.focusNode); + // this.debug(" activeNode: " + this.activeNode); + if( flag !== this.hasFocus() ){ + this._hasFocus = flag; + if( !flag && this.focusNode ) { + // Node also looses focus if widget blurs + this.focusNode.setFocus(false); + } + this.$container.toggleClass("fancytree-treefocus", flag); + this._triggerTreeEvent(flag ? "focusTree" : "blurTree"); + } + } +}); + + +/* ****************************************************************************** + * jQuery UI widget boilerplate + */ + +/** + * The plugin (derrived from <a href=" http://api.jqueryui.com/jQuery.widget/">jQuery.Widget</a>).<br> + * This constructor is not called directly. Use `$(selector).fancytree({})` + * to initialize the plugin instead.<br> + * <pre class="sh_javascript sunlight-highlight-javascript">// Access widget methods and members: + * var tree = $("#tree").fancytree("getTree"); + * var node = $("#tree").fancytree("getActiveNode", "1234"); + * </pre> + * + * @mixin Fancytree_Widget + */ + +$.widget("ui.fancytree", + /** @lends Fancytree_Widget# */ + { + /**These options will be used as defaults + * @type {FancytreeOptions} + */ + options: + { + activeVisible: true, + ajax: { + type: "GET", + cache: false, // false: Append random '_' argument to the request url to prevent caching. +// timeout: 0, // >0: Make sure we get an ajax error if server is unreachable + dataType: "json" // Expect json format and pass json object to callbacks. + }, // + aria: false, // TODO: default to true + autoActivate: true, + autoCollapse: false, +// autoFocus: false, + autoScroll: false, + checkbox: false, + /**defines click behavior*/ + clickFolderMode: 4, + debugLevel: null, // 0..2 (null: use global setting $.ui.fancytree.debugInfo) + disabled: false, // TODO: required anymore? + enableAspx: true, // TODO: document + extensions: [], + // fx: { height: "toggle", duration: 200 }, + // toggleEffect: { effect: "drop", options: {direction: "left"}, duration: 200 }, + // toggleEffect: { effect: "slide", options: {direction: "up"}, duration: 200 }, + toggleEffect: { effect: "blind", options: {direction: "vertical", scale: "box"}, duration: 200 }, + generateIds: false, + icons: true, + idPrefix: "ft_", + focusOnSelect: false, + keyboard: true, + keyPathSeparator: "/", + minExpandLevel: 1, + quicksearch: false, + scrollOfs: {top: 0, bottom: 0}, + scrollParent: null, + selectMode: 2, + strings: { + loading: "Loading…", + loadError: "Load error!" + }, + tabbable: true, + titlesTabbable: false, + _classNames: { + node: "fancytree-node", + folder: "fancytree-folder", + combinedExpanderPrefix: "fancytree-exp-", + combinedIconPrefix: "fancytree-ico-", + hasChildren: "fancytree-has-children", + active: "fancytree-active", + selected: "fancytree-selected", + expanded: "fancytree-expanded", + lazy: "fancytree-lazy", + focused: "fancytree-focused", + partsel: "fancytree-partsel", + unselectable: "fancytree-unselectable", + lastsib: "fancytree-lastsib", + loading: "fancytree-loading", + error: "fancytree-error" + }, + // events + lazyLoad: null, + postProcess: null + }, + /* Set up the widget, Called on first $().fancytree() */ + _create: function() { + this.tree = new Fancytree(this); + + this.$source = this.source || this.element.data("type") === "json" ? this.element + : this.element.find(">ul:first"); + // Subclass Fancytree instance with all enabled extensions + var extension, extName, i, + extensions = this.options.extensions, + base = this.tree; + + for(i=0; i<extensions.length; i++){ + extName = extensions[i]; + extension = $.ui.fancytree._extensions[extName]; + if(!extension){ + $.error("Could not apply extension '" + extName + "' (it is not registered, did you forget to include it?)"); + } + // Add extension options as tree.options.EXTENSION +// _assert(!this.tree.options[extName], "Extension name must not exist as option name: " + extName); + this.tree.options[extName] = $.extend(true, {}, extension.options, this.tree.options[extName]); + // Add a namespace tree.ext.EXTENSION, to hold instance data + _assert(this.tree.ext[extName] === undefined, "Extension name must not exist as Fancytree.ext attribute: '" + extName + "'"); +// this.tree[extName] = extension; + this.tree.ext[extName] = {}; + // Subclass Fancytree methods using proxies. + _subclassObject(this.tree, base, extension, extName); + // current extension becomes base for the next extension + base = extension; + } + // + this.tree._callHook("treeCreate", this.tree); + // Note: 'fancytreecreate' event is fired by widget base class +// this.tree._triggerTreeEvent("create"); + }, + + /* Called on every $().fancytree() */ + _init: function() { + this.tree._callHook("treeInit", this.tree); + // TODO: currently we call bind after treeInit, because treeInit + // might change tree.$container. + // It would be better, to move ebent binding into hooks altogether + this._bind(); + }, + + /* Use the _setOption method to respond to changes to options */ + _setOption: function(key, value) { + var callDefault = true, + rerender = false; + switch( key ) { + case "aria": + case "checkbox": + case "icons": + case "minExpandLevel": + case "tabbable": +// case "nolink": + this.tree._callHook("treeCreate", this.tree); + rerender = true; + break; + case "source": + callDefault = false; + this.tree._callHook("treeLoad", this.tree, value); + break; + } + this.tree.debug("set option " + key + "=" + value + " <" + typeof(value) + ">"); + if(callDefault){ + // In jQuery UI 1.8, you have to manually invoke the _setOption method from the base widget + $.Widget.prototype._setOption.apply(this, arguments); + // TODO: In jQuery UI 1.9 and above, you use the _super method instead +// this._super( "_setOption", key, value ); + } + if(rerender){ + this.tree.render(true, false); // force, not-deep + } + }, + + /** Use the destroy method to clean up any modifications your widget has made to the DOM */ + destroy: function() { + this._unbind(); + this.tree._callHook("treeDestroy", this.tree); + // In jQuery UI 1.8, you must invoke the destroy method from the base widget + $.Widget.prototype.destroy.call(this); + // TODO: delete tree and nodes to make garbage collect easier? + // TODO: In jQuery UI 1.9 and above, you would define _destroy instead of destroy and not call the base method + }, + + // ------------------------------------------------------------------------- + + /* Remove all event handlers for our namespace */ + _unbind: function() { + var ns = this.tree._ns; + this.element.unbind(ns); + this.tree.$container.unbind(ns); + $(document).unbind(ns); + }, + /* Add mouse and kyboard handlers to the container */ + _bind: function() { + var that = this, + opts = this.options, + tree = this.tree, + ns = tree._ns + // selstartEvent = ( $.support.selectstart ? "selectstart" : "mousedown" ) + ; + + // Remove all previuous handlers for this tree + this._unbind(); + + //alert("keydown" + ns + "foc=" + tree.hasFocus() + tree.$container); + // tree.debug("bind events; container: ", tree.$container); + tree.$container.on("focusin" + ns + " focusout" + ns, function(event){ + var node = FT.getNode(event), + flag = (event.type === "focusin"); + // tree.debug("Tree container got event " + event.type, node, event); + // tree.treeOnFocusInOut.call(tree, event); + if(node){ + // For example clicking into an <input> that is part of a node + tree._callHook("nodeSetFocus", node, flag); + }else{ + tree._callHook("treeSetFocus", tree, flag); + } + }).on("selectstart" + ns, "span.fancytree-title", function(event){ + // prevent mouse-drags to select text ranges + // tree.debug("<span title> got event " + event.type); + event.preventDefault(); + }).on("keydown" + ns, function(event){ + // TODO: also bind keyup and keypress + // tree.debug("got event " + event.type + ", hasFocus:" + tree.hasFocus()); + // if(opts.disabled || opts.keyboard === false || !tree.hasFocus() ){ + if(opts.disabled || opts.keyboard === false ){ + return true; + } + var res, + node = tree.focusNode, // node may be null + ctx = tree._makeHookContext(node || tree, event), + prevPhase = tree.phase; + + try { + tree.phase = "userEvent"; + // If a 'fancytreekeydown' handler returns false, skip the default + // handling (implemented by tree.nodeKeydown()). + if(node){ + res = tree._triggerNodeEvent("keydown", node, event); + }else{ + res = tree._triggerTreeEvent("keydown", event); + } + if ( res === "preventNav" ){ + res = true; // prevent keyboard navigation, but don't prevent default handling of embedded input controls + } else if ( res !== false ){ + res = tree._callHook("nodeKeydown", ctx); + } + return res; + } finally { + tree.phase = prevPhase; + } + }).on("click" + ns + " dblclick" + ns, function(event){ + // that.tree.debug("event(" + event + "): !"); + if(opts.disabled){ + return true; + } + var ctx, + et = FT.getEventTarget(event), + node = et.node, + tree = that.tree, + prevPhase = tree.phase; + + // that.tree.debug("event(" + event.type + "): node: ", node); + if( !node ){ + return true; // Allow bubbling of other events + } + ctx = tree._makeHookContext(node, event); +// that.tree.debug("event(" + event.type + "): node: ", node); + try { + tree.phase = "userEvent"; + switch(event.type) { + case "click": + ctx.targetType = et.type; + return ( tree._triggerNodeEvent("click", ctx, event) === false ) ? false : tree._callHook("nodeClick", ctx); + case "dblclick": + ctx.targetType = et.type; + return ( tree._triggerNodeEvent("dblclick", ctx, event) === false ) ? false : tree._callHook("nodeDblclick", ctx); + } +// } catch(e) { +// // var _ = null; // DT issue 117 // TODO +// $.error(e); + } finally { + tree.phase = prevPhase; + } + }); + }, + /** Return the active node or null. + * @returns {FancytreeNode} + */ + getActiveNode: function() { + return this.tree.activeNode; + }, + /** Return the matching node or null. + * @param {string} key + * @returns {FancytreeNode} + */ + getNodeByKey: function(key) { + return this.tree.getNodeByKey(key); + }, + /** Return the invisible system root node. + * @returns {FancytreeNode} + */ + getRootNode: function() { + return this.tree.rootNode; + }, + /** Return the current tree instance. + * @returns {Fancytree} + */ + getTree: function() { + return this.tree; + } +}); + +// $.ui.fancytree was created by the widget factory. Create a local shortcut: +FT = $.ui.fancytree; + +/** + * Static members in the `$.ui.fancytree` namespace.<br> + * <br> + * <pre class="sh_javascript sunlight-highlight-javascript">// Access static members: + * var node = $.ui.fancytree.getNode(element); + * alert($.ui.fancytree.version); + * </pre> + * + * @mixin Fancytree_Static + */ +$.extend($.ui.fancytree, + /** @lends Fancytree_Static# */ + { + /** @type {string} */ + version: "2.13.0", // Set to semver by 'grunt release' + /** @type {string} */ + buildType: "production", // Set to 'production' by 'grunt build' + /** @type {int} */ + debugLevel: 1, // Set to 1 by 'grunt build' + // Used by $.ui.fancytree.debug() and as default for tree.options.debugLevel + + _nextId: 1, + _nextNodeKey: 1, + _extensions: {}, + // focusTree: null, + + /** Expose class object as $.ui.fancytree._FancytreeClass */ + _FancytreeClass: Fancytree, + /** Expose class object as $.ui.fancytree._FancytreeNodeClass */ + _FancytreeNodeClass: FancytreeNode, + /* Feature checks to provide backwards compatibility */ + jquerySupports: { + // http://jqueryui.com/upgrade-guide/1.9/#deprecated-offset-option-merged-into-my-and-at + positionMyOfs: isVersionAtLeast($.ui.version, 1, 9) + }, + /** Throw an error if condition fails (debug method). + * @param {boolean} cond + * @param {string} msg + */ + assert: function(cond, msg){ + return _assert(cond, msg); + }, + /** Return a function that executes *fn* at most every *timeout* ms. + * @param {integer} timeout + * @param {function} fn + * @param {boolean} [invokeAsap=false] + * @param {any} [ctx] + */ + debounce: function(timeout, fn, invokeAsap, ctx) { + var timer; + if(arguments.length === 3 && typeof invokeAsap !== "boolean") { + ctx = invokeAsap; + invokeAsap = false; + } + return function() { + var args = arguments; + ctx = ctx || this; + invokeAsap && !timer && fn.apply(ctx, args); + clearTimeout(timer); + timer = setTimeout(function() { + invokeAsap || fn.apply(ctx, args); + timer = null; + }, timeout); + }; + }, + /** Write message to console if debugLevel >= 2 + * @param {string} msg + */ + debug: function(msg){ + /*jshint expr:true */ + ($.ui.fancytree.debugLevel >= 2) && consoleApply("log", arguments); + }, + /** Write error message to console. + * @param {string} msg + */ + error: function(msg){ + consoleApply("error", arguments); + }, + /** Convert <, >, &, ", ', / to the equivalent entities. + * + * @param {string} s + * @returns {string} + */ + escapeHtml: function(s){ + return ("" + s).replace(/[&<>"'\/]/g, function (s) { + return ENTITY_MAP[s]; + }); + }, + /** Make jQuery.position() arguments backwards compatible, i.e. if + * jQuery UI version <= 1.8, convert + * { my: "left+3 center", at: "left bottom", of: $target } + * to + * { my: "left center", at: "left bottom", of: $target, offset: "3 0" } + * + * See http://jqueryui.com/upgrade-guide/1.9/#deprecated-offset-option-merged-into-my-and-at + * and http://jsfiddle.net/mar10/6xtu9a4e/ + */ + fixPositionOptions: function(opts) { + if( opts.offset || ("" + opts.my + opts.at ).indexOf("%") >= 0 ) { + $.error("expected new position syntax (but '%' is not supported)"); + } + if( ! $.ui.fancytree.jquerySupports.positionMyOfs ) { + var // parse 'left+3 center' into ['left+3 center', 'left', '+3', 'center', undefined] + myParts = /(\w+)([+-]?\d+)?\s+(\w+)([+-]?\d+)?/.exec(opts.my), + atParts = /(\w+)([+-]?\d+)?\s+(\w+)([+-]?\d+)?/.exec(opts.at), + // convert to numbers + dx = (myParts[2] ? (+myParts[2]) : 0) + (atParts[2] ? (+atParts[2]) : 0), + dy = (myParts[4] ? (+myParts[4]) : 0) + (atParts[4] ? (+atParts[4]) : 0); + + opts = $.extend({}, opts, { // make a copy and overwrite + my: myParts[1] + " " + myParts[3], + at: atParts[1] + " " + atParts[3] + }); + if( dx || dy ) { + opts.offset = "" + dx + " " + dy; + } + } + return opts; + }, + /** Return a {node: FancytreeNode, type: TYPE} object for a mouse event. + * + * @param {Event} event Mouse event, e.g. click, ... + * @returns {string} 'title' | 'prefix' | 'expander' | 'checkbox' | 'icon' | undefined + */ + getEventTargetType: function(event){ + return this.getEventTarget(event).type; + }, + /** Return a {node: FancytreeNode, type: TYPE} object for a mouse event. + * + * @param {Event} event Mouse event, e.g. click, ... + * @returns {object} Return a {node: FancytreeNode, type: TYPE} object + * TYPE: 'title' | 'prefix' | 'expander' | 'checkbox' | 'icon' | undefined + */ + getEventTarget: function(event){ + var tcn = event && event.target ? event.target.className : "", + res = {node: this.getNode(event.target), type: undefined}; + // We use a fast version of $(res.node).hasClass() + // See http://jsperf.com/test-for-classname/2 + if( /\bfancytree-title\b/.test(tcn) ){ + res.type = "title"; + }else if( /\bfancytree-expander\b/.test(tcn) ){ + res.type = (res.node.hasChildren() === false ? "prefix" : "expander"); + }else if( /\bfancytree-checkbox\b/.test(tcn) || /\bfancytree-radio\b/.test(tcn) ){ + res.type = "checkbox"; + }else if( /\bfancytree-icon\b/.test(tcn) ){ + res.type = "icon"; + }else if( /\bfancytree-node\b/.test(tcn) ){ + // Somewhere near the title + res.type = "title"; + }else if( event && event.target && $(event.target).closest(".fancytree-title").length ) { + // #228: clicking an embedded element inside a title + res.type = "title"; + } + return res; + }, + /** Return a FancytreeNode instance from element, event, or jQuery object. + * + * @param {Element | jQueryObject | Event} el + * @returns {FancytreeNode} matching node or null + */ + getNode: function(el){ + if(el instanceof FancytreeNode){ + return el; // el already was a FancytreeNode + }else if(el.selector !== undefined){ + el = el[0]; // el was a jQuery object: use the DOM element + }else if(el.originalEvent !== undefined){ + el = el.target; // el was an Event + } + while( el ) { + if(el.ftnode) { + return el.ftnode; + } + el = el.parentNode; + } + return null; + }, + /** Return a Fancytree instance, from element, index, event, or jQueryObject. + * + * @param {Element | jQueryObject | Event | integer | string} [el] + * @returns {Fancytree} matching tree or null + * @example + * $.ui.fancytree.getTree(); // Get first Fancytree instance on page + * $.ui.fancytree.getTree(1); // Get second Fancytree instance on page + * $.ui.fancytree.getTree("#tree"); // Get tree for this matching element + * + * @since 2.13 + */ + getTree: function(el){ + var widget; + + if( el instanceof Fancytree ) { + return el; // el already was a Fancytree + } + if( el === undefined ) { + el = 0; // get first tree + } + if( typeof el === "number" ) { + el = $(".fancytree-container").eq(el); // el was an integer: return nth instance + } else if( typeof el === "string" ) { + el = $(el).eq(0); // el was a selector: use first match + } else if( el.selector !== undefined ) { + el = el.eq(0); // el was a jQuery object: use the first DOM element + } else if( el.originalEvent !== undefined ) { + el = $(el.target); // el was an Event + } + el = el.closest(":ui-fancytree"); + widget = el.data("ui-fancytree") || el.data("fancytree"); // the latter is required by jQuery <= 1.8 + return widget ? widget.tree : null; + }, + /** Write message to console if debugLevel >= 1 + * @param {string} msg + */ + info: function(msg){ + /*jshint expr:true */ + ($.ui.fancytree.debugLevel >= 1) && consoleApply("info", arguments); + }, + /** Convert a keydown or mouse event to a canonical string like 'ctrl+a', 'ctrl+shift+f2', 'shift+leftdblclick'. + * This is especially handy for switch-statements in event handlers. + * @param {event} + * @returns {string} + */ + eventToString: function(event) { + // Poor-man's hotkeys. See here for a complete implementation: + // https://github.com/jeresig/jquery.hotkeys + var which = event.which, + et = event.type, + s = []; + + if( event.altKey ) { s.push("alt"); } + if( event.ctrlKey ) { s.push("ctrl"); } + if( event.metaKey ) { s.push("meta"); } + if( event.shiftKey ) { s.push("shift"); } + + if( et === "click" || et === "dblclick" ) { + s.push(MOUSE_BUTTONS[event.button] + et); + } else { + if( !IGNORE_KEYCODES[which] ) { + s.push( SPECIAL_KEYCODES[which] || String.fromCharCode(which).toLowerCase() ); + } + } + return s.join("+"); + }, + /* @deprecated: use eventToString(event) instead. + */ + keyEventToString: function(event) { + this.warn("keyEventToString() is deprecated: use eventToString()"); + return this.eventToString(event); + }, + /** + * Parse tree data from HTML <ul> markup + * + * @param {jQueryObject} $ul + * @returns {NodeData[]} + */ + parseHtml: function($ul) { + // TODO: understand this: + /*jshint validthis:true */ + var classes, className, extraClasses, i, iPos, l, tmp, tmp2, + $children = $ul.find(">li"), + children = []; + + $children.each(function() { + var allData, lowerCaseAttr, + $li = $(this), + $liSpan = $li.find(">span:first", this), + $liA = $liSpan.length ? null : $li.find(">a:first"), + d = { tooltip: null, data: {} }; + + if( $liSpan.length ) { + d.title = $liSpan.html(); + + } else if( $liA && $liA.length ) { + // If a <li><a> tag is specified, use it literally and extract href/target. + d.title = $liA.html(); + d.data.href = $liA.attr("href"); + d.data.target = $liA.attr("target"); + d.tooltip = $liA.attr("title"); + + } else { + // If only a <li> tag is specified, use the trimmed string up to + // the next child <ul> tag. + d.title = $li.html(); + iPos = d.title.search(/<ul/i); + if( iPos >= 0 ){ + d.title = d.title.substring(0, iPos); + } + } + d.title = $.trim(d.title); + + // Make sure all fields exist + for(i=0, l=CLASS_ATTRS.length; i<l; i++){ + d[CLASS_ATTRS[i]] = undefined; + } + // Initialize to `true`, if class is set and collect extraClasses + classes = this.className.split(" "); + extraClasses = []; + for(i=0, l=classes.length; i<l; i++){ + className = classes[i]; + if(CLASS_ATTR_MAP[className]){ + d[className] = true; + }else{ + extraClasses.push(className); + } + } + d.extraClasses = extraClasses.join(" "); + + // Parse node options from ID, title and class attributes + tmp = $li.attr("title"); + if( tmp ){ + d.tooltip = tmp; // overrides <a title='...'> + } + tmp = $li.attr("id"); + if( tmp ){ + d.key = tmp; + } + // Add <li data-NAME='...'> as node.data.NAME + allData = _getElementDataAsDict($li); + if( allData && !$.isEmptyObject(allData) ) { + // #507: convert data-hidecheckbox (lower case) to hideCheckbox + for( lowerCaseAttr in NODE_ATTR_LOWERCASE_MAP ) { + if( allData.hasOwnProperty(lowerCaseAttr) ) { + allData[NODE_ATTR_LOWERCASE_MAP[lowerCaseAttr]] = allData[lowerCaseAttr]; + delete allData[lowerCaseAttr]; + } + } + // #56: Allow to set special node.attributes from data-... + for(i=0, l=NODE_ATTRS.length; i<l; i++){ + tmp = NODE_ATTRS[i]; + tmp2 = allData[tmp]; + if( tmp2 != null ) { + delete allData[tmp]; + d[tmp] = tmp2; + } + } + // All other data-... goes to node.data... + $.extend(d.data, allData); + } + // Recursive reading of child nodes, if LI tag contains an UL tag + $ul = $li.find(">ul:first"); + if( $ul.length ) { + d.children = $.ui.fancytree.parseHtml($ul); + }else{ + d.children = d.lazy ? undefined : null; + } + children.push(d); +// FT.debug("parse ", d, children); + }); + return children; + }, + /** Add Fancytree extension definition to the list of globally available extensions. + * + * @param {object} definition + */ + registerExtension: function(definition){ + _assert(definition.name != null, "extensions must have a `name` property."); + _assert(definition.version != null, "extensions must have a `version` property."); + $.ui.fancytree._extensions[definition.name] = definition; + }, + /** Inverse of escapeHtml(). + * + * @param {string} s + * @returns {string} + */ + unescapeHtml: function(s){ + var e = document.createElement("div"); + e.innerHTML = s; + return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue; + }, + /** Write warning message to console. + * @param {string} msg + */ + warn: function(msg){ + consoleApply("warn", arguments); + } +}); + +}(jQuery, window, document)); diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.menu.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.menu.js new file mode 100644 index 00000000000..23c22ae3ccb --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.menu.js @@ -0,0 +1,155 @@ +/*! + * jquery.fancytree.menu.js + * + * Enable jQuery UI Menu as context menu for tree nodes. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * @see http://api.jqueryui.com/menu/ + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + +// prevent duplicate loading +// if ( $.ui.fancytree && $.ui.fancytree.version ) { +// $.ui.fancytree.warn("Fancytree: duplicate include"); +// return; +// } + +$.ui.fancytree.registerExtension({ + name: "menu", + version: "0.0.1", + // Default options for this extension. + options: { + enable: true, + selector: null, // + position: {}, // + // Events: + create: $.noop, // + beforeOpen: $.noop, // + open: $.noop, // + focus: $.noop, // + select: $.noop, // + close: $.noop // + }, + // Override virtual methods for this extension. + // `this` : is this extension object + // `this._base` : the Fancytree instance + // `this._super`: the virtual function that was overridden (member of prev. extension or Fancytree) + treeInit: function(ctx){ + var opts = ctx.options, + tree = ctx.tree; + + this._superApply(arguments); + + // Prepare an object that will be passed with menu events + tree.ext.menu.data = { + tree: tree, + node: null, + $menu: null, + menuId: null + }; + +// tree.$container[0].oncontextmenu = function() {return false;}; + // Replace the standard browser context menu with out own + tree.$container.delegate("span.fancytree-node", "contextmenu", function(event) { + var node = $.ui.fancytree.getNode(event), + ctx = {node: node, tree: node.tree, originalEvent: event, options: tree.options}; + tree.ext.menu._openMenu(ctx); + return false; + }); + + // Use jquery.ui.menu + $(opts.menu.selector).menu({ + create: function(event, ui){ + tree.ext.menu.data.$menu = $(this).menu("widget"); + var data = $.extend({}, tree.ext.menu.data); + opts.menu.create.call(tree, event, data); + }, + focus: function(event, ui){ + var data = $.extend({}, tree.ext.menu.data, { + menuItem: ui.item, + menuId: ui.item.find(">a").attr("href") + }); + opts.menu.focus.call(tree, event, data); + }, + select: function(event, ui){ + var data = $.extend({}, tree.ext.menu.data, { + menuItem: ui.item, + menuId: ui.item.find(">a").attr("href") + }); + if( opts.menu.select.call(tree, event, data) !== false){ + tree.ext.menu._closeMenu(ctx); + } + } + }).hide(); + }, + treeDestroy: function(ctx){ + this._superApply(arguments); + }, + _openMenu: function(ctx){ + var data, + tree = ctx.tree, + opts = ctx.options, + $menu = $(opts.menu.selector); + + tree.ext.menu.data.node = ctx.node; + data = $.extend({}, tree.ext.menu.data); + + if( opts.menu.beforeOpen.call(tree, ctx.originalEvent, data) === false){ + return; + } + + $(document).bind("keydown.fancytree", function(event){ + if( event.which === $.ui.keyCode.ESCAPE ){ + tree.ext.menu._closeMenu(ctx); + } + }).bind("mousedown.fancytree", function(event){ + // Close menu when clicked outside menu + if( $(event.target).closest(".ui-menu-item").length === 0 ){ + tree.ext.menu._closeMenu(ctx); + } + }); +// $menu.position($.extend({my: "left top", at: "left bottom", of: event}, opts.menu.position)); + $menu + .css("position", "absolute") + .show() + .position({my: "left top", at: "right top", of: ctx.originalEvent, collision: "fit"}) + .focus(); + + opts.menu.open.call(tree, ctx.originalEvent, data); + }, + _closeMenu: function(ctx){ + var $menu, + tree = ctx.tree, + opts = ctx.options, + data = $.extend({}, tree.ext.menu.data); + if( opts.menu.close.call(tree, ctx.originalEvent, data) === false){ + return; + } + $menu = $(opts.menu.selector); + $(document).unbind("keydown.fancytree, mousedown.fancytree"); + $menu.hide(); + tree.ext.menu.data.node = null; + } +// , +// nodeClick: function(ctx) { +// var event = ctx.originalEvent; +// if(event.which === 2 || (event.which === 1 && event.ctrlKey)){ +// event.preventDefault(); +// ctx.tree.ext.menu._openMenu(ctx); +// return false; +// } +// this._superApply(arguments); +// } +}); +}(jQuery, window, document)); diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.persist.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.persist.js new file mode 100644 index 00000000000..783bb74c166 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.persist.js @@ -0,0 +1,383 @@ +/*! + * jquery.fancytree.persist.js + * + * Persist tree status in cookiesRemove or highlight tree nodes, based on a filter. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * @depends: js-cookie or jquery-cookie + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; +/* global Cookies:false */ + +/******************************************************************************* + * Private functions and variables + */ +var cookieGetter, cookieRemover, cookieSetter, + _assert = $.ui.fancytree.assert, + ACTIVE = "active", + EXPANDED = "expanded", + FOCUS = "focus", + SELECTED = "selected"; + +if( typeof Cookies === "function" ) { + // Assume https://github.com/js-cookie/js-cookie + cookieSetter = Cookies.set; + cookieGetter = Cookies.get; + cookieRemover = Cookies.remove; +} else { + // Fall back to https://github.com/carhartl/jquery-cookie + cookieSetter = cookieGetter = $.cookie; + cookieRemover = $.removeCookie; +} + +/* Recursively load lazy nodes + * @param {string} mode 'load', 'expand', false + */ +function _loadLazyNodes(tree, local, keyList, mode, dfd) { + var i, key, l, node, + foundOne = false, + deferredList = [], + missingKeyList = []; + + keyList = keyList || []; + dfd = dfd || $.Deferred(); + + for( i=0, l=keyList.length; i<l; i++ ) { + key = keyList[i]; + node = tree.getNodeByKey(key); + if( node ) { + if( mode && node.isUndefined() ) { + foundOne = true; + tree.debug("_loadLazyNodes: " + node + " is lazy: loading..."); + if( mode === "expand" ) { + deferredList.push(node.setExpanded()); + } else { + deferredList.push(node.load()); + } + } else { + tree.debug("_loadLazyNodes: " + node + " already loaded."); + node.setExpanded(); + } + } else { + missingKeyList.push(key); + tree.debug("_loadLazyNodes: " + node + " was not yet found."); + } + } + + $.when.apply($, deferredList).always(function(){ + // All lazy-expands have finished + if( foundOne && missingKeyList.length > 0 ) { + // If we read new nodes from server, try to resolve yet-missing keys + _loadLazyNodes(tree, local, missingKeyList, mode, dfd); + } else { + if( missingKeyList.length ) { + tree.warn("_loadLazyNodes: could not load those keys: ", missingKeyList); + for( i=0, l=missingKeyList.length; i<l; i++ ) { + key = keyList[i]; + local._appendKey(EXPANDED, keyList[i], false); + } + } + dfd.resolve(); + } + }); + return dfd; +} + + +/** + * [ext-persist] Remove persistence cookies of the given type(s). + * Called like + * $("#tree").fancytree("getTree").clearCookies("active expanded focus selected"); + * + * @alias Fancytree#clearCookies + * @requires jquery.fancytree.persist.js + */ +$.ui.fancytree._FancytreeClass.prototype.clearCookies = function(types){ + var local = this.ext.persist, + prefix = local.cookiePrefix; + + types = types || "active expanded focus selected"; + if(types.indexOf(ACTIVE) >= 0){ + local._data(prefix + ACTIVE, null); + } + if(types.indexOf(EXPANDED) >= 0){ + local._data(prefix + EXPANDED, null); + } + if(types.indexOf(FOCUS) >= 0){ + local._data(prefix + FOCUS, null); + } + if(types.indexOf(SELECTED) >= 0){ + local._data(prefix + SELECTED, null); + } +}; + + +/** + * [ext-persist] Return persistence information from cookies + * + * Called like + * $("#tree").fancytree("getTree").getPersistData(); + * + * @alias Fancytree#getPersistData + * @requires jquery.fancytree.persist.js + */ +$.ui.fancytree._FancytreeClass.prototype.getPersistData = function(){ + var local = this.ext.persist, + prefix = local.cookiePrefix, + delim = local.cookieDelimiter, + res = {}; + + res[ACTIVE] = local._data(prefix + ACTIVE); + res[EXPANDED] = (local._data(prefix + EXPANDED) || "").split(delim); + res[SELECTED] = (local._data(prefix + SELECTED) || "").split(delim); + res[FOCUS] = local._data(prefix + FOCUS); + return res; +}; + + +/* ***************************************************************************** + * Extension code + */ +$.ui.fancytree.registerExtension({ + name: "persist", + version: "0.3.0", + // Default options for this extension. + options: { + cookieDelimiter: "~", + cookiePrefix: undefined, // 'fancytree-<treeId>-' by default + cookie: { + raw: false, + expires: "", + path: "", + domain: "", + secure: false + }, + expandLazy: false, // true: recursively expand and load lazy nodes + fireActivate: true, // false: suppress `activate` event after active node was restored + overrideSource: true, // true: cookie takes precedence over `source` data attributes. + store: "auto", // 'cookie': force cookie, 'local': force localStore, 'session': force sessionStore + types: "active expanded focus selected" + }, + + /* Generic read/write string data to cookie, sessionStorage or localStorage. */ + _data: function(key, value){ + var ls = this._local.localStorage; // null, sessionStorage, or localStorage + + if( value === undefined ) { + return ls ? ls.getItem(key) : cookieGetter(key); + } else if ( value === null ) { + if( ls ) { + ls.removeItem(key); + } else { + cookieRemover(key); + } + } else { + if( ls ) { + ls.setItem(key, value); + } else { + cookieSetter(key, value, this.options.persist.cookie); + } + } + }, + + /* Append `key` to a cookie. */ + _appendKey: function(type, key, flag){ + key = "" + key; // #90 + var local = this._local, + instOpts = this.options.persist, + delim = instOpts.cookieDelimiter, + cookieName = local.cookiePrefix + type, + data = local._data(cookieName), + keyList = data ? data.split(delim) : [], + idx = $.inArray(key, keyList); + // Remove, even if we add a key, so the key is always the last entry + if(idx >= 0){ + keyList.splice(idx, 1); + } + // Append key to cookie + if(flag){ + keyList.push(key); + } + local._data(cookieName, keyList.join(delim)); + }, + + treeInit: function(ctx){ + var tree = ctx.tree, + opts = ctx.options, + local = this._local, + instOpts = this.options.persist; + + // For 'auto' or 'cookie' mode, the cookie plugin must be available + _assert((instOpts.store !== "auto" && instOpts.store !== "cookie") || cookieGetter, + "Missing required plugin for 'persist' extension: js.cookie.js or jquery.cookie.js"); + + local.cookiePrefix = instOpts.cookiePrefix || ("fancytree-" + tree._id + "-"); + local.storeActive = instOpts.types.indexOf(ACTIVE) >= 0; + local.storeExpanded = instOpts.types.indexOf(EXPANDED) >= 0; + local.storeSelected = instOpts.types.indexOf(SELECTED) >= 0; + local.storeFocus = instOpts.types.indexOf(FOCUS) >= 0; + if( instOpts.store === "cookie" || !window.localStorage ) { + local.localStorage = null; + } else { + local.localStorage = (instOpts.store === "local") ? window.localStorage : window.sessionStorage; + } + + // Bind init-handler to apply cookie state + tree.$div.bind("fancytreeinit", function(event){ + var cookie, dfd, i, keyList, node, + prevFocus = local._data(local.cookiePrefix + FOCUS), // record this before node.setActive() overrides it; + noEvents = instOpts.fireActivate === false; + + // tree.debug("document.cookie:", document.cookie); + + cookie = local._data(local.cookiePrefix + EXPANDED); + keyList = cookie && cookie.split(instOpts.cookieDelimiter); + + if( local.storeExpanded ) { + // Recursively load nested lazy nodes if expandLazy is 'expand' or 'load' + // Also remove expand-cookies for unmatched nodes + dfd = _loadLazyNodes(tree, local, keyList, instOpts.expandLazy ? "expand" : false , null); + } else { + // nothing to do + dfd = new $.Deferred().resolve(); + } + + dfd.done(function(){ + if(local.storeSelected){ + cookie = local._data(local.cookiePrefix + SELECTED); + if(cookie){ + keyList = cookie.split(instOpts.cookieDelimiter); + for(i=0; i<keyList.length; i++){ + node = tree.getNodeByKey(keyList[i]); + if(node){ + if(node.selected === undefined || instOpts.overrideSource && (node.selected === false)){ +// node.setSelected(); + node.selected = true; + node.renderStatus(); + } + }else{ + // node is no longer member of the tree: remove from cookie also + local._appendKey(SELECTED, keyList[i], false); + } + } + } + // In selectMode 3 we have to fix the child nodes, since we + // only stored the selected *top* nodes + if( tree.options.selectMode === 3 ){ + tree.visit(function(n){ + if( n.selected ) { + n.fixSelection3AfterClick(); + return "skip"; + } + }); + } + } + if(local.storeActive){ + cookie = local._data(local.cookiePrefix + ACTIVE); + if(cookie && (opts.persist.overrideSource || !tree.activeNode)){ + node = tree.getNodeByKey(cookie); + if(node){ + node.debug("persist: set active", cookie); + // We only want to set the focus if the container + // had the keyboard focus before + node.setActive(true, { + noFocus: true, + noEvents: noEvents + }); + } + } + } + if(local.storeFocus && prevFocus){ + node = tree.getNodeByKey(prevFocus); + if(node){ + // node.debug("persist: set focus", cookie); + if( tree.options.titlesTabbable ) { + $(node.span).find(".fancytree-title").focus(); + } else { + $(tree.$container).focus(); + } + // node.setFocus(); + } + } + tree._triggerTreeEvent("restore", null, {}); + }); + }); + // Init the tree + return this._superApply(arguments); + }, + nodeSetActive: function(ctx, flag, opts) { + var res, + local = this._local; + + flag = (flag !== false); + res = this._superApply(arguments); + + if(local.storeActive){ + local._data(local.cookiePrefix + ACTIVE, this.activeNode ? this.activeNode.key : null); + } + return res; + }, + nodeSetExpanded: function(ctx, flag, opts) { + var res, + node = ctx.node, + local = this._local; + + flag = (flag !== false); + res = this._superApply(arguments); + + if(local.storeExpanded){ + local._appendKey(EXPANDED, node.key, flag); + } + return res; + }, + nodeSetFocus: function(ctx, flag) { + var res, + local = this._local; + + flag = (flag !== false); + res = this._superApply(arguments); + + if( local.storeFocus ) { + local._data(local.cookiePrefix + FOCUS, this.focusNode ? this.focusNode.key : null); + } + return res; + }, + nodeSetSelected: function(ctx, flag) { + var res, selNodes, + tree = ctx.tree, + node = ctx.node, + local = this._local; + + flag = (flag !== false); + res = this._superApply(arguments); + + if(local.storeSelected){ + if( tree.options.selectMode === 3 ){ + // In selectMode 3 we only store the the selected *top* nodes. + // De-selecting a node may also de-select some parents, so we + // calculate the current status again + selNodes = $.map(tree.getSelectedNodes(true), function(n){ + return n.key; + }); + selNodes = selNodes.join(ctx.options.persist.cookieDelimiter); + local._data(local.cookiePrefix + SELECTED, selNodes); + } else { + // beforeSelect can prevent the change - flag doesn't reflect the node.selected state + local._appendKey(SELECTED, node.key, node.selected); + } + } + return res; + } +}); +}(jQuery, window, document)); diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.table.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.table.js new file mode 100644 index 00000000000..4367b9dfcd2 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.table.js @@ -0,0 +1,366 @@ +/*! + * jquery.fancytree.table.js + * + * Render tree as table (aka 'treegrid', 'tabletree'). + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + +/* ***************************************************************************** + * Private functions and variables + */ +function _assert(cond, msg){ + msg = msg || ""; + if(!cond){ + $.error("Assertion failed " + msg); + } +} + +function insertSiblingAfter(referenceNode, newNode) { + referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); +} + +/* Show/hide all rows that are structural descendants of `parent`. */ +function setChildRowVisibility(parent, flag) { + parent.visit(function(node){ + var tr = node.tr; + // currentFlag = node.hide ? false : flag; // fix for ext-filter + if(tr){ + tr.style.display = (node.hide || !flag) ? "none" : ""; + } + if(!node.expanded){ + return "skip"; + } + }); +} + +/* Find node that is rendered in previous row. */ +function findPrevRowNode(node){ + var i, last, prev, + parent = node.parent, + siblings = parent ? parent.children : null; + + if(siblings && siblings.length > 1 && siblings[0] !== node){ + // use the lowest descendant of the preceeding sibling + i = $.inArray(node, siblings); + prev = siblings[i - 1]; + _assert(prev.tr); + // descend to lowest child (with a <tr> tag) + while(prev.children){ + last = prev.children[prev.children.length - 1]; + if(!last.tr){ + break; + } + prev = last; + } + }else{ + // if there is no preceding sibling, use the direct parent + prev = parent; + } + return prev; +} + + +$.ui.fancytree.registerExtension({ + name: "table", + version: "0.2.1", + // Default options for this extension. + options: { + checkboxColumnIdx: null, // render the checkboxes into the this column index (default: nodeColumnIdx) + customStatus: false, // true: generate renderColumns events for status nodes + indentation: 16, // indent every node level by 16px + nodeColumnIdx: 0 // render node expander, icon, and title to this column (default: #0) + }, + // Overide virtual methods for this extension. + // `this` : is this extension object + // `this._super`: the virtual function that was overriden (member of prev. extension or Fancytree) + treeInit: function(ctx){ + var i, $row, tdRole, + tree = ctx.tree, + $table = tree.widget.element; + + $table.addClass("fancytree-container fancytree-ext-table"); + tree.tbody = $table.find("> tbody")[0]; + tree.columnCount = $("thead >tr >th", $table).length; + $(tree.tbody).empty(); + + tree.rowFragment = document.createDocumentFragment(); + $row = $("<tr />"); + tdRole = ""; + if(ctx.options.aria){ + $row.attr("role", "row"); + tdRole = " role='gridcell'"; + } + for(i=0; i<tree.columnCount; i++) { + if(ctx.options.table.nodeColumnIdx === i){ + $row.append("<td" + tdRole + "><span class='fancytree-node' /></td>"); + }else{ + $row.append("<td" + tdRole + " />"); + } + } + tree.rowFragment.appendChild($row.get(0)); + + // Make sure that status classes are set on the node's <tr> elements + tree.statusClassPropName = "tr"; + tree.ariaPropName = "tr"; + this.nodeContainerAttrName = "tr"; + + // #489: make sure $container is set to <table>, even if ext-dnd is listed before ext-table + tree.$container = $table; + + this._superApply(arguments); + + // standard Fancytree created a root UL + $(tree.rootNode.ul).remove(); + tree.rootNode.ul = null; +// tree.$container = $table; + // Add container to the TAB chain + this.$container.attr("tabindex", this.options.tabbable ? "0" : "-1"); + if(this.options.aria){ + tree.$container + .attr("role", "treegrid") + .attr("aria-readonly", true); + } + }, + /* Called by nodeRender to sync node order with tag order.*/ +// nodeFixOrder: function(ctx) { +// }, + nodeRemoveChildMarkup: function(ctx) { + var node = ctx.node; +// node.debug("nodeRemoveChildMarkup()"); + node.visit(function(n){ + if(n.tr){ + $(n.tr).remove(); + n.tr = null; + } + }); + }, + nodeRemoveMarkup: function(ctx) { + var node = ctx.node; +// node.debug("nodeRemoveMarkup()"); + if(node.tr){ + $(node.tr).remove(); + node.tr = null; + } + this.nodeRemoveChildMarkup(ctx); + }, + /* Override standard render. */ + nodeRender: function(ctx, force, deep, collapsed, _recursive) { + var children, firstTr, i, l, newRow, prevNode, prevTr, subCtx, + tree = ctx.tree, + node = ctx.node, + opts = ctx.options, + isRootNode = !node.parent; + + if( !_recursive ){ + ctx.hasCollapsedParents = node.parent && !node.parent.expanded; + } + // $.ui.fancytree.debug("*** nodeRender " + node + ", isRoot=" + isRootNode, "tr=" + node.tr, "hcp=" + ctx.hasCollapsedParents, "parent.tr=" + (node.parent && node.parent.tr)); + if( !isRootNode ){ + if(!node.tr){ + if( ctx.hasCollapsedParents && !deep ) { + // #166: we assume that the parent will be (recursively) rendered + // later anyway. + node.debug("nodeRender ignored due to unrendered parent"); + return; + } + // Create new <tr> after previous row + newRow = tree.rowFragment.firstChild.cloneNode(true); + prevNode = findPrevRowNode(node); + // $.ui.fancytree.debug("*** nodeRender " + node + ": prev: " + prevNode.key); + _assert(prevNode); + if(collapsed === true && _recursive){ + // hide all child rows, so we can use an animation to show it later + newRow.style.display = "none"; + }else if(deep && ctx.hasCollapsedParents){ + // also hide this row if deep === true but any parent is collapsed + newRow.style.display = "none"; +// newRow.style.color = "red"; + } + if(!prevNode.tr){ + _assert(!prevNode.parent, "prev. row must have a tr, or is system root"); + tree.tbody.appendChild(newRow); + }else{ + insertSiblingAfter(prevNode.tr, newRow); + } + node.tr = newRow; + if( node.key && opts.generateIds ){ + node.tr.id = opts.idPrefix + node.key; + } + node.tr.ftnode = node; + if(opts.aria){ + // TODO: why doesn't this work: +// node.li.role = "treeitem"; + $(node.tr).attr("aria-labelledby", "ftal_" + node.key); + } + node.span = $("span.fancytree-node", node.tr).get(0); + // Set icon, link, and title (normally this is only required on initial render) + this.nodeRenderTitle(ctx); + // Allow tweaking, binding, after node was created for the first time +// tree._triggerNodeEvent("createNode", ctx); + if ( opts.createNode ){ + opts.createNode.call(tree, {type: "createNode"}, ctx); + } + } else { + if( force ) { + // Set icon, link, and title (normally this is only required on initial render) + this.nodeRenderTitle(ctx); // triggers renderColumns() + } else { + // Update element classes according to node state + this.nodeRenderStatus(ctx); + } + } + } + // Allow tweaking after node state was rendered +// tree._triggerNodeEvent("renderNode", ctx); + if ( opts.renderNode ){ + opts.renderNode.call(tree, {type: "renderNode"}, ctx); + } + // Visit child nodes + // Add child markup + children = node.children; + if(children && (isRootNode || deep || node.expanded)){ + for(i=0, l=children.length; i<l; i++) { + subCtx = $.extend({}, ctx, {node: children[i]}); + subCtx.hasCollapsedParents = subCtx.hasCollapsedParents || !node.expanded; + this.nodeRender(subCtx, force, deep, collapsed, true); + } + } + // Make sure, that <tr> order matches node.children order. + if(children && !_recursive){ // we only have to do it once, for the root branch + prevTr = node.tr || null; + firstTr = tree.tbody.firstChild; + // Iterate over all descendants + node.visit(function(n){ + if(n.tr){ + if(!n.parent.expanded && n.tr.style.display !== "none"){ + // fix after a node was dropped over a collapsed + n.tr.style.display = "none"; + setChildRowVisibility(n, false); + } + if(n.tr.previousSibling !== prevTr){ + node.debug("_fixOrder: mismatch at node: " + n); + var nextTr = prevTr ? prevTr.nextSibling : firstTr; + tree.tbody.insertBefore(n.tr, nextTr); + } + prevTr = n.tr; + } + }); + } + // Update element classes according to node state + // if(!isRootNode){ + // this.nodeRenderStatus(ctx); + // } + }, + nodeRenderTitle: function(ctx, title) { + var $cb, + node = ctx.node, + opts = ctx.options; + + this._superApply(arguments); + // Move checkbox to custom column + if(opts.checkbox && opts.table.checkboxColumnIdx != null ){ + $cb = $("span.fancytree-checkbox", node.span).detach(); + $(node.tr).find("td").eq(+opts.table.checkboxColumnIdx).html($cb); + } + // Update element classes according to node state + if( ! node.isRoot() ){ + this.nodeRenderStatus(ctx); + } + if( !opts.table.customStatus && node.isStatusNode() ) { + // default rendering for status node: leave other cells empty + } else if ( opts.renderColumns ) { + // Let user code write column content + opts.renderColumns.call(ctx.tree, {type: "renderColumns"}, ctx); + } + }, + nodeRenderStatus: function(ctx) { + var indent, + node = ctx.node, + opts = ctx.options; + + this._superApply(arguments); + + $(node.tr).removeClass("fancytree-node"); + // indent + indent = (node.getLevel() - 1) * opts.table.indentation; + $(node.span).css({paddingLeft: indent + "px"}); // #460 + // $(node.span).css({marginLeft: indent + "px"}); + }, + /* Expand node, return Deferred.promise. */ + nodeSetExpanded: function(ctx, flag, opts) { + var dfd = new $.Deferred(), + subOpts = $.extend({}, opts, {noEvents: true, noAnimation: true}); + + opts = opts || {}; + + function _afterExpand(ok) { + flag = (flag !== false); + setChildRowVisibility(ctx.node, flag); + if( ok ) { + if( flag && ctx.options.autoScroll && !opts.noAnimation && ctx.node.hasChildren() ) { + // Scroll down to last child, but keep current node visible + ctx.node.getLastChild().scrollIntoView(true, {topNode: ctx.node}).always(function(){ + if( !opts.noEvents ) { + ctx.tree._triggerNodeEvent(flag ? "expand" : "collapse", ctx); + } + dfd.resolveWith(ctx.node); + }); + } else { + if( !opts.noEvents ) { + ctx.tree._triggerNodeEvent(flag ? "expand" : "collapse", ctx); + } + dfd.resolveWith(ctx.node); + } + } else { + if( !opts.noEvents ) { + ctx.tree._triggerNodeEvent(flag ? "expand" : "collapse", ctx); + } + dfd.rejectWith(ctx.node); + } + } + // Call base-expand with disabled events and animation + this._super(ctx, flag, subOpts).done(function () { + _afterExpand(true); + }).fail(function () { + _afterExpand(false); + }); + return dfd.promise(); + }, + nodeSetStatus: function(ctx, status, message, details) { + if(status === "ok"){ + var node = ctx.node, + firstChild = ( node.children ? node.children[0] : null ); + if ( firstChild && firstChild.isStatusNode() ) { + $(firstChild.tr).remove(); + } + } + return this._superApply(arguments); + }, + treeClear: function(ctx) { + this.nodeRemoveChildMarkup(this._makeHookContext(this.rootNode)); + return this._superApply(arguments); + }, + treeDestroy: function(ctx) { + this.$container.find("tbody").empty(); + this.$source && this.$source.removeClass("ui-helper-hidden"); + } + /*, + treeSetFocus: function(ctx, flag) { +// alert("treeSetFocus" + ctx.tree.$container); + ctx.tree.$container.focus(); + $.ui.fancytree.focusTree = ctx.tree; + }*/ +}); +}(jQuery, window, document)); diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.themeroller.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.themeroller.js new file mode 100644 index 00000000000..be9ba09df9b --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.themeroller.js @@ -0,0 +1,78 @@ +/*! + * jquery.fancytree.themeroller.js + * + * Enable jQuery UI ThemeRoller styles. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * @see http://jqueryui.com/themeroller/ + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + +/******************************************************************************* + * Extension code + */ +$.ui.fancytree.registerExtension({ + name: "themeroller", + version: "0.0.1", + // Default options for this extension. + options: { + activeClass: "ui-state-active", + foccusClass: "ui-state-focus", + hoverClass: "ui-state-hover", + selectedClass: "ui-state-highlight" + }, + + treeInit: function(ctx){ + this._superApply(arguments); + var $el = ctx.widget.element; + + if($el[0].nodeName === "TABLE"){ + $el.addClass("ui-widget ui-corner-all"); + $el.find(">thead tr").addClass("ui-widget-header"); + $el.find(">tbody").addClass("ui-widget-conent"); + }else{ + $el.addClass("ui-widget ui-widget-content ui-corner-all"); + } + + $el.delegate(".fancytree-node", "mouseenter mouseleave", function(event){ + var node = $.ui.fancytree.getNode(event.target), + flag = (event.type === "mouseenter"); + node.debug("hover: " + flag); + $(node.tr ? node.tr : node.span).toggleClass("ui-state-hover ui-corner-all", flag); + }); + }, + treeDestroy: function(ctx){ + this._superApply(arguments); + ctx.widget.element.removeClass("ui-widget ui-widget-content ui-corner-all"); + }, + nodeRenderStatus: function(ctx){ + var node = ctx.node, + $el = $(node.tr ? node.tr : node.span); + this._superApply(arguments); +/* + .ui-state-highlight: Class to be applied to highlighted or selected elements. Applies "highlight" container styles to an element and its child text, links, and icons. + .ui-state-error: Class to be applied to error messaging container elements. Applies "error" container styles to an element and its child text, links, and icons. + .ui-state-error-text: An additional class that applies just the error text color without background. Can be used on form labels for instance. Also applies error icon color to child icons. + + .ui-state-default: Class to be applied to clickable button-like elements. Applies "clickable default" container styles to an element and its child text, links, and icons. + .ui-state-hover: Class to be applied on mouseover to clickable button-like elements. Applies "clickable hover" container styles to an element and its child text, links, and icons. + .ui-state-focus: Class to be applied on keyboard focus to clickable button-like elements. Applies "clickable hover" container styles to an element and its child text, links, and icons. + .ui-state-active: Class to be applied on mousedown to clickable button-like elements. Applies "clickable active" container styles to an element and its child text, links, and icons. +*/ + $el.toggleClass("ui-state-active", node.isActive()); + $el.toggleClass("ui-state-focus", node.hasFocus()); + $el.toggleClass("ui-state-highlight", node.isSelected()); + } +}); +}(jQuery, window, document)); diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.wide.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.wide.js new file mode 100644 index 00000000000..e3a41b70d8e --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-fancytree/js/src/jquery.fancytree.wide.js @@ -0,0 +1,183 @@ +/*! + * jquery.fancytree.wide.js + * Support for 100% wide selection bars. + * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) + * + * Copyright (c) 2008-2015, Martin Wendt (http://wwWendt.de) + * + * Released under the MIT license + * https://github.com/mar10/fancytree/wiki/LicenseInfo + * + * @version 2.13.0 + * @date 2015-11-16T07:33 + */ + +;(function($, window, document, undefined) { + +"use strict"; + +var reNumUnit = /^([+-]?(?:\d+|\d*\.\d+))([a-z]*|%)$/; // split "1.5em" to ["1.5", "em"] + +/******************************************************************************* + * Private functions and variables + */ +// var _assert = $.ui.fancytree.assert; + +/* Calculate inner width without scrollbar */ +// function realInnerWidth($el) { +// // http://blog.jquery.com/2012/08/16/jquery-1-8-box-sizing-width-csswidth-and-outerwidth/ +// // inst.contWidth = parseFloat(this.$container.css("width"), 10); +// // 'Client width without scrollbar' - 'padding' +// return $el[0].clientWidth - ($el.innerWidth() - parseFloat($el.css("width"), 10)); +// } + +/* Create a global embedded CSS style for the tree. */ +function defineHeadStyleElement(id, cssText) { + id = "fancytree-style-" + id; + var $headStyle = $("#" + id); + + if( !cssText ) { + $headStyle.remove(); + return null; + } + if( !$headStyle.length ) { + $headStyle = $("<style />") + .attr("id", id) + .addClass("fancytree-style") + .prop("type", "text/css") + .appendTo("head"); + } + try { + $headStyle.html(cssText); + } catch ( e ) { + // fix for IE 6-8 + $headStyle[0].styleSheet.cssText = cssText; + } + return $headStyle; +} + +/* Calculate the CSS rules that indent title spans. */ +function renderLevelCss(containerId, depth, levelOfs, lineOfs, measureUnit) { + var i, + prefix = "#" + containerId + " span.fancytree-level-", + rules = []; + + for(i = 0; i < depth; i++) { + rules.push(prefix + (i + 1) + " span.fancytree-title { padding-left: " + + (i * levelOfs + lineOfs) + measureUnit + "; }"); + } + // Some UI animations wrap the UL inside a DIV and set position:relative on both. + // This breaks the left:0 and padding-left:nn settings of the title + rules.push("#" + containerId + + " div.ui-effects-wrapper ul li span.fancytree-title " + + "{ padding-left: 3px; position: static; width: auto; }"); + return rules.join("\n"); +} + + +// /** +// * [ext-wide] Recalculate the width of the selection bar after the tree container +// * was resized.<br> +// * May be called explicitly on container resize, since there is no resize event +// * for DIV tags. +// * +// * @alias Fancytree#wideUpdate +// * @requires jquery.fancytree.wide.js +// */ +// $.ui.fancytree._FancytreeClass.prototype.wideUpdate = function(){ +// var inst = this.ext.wide, +// prevCw = inst.contWidth, +// prevLo = inst.lineOfs; + +// inst.contWidth = realInnerWidth(this.$container); +// // Each title is precceeded by 2 or 3 icons (16px + 3 margin) +// // + 1px title border and 3px title padding +// // TODO: use code from treeInit() below +// inst.lineOfs = (this.options.checkbox ? 3 : 2) * 19; +// if( prevCw !== inst.contWidth || prevLo !== inst.lineOfs ) { +// this.debug("wideUpdate: " + inst.contWidth); +// this.visit(function(node){ +// node.tree._callHook("nodeRenderTitle", node); +// }); +// } +// }; + +/******************************************************************************* + * Extension code + */ +$.ui.fancytree.registerExtension({ + name: "wide", + version: "0.0.3", + // Default options for this extension. + options: { + iconWidth: null, // Adjust this if @fancy-icon-width != "16px" + iconSpacing: null, // Adjust this if @fancy-icon-spacing != "3px" + levelOfs: null // Adjust this if ul padding != "16px" + }, + + treeCreate: function(ctx){ + this._superApply(arguments); + this.$container.addClass("fancytree-ext-wide"); + + var containerId, cssText, iconSpacingUnit, iconWidthUnit, levelOfsUnit, + instOpts = ctx.options.wide, + // css sniffing + $dummyLI = $("<li id='fancytreeTemp'><span class='fancytree-node'><span class='fancytree-icon' /><span class='fancytree-title' /></span><ul />") + .appendTo(ctx.tree.$container), + $dummyIcon = $dummyLI.find(".fancytree-icon"), + $dummyUL = $dummyLI.find("ul"), + // $dummyTitle = $dummyLI.find(".fancytree-title"), + iconSpacing = instOpts.iconSpacing || $dummyIcon.css("margin-left"), + iconWidth = instOpts.iconWidth || $dummyIcon.css("width"), + levelOfs = instOpts.levelOfs || $dummyUL.css("padding-left"); + + $dummyLI.remove(); + + iconSpacingUnit = iconSpacing.match(reNumUnit)[2]; + iconSpacing = parseFloat(iconSpacing, 10); + iconWidthUnit = iconWidth.match(reNumUnit)[2]; + iconWidth = parseFloat(iconWidth, 10); + levelOfsUnit = levelOfs.match(reNumUnit)[2]; + if( iconSpacingUnit !== iconWidthUnit || levelOfsUnit !== iconWidthUnit ) { + $.error("iconWidth, iconSpacing, and levelOfs must have the same css measure unit"); + } + this._local.measureUnit = iconWidthUnit; + this._local.levelOfs = parseFloat(levelOfs); + this._local.lineOfs = (1 + (ctx.options.checkbox ? 1 : 0) + (ctx.options.icons ? 1 : 0)) * (iconWidth + iconSpacing) + iconSpacing; + this._local.maxDepth = 10; + + // Get/Set a unique Id on the container (if not already exists) + containerId = this.$container.uniqueId().attr("id"); + // Generated css rules for some levels (extended on demand) + cssText = renderLevelCss(containerId, this._local.maxDepth, + this._local.levelOfs, this._local.lineOfs, this._local.measureUnit); + defineHeadStyleElement(containerId, cssText); + }, + treeDestroy: function(ctx){ + // Remove generated css rules + defineHeadStyleElement(this.$container.attr("id"), null); + return this._superApply(arguments); + }, + nodeRenderStatus: function(ctx) { + var containerId, cssText, res, + node = ctx.node, + level = node.getLevel(); + + res = this._superApply(arguments); + // Generate some more level-n rules if required + if( level > this._local.maxDepth ) { + containerId = this.$container.attr("id"); + this._local.maxDepth *= 2; + node.debug("Define global ext-wide css up to level " + this._local.maxDepth); + cssText = renderLevelCss(containerId, this._local.maxDepth, + this._local.levelOfs, this._local.lineOfs, this._local.measureUnit); + defineHeadStyleElement(containerId, cssText); + } + // Add level-n class to apply indentation padding. + // (Setting element style would not work, since it cannot easily be + // overriden while animations run) + $(node.span).addClass("fancytree-level-" + level); + return res; + } +}); +}(jQuery, window, document)); diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-ui/LICENSE.txt b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-ui/LICENSE.txt new file mode 100644 index 00000000000..5bed848ae9d --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-ui/LICENSE.txt @@ -0,0 +1 @@ +Open Source - MIT License \ No newline at end of file diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-ui/VERSION.txt b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-ui/VERSION.txt new file mode 100644 index 00000000000..67437808808 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-ui/VERSION.txt @@ -0,0 +1 @@ +1.11.4 \ No newline at end of file diff --git a/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-ui/js/jquery-ui-custom.js b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-ui/js/jquery-ui-custom.js new file mode 100644 index 00000000000..31ee9cd8116 --- /dev/null +++ b/plasmid/source/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jquery-ui/js/jquery-ui-custom.js @@ -0,0 +1,16617 @@ +/*! jQuery UI - v1.11.4 - 2015-03-11 +* http://jqueryui.com +* Includes: core.js, widget.js, mouse.js, position.js, accordion.js, autocomplete.js, button.js, datepicker.js, dialog.js, draggable.js, droppable.js, effect.js, effect-blind.js, effect-bounce.js, effect-clip.js, effect-drop.js, effect-explode.js, effect-fade.js, effect-fold.js, effect-highlight.js, effect-puff.js, effect-pulsate.js, effect-scale.js, effect-shake.js, effect-size.js, effect-slide.js, effect-transfer.js, menu.js, progressbar.js, resizable.js, selectable.js, selectmenu.js, slider.js, sortable.js, spinner.js, tabs.js, tooltip.js +* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */ + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define([ "jquery" ], factory ); + } else { + + // Browser globals + factory( jQuery ); + } +}(function( $ ) { +/*! + * jQuery UI Core 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/category/ui-core/ + */ + + +// $.ui might exist from components with no dependencies, e.g., $.ui.position +$.ui = $.ui || {}; + +$.extend( $.ui, { + version: "1.11.4", + + keyCode: { + BACKSPACE: 8, + COMMA: 188, + DELETE: 46, + DOWN: 40, + END: 35, + ENTER: 13, + ESCAPE: 27, + HOME: 36, + LEFT: 37, + PAGE_DOWN: 34, + PAGE_UP: 33, + PERIOD: 190, + RIGHT: 39, + SPACE: 32, + TAB: 9, + UP: 38 + } +}); + +// plugins +$.fn.extend({ + scrollParent: function( includeHidden ) { + var position = this.css( "position" ), + excludeStaticParent = position === "absolute", + overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/, + scrollParent = this.parents().filter( function() { + var parent = $( this ); + if ( excludeStaticParent && parent.css( "position" ) === "static" ) { + return false; + } + return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + parent.css( "overflow-x" ) ); + }).eq( 0 ); + + return position === "fixed" || !scrollParent.length ? $( this[ 0 ].ownerDocument || document ) : scrollParent; + }, + + uniqueId: (function() { + var uuid = 0; + + return function() { + return this.each(function() { + if ( !this.id ) { + this.id = "ui-id-" + ( ++uuid ); + } + }); + }; + })(), + + removeUniqueId: function() { + return this.each(function() { + if ( /^ui-id-\d+$/.test( this.id ) ) { + $( this ).removeAttr( "id" ); + } + }); + } +}); + +// selectors +function focusable( element, isTabIndexNotNaN ) { + var map, mapName, img, + nodeName = element.nodeName.toLowerCase(); + if ( "area" === nodeName ) { + map = element.parentNode; + mapName = map.name; + if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { + return false; + } + img = $( "img[usemap='#" + mapName + "']" )[ 0 ]; + return !!img && visible( img ); + } + return ( /^(input|select|textarea|button|object)$/.test( nodeName ) ? + !element.disabled : + "a" === nodeName ? + element.href || isTabIndexNotNaN : + isTabIndexNotNaN) && + // the element and all of its ancestors must be visible + visible( element ); +} + +function visible( element ) { + return $.expr.filters.visible( element ) && + !$( element ).parents().addBack().filter(function() { + return $.css( this, "visibility" ) === "hidden"; + }).length; +} + +$.extend( $.expr[ ":" ], { + data: $.expr.createPseudo ? + $.expr.createPseudo(function( dataName ) { + return function( elem ) { + return !!$.data( elem, dataName ); + }; + }) : + // support: jQuery <1.8 + function( elem, i, match ) { + return !!$.data( elem, match[ 3 ] ); + }, + + focusable: function( element ) { + return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); + }, + + tabbable: function( element ) { + var tabIndex = $.attr( element, "tabindex" ), + isTabIndexNaN = isNaN( tabIndex ); + return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); + } +}); + +// support: jQuery <1.8 +if ( !$( "<a>" ).outerWidth( 1 ).jquery ) { + $.each( [ "Width", "Height" ], function( i, name ) { + var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], + type = name.toLowerCase(), + orig = { + innerWidth: $.fn.innerWidth, + innerHeight: $.fn.innerHeight, + outerWidth: $.fn.outerWidth, + outerHeight: $.fn.outerHeight + }; + + function reduce( elem, size, border, margin ) { + $.each( side, function() { + size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; + if ( border ) { + size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; + } + if ( margin ) { + size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; + } + }); + return size; + } + + $.fn[ "inner" + name ] = function( size ) { + if ( size === undefined ) { + return orig[ "inner" + name ].call( this ); + } + + return this.each(function() { + $( this ).css( type, reduce( this, size ) + "px" ); + }); + }; + + $.fn[ "outer" + name] = function( size, margin ) { + if ( typeof size !== "number" ) { + return orig[ "outer" + name ].call( this, size ); + } + + return this.each(function() { + $( this).css( type, reduce( this, size, true, margin ) + "px" ); + }); + }; + }); +} + +// support: jQuery <1.8 +if ( !$.fn.addBack ) { + $.fn.addBack = function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + }; +} + +// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) +if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { + $.fn.removeData = (function( removeData ) { + return function( key ) { + if ( arguments.length ) { + return removeData.call( this, $.camelCase( key ) ); + } else { + return removeData.call( this ); + } + }; + })( $.fn.removeData ); +} + +// deprecated +$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); + +$.fn.extend({ + focus: (function( orig ) { + return function( delay, fn ) { + return typeof delay === "number" ? + this.each(function() { + var elem = this; + setTimeout(function() { + $( elem ).focus(); + if ( fn ) { + fn.call( elem ); + } + }, delay ); + }) : + orig.apply( this, arguments ); + }; + })( $.fn.focus ), + + disableSelection: (function() { + var eventType = "onselectstart" in document.createElement( "div" ) ? + "selectstart" : + "mousedown"; + + return function() { + return this.bind( eventType + ".ui-disableSelection", function( event ) { + event.preventDefault(); + }); + }; + })(), + + enableSelection: function() { + return this.unbind( ".ui-disableSelection" ); + }, + + zIndex: function( zIndex ) { + if ( zIndex !== undefined ) { + return this.css( "zIndex", zIndex ); + } + + if ( this.length ) { + var elem = $( this[ 0 ] ), position, value; + while ( elem.length && elem[ 0 ] !== document ) { + // Ignore z-index if position is set to a value where z-index is ignored by the browser + // This makes behavior of this function consistent across browsers + // WebKit always returns auto if the element is positioned + position = elem.css( "position" ); + if ( position === "absolute" || position === "relative" || position === "fixed" ) { + // IE returns 0 when zIndex is not specified + // other browsers return a string + // we ignore the case of nested elements with an explicit value of 0 + // <div style="z-index: -10;"><div style="z-index: 0;"></div></div> + value = parseInt( elem.css( "zIndex" ), 10 ); + if ( !isNaN( value ) && value !== 0 ) { + return value; + } + } + elem = elem.parent(); + } + } + + return 0; + } +}); + +// $.ui.plugin is deprecated. Use $.widget() extensions instead. +$.ui.plugin = { + add: function( module, option, set ) { + var i, + proto = $.ui[ module ].prototype; + for ( i in set ) { + proto.plugins[ i ] = proto.plugins[ i ] || []; + proto.plugins[ i ].push( [ option, set[ i ] ] ); + } + }, + call: function( instance, name, args, allowDisconnected ) { + var i, + set = instance.plugins[ name ]; + + if ( !set ) { + return; + } + + if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) ) { + return; + } + + for ( i = 0; i < set.length; i++ ) { + if ( instance.options[ set[ i ][ 0 ] ] ) { + set[ i ][ 1 ].apply( instance.element, args ); + } + } + } +}; + + +/*! + * jQuery UI Widget 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/jQuery.widget/ + */ + + +var widget_uuid = 0, + widget_slice = Array.prototype.slice; + +$.cleanData = (function( orig ) { + return function( elems ) { + var events, elem, i; + for ( i = 0; (elem = elems[i]) != null; i++ ) { + try { + + // Only trigger remove when necessary to save time + events = $._data( elem, "events" ); + if ( events && events.remove ) { + $( elem ).triggerHandler( "remove" ); + } + + // http://bugs.jquery.com/ticket/8235 + } catch ( e ) {} + } + orig( elems ); + }; +})( $.cleanData ); + +$.widget = function( name, base, prototype ) { + var fullName, existingConstructor, constructor, basePrototype, + // proxiedPrototype allows the provided prototype to remain unmodified + // so that it can be used as a mixin for multiple widgets (#8876) + proxiedPrototype = {}, + namespace = name.split( "." )[ 0 ]; + + name = name.split( "." )[ 1 ]; + fullName = namespace + "-" + name; + + if ( !prototype ) { + prototype = base; + base = $.Widget; + } + + // create selector for plugin + $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { + return !!$.data( elem, fullName ); + }; + + $[ namespace ] = $[ namespace ] || {}; + existingConstructor = $[ namespace ][ name ]; + constructor = $[ namespace ][ name ] = function( options, element ) { + // allow instantiation without "new" keyword + if ( !this._createWidget ) { + return new constructor( options, element ); + } + + // allow instantiation without initializing for simple inheritance + // must use "new" keyword (the code above always passes args) + if ( arguments.length ) { + this._createWidget( options, element ); + } + }; + // extend with the existing constructor to carry over any static properties + $.extend( constructor, existingConstructor, { + version: prototype.version, + // copy the object used to create the prototype in case we need to + // redefine the widget later + _proto: $.extend( {}, prototype ), + // track widgets that inherit from this widget in case this widget is + // redefined after a widget inherits from it + _childConstructors: [] + }); + + basePrototype = new base(); + // we need to make the options hash a property directly on the new instance + // otherwise we'll modify the options hash on the prototype that we're + // inheriting from + basePrototype.options = $.widget.extend( {}, basePrototype.options ); + $.each( prototype, function( prop, value ) { + if ( !$.isFunction( value ) ) { + proxiedPrototype[ prop ] = value; + return; + } + proxiedPrototype[ prop ] = (function() { + var _super = function() { + return base.prototype[ prop ].apply( this, arguments ); + }, + _superApply = function( args ) { + return base.prototype[ prop ].apply( this, args ); + }; + return function() { + var __super = this._super, + __superApply = this._superApply, + returnValue; + + this._super = _super; + this._superApply = _superApply; + + returnValue = value.apply( this, arguments ); + + this._super = __super; + this._superApply = __superApply; + + return returnValue; + }; + })(); + }); + constructor.prototype = $.widget.extend( basePrototype, { + // TODO: remove support for widgetEventPrefix + // always use the name + a colon as the prefix, e.g., draggable:start + // don't prefix for widgets that aren't DOM-based + widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name + }, proxiedPrototype, { + constructor: constructor, + namespace: namespace, + widgetName: name, + widgetFullName: fullName + }); + + // If this widget is being redefined then we need to find all widgets that + // are inheriting from it and redefine all of them so that they inherit from + // the new version of this widget. We're essentially trying to replace one + // level in the prototype chain. + if ( existingConstructor ) { + $.each( existingConstructor._childConstructors, function( i, child ) { + var childPrototype = child.prototype; + + // redefine the child widget using the same prototype that was + // originally used, but inherit from the new version of the base + $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); + }); + // remove the list of existing child constructors from the old constructor + // so the old child constructors can be garbage collected + delete existingConstructor._childConstructors; + } else { + base._childConstructors.push( constructor ); + } + + $.widget.bridge( name, constructor ); + + return constructor; +}; + +$.widget.extend = function( target ) { + var input = widget_slice.call( arguments, 1 ), + inputIndex = 0, + inputLength = input.length, + key, + value; + for ( ; inputIndex < inputLength; inputIndex++ ) { + for ( key in input[ inputIndex ] ) { + value = input[ inputIndex ][ key ]; + if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { + // Clone objects + if ( $.isPlainObject( value ) ) { + target[ key ] = $.isPlainObject( target[ key ] ) ? + $.widget.extend( {}, target[ key ], value ) : + // Don't extend strings, arrays, etc. with objects + $.widget.extend( {}, value ); + // Copy everything else by reference + } else { + target[ key ] = value; + } + } + } + } + return target; +}; + +$.widget.bridge = function( name, object ) { + var fullName = object.prototype.widgetFullName || name; + $.fn[ name ] = function( options ) { + var isMethodCall = typeof options === "string", + args = widget_slice.call( arguments, 1 ), + returnValue = this; + + if ( isMethodCall ) { + this.each(function() { + var methodValue, + instance = $.data( this, fullName ); + if ( options === "instance" ) { + returnValue = instance; + return false; + } + if ( !instance ) { + return $.error( "cannot call methods on " + name + " prior to initialization; " + + "attempted to call method '" + options + "'" ); + } + if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { + return $.error( "no such method '" + options + "' for " + name + " widget instance" ); + } + methodValue = instance[ options ].apply( instance, args ); + if ( methodValue !== instance && methodValue !== undefined ) { + returnValue = methodValue && methodValue.jquery ? + returnValue.pushStack( methodValue.get() ) : + methodValue; + return false; + } + }); + } else { + + // Allow multiple hashes to be passed on init + if ( args.length ) { + options = $.widget.extend.apply( null, [ options ].concat(args) ); + } + + this.each(function() { + var instance = $.data( this, fullName ); + if ( instance ) { + instance.option( options || {} ); + if ( instance._init ) { + instance._init(); + } + } else { + $.data( this, fullName, new object( options, this ) ); + } + }); + } + + return returnValue; + }; +}; + +$.Widget = function( /* options, element */ ) {}; +$.Widget._childConstructors = []; + +$.Widget.prototype = { + widgetName: "widget", + widgetEventPrefix: "", + defaultElement: "<div>", + options: { + disabled: false, + + // callbacks + create: null + }, + _createWidget: function( options, element ) { + element = $( element || this.defaultElement || this )[ 0 ]; + this.element = $( element ); + this.uuid = widget_uuid++; + this.eventNamespace = "." + this.widgetName + this.uuid; + + this.bindings = $(); + this.hoverable = $(); + this.focusable = $(); + + if ( element !== this ) { + $.data( element, this.widgetFullName, this ); + this._on( true, this.element, { + remove: function( event ) { + if ( event.target === element ) { + this.destroy(); + } + } + }); + this.document = $( element.style ? + // element within the document + element.ownerDocument : + // element is window or document + element.document || element ); + this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); + } + + this.options = $.widget.extend( {}, + this.options, + this._getCreateOptions(), + options ); + + this._create(); + this._trigger( "create", null, this._getCreateEventData() ); + this._init(); + }, + _getCreateOptions: $.noop, + _getCreateEventData: $.noop, + _create: $.noop, + _init: $.noop, + + destroy: function() { + this._destroy(); + // we can probably remove the unbind calls in 2.0 + // all event bindings should go through this._on() + this.element + .unbind( this.eventNamespace ) + .removeData( this.widgetFullName ) + // support: jquery <1.6.3 + // http://bugs.jquery.com/ticket/9413 + .removeData( $.camelCase( this.widgetFullName ) ); + this.widget() + .unbind( this.eventNamespace ) + .removeAttr( "aria-disabled" ) + .removeClass( + this.widgetFullName + "-disabled " + + "ui-state-disabled" ); + + // clean up events and states + this.bindings.unbind( this.eventNamespace ); + this.hoverable.removeClass( "ui-state-hover" ); + this.focusable.removeClass( "ui-state-focus" ); + }, + _destroy: $.noop, + + widget: function() { + return this.element; + }, + + option: function( key, value ) { + var options = key, + parts, + curOption, + i; + + if ( arguments.length === 0 ) { + // don't return a reference to the internal hash + return $.widget.extend( {}, this.options ); + } + + if ( typeof key === "string" ) { + // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } + options = {}; + parts = key.split( "." ); + key = parts.shift(); + if ( parts.length ) { + curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); + for ( i = 0; i < parts.length - 1; i++ ) { + curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; + curOption = curOption[ parts[ i ] ]; + } + key = parts.pop(); + if ( arguments.length === 1 ) { + return curOption[ key ] === undefined ? null : curOption[ key ]; + } + curOption[ key ] = value; + } else { + if ( arguments.length === 1 ) { + return this.options[ key ] === undefined ? null : this.options[ key ]; + } + options[ key ] = value; + } + } + + this._setOptions( options ); + + return this; + }, + _setOptions: function( options ) { + var key; + + for ( key in options ) { + this._setOption( key, options[ key ] ); + } + + return this; + }, + _setOption: function( key, value ) { + this.options[ key ] = value; + + if ( key === "disabled" ) { + this.widget() + .toggleClass( this.widgetFullName + "-disabled", !!value ); + + // If the widget is becoming disabled, then nothing is interactive + if ( value ) { + this.hoverable.removeClass( "ui-state-hover" ); + this.focusable.removeClass( "ui-state-focus" ); + } + } + + return this; + }, + + enable: function() { + return this._setOptions({ disabled: false }); + }, + disable: function() { + return this._setOptions({ disabled: true }); + }, + + _on: function( suppressDisabledCheck, element, handlers ) { + var delegateElement, + instance = this; + + // no suppressDisabledCheck flag, shuffle arguments + if ( typeof suppressDisabledCheck !== "boolean" ) { + handlers = element; + element = suppressDisabledCheck; + suppressDisabledCheck = false; + } + + // no element argument, shuffle and use this.element + if ( !handlers ) { + handlers = element; + element = this.element; + delegateElement = this.widget(); + } else { + element = delegateElement = $( element ); + this.bindings = this.bindings.add( element ); + } + + $.each( handlers, function( event, handler ) { + function handlerProxy() { + // allow widgets to customize the disabled handling + // - disabled as an array instead of boolean + // - disabled class as method for disabling individual parts + if ( !suppressDisabledCheck && + ( instance.options.disabled === true || + $( this ).hasClass( "ui-state-disabled" ) ) ) { + return; + } + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + + // copy the guid so direct unbinding works + if ( typeof handler !== "string" ) { + handlerProxy.guid = handler.guid = + handler.guid || handlerProxy.guid || $.guid++; + } + + var match = event.match( /^([\w:-]*)\s*(.*)$/ ), + eventName = match[1] + instance.eventNamespace, + selector = match[2]; + if ( selector ) { + delegateElement.delegate( selector, eventName, handlerProxy ); + } else { + element.bind( eventName, handlerProxy ); + } + }); + }, + + _off: function( element, eventName ) { + eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + + this.eventNamespace; + element.unbind( eventName ).undelegate( eventName ); + + // Clear the stack to avoid memory leaks (#10056) + this.bindings = $( this.bindings.not( element ).get() ); + this.focusable = $( this.focusable.not( element ).get() ); + this.hoverable = $( this.hoverable.not( element ).get() ); + }, + + _delay: function( handler, delay ) { + function handlerProxy() { + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + var instance = this; + return setTimeout( handlerProxy, delay || 0 ); + }, + + _hoverable: function( element ) { + this.hoverable = this.hoverable.add( element ); + this._on( element, { + mouseenter: function( event ) { + $( event.currentTarget ).addClass( "ui-state-hover" ); + }, + mouseleave: function( event ) { + $( event.currentTarget ).removeClass( "ui-state-hover" ); + } + }); + }, + + _focusable: function( element ) { + this.focusable = this.focusable.add( element ); + this._on( element, { + focusin: function( event ) { + $( event.currentTarget ).addClass( "ui-state-focus" ); + }, + focusout: function( event ) { + $( event.currentTarget ).removeClass( "ui-state-focus" ); + } + }); + }, + + _trigger: function( type, event, data ) { + var prop, orig, + callback = this.options[ type ]; + + data = data || {}; + event = $.Event( event ); + event.type = ( type === this.widgetEventPrefix ? + type : + this.widgetEventPrefix + type ).toLowerCase(); + // the original event may come from any element + // so we need to reset the target on the new event + event.target = this.element[ 0 ]; + + // copy original event properties over to the new event + orig = event.originalEvent; + if ( orig ) { + for ( prop in orig ) { + if ( !( prop in event ) ) { + event[ prop ] = orig[ prop ]; + } + } + } + + this.element.trigger( event, data ); + return !( $.isFunction( callback ) && + callback.apply( this.element[0], [ event ].concat( data ) ) === false || + event.isDefaultPrevented() ); + } +}; + +$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { + $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { + if ( typeof options === "string" ) { + options = { effect: options }; + } + var hasOptions, + effectName = !options ? + method : + options === true || typeof options === "number" ? + defaultEffect : + options.effect || defaultEffect; + options = options || {}; + if ( typeof options === "number" ) { + options = { duration: options }; + } + hasOptions = !$.isEmptyObject( options ); + options.complete = callback; + if ( options.delay ) { + element.delay( options.delay ); + } + if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { + element[ method ]( options ); + } else if ( effectName !== method && element[ effectName ] ) { + element[ effectName ]( options.duration, options.easing, callback ); + } else { + element.queue(function( next ) { + $( this )[ method ](); + if ( callback ) { + callback.call( element[ 0 ] ); + } + next(); + }); + } + }; +}); + +var widget = $.widget; + + +/*! + * jQuery UI Mouse 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/mouse/ + */ + + +var mouseHandled = false; +$( document ).mouseup( function() { + mouseHandled = false; +}); + +var mouse = $.widget("ui.mouse", { + version: "1.11.4", + options: { + cancel: "input,textarea,button,select,option", + distance: 1, + delay: 0 + }, + _mouseInit: function() { + var that = this; + + this.element + .bind("mousedown." + this.widgetName, function(event) { + return that._mouseDown(event); + }) + .bind("click." + this.widgetName, function(event) { + if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { + $.removeData(event.target, that.widgetName + ".preventClickEvent"); + event.stopImmediatePropagation(); + return false; + } + }); + + this.started = false; + }, + + // TODO: make sure destroying one instance of mouse doesn't mess with + // other instances of mouse + _mouseDestroy: function() { + this.element.unbind("." + this.widgetName); + if ( this._mouseMoveDelegate ) { + this.document + .unbind("mousemove." + this.widgetName, this._mouseMoveDelegate) + .unbind("mouseup." + this.widgetName, this._mouseUpDelegate); + } + }, + + _mouseDown: function(event) { + // don't let more than one widget handle mouseStart + if ( mouseHandled ) { + return; + } + + this._mouseMoved = false; + + // we may have missed mouseup (out of window) + (this._mouseStarted && this._mouseUp(event)); + + this._mouseDownEvent = event; + + var that = this, + btnIsLeft = (event.which === 1), + // event.target.nodeName works around a bug in IE 8 with + // disabled inputs (#7620) + elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); + if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { + return true; + } + + this.mouseDelayMet = !this.options.delay; + if (!this.mouseDelayMet) { + this._mouseDelayTimer = setTimeout(function() { + that.mouseDelayMet = true; + }, this.options.delay); + } + + if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { + this._mouseStarted = (this._mouseStart(event) !== false); + if (!this._mouseStarted) { + event.preventDefault(); + return true; + } + } + + // Click event may never have fired (Gecko & Opera) + if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { + $.removeData(event.target, this.widgetName + ".preventClickEvent"); + } + + // these delegates are required to keep context + this._mouseMoveDelegate = function(event) { + return that._mouseMove(event); + }; + this._mouseUpDelegate = function(event) { + return that._mouseUp(event); + }; + + this.document + .bind( "mousemove." + this.widgetName, this._mouseMoveDelegate ) + .bind( "mouseup." + this.widgetName, this._mouseUpDelegate ); + + event.preventDefault(); + + mouseHandled = true; + return true; + }, + + _mouseMove: function(event) { + // Only check for mouseups outside the document if you've moved inside the document + // at least once. This prevents the firing of mouseup in the case of IE<9, which will + // fire a mousemove event if content is placed under the cursor. See #7778 + // Support: IE <9 + if ( this._mouseMoved ) { + // IE mouseup check - mouseup happened when mouse was out of window + if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { + return this._mouseUp(event); + + // Iframe mouseup check - mouseup occurred in another document + } else if ( !event.which ) { + return this._mouseUp( event ); + } + } + + if ( event.which || event.button ) { + this._mouseMoved = true; + } + + if (this._mouseStarted) { + this._mouseDrag(event); + return event.preventDefault(); + } + + if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { + this._mouseStarted = + (this._mouseStart(this._mouseDownEvent, event) !== false); + (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); + } + + return !this._mouseStarted; + }, + + _mouseUp: function(event) { + this.document + .unbind( "mousemove." + this.widgetName, this._mouseMoveDelegate ) + .unbind( "mouseup." + this.widgetName, this._mouseUpDelegate ); + + if (this._mouseStarted) { + this._mouseStarted = false; + + if (event.target === this._mouseDownEvent.target) { + $.data(event.target, this.widgetName + ".preventClickEvent", true); + } + + this._mouseStop(event); + } + + mouseHandled = false; + return false; + }, + + _mouseDistanceMet: function(event) { + return (Math.max( + Math.abs(this._mouseDownEvent.pageX - event.pageX), + Math.abs(this._mouseDownEvent.pageY - event.pageY) + ) >= this.options.distance + ); + }, + + _mouseDelayMet: function(/* event */) { + return this.mouseDelayMet; + }, + + // These are placeholder methods, to be overriden by extending plugin + _mouseStart: function(/* event */) {}, + _mouseDrag: function(/* event */) {}, + _mouseStop: function(/* event */) {}, + _mouseCapture: function(/* event */) { return true; } +}); + + +/*! + * jQuery UI Position 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/position/ + */ + +(function() { + +$.ui = $.ui || {}; + +var cachedScrollbarWidth, supportsOffsetFractions, + max = Math.max, + abs = Math.abs, + round = Math.round, + rhorizontal = /left|center|right/, + rvertical = /top|center|bottom/, + roffset = /[\+\-]\d+(\.[\d]+)?%?/, + rposition = /^\w+/, + rpercent = /%$/, + _position = $.fn.position; + +function getOffsets( offsets, width, height ) { + return [ + parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), + parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) + ]; +} + +function parseCss( element, property ) { + return parseInt( $.css( element, property ), 10 ) || 0; +} + +function getDimensions( elem ) { + var raw = elem[0]; + if ( raw.nodeType === 9 ) { + return { + width: elem.width(), + height: elem.height(), + offset: { top: 0, left: 0 } + }; + } + if ( $.isWindow( raw ) ) { + return { + width: elem.width(), + height: elem.height(), + offset: { top: elem.scrollTop(), left: elem.scrollLeft() } + }; + } + if ( raw.preventDefault ) { + return { + width: 0, + height: 0, + offset: { top: raw.pageY, left: raw.pageX } + }; + } + return { + width: elem.outerWidth(), + height: elem.outerHeight(), + offset: elem.offset() + }; +} + +$.position = { + scrollbarWidth: function() { + if ( cachedScrollbarWidth !== undefined ) { + return cachedScrollbarWidth; + } + var w1, w2, + div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ), + innerDiv = div.children()[0]; + + $( "body" ).append( div ); + w1 = innerDiv.offsetWidth; + div.css( "overflow", "scroll" ); + + w2 = innerDiv.offsetWidth; + + if ( w1 === w2 ) { + w2 = div[0].clientWidth; + } + + div.remove(); + + return (cachedScrollbarWidth = w1 - w2); + }, + getScrollInfo: function( within ) { + var overflowX = within.isWindow || within.isDocument ? "" : + within.element.css( "overflow-x" ), + overflowY = within.isWindow || within.isDocument ? "" : + within.element.css( "overflow-y" ), + hasOverflowX = overflowX === "scroll" || + ( overflowX === "auto" && within.width < within.element[0].scrollWidth ), + hasOverflowY = overflowY === "scroll" || + ( overflowY === "auto" && within.height < within.element[0].scrollHeight ); + return { + width: hasOverflowY ? $.position.scrollbarWidth() : 0, + height: hasOverflowX ? $.position.scrollbarWidth() : 0 + }; + }, + getWithinInfo: function( element ) { + var withinElement = $( element || window ), + isWindow = $.isWindow( withinElement[0] ), + isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9; + return { + element: withinElement, + isWindow: isWindow, + isDocument: isDocument, + offset: withinElement.offset() || { left: 0, top: 0 }, + scrollLeft: withinElement.scrollLeft(), + scrollTop: withinElement.scrollTop(), + + // support: jQuery 1.6.x + // jQuery 1.6 doesn't support .outerWidth/Height() on documents or windows + width: isWindow || isDocument ? withinElement.width() : withinElement.outerWidth(), + height: isWindow || isDocument ? withinElement.height() : withinElement.outerHeight() + }; + } +}; + +$.fn.position = function( options ) { + if ( !options || !options.of ) { + return _position.apply( this, arguments ); + } + + // make a copy, we don't want to modify arguments + options = $.extend( {}, options ); + + var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, + target = $( options.of ), + within = $.position.getWithinInfo( options.within ), + scrollInfo = $.position.getScrollInfo( within ), + collision = ( options.collision || "flip" ).split( " " ), + offsets = {}; + + dimensions = getDimensions( target ); + if ( target[0].preventDefault ) { + // force left top to allow flipping + options.at = "left top"; + } + targetWidth = dimensions.width; + targetHeight = dimensions.height; + targetOffset = dimensions.offset; + // clone to reuse original targetOffset later + basePosition = $.extend( {}, targetOffset ); + + // force my and at to have valid horizontal and vertical positions + // if a value is missing or invalid, it will be converted to center + $.each( [ "my", "at" ], function() { + var pos = ( options[ this ] || "" ).split( " " ), + horizontalOffset, + verticalOffset; + + if ( pos.length === 1) { + pos = rhorizontal.test( pos[ 0 ] ) ? + pos.concat( [ "center" ] ) : + rvertical.test( pos[ 0 ] ) ? + [ "center" ].concat( pos ) : + [ "center", "center" ]; + } + pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; + pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; + + // calculate offsets + horizontalOffset = roffset.exec( pos[ 0 ] ); + verticalOffset = roffset.exec( pos[ 1 ] ); + offsets[ this ] = [ + horizontalOffset ? horizontalOffset[ 0 ] : 0, + verticalOffset ? verticalOffset[ 0 ] : 0 + ]; + + // reduce to just the positions without the offsets + options[ this ] = [ + rposition.exec( pos[ 0 ] )[ 0 ], + rposition.exec( pos[ 1 ] )[ 0 ] + ]; + }); + + // normalize collision option + if ( collision.length === 1 ) { + collision[ 1 ] = collision[ 0 ]; + } + + if ( options.at[ 0 ] === "right" ) { + basePosition.left += targetWidth; + } else if ( options.at[ 0 ] === "center" ) { + basePosition.left += targetWidth / 2; + } + + if ( options.at[ 1 ] === "bottom" ) { + basePosition.top += targetHeight; + } else if ( options.at[ 1 ] === "center" ) { + basePosition.top += targetHeight / 2; + } + + atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); + basePosition.left += atOffset[ 0 ]; + basePosition.top += atOffset[ 1 ]; + + return this.each(function() { + var collisionPosition, using, + elem = $( this ), + elemWidth = elem.outerWidth(), + elemHeight = elem.outerHeight(), + marginLeft = parseCss( this, "marginLeft" ), + marginTop = parseCss( this, "marginTop" ), + collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width, + collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height, + position = $.extend( {}, basePosition ), + myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); + + if ( options.my[ 0 ] === "right" ) { + position.left -= elemWidth; + } else if ( options.my[ 0 ] === "center" ) { + position.left -= elemWidth / 2; + } + + if ( options.my[ 1 ] === "bottom" ) { + position.top -= elemHeight; + } else if ( options.my[ 1 ] === "center" ) { + position.top -= elemHeight / 2; + } + + position.left += myOffset[ 0 ]; + position.top += myOffset[ 1 ]; + + // if the browser doesn't support fractions, then round for consistent results + if ( !supportsOffsetFractions ) { + position.left = round( position.left ); + position.top = round( position.top ); + } + + collisionPosition = { + marginLeft: marginLeft, + marginTop: marginTop + }; + + $.each( [ "left", "top" ], function( i, dir ) { + if ( $.ui.position[ collision[ i ] ] ) { + $.ui.position[ collision[ i ] ][ dir ]( position, { + targetWidth: targetWidth, + targetHeight: targetHeight, + elemWidth: elemWidth, + elemHeight: elemHeight, + collisionPosition: collisionPosition, + collisionWidth: collisionWidth, + collisionHeight: collisionHeight, + offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], + my: options.my, + at: options.at, + within: within, + elem: elem + }); + } + }); + + if ( options.using ) { + // adds feedback as second argument to using callback, if present + using = function( props ) { + var left = targetOffset.left - position.left, + right = left + targetWidth - elemWidth, + top = targetOffset.top - position.top, + bottom = top + targetHeight - elemHeight, + feedback = { + target: { + element: target, + left: targetOffset.left, + top: targetOffset.top, + width: targetWidth, + height: targetHeight + }, + element: { + element: elem, + left: position.left, + top: position.top, + width: elemWidth, + height: elemHeight + }, + horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", + vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" + }; + if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { + feedback.horizontal = "center"; + } + if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { + feedback.vertical = "middle"; + } + if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { + feedback.important = "horizontal"; + } else { + feedback.important = "vertical"; + } + options.using.call( this, props, feedback ); + }; + } + + elem.offset( $.extend( position, { using: using } ) ); + }); +}; + +$.ui.position = { + fit: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, + outerWidth = within.width, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = withinOffset - collisionPosLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, + newOverRight; + + // element is wider than within + if ( data.collisionWidth > outerWidth ) { + // element is initially over the left side of within + if ( overLeft > 0 && overRight <= 0 ) { + newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset; + position.left += overLeft - newOverRight; + // element is initially over right side of within + } else if ( overRight > 0 && overLeft <= 0 ) { + position.left = withinOffset; + // element is initially over both left and right sides of within + } else { + if ( overLeft > overRight ) { + position.left = withinOffset + outerWidth - data.collisionWidth; + } else { + position.left = withinOffset; + } + } + // too far left -> align with left edge + } else if ( overLeft > 0 ) { + position.left += overLeft; + // too far right -> align with right edge + } else if ( overRight > 0 ) { + position.left -= overRight; + // adjust based on position and margin + } else { + position.left = max( position.left - collisionPosLeft, position.left ); + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollTop : within.offset.top, + outerHeight = data.within.height, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = withinOffset - collisionPosTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, + newOverBottom; + + // element is taller than within + if ( data.collisionHeight > outerHeight ) { + // element is initially over the top of within + if ( overTop > 0 && overBottom <= 0 ) { + newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset; + position.top += overTop - newOverBottom; + // element is initially over bottom of within + } else if ( overBottom > 0 && overTop <= 0 ) { + position.top = withinOffset; + // element is initially over both top and bottom of within + } else { + if ( overTop > overBottom ) { + position.top = withinOffset + outerHeight - data.collisionHeight; + } else { + position.top = withinOffset; + } + } + // too far up -> align with top + } else if ( overTop > 0 ) { + position.top += overTop; + // too far down -> align with bottom edge + } else if ( overBottom > 0 ) { + position.top -= overBottom; + // adjust based on position and margin + } else { + position.top = max( position.top - collisionPosTop, position.top ); + } + } + }, + flip: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.offset.left + within.scrollLeft, + outerWidth = within.width, + offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = collisionPosLeft - offsetLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, + myOffset = data.my[ 0 ] === "left" ? + -data.elemWidth : + data.my[ 0 ] === "right" ? + data.elemWidth : + 0, + atOffset = data.at[ 0 ] === "left" ? + data.targetWidth : + data.at[ 0 ] === "right" ? + -data.targetWidth : + 0, + offset = -2 * data.offset[ 0 ], + newOverRight, + newOverLeft; + + if ( overLeft < 0 ) { + newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset; + if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { + position.left += myOffset + atOffset + offset; + } + } else if ( overRight > 0 ) { + newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft; + if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { + position.left += myOffset + atOffset + offset; + } + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.offset.top + within.scrollTop, + outerHeight = within.height, + offsetTop = within.isWindow ? within.scrollTop : within.offset.top, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = collisionPosTop - offsetTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, + top = data.my[ 1 ] === "top", + myOffset = top ? + -data.elemHeight : + data.my[ 1 ] === "bottom" ? + data.elemHeight : + 0, + atOffset = data.at[ 1 ] === "top" ? + data.targetHeight : + data.at[ 1 ] === "bottom" ? + -data.targetHeight : + 0, + offset = -2 * data.offset[ 1 ], + newOverTop, + newOverBottom; + if ( overTop < 0 ) { + newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset; + if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) { + position.top += myOffset + atOffset + offset; + } + } else if ( overBottom > 0 ) { + newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop; + if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) { + position.top += myOffset + atOffset + offset; + } + } + } + }, + flipfit: { + left: function() { + $.ui.position.flip.left.apply( this, arguments ); + $.ui.position.fit.left.apply( this, arguments ); + }, + top: function() { + $.ui.position.flip.top.apply( this, arguments ); + $.ui.position.fit.top.apply( this, arguments ); + } + } +}; + +// fraction support test +(function() { + var testElement, testElementParent, testElementStyle, offsetLeft, i, + body = document.getElementsByTagName( "body" )[ 0 ], + div = document.createElement( "div" ); + + //Create a "fake body" for testing based on method used in jQuery.support + testElement = document.createElement( body ? "div" : "body" ); + testElementStyle = { + visibility: "hidden", + width: 0, + height: 0, + border: 0, + margin: 0, + background: "none" + }; + if ( body ) { + $.extend( testElementStyle, { + position: "absolute", + left: "-1000px", + top: "-1000px" + }); + } + for ( i in testElementStyle ) { + testElement.style[ i ] = testElementStyle[ i ]; + } + testElement.appendChild( div ); + testElementParent = body || document.documentElement; + testElementParent.insertBefore( testElement, testElementParent.firstChild ); + + div.style.cssText = "position: absolute; left: 10.7432222px;"; + + offsetLeft = $( div ).offset().left; + supportsOffsetFractions = offsetLeft > 10 && offsetLeft < 11; + + testElement.innerHTML = ""; + testElementParent.removeChild( testElement ); +})(); + +})(); + +var position = $.ui.position; + + +/*! + * jQuery UI Accordion 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/accordion/ + */ + + +var accordion = $.widget( "ui.accordion", { + version: "1.11.4", + options: { + active: 0, + animate: {}, + collapsible: false, + event: "click", + header: "> li > :first-child,> :not(li):even", + heightStyle: "auto", + icons: { + activeHeader: "ui-icon-triangle-1-s", + header: "ui-icon-triangle-1-e" + }, + + // callbacks + activate: null, + beforeActivate: null + }, + + hideProps: { + borderTopWidth: "hide", + borderBottomWidth: "hide", + paddingTop: "hide", + paddingBottom: "hide", + height: "hide" + }, + + showProps: { + borderTopWidth: "show", + borderBottomWidth: "show", + paddingTop: "show", + paddingBottom: "show", + height: "show" + }, + + _create: function() { + var options = this.options; + this.prevShow = this.prevHide = $(); + this.element.addClass( "ui-accordion ui-widget ui-helper-reset" ) + // ARIA + .attr( "role", "tablist" ); + + // don't allow collapsible: false and active: false / null + if ( !options.collapsible && (options.active === false || options.active == null) ) { + options.active = 0; + } + + this._processPanels(); + // handle negative values + if ( options.active < 0 ) { + options.active += this.headers.length; + } + this._refresh(); + }, + + _getCreateEventData: function() { + return { + header: this.active, + panel: !this.active.length ? $() : this.active.next() + }; + }, + + _createIcons: function() { + var icons = this.options.icons; + if ( icons ) { + $( "<span>" ) + .addClass( "ui-accordion-header-icon ui-icon " + icons.header ) + .prependTo( this.headers ); + this.active.children( ".ui-accordion-header-icon" ) + .removeClass( icons.header ) + .addClass( icons.activeHeader ); + this.headers.addClass( "ui-accordion-icons" ); + } + }, + + _destroyIcons: function() { + this.headers + .removeClass( "ui-accordion-icons" ) + .children( ".ui-accordion-header-icon" ) + .remove(); + }, + + _destroy: function() { + var contents; + + // clean up main element + this.element + .removeClass( "ui-accordion ui-widget ui-helper-reset" ) + .removeAttr( "role" ); + + // clean up headers + this.headers + .removeClass( "ui-accordion-header ui-accordion-header-active ui-state-default " + + "ui-corner-all ui-state-active ui-state-disabled ui-corner-top" ) + .removeAttr( "role" ) + .removeAttr( "aria-expanded" ) + .removeAttr( "aria-selected" ) + .removeAttr( "aria-controls" ) + .removeAttr( "tabIndex" ) + .removeUniqueId(); + + this._destroyIcons(); + + // clean up content panels + contents = this.headers.next() + .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom " + + "ui-accordion-content ui-accordion-content-active ui-state-disabled" ) + .css( "display", "" ) + .removeAttr( "role" ) + .removeAttr( "aria-hidden" ) + .removeAttr( "aria-labelledby" ) + .removeUniqueId(); + + if ( this.options.heightStyle !== "content" ) { + contents.css( "height", "" ); + } + }, + + _setOption: function( key, value ) { + if ( key === "active" ) { + // _activate() will handle invalid values and update this.options + this._activate( value ); + return; + } + + if ( key === "event" ) { + if ( this.options.event ) { + this._off( this.headers, this.options.event ); + } + this._setupEvents( value ); + } + + this._super( key, value ); + + // setting collapsible: false while collapsed; open first panel + if ( key === "collapsible" && !value && this.options.active === false ) { + this._activate( 0 ); + } + + if ( key === "icons" ) { + this._destroyIcons(); + if ( value ) { + this._createIcons(); + } + } + + // #5332 - opacity doesn't cascade to positioned elements in IE + // so we need to add the disabled class to the headers and panels + if ( key === "disabled" ) { + this.element + .toggleClass( "ui-state-disabled", !!value ) + .attr( "aria-disabled", value ); + this.headers.add( this.headers.next() ) + .toggleClass( "ui-state-disabled", !!value ); + } + }, + + _keydown: function( event ) { + if ( event.altKey || event.ctrlKey ) { + return; + } + + var keyCode = $.ui.keyCode, + length = this.headers.length, + currentIndex = this.headers.index( event.target ), + toFocus = false; + + switch ( event.keyCode ) { + case keyCode.RIGHT: + case keyCode.DOWN: + toFocus = this.headers[ ( currentIndex + 1 ) % length ]; + break; + case keyCode.LEFT: + case keyCode.UP: + toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; + break; + case keyCode.SPACE: + case keyCode.ENTER: + this._eventHandler( event ); + break; + case keyCode.HOME: + toFocus = this.headers[ 0 ]; + break; + case keyCode.END: + toFocus = this.headers[ length - 1 ]; + break; + } + + if ( toFocus ) { + $( event.target ).attr( "tabIndex", -1 ); + $( toFocus ).attr( "tabIndex", 0 ); + toFocus.focus(); + event.preventDefault(); + } + }, + + _panelKeyDown: function( event ) { + if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { + $( event.currentTarget ).prev().focus(); + } + }, + + refresh: function() { + var options = this.options; + this._processPanels(); + + // was collapsed or no panel + if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) { + options.active = false; + this.active = $(); + // active false only when collapsible is true + } else if ( options.active === false ) { + this._activate( 0 ); + // was active, but active panel is gone + } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { + // all remaining panel are disabled + if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) { + options.active = false; + this.active = $(); + // activate previous panel + } else { + this._activate( Math.max( 0, options.active - 1 ) ); + } + // was active, active panel still exists + } else { + // make sure active index is correct + options.active = this.headers.index( this.active ); + } + + this._destroyIcons(); + + this._refresh(); + }, + + _processPanels: function() { + var prevHeaders = this.headers, + prevPanels = this.panels; + + this.headers = this.element.find( this.options.header ) + .addClass( "ui-accordion-header ui-state-default ui-corner-all" ); + + this.panels = this.headers.next() + .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ) + .filter( ":not(.ui-accordion-content-active)" ) + .hide(); + + // Avoid memory leaks (#10056) + if ( prevPanels ) { + this._off( prevHeaders.not( this.headers ) ); + this._off( prevPanels.not( this.panels ) ); + } + }, + + _refresh: function() { + var maxHeight, + options = this.options, + heightStyle = options.heightStyle, + parent = this.element.parent(); + + this.active = this._findActive( options.active ) + .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ) + .removeClass( "ui-corner-all" ); + this.active.next() + .addClass( "ui-accordion-content-active" ) + .show(); + + this.headers + .attr( "role", "tab" ) + .each(function() { + var header = $( this ), + headerId = header.uniqueId().attr( "id" ), + panel = header.next(), + panelId = panel.uniqueId().attr( "id" ); + header.attr( "aria-controls", panelId ); + panel.attr( "aria-labelledby", headerId ); + }) + .next() + .attr( "role", "tabpanel" ); + + this.headers + .not( this.active ) + .attr({ + "aria-selected": "false", + "aria-expanded": "false", + tabIndex: -1 + }) + .next() + .attr({ + "aria-hidden": "true" + }) + .hide(); + + // make sure at least one header is in the tab order + if ( !this.active.length ) { + this.headers.eq( 0 ).attr( "tabIndex", 0 ); + } else { + this.active.attr({ + "aria-selected": "true", + "aria-expanded": "true", + tabIndex: 0 + }) + .next() + .attr({ + "aria-hidden": "false" + }); + } + + this._createIcons(); + + this._setupEvents( options.event ); + + if ( heightStyle === "fill" ) { + maxHeight = parent.height(); + this.element.siblings( ":visible" ).each(function() { + var elem = $( this ), + position = elem.css( "position" ); + + if ( position === "absolute" || position === "fixed" ) { + return; + } + maxHeight -= elem.outerHeight( true ); + }); + + this.headers.each(function() { + maxHeight -= $( this ).outerHeight( true ); + }); + + this.headers.next() + .each(function() { + $( this ).height( Math.max( 0, maxHeight - + $( this ).innerHeight() + $( this ).height() ) ); + }) + .css( "overflow", "auto" ); + } else if ( heightStyle === "auto" ) { + maxHeight = 0; + this.headers.next() + .each(function() { + maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); + }) + .height( maxHeight ); + } + }, + + _activate: function( index ) { + var active = this._findActive( index )[ 0 ]; + + // trying to activate the already active panel + if ( active === this.active[ 0 ] ) { + return; + } + + // trying to collapse, simulate a click on the currently active header + active = active || this.active[ 0 ]; + + this._eventHandler({ + target: active, + currentTarget: active, + preventDefault: $.noop + }); + }, + + _findActive: function( selector ) { + return typeof selector === "number" ? this.headers.eq( selector ) : $(); + }, + + _setupEvents: function( event ) { + var events = { + keydown: "_keydown" + }; + if ( event ) { + $.each( event.split( " " ), function( index, eventName ) { + events[ eventName ] = "_eventHandler"; + }); + } + + this._off( this.headers.add( this.headers.next() ) ); + this._on( this.headers, events ); + this._on( this.headers.next(), { keydown: "_panelKeyDown" }); + this._hoverable( this.headers ); + this._focusable( this.headers ); + }, + + _eventHandler: function( event ) { + var options = this.options, + active = this.active, + clicked = $( event.currentTarget ), + clickedIsActive = clicked[ 0 ] === active[ 0 ], + collapsing = clickedIsActive && options.collapsible, + toShow = collapsing ? $() : clicked.next(), + toHide = active.next(), + eventData = { + oldHeader: active, + oldPanel: toHide, + newHeader: collapsing ? $() : clicked, + newPanel: toShow + }; + + event.preventDefault(); + + if ( + // click on active header, but not collapsible + ( clickedIsActive && !options.collapsible ) || + // allow canceling activation + ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { + return; + } + + options.active = collapsing ? false : this.headers.index( clicked ); + + // when the call to ._toggle() comes after the class changes + // it causes a very odd bug in IE 8 (see #6720) + this.active = clickedIsActive ? $() : clicked; + this._toggle( eventData ); + + // switch classes + // corner classes on the previously active header stay after the animation + active.removeClass( "ui-accordion-header-active ui-state-active" ); + if ( options.icons ) { + active.children( ".ui-accordion-header-icon" ) + .removeClass( options.icons.activeHeader ) + .addClass( options.icons.header ); + } + + if ( !clickedIsActive ) { + clicked + .removeClass( "ui-corner-all" ) + .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ); + if ( options.icons ) { + clicked.children( ".ui-accordion-header-icon" ) + .removeClass( options.icons.header ) + .addClass( options.icons.activeHeader ); + } + + clicked + .next() + .addClass( "ui-accordion-content-active" ); + } + }, + + _toggle: function( data ) { + var toShow = data.newPanel, + toHide = this.prevShow.length ? this.prevShow : data.oldPanel; + + // handle activating a panel during the animation for another activation + this.prevShow.add( this.prevHide ).stop( true, true ); + this.prevShow = toShow; + this.prevHide = toHide; + + if ( this.options.animate ) { + this._animate( toShow, toHide, data ); + } else { + toHide.hide(); + toShow.show(); + this._toggleComplete( data ); + } + + toHide.attr({ + "aria-hidden": "true" + }); + toHide.prev().attr({ + "aria-selected": "false", + "aria-expanded": "false" + }); + // if we're switching panels, remove the old header from the tab order + // if we're opening from collapsed state, remove the previous header from the tab order + // if we're collapsing, then keep the collapsing header in the tab order + if ( toShow.length && toHide.length ) { + toHide.prev().attr({ + "tabIndex": -1, + "aria-expanded": "false" + }); + } else if ( toShow.length ) { + this.headers.filter(function() { + return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0; + }) + .attr( "tabIndex", -1 ); + } + + toShow + .attr( "aria-hidden", "false" ) + .prev() + .attr({ + "aria-selected": "true", + "aria-expanded": "true", + tabIndex: 0 + }); + }, + + _animate: function( toShow, toHide, data ) { + var total, easing, duration, + that = this, + adjust = 0, + boxSizing = toShow.css( "box-sizing" ), + down = toShow.length && + ( !toHide.length || ( toShow.index() < toHide.index() ) ), + animate = this.options.animate || {}, + options = down && animate.down || animate, + complete = function() { + that._toggleComplete( data ); + }; + + if ( typeof options === "number" ) { + duration = options; + } + if ( typeof options === "string" ) { + easing = options; + } + // fall back from options to animation in case of partial down settings + easing = easing || options.easing || animate.easing; + duration = duration || options.duration || animate.duration; + + if ( !toHide.length ) { + return toShow.animate( this.showProps, duration, easing, complete ); + } + if ( !toShow.length ) { + return toHide.animate( this.hideProps, duration, easing, complete ); + } + + total = toShow.show().outerHeight(); + toHide.animate( this.hideProps, { + duration: duration, + easing: easing, + step: function( now, fx ) { + fx.now = Math.round( now ); + } + }); + toShow + .hide() + .animate( this.showProps, { + duration: duration, + easing: easing, + complete: complete, + step: function( now, fx ) { + fx.now = Math.round( now ); + if ( fx.prop !== "height" ) { + if ( boxSizing === "content-box" ) { + adjust += fx.now; + } + } else if ( that.options.heightStyle !== "content" ) { + fx.now = Math.round( total - toHide.outerHeight() - adjust ); + adjust = 0; + } + } + }); + }, + + _toggleComplete: function( data ) { + var toHide = data.oldPanel; + + toHide + .removeClass( "ui-accordion-content-active" ) + .prev() + .removeClass( "ui-corner-top" ) + .addClass( "ui-corner-all" ); + + // Work around for rendering bug in IE (#5421) + if ( toHide.length ) { + toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className; + } + this._trigger( "activate", null, data ); + } +}); + + +/*! + * jQuery UI Menu 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/menu/ + */ + + +var menu = $.widget( "ui.menu", { + version: "1.11.4", + defaultElement: "<ul>", + delay: 300, + options: { + icons: { + submenu: "ui-icon-carat-1-e" + }, + items: "> *", + menus: "ul", + position: { + my: "left-1 top", + at: "right top" + }, + role: "menu", + + // callbacks + blur: null, + focus: null, + select: null + }, + + _create: function() { + this.activeMenu = this.element; + + // Flag used to prevent firing of the click handler + // as the event bubbles up through nested menus + this.mouseHandled = false; + this.element + .uniqueId() + .addClass( "ui-menu ui-widget ui-widget-content" ) + .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length ) + .attr({ + role: this.options.role, + tabIndex: 0 + }); + + if ( this.options.disabled ) { + this.element + .addClass( "ui-state-disabled" ) + .attr( "aria-disabled", "true" ); + } + + this._on({ + // Prevent focus from sticking to links inside menu after clicking + // them (focus should always stay on UL during navigation). + "mousedown .ui-menu-item": function( event ) { + event.preventDefault(); + }, + "click .ui-menu-item": function( event ) { + var target = $( event.target ); + if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) { + this.select( event ); + + // Only set the mouseHandled flag if the event will bubble, see #9469. + if ( !event.isPropagationStopped() ) { + this.mouseHandled = true; + } + + // Open submenu on click + if ( target.has( ".ui-menu" ).length ) { + this.expand( event ); + } else if ( !this.element.is( ":focus" ) && $( this.document[ 0 ].activeElement ).closest( ".ui-menu" ).length ) { + + // Redirect focus to the menu + this.element.trigger( "focus", [ true ] ); + + // If the active item is on the top level, let it stay active. + // Otherwise, blur the active item since it is no longer visible. + if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) { + clearTimeout( this.timer ); + } + } + } + }, + "mouseenter .ui-menu-item": function( event ) { + // Ignore mouse events while typeahead is active, see #10458. + // Prevents focusing the wrong item when typeahead causes a scroll while the mouse + // is over an item in the menu + if ( this.previousFilter ) { + return; + } + var target = $( event.currentTarget ); + // Remove ui-state-active class from siblings of the newly focused menu item + // to avoid a jump caused by adjacent elements both having a class with a border + target.siblings( ".ui-state-active" ).removeClass( "ui-state-active" ); + this.focus( event, target ); + }, + mouseleave: "collapseAll", + "mouseleave .ui-menu": "collapseAll", + focus: function( event, keepActiveItem ) { + // If there's already an active item, keep it active + // If not, activate the first item + var item = this.active || this.element.find( this.options.items ).eq( 0 ); + + if ( !keepActiveItem ) { + this.focus( event, item ); + } + }, + blur: function( event ) { + this._delay(function() { + if ( !$.contains( this.element[0], this.document[0].activeElement ) ) { + this.collapseAll( event ); + } + }); + }, + keydown: "_keydown" + }); + + this.refresh(); + + // Clicks outside of a menu collapse any open menus + this._on( this.document, { + click: function( event ) { + if ( this._closeOnDocumentClick( event ) ) { + this.collapseAll( event ); + } + + // Reset the mouseHandled flag + this.mouseHandled = false; + } + }); + }, + + _destroy: function() { + // Destroy (sub)menus + this.element + .removeAttr( "aria-activedescendant" ) + .find( ".ui-menu" ).addBack() + .removeClass( "ui-menu ui-widget ui-widget-content ui-menu-icons ui-front" ) + .removeAttr( "role" ) + .removeAttr( "tabIndex" ) + .removeAttr( "aria-labelledby" ) + .removeAttr( "aria-expanded" ) + .removeAttr( "aria-hidden" ) + .removeAttr( "aria-disabled" ) + .removeUniqueId() + .show(); + + // Destroy menu items + this.element.find( ".ui-menu-item" ) + .removeClass( "ui-menu-item" ) + .removeAttr( "role" ) + .removeAttr( "aria-disabled" ) + .removeUniqueId() + .removeClass( "ui-state-hover" ) + .removeAttr( "tabIndex" ) + .removeAttr( "role" ) + .removeAttr( "aria-haspopup" ) + .children().each( function() { + var elem = $( this ); + if ( elem.data( "ui-menu-submenu-carat" ) ) { + elem.remove(); + } + }); + + // Destroy menu dividers + this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" ); + }, + + _keydown: function( event ) { + var match, prev, character, skip, + preventDefault = true; + + switch ( event.keyCode ) { + case $.ui.keyCode.PAGE_UP: + this.previousPage( event ); + break; + case $.ui.keyCode.PAGE_DOWN: + this.nextPage( event ); + break; + case $.ui.keyCode.HOME: + this._move( "first", "first", event ); + break; + case $.ui.keyCode.END: + this._move( "last", "last", event ); + break; + case $.ui.keyCode.UP: + this.previous( event ); + break; + case $.ui.keyCode.DOWN: + this.next( event ); + break; + case $.ui.keyCode.LEFT: + this.collapse( event ); + break; + case $.ui.keyCode.RIGHT: + if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { + this.expand( event ); + } + break; + case $.ui.keyCode.ENTER: + case $.ui.keyCode.SPACE: + this._activate( event ); + break; + case $.ui.keyCode.ESCAPE: + this.collapse( event ); + break; + default: + preventDefault = false; + prev = this.previousFilter || ""; + character = String.fromCharCode( event.keyCode ); + skip = false; + + clearTimeout( this.filterTimer ); + + if ( character === prev ) { + skip = true; + } else { + character = prev + character; + } + + match = this._filterMenuItems( character ); + match = skip && match.index( this.active.next() ) !== -1 ? + this.active.nextAll( ".ui-menu-item" ) : + match; + + // If no matches on the current filter, reset to the last character pressed + // to move down the menu to the first item that starts with that character + if ( !match.length ) { + character = String.fromCharCode( event.keyCode ); + match = this._filterMenuItems( character ); + } + + if ( match.length ) { + this.focus( event, match ); + this.previousFilter = character; + this.filterTimer = this._delay(function() { + delete this.previousFilter; + }, 1000 ); + } else { + delete this.previousFilter; + } + } + + if ( preventDefault ) { + event.preventDefault(); + } + }, + + _activate: function( event ) { + if ( !this.active.is( ".ui-state-disabled" ) ) { + if ( this.active.is( "[aria-haspopup='true']" ) ) { + this.expand( event ); + } else { + this.select( event ); + } + } + }, + + refresh: function() { + var menus, items, + that = this, + icon = this.options.icons.submenu, + submenus = this.element.find( this.options.menus ); + + this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length ); + + // Initialize nested menus + submenus.filter( ":not(.ui-menu)" ) + .addClass( "ui-menu ui-widget ui-widget-content ui-front" ) + .hide() + .attr({ + role: this.options.role, + "aria-hidden": "true", + "aria-expanded": "false" + }) + .each(function() { + var menu = $( this ), + item = menu.parent(), + submenuCarat = $( "<span>" ) + .addClass( "ui-menu-icon ui-icon " + icon ) + .data( "ui-menu-submenu-carat", true ); + + item + .attr( "aria-haspopup", "true" ) + .prepend( submenuCarat ); + menu.attr( "aria-labelledby", item.attr( "id" ) ); + }); + + menus = submenus.add( this.element ); + items = menus.find( this.options.items ); + + // Initialize menu-items containing spaces and/or dashes only as dividers + items.not( ".ui-menu-item" ).each(function() { + var item = $( this ); + if ( that._isDivider( item ) ) { + item.addClass( "ui-widget-content ui-menu-divider" ); + } + }); + + // Don't refresh list items that are already adapted + items.not( ".ui-menu-item, .ui-menu-divider" ) + .addClass( "ui-menu-item" ) + .uniqueId() + .attr({ + tabIndex: -1, + role: this._itemRole() + }); + + // Add aria-disabled attribute to any disabled menu item + items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" ); + + // If the active item has been removed, blur the menu + if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { + this.blur(); + } + }, + + _itemRole: function() { + return { + menu: "menuitem", + listbox: "option" + }[ this.options.role ]; + }, + + _setOption: function( key, value ) { + if ( key === "icons" ) { + this.element.find( ".ui-menu-icon" ) + .removeClass( this.options.icons.submenu ) + .addClass( value.submenu ); + } + if ( key === "disabled" ) { + this.element + .toggleClass( "ui-state-disabled", !!value ) + .attr( "aria-disabled", value ); + } + this._super( key, value ); + }, + + focus: function( event, item ) { + var nested, focused; + this.blur( event, event && event.type === "focus" ); + + this._scrollIntoView( item ); + + this.active = item.first(); + focused = this.active.addClass( "ui-state-focus" ).removeClass( "ui-state-active" ); + // Only update aria-activedescendant if there's a role + // otherwise we assume focus is managed elsewhere + if ( this.options.role ) { + this.element.attr( "aria-activedescendant", focused.attr( "id" ) ); + } + + // Highlight active parent menu item, if any + this.active + .parent() + .closest( ".ui-menu-item" ) + .addClass( "ui-state-active" ); + + if ( event && event.type === "keydown" ) { + this._close(); + } else { + this.timer = this._delay(function() { + this._close(); + }, this.delay ); + } + + nested = item.children( ".ui-menu" ); + if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) { + this._startOpening(nested); + } + this.activeMenu = item.parent(); + + this._trigger( "focus", event, { item: item } ); + }, + + _scrollIntoView: function( item ) { + var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight; + if ( this._hasScroll() ) { + borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0; + paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0; + offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop; + scroll = this.activeMenu.scrollTop(); + elementHeight = this.activeMenu.height(); + itemHeight = item.outerHeight(); + + if ( offset < 0 ) { + this.activeMenu.scrollTop( scroll + offset ); + } else if ( offset + itemHeight > elementHeight ) { + this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight ); + } + } + }, + + blur: function( event, fromFocus ) { + if ( !fromFocus ) { + clearTimeout( this.timer ); + } + + if ( !this.active ) { + return; + } + + this.active.removeClass( "ui-state-focus" ); + this.active = null; + + this._trigger( "blur", event, { item: this.active } ); + }, + + _startOpening: function( submenu ) { + clearTimeout( this.timer ); + + // Don't open if already open fixes a Firefox bug that caused a .5 pixel + // shift in the submenu position when mousing over the carat icon + if ( submenu.attr( "aria-hidden" ) !== "true" ) { + return; + } + + this.timer = this._delay(function() { + this._close(); + this._open( submenu ); + }, this.delay ); + }, + + _open: function( submenu ) { + var position = $.extend({ + of: this.active + }, this.options.position ); + + clearTimeout( this.timer ); + this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) ) + .hide() + .attr( "aria-hidden", "true" ); + + submenu + .show() + .removeAttr( "aria-hidden" ) + .attr( "aria-expanded", "true" ) + .position( position ); + }, + + collapseAll: function( event, all ) { + clearTimeout( this.timer ); + this.timer = this._delay(function() { + // If we were passed an event, look for the submenu that contains the event + var currentMenu = all ? this.element : + $( event && event.target ).closest( this.element.find( ".ui-menu" ) ); + + // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway + if ( !currentMenu.length ) { + currentMenu = this.element; + } + + this._close( currentMenu ); + + this.blur( event ); + this.activeMenu = currentMenu; + }, this.delay ); + }, + + // With no arguments, closes the currently active menu - if nothing is active + // it closes all menus. If passed an argument, it will search for menus BELOW + _close: function( startMenu ) { + if ( !startMenu ) { + startMenu = this.active ? this.active.parent() : this.element; + } + + startMenu + .find( ".ui-menu" ) + .hide() + .attr( "aria-hidden", "true" ) + .attr( "aria-expanded", "false" ) + .end() + .find( ".ui-state-active" ).not( ".ui-state-focus" ) + .removeClass( "ui-state-active" ); + }, + + _closeOnDocumentClick: function( event ) { + return !$( event.target ).closest( ".ui-menu" ).length; + }, + + _isDivider: function( item ) { + + // Match hyphen, em dash, en dash + return !/[^\-\u2014\u2013\s]/.test( item.text() ); + }, + + collapse: function( event ) { + var newItem = this.active && + this.active.parent().closest( ".ui-menu-item", this.element ); + if ( newItem && newItem.length ) { + this._close(); + this.focus( event, newItem ); + } + }, + + expand: function( event ) { + var newItem = this.active && + this.active + .children( ".ui-menu " ) + .find( this.options.items ) + .first(); + + if ( newItem && newItem.length ) { + this._open( newItem.parent() ); + + // Delay so Firefox will not hide activedescendant change in expanding submenu from AT + this._delay(function() { + this.focus( event, newItem ); + }); + } + }, + + next: function( event ) { + this._move( "next", "first", event ); + }, + + previous: function( event ) { + this._move( "prev", "last", event ); + }, + + isFirstItem: function() { + return this.active && !this.active.prevAll( ".ui-menu-item" ).length; + }, + + isLastItem: function() { + return this.active && !this.active.nextAll( ".ui-menu-item" ).length; + }, + + _move: function( direction, filter, event ) { + var next; + if ( this.active ) { + if ( direction === "first" || direction === "last" ) { + next = this.active + [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" ) + .eq( -1 ); + } else { + next = this.active + [ direction + "All" ]( ".ui-menu-item" ) + .eq( 0 ); + } + } + if ( !next || !next.length || !this.active ) { + next = this.activeMenu.find( this.options.items )[ filter ](); + } + + this.focus( event, next ); + }, + + nextPage: function( event ) { + var item, base, height; + + if ( !this.active ) { + this.next( event ); + return; + } + if ( this.isLastItem() ) { + return; + } + if ( this._hasScroll() ) { + base = this.active.offset().top; + height = this.element.height(); + this.active.nextAll( ".ui-menu-item" ).each(function() { + item = $( this ); + return item.offset().top - base - height < 0; + }); + + this.focus( event, item ); + } else { + this.focus( event, this.activeMenu.find( this.options.items ) + [ !this.active ? "first" : "last" ]() ); + } + }, + + previousPage: function( event ) { + var item, base, height; + if ( !this.active ) { + this.next( event ); + return; + } + if ( this.isFirstItem() ) { + return; + } + if ( this._hasScroll() ) { + base = this.active.offset().top; + height = this.element.height(); + this.active.prevAll( ".ui-menu-item" ).each(function() { + item = $( this ); + return item.offset().top - base + height > 0; + }); + + this.focus( event, item ); + } else { + this.focus( event, this.activeMenu.find( this.options.items ).first() ); + } + }, + + _hasScroll: function() { + return this.element.outerHeight() < this.element.prop( "scrollHeight" ); + }, + + select: function( event ) { + // TODO: It should never be possible to not have an active item at this + // point, but the tests don't trigger mouseenter before click. + this.active = this.active || $( event.target ).closest( ".ui-menu-item" ); + var ui = { item: this.active }; + if ( !this.active.has( ".ui-menu" ).length ) { + this.collapseAll( event, true ); + } + this._trigger( "select", event, ui ); + }, + + _filterMenuItems: function(character) { + var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ), + regex = new RegExp( "^" + escapedCharacter, "i" ); + + return this.activeMenu + .find( this.options.items ) + + // Only match on items, not dividers or other content (#10571) + .filter( ".ui-menu-item" ) + .filter(function() { + return regex.test( $.trim( $( this ).text() ) ); + }); + } +}); + + +/*! + * jQuery UI Autocomplete 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/autocomplete/ + */ + + +$.widget( "ui.autocomplete", { + version: "1.11.4", + defaultElement: "<input>", + options: { + appendTo: null, + autoFocus: false, + delay: 300, + minLength: 1, + position: { + my: "left top", + at: "left bottom", + collision: "none" + }, + source: null, + + // callbacks + change: null, + close: null, + focus: null, + open: null, + response: null, + search: null, + select: null + }, + + requestIndex: 0, + pending: 0, + + _create: function() { + // Some browsers only repeat keydown events, not keypress events, + // so we use the suppressKeyPress flag to determine if we've already + // handled the keydown event. #7269 + // Unfortunately the code for & in keypress is the same as the up arrow, + // so we use the suppressKeyPressRepeat flag to avoid handling keypress + // events when we know the keydown event was used to modify the + // search term. #7799 + var suppressKeyPress, suppressKeyPressRepeat, suppressInput, + nodeName = this.element[ 0 ].nodeName.toLowerCase(), + isTextarea = nodeName === "textarea", + isInput = nodeName === "input"; + + this.isMultiLine = + // Textareas are always multi-line + isTextarea ? true : + // Inputs are always single-line, even if inside a contentEditable element + // IE also treats inputs as contentEditable + isInput ? false : + // All other element types are determined by whether or not they're contentEditable + this.element.prop( "isContentEditable" ); + + this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; + this.isNewMenu = true; + + this.element + .addClass( "ui-autocomplete-input" ) + .attr( "autocomplete", "off" ); + + this._on( this.element, { + keydown: function( event ) { + if ( this.element.prop( "readOnly" ) ) { + suppressKeyPress = true; + suppressInput = true; + suppressKeyPressRepeat = true; + return; + } + + suppressKeyPress = false; + suppressInput = false; + suppressKeyPressRepeat = false; + var keyCode = $.ui.keyCode; + switch ( event.keyCode ) { + case keyCode.PAGE_UP: + suppressKeyPress = true; + this._move( "previousPage", event ); + break; + case keyCode.PAGE_DOWN: + suppressKeyPress = true; + this._move( "nextPage", event ); + break; + case keyCode.UP: + suppressKeyPress = true; + this._keyEvent( "previous", event ); + break; + case keyCode.DOWN: + suppressKeyPress = true; + this._keyEvent( "next", event ); + break; + case keyCode.ENTER: + // when menu is open and has focus + if ( this.menu.active ) { + // #6055 - Opera still allows the keypress to occur + // which causes forms to submit + suppressKeyPress = true; + event.preventDefault(); + this.menu.select( event ); + } + break; + case keyCode.TAB: + if ( this.menu.active ) { + this.menu.select( event ); + } + break; + case keyCode.ESCAPE: + if ( this.menu.element.is( ":visible" ) ) { + if ( !this.isMultiLine ) { + this._value( this.term ); + } + this.close( event ); + // Different browsers have different default behavior for escape + // Single press can mean undo or clear + // Double press in IE means clear the whole form + event.preventDefault(); + } + break; + default: + suppressKeyPressRepeat = true; + // search timeout should be triggered before the input value is changed + this._searchTimeout( event ); + break; + } + }, + keypress: function( event ) { + if ( suppressKeyPress ) { + suppressKeyPress = false; + if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { + event.preventDefault(); + } + return; + } + if ( suppressKeyPressRepeat ) { + return; + } + + // replicate some key handlers to allow them to repeat in Firefox and Opera + var keyCode = $.ui.keyCode; + switch ( event.keyCode ) { + case keyCode.PAGE_UP: + this._move( "previousPage", event ); + break; + case keyCode.PAGE_DOWN: + this._move( "nextPage", event ); + break; + case keyCode.UP: + this._keyEvent( "previous", event ); + break; + case keyCode.DOWN: + this._keyEvent( "next", event ); + break; + } + }, + input: function( event ) { + if ( suppressInput ) { + suppressInput = false; + event.preventDefault(); + return; + } + this._searchTimeout( event ); + }, + focus: function() { + this.selectedItem = null; + this.previous = this._value(); + }, + blur: function( event ) { + if ( this.cancelBlur ) { + delete this.cancelBlur; + return; + } + + clearTimeout( this.searching ); + this.close( event ); + this._change( event ); + } + }); + + this._initSource(); + this.menu = $( "<ul>" ) + .addClass( "ui-autocomplete ui-front" ) + .appendTo( this._appendTo() ) + .menu({ + // disable ARIA support, the live region takes care of that + role: null + }) + .hide() + .menu( "instance" ); + + this._on( this.menu.element, { + mousedown: function( event ) { + // prevent moving focus out of the text field + event.preventDefault(); + + // IE doesn't prevent moving focus even with event.preventDefault() + // so we set a flag to know when we should ignore the blur event + this.cancelBlur = true; + this._delay(function() { + delete this.cancelBlur; + }); + + // clicking on the scrollbar causes focus to shift to the body + // but we can't detect a mouseup or a click immediately afterward + // so we have to track the next mousedown and close the menu if + // the user clicks somewhere outside of the autocomplete + var menuElement = this.menu.element[ 0 ]; + if ( !$( event.target ).closest( ".ui-menu-item" ).length ) { + this._delay(function() { + var that = this; + this.document.one( "mousedown", function( event ) { + if ( event.target !== that.element[ 0 ] && + event.target !== menuElement && + !$.contains( menuElement, event.target ) ) { + that.close(); + } + }); + }); + } + }, + menufocus: function( event, ui ) { + var label, item; + // support: Firefox + // Prevent accidental activation of menu items in Firefox (#7024 #9118) + if ( this.isNewMenu ) { + this.isNewMenu = false; + if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) { + this.menu.blur(); + + this.document.one( "mousemove", function() { + $( event.target ).trigger( event.originalEvent ); + }); + + return; + } + } + + item = ui.item.data( "ui-autocomplete-item" ); + if ( false !== this._trigger( "focus", event, { item: item } ) ) { + // use value to match what will end up in the input, if it was a key event + if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) { + this._value( item.value ); + } + } + + // Announce the value in the liveRegion + label = ui.item.attr( "aria-label" ) || item.value; + if ( label && $.trim( label ).length ) { + this.liveRegion.children().hide(); + $( "<div>" ).text( label ).appendTo( this.liveRegion ); + } + }, + menuselect: function( event, ui ) { + var item = ui.item.data( "ui-autocomplete-item" ), + previous = this.previous; + + // only trigger when focus was lost (click on menu) + if ( this.element[ 0 ] !== this.document[ 0 ].activeElement ) { + this.element.focus(); + this.previous = previous; + // #6109 - IE triggers two focus events and the second + // is asynchronous, so we need to reset the previous + // term synchronously and asynchronously :-( + this._delay(function() { + this.previous = previous; + this.selectedItem = item; + }); + } + + if ( false !== this._trigger( "select", event, { item: item } ) ) { + this._value( item.value ); + } + // reset the term after the select event + // this allows custom select handling to work properly + this.term = this._value(); + + this.close( event ); + this.selectedItem = item; + } + }); + + this.liveRegion = $( "<span>", { + role: "status", + "aria-live": "assertive", + "aria-relevant": "additions" + }) + .addClass( "ui-helper-hidden-accessible" ) + .appendTo( this.document[ 0 ].body ); + + // turning off autocomplete prevents the browser from remembering the + // value when navigating through history, so we re-enable autocomplete + // if the page is unloaded before the widget is destroyed. #7790 + this._on( this.window, { + beforeunload: function() { + this.element.removeAttr( "autocomplete" ); + } + }); + }, + + _destroy: function() { + clearTimeout( this.searching ); + this.element + .removeClass( "ui-autocomplete-input" ) + .removeAttr( "autocomplete" ); + this.menu.element.remove(); + this.liveRegion.remove(); + }, + + _setOption: function( key, value ) { + this._super( key, value ); + if ( key === "source" ) { + this._initSource(); + } + if ( key === "appendTo" ) { + this.menu.element.appendTo( this._appendTo() ); + } + if ( key === "disabled" && value && this.xhr ) { + this.xhr.abort(); + } + }, + + _appendTo: function() { + var element = this.options.appendTo; + + if ( element ) { + element = element.jquery || element.nodeType ? + $( element ) : + this.document.find( element ).eq( 0 ); + } + + if ( !element || !element[ 0 ] ) { + element = this.element.closest( ".ui-front" ); + } + + if ( !element.length ) { + element = this.document[ 0 ].body; + } + + return element; + }, + + _initSource: function() { + var array, url, + that = this; + if ( $.isArray( this.options.source ) ) { + array = this.options.source; + this.source = function( request, response ) { + response( $.ui.autocomplete.filter( array, request.term ) ); + }; + } else if ( typeof this.options.source === "string" ) { + url = this.options.source; + this.source = function( request, response ) { + if ( that.xhr ) { + that.xhr.abort(); + } + that.xhr = $.ajax({ + url: url, + data: request, + dataType: "json", + success: function( data ) { + response( data ); + }, + error: function() { + response([]); + } + }); + }; + } else { + this.source = this.options.source; + } + }, + + _searchTimeout: function( event ) { + clearTimeout( this.searching ); + this.searching = this._delay(function() { + + // Search if the value has changed, or if the user retypes the same value (see #7434) + var equalValues = this.term === this._value(), + menuVisible = this.menu.element.is( ":visible" ), + modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey; + + if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) { + this.selectedItem = null; + this.search( null, event ); + } + }, this.options.delay ); + }, + + search: function( value, event ) { + value = value != null ? value : this._value(); + + // always save the actual value, not the one passed as an argument + this.term = this._value(); + + if ( value.length < this.options.minLength ) { + return this.close( event ); + } + + if ( this._trigger( "search", event ) === false ) { + return; + } + + return this._search( value ); + }, + + _search: function( value ) { + this.pending++; + this.element.addClass( "ui-autocomplete-loading" ); + this.cancelSearch = false; + + this.source( { term: value }, this._response() ); + }, + + _response: function() { + var index = ++this.requestIndex; + + return $.proxy(function( content ) { + if ( index === this.requestIndex ) { + this.__response( content ); + } + + this.pending--; + if ( !this.pending ) { + this.element.removeClass( "ui-autocomplete-loading" ); + } + }, this ); + }, + + __response: function( content ) { + if ( content ) { + content = this._normalize( content ); + } + this._trigger( "response", null, { content: content } ); + if ( !this.options.disabled && content && content.length && !this.cancelSearch ) { + this._suggest( content ); + this._trigger( "open" ); + } else { + // use ._close() instead of .close() so we don't cancel future searches + this._close(); + } + }, + + close: function( event ) { + this.cancelSearch = true; + this._close( event ); + }, + + _close: function( event ) { + if ( this.menu.element.is( ":visible" ) ) { + this.menu.element.hide(); + this.menu.blur(); + this.isNewMenu = true; + this._trigger( "close", event ); + } + }, + + _change: function( event ) { + if ( this.previous !== this._value() ) { + this._trigger( "change", event, { item: this.selectedItem } ); + } + }, + + _normalize: function( items ) { + // assume all items have the right format when the first item is complete + if ( items.length && items[ 0 ].label && items[ 0 ].value ) { + return items; + } + return $.map( items, function( item ) { + if ( typeof item === "string" ) { + return { + label: item, + value: item + }; + } + return $.extend( {}, item, { + label: item.label || item.value, + value: item.value || item.label + }); + }); + }, + + _suggest: function( items ) { + var ul = this.menu.element.empty(); + this._renderMenu( ul, items ); + this.isNewMenu = true; + this.menu.refresh(); + + // size and position menu + ul.show(); + this._resizeMenu(); + ul.position( $.extend({ + of: this.element + }, this.options.position ) ); + + if ( this.options.autoFocus ) { + this.menu.next(); + } + }, + + _resizeMenu: function() { + var ul = this.menu.element; + ul.outerWidth( Math.max( + // Firefox wraps long text (possibly a rounding bug) + // so we add 1px to avoid the wrapping (#7513) + ul.width( "" ).outerWidth() + 1, + this.element.outerWidth() + ) ); + }, + + _renderMenu: function( ul, items ) { + var that = this; + $.each( items, function( index, item ) { + that._renderItemData( ul, item ); + }); + }, + + _renderItemData: function( ul, item ) { + return this._renderItem( ul, item ).data( "ui-autocomplete-item", item ); + }, + + _renderItem: function( ul, item ) { + return $( "<li>" ).text( item.label ).appendTo( ul ); + }, + + _move: function( direction, event ) { + if ( !this.menu.element.is( ":visible" ) ) { + this.search( null, event ); + return; + } + if ( this.menu.isFirstItem() && /^previous/.test( direction ) || + this.menu.isLastItem() && /^next/.test( direction ) ) { + + if ( !this.isMultiLine ) { + this._value( this.term ); + } + + this.menu.blur(); + return; + } + this.menu[ direction ]( event ); + }, + + widget: function() { + return this.menu.element; + }, + + _value: function() { + return this.valueMethod.apply( this.element, arguments ); + }, + + _keyEvent: function( keyEvent, event ) { + if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { + this._move( keyEvent, event ); + + // prevents moving cursor to beginning/end of the text field in some browsers + event.preventDefault(); + } + } +}); + +$.extend( $.ui.autocomplete, { + escapeRegex: function( value ) { + return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ); + }, + filter: function( array, term ) { + var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" ); + return $.grep( array, function( value ) { + return matcher.test( value.label || value.value || value ); + }); + } +}); + +// live region extension, adding a `messages` option +// NOTE: This is an experimental API. We are still investigating +// a full solution for string manipulation and internationalization. +$.widget( "ui.autocomplete", $.ui.autocomplete, { + options: { + messages: { + noResults: "No search results.", + results: function( amount ) { + return amount + ( amount > 1 ? " results are" : " result is" ) + + " available, use up and down arrow keys to navigate."; + } + } + }, + + __response: function( content ) { + var message; + this._superApply( arguments ); + if ( this.options.disabled || this.cancelSearch ) { + return; + } + if ( content && content.length ) { + message = this.options.messages.results( content.length ); + } else { + message = this.options.messages.noResults; + } + this.liveRegion.children().hide(); + $( "<div>" ).text( message ).appendTo( this.liveRegion ); + } +}); + +var autocomplete = $.ui.autocomplete; + + +/*! + * jQuery UI Button 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/button/ + */ + + +var lastActive, + baseClasses = "ui-button ui-widget ui-state-default ui-corner-all", + typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only", + formResetHandler = function() { + var form = $( this ); + setTimeout(function() { + form.find( ":ui-button" ).button( "refresh" ); + }, 1 ); + }, + radioGroup = function( radio ) { + var name = radio.name, + form = radio.form, + radios = $( [] ); + if ( name ) { + name = name.replace( /'/g, "\\'" ); + if ( form ) { + radios = $( form ).find( "[name='" + name + "'][type=radio]" ); + } else { + radios = $( "[name='" + name + "'][type=radio]", radio.ownerDocument ) + .filter(function() { + return !this.form; + }); + } + } + return radios; + }; + +$.widget( "ui.button", { + version: "1.11.4", + defaultElement: "<button>", + options: { + disabled: null, + text: true, + label: null, + icons: { + primary: null, + secondary: null + } + }, + _create: function() { + this.element.closest( "form" ) + .unbind( "reset" + this.eventNamespace ) + .bind( "reset" + this.eventNamespace, formResetHandler ); + + if ( typeof this.options.disabled !== "boolean" ) { + this.options.disabled = !!this.element.prop( "disabled" ); + } else { + this.element.prop( "disabled", this.options.disabled ); + } + + this._determineButtonType(); + this.hasTitle = !!this.buttonElement.attr( "title" ); + + var that = this, + options = this.options, + toggleButton = this.type === "checkbox" || this.type === "radio", + activeClass = !toggleButton ? "ui-state-active" : ""; + + if ( options.label === null ) { + options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html()); + } + + this._hoverable( this.buttonElement ); + + this.buttonElement + .addClass( baseClasses ) + .attr( "role", "button" ) + .bind( "mouseenter" + this.eventNamespace, function() { + if ( options.disabled ) { + return; + } + if ( this === lastActive ) { + $( this ).addClass( "ui-state-active" ); + } + }) + .bind( "mouseleave" + this.eventNamespace, function() { + if ( options.disabled ) { + return; + } + $( this ).removeClass( activeClass ); + }) + .bind( "click" + this.eventNamespace, function( event ) { + if ( options.disabled ) { + event.preventDefault(); + event.stopImmediatePropagation(); + } + }); + + // Can't use _focusable() because the element that receives focus + // and the element that gets the ui-state-focus class are different + this._on({ + focus: function() { + this.buttonElement.addClass( "ui-state-focus" ); + }, + blur: function() { + this.buttonElement.removeClass( "ui-state-focus" ); + } + }); + + if ( toggleButton ) { + this.element.bind( "change" + this.eventNamespace, function() { + that.refresh(); + }); + } + + if ( this.type === "checkbox" ) { + this.buttonElement.bind( "click" + this.eventNamespace, function() { + if ( options.disabled ) { + return false; + } + }); + } else if ( this.type === "radio" ) { + this.buttonElement.bind( "click" + this.eventNamespace, function() { + if ( options.disabled ) { + return false; + } + $( this ).addClass( "ui-state-active" ); + that.buttonElement.attr( "aria-pressed", "true" ); + + var radio = that.element[ 0 ]; + radioGroup( radio ) + .not( radio ) + .map(function() { + return $( this ).button( "widget" )[ 0 ]; + }) + .removeClass( "ui-state-active" ) + .attr( "aria-pressed", "false" ); + }); + } else { + this.buttonElement + .bind( "mousedown" + this.eventNamespace, function() { + if ( options.disabled ) { + return false; + } + $( this ).addClass( "ui-state-active" ); + lastActive = this; + that.document.one( "mouseup", function() { + lastActive = null; + }); + }) + .bind( "mouseup" + this.eventNamespace, function() { + if ( options.disabled ) { + return false; + } + $( this ).removeClass( "ui-state-active" ); + }) + .bind( "keydown" + this.eventNamespace, function(event) { + if ( options.disabled ) { + return false; + } + if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) { + $( this ).addClass( "ui-state-active" ); + } + }) + // see #8559, we bind to blur here in case the button element loses + // focus between keydown and keyup, it would be left in an "active" state + .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() { + $( this ).removeClass( "ui-state-active" ); + }); + + if ( this.buttonElement.is("a") ) { + this.buttonElement.keyup(function(event) { + if ( event.keyCode === $.ui.keyCode.SPACE ) { + // TODO pass through original event correctly (just as 2nd argument doesn't work) + $( this ).click(); + } + }); + } + } + + this._setOption( "disabled", options.disabled ); + this._resetButton(); + }, + + _determineButtonType: function() { + var ancestor, labelSelector, checked; + + if ( this.element.is("[type=checkbox]") ) { + this.type = "checkbox"; + } else if ( this.element.is("[type=radio]") ) { + this.type = "radio"; + } else if ( this.element.is("input") ) { + this.type = "input"; + } else { + this.type = "button"; + } + + if ( this.type === "checkbox" || this.type === "radio" ) { + // we don't search against the document in case the element + // is disconnected from the DOM + ancestor = this.element.parents().last(); + labelSelector = "label[for='" + this.element.attr("id") + "']"; + this.buttonElement = ancestor.find( labelSelector ); + if ( !this.buttonElement.length ) { + ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings(); + this.buttonElement = ancestor.filter( labelSelector ); + if ( !this.buttonElement.length ) { + this.buttonElement = ancestor.find( labelSelector ); + } + } + this.element.addClass( "ui-helper-hidden-accessible" ); + + checked = this.element.is( ":checked" ); + if ( checked ) { + this.buttonElement.addClass( "ui-state-active" ); + } + this.buttonElement.prop( "aria-pressed", checked ); + } else { + this.buttonElement = this.element; + } + }, + + widget: function() { + return this.buttonElement; + }, + + _destroy: function() { + this.element + .removeClass( "ui-helper-hidden-accessible" ); + this.buttonElement + .removeClass( baseClasses + " ui-state-active " + typeClasses ) + .removeAttr( "role" ) + .removeAttr( "aria-pressed" ) + .html( this.buttonElement.find(".ui-button-text").html() ); + + if ( !this.hasTitle ) { + this.buttonElement.removeAttr( "title" ); + } + }, + + _setOption: function( key, value ) { + this._super( key, value ); + if ( key === "disabled" ) { + this.widget().toggleClass( "ui-state-disabled", !!value ); + this.element.prop( "disabled", !!value ); + if ( value ) { + if ( this.type === "checkbox" || this.type === "radio" ) { + this.buttonElement.removeClass( "ui-state-focus" ); + } else { + this.buttonElement.removeClass( "ui-state-focus ui-state-active" ); + } + } + return; + } + this._resetButton(); + }, + + refresh: function() { + //See #8237 & #8828 + var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" ); + + if ( isDisabled !== this.options.disabled ) { + this._setOption( "disabled", isDisabled ); + } + if ( this.type === "radio" ) { + radioGroup( this.element[0] ).each(function() { + if ( $( this ).is( ":checked" ) ) { + $( this ).button( "widget" ) + .addClass( "ui-state-active" ) + .attr( "aria-pressed", "true" ); + } else { + $( this ).button( "widget" ) + .removeClass( "ui-state-active" ) + .attr( "aria-pressed", "false" ); + } + }); + } else if ( this.type === "checkbox" ) { + if ( this.element.is( ":checked" ) ) { + this.buttonElement + .addClass( "ui-state-active" ) + .attr( "aria-pressed", "true" ); + } else { + this.buttonElement + .removeClass( "ui-state-active" ) + .attr( "aria-pressed", "false" ); + } + } + }, + + _resetButton: function() { + if ( this.type === "input" ) { + if ( this.options.label ) { + this.element.val( this.options.label ); + } + return; + } + var buttonElement = this.buttonElement.removeClass( typeClasses ), + buttonText = $( "<span></span>", this.document[0] ) + .addClass( "ui-button-text" ) + .html( this.options.label ) + .appendTo( buttonElement.empty() ) + .text(), + icons = this.options.icons, + multipleIcons = icons.primary && icons.secondary, + buttonClasses = []; + + if ( icons.primary || icons.secondary ) { + if ( this.options.text ) { + buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) ); + } + + if ( icons.primary ) { + buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" ); + } + + if ( icons.secondary ) { + buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" ); + } + + if ( !this.options.text ) { + buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" ); + + if ( !this.hasTitle ) { + buttonElement.attr( "title", $.trim( buttonText ) ); + } + } + } else { + buttonClasses.push( "ui-button-text-only" ); + } + buttonElement.addClass( buttonClasses.join( " " ) ); + } +}); + +$.widget( "ui.buttonset", { + version: "1.11.4", + options: { + items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)" + }, + + _create: function() { + this.element.addClass( "ui-buttonset" ); + }, + + _init: function() { + this.refresh(); + }, + + _setOption: function( key, value ) { + if ( key === "disabled" ) { + this.buttons.button( "option", key, value ); + } + + this._super( key, value ); + }, + + refresh: function() { + var rtl = this.element.css( "direction" ) === "rtl", + allButtons = this.element.find( this.options.items ), + existingButtons = allButtons.filter( ":ui-button" ); + + // Initialize new buttons + allButtons.not( ":ui-button" ).button(); + + // Refresh existing buttons + existingButtons.button( "refresh" ); + + this.buttons = allButtons + .map(function() { + return $( this ).button( "widget" )[ 0 ]; + }) + .removeClass( "ui-corner-all ui-corner-left ui-corner-right" ) + .filter( ":first" ) + .addClass( rtl ? "ui-corner-right" : "ui-corner-left" ) + .end() + .filter( ":last" ) + .addClass( rtl ? "ui-corner-left" : "ui-corner-right" ) + .end() + .end(); + }, + + _destroy: function() { + this.element.removeClass( "ui-buttonset" ); + this.buttons + .map(function() { + return $( this ).button( "widget" )[ 0 ]; + }) + .removeClass( "ui-corner-left ui-corner-right" ) + .end() + .button( "destroy" ); + } +}); + +var button = $.ui.button; + + +/*! + * jQuery UI Datepicker 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/datepicker/ + */ + + +$.extend($.ui, { datepicker: { version: "1.11.4" } }); + +var datepicker_instActive; + +function datepicker_getZindex( elem ) { + var position, value; + while ( elem.length && elem[ 0 ] !== document ) { + // Ignore z-index if position is set to a value where z-index is ignored by the browser + // This makes behavior of this function consistent across browsers + // WebKit always returns auto if the element is positioned + position = elem.css( "position" ); + if ( position === "absolute" || position === "relative" || position === "fixed" ) { + // IE returns 0 when zIndex is not specified + // other browsers return a string + // we ignore the case of nested elements with an explicit value of 0 + // <div style="z-index: -10;"><div style="z-index: 0;"></div></div> + value = parseInt( elem.css( "zIndex" ), 10 ); + if ( !isNaN( value ) && value !== 0 ) { + return value; + } + } + elem = elem.parent(); + } + + return 0; +} +/* Date picker manager. + Use the singleton instance of this class, $.datepicker, to interact with the date picker. + Settings for (groups of) date pickers are maintained in an instance object, + allowing multiple different settings on the same page. */ + +function Datepicker() { + this._curInst = null; // The current instance in use + this._keyEvent = false; // If the last event was a key event + this._disabledInputs = []; // List of date picker inputs that have been disabled + this._datepickerShowing = false; // True if the popup picker is showing , false if not + this._inDialog = false; // True if showing within a "dialog", false if not + this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division + this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class + this._appendClass = "ui-datepicker-append"; // The name of the append marker class + this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class + this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class + this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class + this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class + this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class + this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class + this.regional = []; // Available regional settings, indexed by language code + this.regional[""] = { // Default regional settings + closeText: "Done", // Display text for close link + prevText: "Prev", // Display text for previous month link + nextText: "Next", // Display text for next month link + currentText: "Today", // Display text for current month link + monthNames: ["January","February","March","April","May","June", + "July","August","September","October","November","December"], // Names of months for drop-down and formatting + monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting + dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting + dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting + dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday + weekHeader: "Wk", // Column header for week of the year + dateFormat: "mm/dd/yy", // See format options on parseDate + firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... + isRTL: false, // True if right-to-left language, false if left-to-right + showMonthAfterYear: false, // True if the year select precedes month, false for month then year + yearSuffix: "" // Additional text to append to the year in the month headers + }; + this._defaults = { // Global defaults for all the date picker instances + showOn: "focus", // "focus" for popup on focus, + // "button" for trigger button, or "both" for either + showAnim: "fadeIn", // Name of jQuery animation for popup + showOptions: {}, // Options for enhanced animations + defaultDate: null, // Used when field is blank: actual date, + // +/-number for offset from today, null for today + appendText: "", // Display text following the input box, e.g. showing the format + buttonText: "...", // Text for trigger button + buttonImage: "", // URL for trigger button image + buttonImageOnly: false, // True if the image appears alone, false if it appears on a button + hideIfNoPrevNext: false, // True to hide next/previous month links + // if not applicable, false to just disable them + navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links + gotoCurrent: false, // True if today link goes back to current selection instead + changeMonth: false, // True if month can be selected directly, false if only prev/next + changeYear: false, // True if year can be selected directly, false if only prev/next + yearRange: "c-10:c+10", // Range of years to display in drop-down, + // either relative to today's year (-nn:+nn), relative to currently displayed year + // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n) + showOtherMonths: false, // True to show dates in other months, false to leave blank + selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable + showWeek: false, // True to show week of the year, false to not show it + calculateWeek: this.iso8601Week, // How to calculate the week of the year, + // takes a Date and returns the number of the week for it + shortYearCutoff: "+10", // Short year values < this are in the current century, + // > this are in the previous century, + // string value starting with "+" for current year + value + minDate: null, // The earliest selectable date, or null for no limit + maxDate: null, // The latest selectable date, or null for no limit + duration: "fast", // Duration of display/closure + beforeShowDay: null, // Function that takes a date and returns an array with + // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "", + // [2] = cell title (optional), e.g. $.datepicker.noWeekends + beforeShow: null, // Function that takes an input field and + // returns a set of custom settings for the date picker + onSelect: null, // Define a callback function when a date is selected + onChangeMonthYear: null, // Define a callback function when the month or year is changed + onClose: null, // Define a callback function when the datepicker is closed + numberOfMonths: 1, // Number of months to show at a time + showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) + stepMonths: 1, // Number of months to step back/forward + stepBigMonths: 12, // Number of months to step back/forward for the big links + altField: "", // Selector for an alternate field to store selected dates into + altFormat: "", // The date format to use for the alternate field + constrainInput: true, // The input is constrained by the current date format + showButtonPanel: false, // True to show button panel, false to not show it + autoSize: false, // True to size the input for the date format, false to leave as is + disabled: false // The initial disabled state + }; + $.extend(this._defaults, this.regional[""]); + this.regional.en = $.extend( true, {}, this.regional[ "" ]); + this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en ); + this.dpDiv = datepicker_bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")); +} + +$.extend(Datepicker.prototype, { + /* Class name added to elements to indicate already configured with a date picker. */ + markerClassName: "hasDatepicker", + + //Keep track of the maximum number of rows displayed (see #7043) + maxRows: 4, + + // TODO rename to "widget" when switching to widget factory + _widgetDatepicker: function() { + return this.dpDiv; + }, + + /* Override the default settings for all instances of the date picker. + * @param settings object - the new settings to use as defaults (anonymous object) + * @return the manager object + */ + setDefaults: function(settings) { + datepicker_extendRemove(this._defaults, settings || {}); + return this; + }, + + /* Attach the date picker to a jQuery selection. + * @param target element - the target input field or division or span + * @param settings object - the new settings to use for this date picker instance (anonymous) + */ + _attachDatepicker: function(target, settings) { + var nodeName, inline, inst; + nodeName = target.nodeName.toLowerCase(); + inline = (nodeName === "div" || nodeName === "span"); + if (!target.id) { + this.uuid += 1; + target.id = "dp" + this.uuid; + } + inst = this._newInst($(target), inline); + inst.settings = $.extend({}, settings || {}); + if (nodeName === "input") { + this._connectDatepicker(target, inst); + } else if (inline) { + this._inlineDatepicker(target, inst); + } + }, + + /* Create a new instance object. */ + _newInst: function(target, inline) { + var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars + return {id: id, input: target, // associated target + selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection + drawMonth: 0, drawYear: 0, // month being drawn + inline: inline, // is datepicker inline or not + dpDiv: (!inline ? this.dpDiv : // presentation div + datepicker_bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))}; + }, + + /* Attach the date picker to an input field. */ + _connectDatepicker: function(target, inst) { + var input = $(target); + inst.append = $([]); + inst.trigger = $([]); + if (input.hasClass(this.markerClassName)) { + return; + } + this._attachments(input, inst); + input.addClass(this.markerClassName).keydown(this._doKeyDown). + keypress(this._doKeyPress).keyup(this._doKeyUp); + this._autoSize(inst); + $.data(target, "datepicker", inst); + //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665) + if( inst.settings.disabled ) { + this._disableDatepicker( target ); + } + }, + + /* Make attachments based on settings. */ + _attachments: function(input, inst) { + var showOn, buttonText, buttonImage, + appendText = this._get(inst, "appendText"), + isRTL = this._get(inst, "isRTL"); + + if (inst.append) { + inst.append.remove(); + } + if (appendText) { + inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>"); + input[isRTL ? "before" : "after"](inst.append); + } + + input.unbind("focus", this._showDatepicker); + + if (inst.trigger) { + inst.trigger.remove(); + } + + showOn = this._get(inst, "showOn"); + if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field + input.focus(this._showDatepicker); + } + if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked + buttonText = this._get(inst, "buttonText"); + buttonImage = this._get(inst, "buttonImage"); + inst.trigger = $(this._get(inst, "buttonImageOnly") ? + $("<img/>").addClass(this._triggerClass). + attr({ src: buttonImage, alt: buttonText, title: buttonText }) : + $("<button type='button'></button>").addClass(this._triggerClass). + html(!buttonImage ? buttonText : $("<img/>").attr( + { src:buttonImage, alt:buttonText, title:buttonText }))); + input[isRTL ? "before" : "after"](inst.trigger); + inst.trigger.click(function() { + if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) { + $.datepicker._hideDatepicker(); + } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) { + $.datepicker._hideDatepicker(); + $.datepicker._showDatepicker(input[0]); + } else { + $.datepicker._showDatepicker(input[0]); + } + return false; + }); + } + }, + + /* Apply the maximum length for the date format. */ + _autoSize: function(inst) { + if (this._get(inst, "autoSize") && !inst.inline) { + var findMax, max, maxI, i, + date = new Date(2009, 12 - 1, 20), // Ensure double digits + dateFormat = this._get(inst, "dateFormat"); + + if (dateFormat.match(/[DM]/)) { + findMax = function(names) { + max = 0; + maxI = 0; + for (i = 0; i < names.length; i++) { + if (names[i].length > max) { + max = names[i].length; + maxI = i; + } + } + return maxI; + }; + date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ? + "monthNames" : "monthNamesShort")))); + date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ? + "dayNames" : "dayNamesShort"))) + 20 - date.getDay()); + } + inst.input.attr("size", this._formatDate(inst, date).length); + } + }, + + /* Attach an inline date picker to a div. */ + _inlineDatepicker: function(target, inst) { + var divSpan = $(target); + if (divSpan.hasClass(this.markerClassName)) { + return; + } + divSpan.addClass(this.markerClassName).append(inst.dpDiv); + $.data(target, "datepicker", inst); + this._setDate(inst, this._getDefaultDate(inst), true); + this._updateDatepicker(inst); + this._updateAlternate(inst); + //If disabled option is true, disable the datepicker before showing it (see ticket #5665) + if( inst.settings.disabled ) { + this._disableDatepicker( target ); + } + // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements + // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height + inst.dpDiv.css( "display", "block" ); + }, + + /* Pop-up the date picker in a "dialog" box. + * @param input element - ignored + * @param date string or Date - the initial date to display + * @param onSelect function - the function to call when a date is selected + * @param settings object - update the dialog date picker instance's settings (anonymous object) + * @param pos int[2] - coordinates for the dialog's position within the screen or + * event - with x/y coordinates or + * leave empty for default (screen centre) + * @return the manager object + */ + _dialogDatepicker: function(input, date, onSelect, settings, pos) { + var id, browserWidth, browserHeight, scrollX, scrollY, + inst = this._dialogInst; // internal instance + + if (!inst) { + this.uuid += 1; + id = "dp" + this.uuid; + this._dialogInput = $("<input type='text' id='" + id + + "' style='position: absolute; top: -100px; width: 0px;'/>"); + this._dialogInput.keydown(this._doKeyDown); + $("body").append(this._dialogInput); + inst = this._dialogInst = this._newInst(this._dialogInput, false); + inst.settings = {}; + $.data(this._dialogInput[0], "datepicker", inst); + } + datepicker_extendRemove(inst.settings, settings || {}); + date = (date && date.constructor === Date ? this._formatDate(inst, date) : date); + this._dialogInput.val(date); + + this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null); + if (!this._pos) { + browserWidth = document.documentElement.clientWidth; + browserHeight = document.documentElement.clientHeight; + scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; + scrollY = document.documentElement.scrollTop || document.body.scrollTop; + this._pos = // should use actual width/height below + [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY]; + } + + // move input on screen for focus, but hidden behind dialog + this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px"); + inst.settings.onSelect = onSelect; + this._inDialog = true; + this.dpDiv.addClass(this._dialogClass); + this._showDatepicker(this._dialogInput[0]); + if ($.blockUI) { + $.blockUI(this.dpDiv); + } + $.data(this._dialogInput[0], "datepicker", inst); + return this; + }, + + /* Detach a datepicker from its control. + * @param target element - the target input field or division or span + */ + _destroyDatepicker: function(target) { + var nodeName, + $target = $(target), + inst = $.data(target, "datepicker"); + + if (!$target.hasClass(this.markerClassName)) { + return; + } + + nodeName = target.nodeName.toLowerCase(); + $.removeData(target, "datepicker"); + if (nodeName === "input") { + inst.append.remove(); + inst.trigger.remove(); + $target.removeClass(this.markerClassName). + unbind("focus", this._showDatepicker). + unbind("keydown", this._doKeyDown). + unbind("keypress", this._doKeyPress). + unbind("keyup", this._doKeyUp); + } else if (nodeName === "div" || nodeName === "span") { + $target.removeClass(this.markerClassName).empty(); + } + + if ( datepicker_instActive === inst ) { + datepicker_instActive = null; + } + }, + + /* Enable the date picker to a jQuery selection. + * @param target element - the target input field or division or span + */ + _enableDatepicker: function(target) { + var nodeName, inline, + $target = $(target), + inst = $.data(target, "datepicker"); + + if (!$target.hasClass(this.markerClassName)) { + return; + } + + nodeName = target.nodeName.toLowerCase(); + if (nodeName === "input") { + target.disabled = false; + inst.trigger.filter("button"). + each(function() { this.disabled = false; }).end(). + filter("img").css({opacity: "1.0", cursor: ""}); + } else if (nodeName === "div" || nodeName === "span") { + inline = $target.children("." + this._inlineClass); + inline.children().removeClass("ui-state-disabled"); + inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). + prop("disabled", false); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value === target ? null : value); }); // delete entry + }, + + /* Disable the date picker to a jQuery selection. + * @param target element - the target input field or division or span + */ + _disableDatepicker: function(target) { + var nodeName, inline, + $target = $(target), + inst = $.data(target, "datepicker"); + + if (!$target.hasClass(this.markerClassName)) { + return; + } + + nodeName = target.nodeName.toLowerCase(); + if (nodeName === "input") { + target.disabled = true; + inst.trigger.filter("button"). + each(function() { this.disabled = true; }).end(). + filter("img").css({opacity: "0.5", cursor: "default"}); + } else if (nodeName === "div" || nodeName === "span") { + inline = $target.children("." + this._inlineClass); + inline.children().addClass("ui-state-disabled"); + inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). + prop("disabled", true); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value === target ? null : value); }); // delete entry + this._disabledInputs[this._disabledInputs.length] = target; + }, + + /* Is the first field in a jQuery collection disabled as a datepicker? + * @param target element - the target input field or division or span + * @return boolean - true if disabled, false if enabled + */ + _isDisabledDatepicker: function(target) { + if (!target) { + return false; + } + for (var i = 0; i < this._disabledInputs.length; i++) { + if (this._disabledInputs[i] === target) { + return true; + } + } + return false; + }, + + /* Retrieve the instance data for the target control. + * @param target element - the target input field or division or span + * @return object - the associated instance data + * @throws error if a jQuery problem getting data + */ + _getInst: function(target) { + try { + return $.data(target, "datepicker"); + } + catch (err) { + throw "Missing instance data for this datepicker"; + } + }, + + /* Update or retrieve the settings for a date picker attached to an input field or division. + * @param target element - the target input field or division or span + * @param name object - the new settings to update or + * string - the name of the setting to change or retrieve, + * when retrieving also "all" for all instance settings or + * "defaults" for all global defaults + * @param value any - the new value for the setting + * (omit if above is an object or to retrieve a value) + */ + _optionDatepicker: function(target, name, value) { + var settings, date, minDate, maxDate, + inst = this._getInst(target); + + if (arguments.length === 2 && typeof name === "string") { + return (name === "defaults" ? $.extend({}, $.datepicker._defaults) : + (inst ? (name === "all" ? $.extend({}, inst.settings) : + this._get(inst, name)) : null)); + } + + settings = name || {}; + if (typeof name === "string") { + settings = {}; + settings[name] = value; + } + + if (inst) { + if (this._curInst === inst) { + this._hideDatepicker(); + } + + date = this._getDateDatepicker(target, true); + minDate = this._getMinMaxDate(inst, "min"); + maxDate = this._getMinMaxDate(inst, "max"); + datepicker_extendRemove(inst.settings, settings); + // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided + if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) { + inst.settings.minDate = this._formatDate(inst, minDate); + } + if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) { + inst.settings.maxDate = this._formatDate(inst, maxDate); + } + if ( "disabled" in settings ) { + if ( settings.disabled ) { + this._disableDatepicker(target); + } else { + this._enableDatepicker(target); + } + } + this._attachments($(target), inst); + this._autoSize(inst); + this._setDate(inst, date); + this._updateAlternate(inst); + this._updateDatepicker(inst); + } + }, + + // change method deprecated + _changeDatepicker: function(target, name, value) { + this._optionDatepicker(target, name, value); + }, + + /* Redraw the date picker attached to an input field or division. + * @param target element - the target input field or division or span + */ + _refreshDatepicker: function(target) { + var inst = this._getInst(target); + if (inst) { + this._updateDatepicker(inst); + } + }, + + /* Set the dates for a jQuery selection. + * @param target element - the target input field or division or span + * @param date Date - the new date + */ + _setDateDatepicker: function(target, date) { + var inst = this._getInst(target); + if (inst) { + this._setDate(inst, date); + this._updateDatepicker(inst); + this._updateAlternate(inst); + } + }, + + /* Get the date(s) for the first entry in a jQuery selection. + * @param target element - the target input field or division or span + * @param noDefault boolean - true if no default date is to be used + * @return Date - the current date + */ + _getDateDatepicker: function(target, noDefault) { + var inst = this._getInst(target); + if (inst && !inst.inline) { + this._setDateFromField(inst, noDefault); + } + return (inst ? this._getDate(inst) : null); + }, + + /* Handle keystrokes. */ + _doKeyDown: function(event) { + var onSelect, dateStr, sel, + inst = $.datepicker._getInst(event.target), + handled = true, + isRTL = inst.dpDiv.is(".ui-datepicker-rtl"); + + inst._keyEvent = true; + if ($.datepicker._datepickerShowing) { + switch (event.keyCode) { + case 9: $.datepicker._hideDatepicker(); + handled = false; + break; // hide on tab out + case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." + + $.datepicker._currentClass + ")", inst.dpDiv); + if (sel[0]) { + $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]); + } + + onSelect = $.datepicker._get(inst, "onSelect"); + if (onSelect) { + dateStr = $.datepicker._formatDate(inst); + + // trigger custom callback + onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); + } else { + $.datepicker._hideDatepicker(); + } + + return false; // don't submit the form + case 27: $.datepicker._hideDatepicker(); + break; // hide on escape + case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, "stepBigMonths") : + -$.datepicker._get(inst, "stepMonths")), "M"); + break; // previous month/year on page up/+ ctrl + case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, "stepBigMonths") : + +$.datepicker._get(inst, "stepMonths")), "M"); + break; // next month/year on page down/+ ctrl + case 35: if (event.ctrlKey || event.metaKey) { + $.datepicker._clearDate(event.target); + } + handled = event.ctrlKey || event.metaKey; + break; // clear on ctrl or command +end + case 36: if (event.ctrlKey || event.metaKey) { + $.datepicker._gotoToday(event.target); + } + handled = event.ctrlKey || event.metaKey; + break; // current on ctrl or command +home + case 37: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D"); + } + handled = event.ctrlKey || event.metaKey; + // -1 day on ctrl or command +left + if (event.originalEvent.altKey) { + $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, "stepBigMonths") : + -$.datepicker._get(inst, "stepMonths")), "M"); + } + // next month/year on alt +left on Mac + break; + case 38: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, -7, "D"); + } + handled = event.ctrlKey || event.metaKey; + break; // -1 week on ctrl or command +up + case 39: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D"); + } + handled = event.ctrlKey || event.metaKey; + // +1 day on ctrl or command +right + if (event.originalEvent.altKey) { + $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, "stepBigMonths") : + +$.datepicker._get(inst, "stepMonths")), "M"); + } + // next month/year on alt +right + break; + case 40: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, +7, "D"); + } + handled = event.ctrlKey || event.metaKey; + break; // +1 week on ctrl or command +down + default: handled = false; + } + } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home + $.datepicker._showDatepicker(this); + } else { + handled = false; + } + + if (handled) { + event.preventDefault(); + event.stopPropagation(); + } + }, + + /* Filter entered characters - based on date format. */ + _doKeyPress: function(event) { + var chars, chr, + inst = $.datepicker._getInst(event.target); + + if ($.datepicker._get(inst, "constrainInput")) { + chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat")); + chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode); + return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1); + } + }, + + /* Synchronise manual entry and field/alternate field. */ + _doKeyUp: function(event) { + var date, + inst = $.datepicker._getInst(event.target); + + if (inst.input.val() !== inst.lastVal) { + try { + date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"), + (inst.input ? inst.input.val() : null), + $.datepicker._getFormatConfig(inst)); + + if (date) { // only if valid + $.datepicker._setDateFromField(inst); + $.datepicker._updateAlternate(inst); + $.datepicker._updateDatepicker(inst); + } + } + catch (err) { + } + } + return true; + }, + + /* Pop-up the date picker for a given input field. + * If false returned from beforeShow event handler do not show. + * @param input element - the input field attached to the date picker or + * event - if triggered by focus + */ + _showDatepicker: function(input) { + input = input.target || input; + if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger + input = $("input", input.parentNode)[0]; + } + + if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here + return; + } + + var inst, beforeShow, beforeShowSettings, isFixed, + offset, showAnim, duration; + + inst = $.datepicker._getInst(input); + if ($.datepicker._curInst && $.datepicker._curInst !== inst) { + $.datepicker._curInst.dpDiv.stop(true, true); + if ( inst && $.datepicker._datepickerShowing ) { + $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] ); + } + } + + beforeShow = $.datepicker._get(inst, "beforeShow"); + beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {}; + if(beforeShowSettings === false){ + return; + } + datepicker_extendRemove(inst.settings, beforeShowSettings); + + inst.lastVal = null; + $.datepicker._lastInput = input; + $.datepicker._setDateFromField(inst); + + if ($.datepicker._inDialog) { // hide cursor + input.value = ""; + } + if (!$.datepicker._pos) { // position below input + $.datepicker._pos = $.datepicker._findPos(input); + $.datepicker._pos[1] += input.offsetHeight; // add the height + } + + isFixed = false; + $(input).parents().each(function() { + isFixed |= $(this).css("position") === "fixed"; + return !isFixed; + }); + + offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; + $.datepicker._pos = null; + //to avoid flashes on Firefox + inst.dpDiv.empty(); + // determine sizing offscreen + inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"}); + $.datepicker._updateDatepicker(inst); + // fix width for dynamic number of date pickers + // and adjust position before showing + offset = $.datepicker._checkOffset(inst, offset, isFixed); + inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ? + "static" : (isFixed ? "fixed" : "absolute")), display: "none", + left: offset.left + "px", top: offset.top + "px"}); + + if (!inst.inline) { + showAnim = $.datepicker._get(inst, "showAnim"); + duration = $.datepicker._get(inst, "duration"); + inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 ); + $.datepicker._datepickerShowing = true; + + if ( $.effects && $.effects.effect[ showAnim ] ) { + inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration); + } else { + inst.dpDiv[showAnim || "show"](showAnim ? duration : null); + } + + if ( $.datepicker._shouldFocusInput( inst ) ) { + inst.input.focus(); + } + + $.datepicker._curInst = inst; + } + }, + + /* Generate the date picker content. */ + _updateDatepicker: function(inst) { + this.maxRows = 4; //Reset the max number of rows being displayed (see #7043) + datepicker_instActive = inst; // for delegate hover events + inst.dpDiv.empty().append(this._generateHTML(inst)); + this._attachHandlers(inst); + + var origyearshtml, + numMonths = this._getNumberOfMonths(inst), + cols = numMonths[1], + width = 17, + activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" ); + + if ( activeCell.length > 0 ) { + datepicker_handleMouseover.apply( activeCell.get( 0 ) ); + } + + inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""); + if (cols > 1) { + inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em"); + } + inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") + + "Class"]("ui-datepicker-multi"); + inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") + + "Class"]("ui-datepicker-rtl"); + + if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) { + inst.input.focus(); + } + + // deffered render of the years select (to avoid flashes on Firefox) + if( inst.yearshtml ){ + origyearshtml = inst.yearshtml; + setTimeout(function(){ + //assure that inst.yearshtml didn't change. + if( origyearshtml === inst.yearshtml && inst.yearshtml ){ + inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml); + } + origyearshtml = inst.yearshtml = null; + }, 0); + } + }, + + // #6694 - don't focus the input if it's already focused + // this breaks the change event in IE + // Support: IE and jQuery <1.9 + _shouldFocusInput: function( inst ) { + return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" ); + }, + + /* Check positioning to remain on screen. */ + _checkOffset: function(inst, offset, isFixed) { + var dpWidth = inst.dpDiv.outerWidth(), + dpHeight = inst.dpDiv.outerHeight(), + inputWidth = inst.input ? inst.input.outerWidth() : 0, + inputHeight = inst.input ? inst.input.outerHeight() : 0, + viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()), + viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop()); + + offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0); + offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0; + offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; + + // now check if datepicker is showing outside window viewport - move to a better place if so. + offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? + Math.abs(offset.left + dpWidth - viewWidth) : 0); + offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? + Math.abs(dpHeight + inputHeight) : 0); + + return offset; + }, + + /* Find an object's position on the screen. */ + _findPos: function(obj) { + var position, + inst = this._getInst(obj), + isRTL = this._get(inst, "isRTL"); + + while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) { + obj = obj[isRTL ? "previousSibling" : "nextSibling"]; + } + + position = $(obj).offset(); + return [position.left, position.top]; + }, + + /* Hide the date picker from view. + * @param input element - the input field attached to the date picker + */ + _hideDatepicker: function(input) { + var showAnim, duration, postProcess, onClose, + inst = this._curInst; + + if (!inst || (input && inst !== $.data(input, "datepicker"))) { + return; + } + + if (this._datepickerShowing) { + showAnim = this._get(inst, "showAnim"); + duration = this._get(inst, "duration"); + postProcess = function() { + $.datepicker._tidyDialog(inst); + }; + + // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed + if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) { + inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess); + } else { + inst.dpDiv[(showAnim === "slideDown" ? "slideUp" : + (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess); + } + + if (!showAnim) { + postProcess(); + } + this._datepickerShowing = false; + + onClose = this._get(inst, "onClose"); + if (onClose) { + onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]); + } + + this._lastInput = null; + if (this._inDialog) { + this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" }); + if ($.blockUI) { + $.unblockUI(); + $("body").append(this.dpDiv); + } + } + this._inDialog = false; + } + }, + + /* Tidy up after a dialog display. */ + _tidyDialog: function(inst) { + inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar"); + }, + + /* Close date picker if clicked elsewhere. */ + _checkExternalClick: function(event) { + if (!$.datepicker._curInst) { + return; + } + + var $target = $(event.target), + inst = $.datepicker._getInst($target[0]); + + if ( ( ( $target[0].id !== $.datepicker._mainDivId && + $target.parents("#" + $.datepicker._mainDivId).length === 0 && + !$target.hasClass($.datepicker.markerClassName) && + !$target.closest("." + $.datepicker._triggerClass).length && + $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) || + ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) { + $.datepicker._hideDatepicker(); + } + }, + + /* Adjust one of the date sub-fields. */ + _adjustDate: function(id, offset, period) { + var target = $(id), + inst = this._getInst(target[0]); + + if (this._isDisabledDatepicker(target[0])) { + return; + } + this._adjustInstDate(inst, offset + + (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning + period); + this._updateDatepicker(inst); + }, + + /* Action for current link. */ + _gotoToday: function(id) { + var date, + target = $(id), + inst = this._getInst(target[0]); + + if (this._get(inst, "gotoCurrent") && inst.currentDay) { + inst.selectedDay = inst.currentDay; + inst.drawMonth = inst.selectedMonth = inst.currentMonth; + inst.drawYear = inst.selectedYear = inst.currentYear; + } else { + date = new Date(); + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + } + this._notifyChange(inst); + this._adjustDate(target); + }, + + /* Action for selecting a new month/year. */ + _selectMonthYear: function(id, select, period) { + var target = $(id), + inst = this._getInst(target[0]); + + inst["selected" + (period === "M" ? "Month" : "Year")] = + inst["draw" + (period === "M" ? "Month" : "Year")] = + parseInt(select.options[select.selectedIndex].value,10); + + this._notifyChange(inst); + this._adjustDate(target); + }, + + /* Action for selecting a day. */ + _selectDay: function(id, month, year, td) { + var inst, + target = $(id); + + if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) { + return; + } + + inst = this._getInst(target[0]); + inst.selectedDay = inst.currentDay = $("a", td).html(); + inst.selectedMonth = inst.currentMonth = month; + inst.selectedYear = inst.currentYear = year; + this._selectDate(id, this._formatDate(inst, + inst.currentDay, inst.currentMonth, inst.currentYear)); + }, + + /* Erase the input field and hide the date picker. */ + _clearDate: function(id) { + var target = $(id); + this._selectDate(target, ""); + }, + + /* Update the input field with the selected date. */ + _selectDate: function(id, dateStr) { + var onSelect, + target = $(id), + inst = this._getInst(target[0]); + + dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); + if (inst.input) { + inst.input.val(dateStr); + } + this._updateAlternate(inst); + + onSelect = this._get(inst, "onSelect"); + if (onSelect) { + onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback + } else if (inst.input) { + inst.input.trigger("change"); // fire the change event + } + + if (inst.inline){ + this._updateDatepicker(inst); + } else { + this._hideDatepicker(); + this._lastInput = inst.input[0]; + if (typeof(inst.input[0]) !== "object") { + inst.input.focus(); // restore focus + } + this._lastInput = null; + } + }, + + /* Update any alternate field to synchronise with the main field. */ + _updateAlternate: function(inst) { + var altFormat, date, dateStr, + altField = this._get(inst, "altField"); + + if (altField) { // update alternate field too + altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat"); + date = this._getDate(inst); + dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst)); + $(altField).each(function() { $(this).val(dateStr); }); + } + }, + + /* Set as beforeShowDay function to prevent selection of weekends. + * @param date Date - the date to customise + * @return [boolean, string] - is this date selectable?, what is its CSS class? + */ + noWeekends: function(date) { + var day = date.getDay(); + return [(day > 0 && day < 6), ""]; + }, + + /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. + * @param date Date - the date to get the week for + * @return number - the number of the week within the year that contains this date + */ + iso8601Week: function(date) { + var time, + checkDate = new Date(date.getTime()); + + // Find Thursday of this week starting on Monday + checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); + + time = checkDate.getTime(); + checkDate.setMonth(0); // Compare with Jan 1 + checkDate.setDate(1); + return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; + }, + + /* Parse a string value into a date object. + * See formatDate below for the possible formats. + * + * @param format string - the expected format of the date + * @param value string - the date in the above format + * @param settings Object - attributes include: + * shortYearCutoff number - the cutoff year for determining the century (optional) + * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + * dayNames string[7] - names of the days from Sunday (optional) + * monthNamesShort string[12] - abbreviated names of the months (optional) + * monthNames string[12] - names of the months (optional) + * @return Date - the extracted date value or null if value is blank + */ + parseDate: function (format, value, settings) { + if (format == null || value == null) { + throw "Invalid arguments"; + } + + value = (typeof value === "object" ? value.toString() : value + ""); + if (value === "") { + return null; + } + + var iFormat, dim, extra, + iValue = 0, + shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff, + shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp : + new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)), + dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort, + dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames, + monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort, + monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames, + year = -1, + month = -1, + day = -1, + doy = -1, + literal = false, + date, + // Check whether a format character is doubled + lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); + if (matches) { + iFormat++; + } + return matches; + }, + // Extract a number from the string value + getNumber = function(match) { + var isDoubled = lookAhead(match), + size = (match === "@" ? 14 : (match === "!" ? 20 : + (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))), + minSize = (match === "y" ? size : 1), + digits = new RegExp("^\\d{" + minSize + "," + size + "}"), + num = value.substring(iValue).match(digits); + if (!num) { + throw "Missing number at position " + iValue; + } + iValue += num[0].length; + return parseInt(num[0], 10); + }, + // Extract a name from the string value and convert to an index + getName = function(match, shortNames, longNames) { + var index = -1, + names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) { + return [ [k, v] ]; + }).sort(function (a, b) { + return -(a[1].length - b[1].length); + }); + + $.each(names, function (i, pair) { + var name = pair[1]; + if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) { + index = pair[0]; + iValue += name.length; + return false; + } + }); + if (index !== -1) { + return index + 1; + } else { + throw "Unknown name at position " + iValue; + } + }, + // Confirm that a literal character matches the string value + checkLiteral = function() { + if (value.charAt(iValue) !== format.charAt(iFormat)) { + throw "Unexpected literal at position " + iValue; + } + iValue++; + }; + + for (iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === "'" && !lookAhead("'")) { + literal = false; + } else { + checkLiteral(); + } + } else { + switch (format.charAt(iFormat)) { + case "d": + day = getNumber("d"); + break; + case "D": + getName("D", dayNamesShort, dayNames); + break; + case "o": + doy = getNumber("o"); + break; + case "m": + month = getNumber("m"); + break; + case "M": + month = getName("M", monthNamesShort, monthNames); + break; + case "y": + year = getNumber("y"); + break; + case "@": + date = new Date(getNumber("@")); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); + break; + case "!": + date = new Date((getNumber("!") - this._ticksTo1970) / 10000); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); + break; + case "'": + if (lookAhead("'")){ + checkLiteral(); + } else { + literal = true; + } + break; + default: + checkLiteral(); + } + } + } + + if (iValue < value.length){ + extra = value.substr(iValue); + if (!/^\s+/.test(extra)) { + throw "Extra/unparsed characters found in date: " + extra; + } + } + + if (year === -1) { + year = new Date().getFullYear(); + } else if (year < 100) { + year += new Date().getFullYear() - new Date().getFullYear() % 100 + + (year <= shortYearCutoff ? 0 : -100); + } + + if (doy > -1) { + month = 1; + day = doy; + do { + dim = this._getDaysInMonth(year, month - 1); + if (day <= dim) { + break; + } + month++; + day -= dim; + } while (true); + } + + date = this._daylightSavingAdjust(new Date(year, month - 1, day)); + if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) { + throw "Invalid date"; // E.g. 31/02/00 + } + return date; + }, + + /* Standard date formats. */ + ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601) + COOKIE: "D, dd M yy", + ISO_8601: "yy-mm-dd", + RFC_822: "D, d M y", + RFC_850: "DD, dd-M-y", + RFC_1036: "D, d M y", + RFC_1123: "D, d M yy", + RFC_2822: "D, d M yy", + RSS: "D, d M y", // RFC 822 + TICKS: "!", + TIMESTAMP: "@", + W3C: "yy-mm-dd", // ISO 8601 + + _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + + Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000), + + /* Format a date object into a string value. + * The format can be combinations of the following: + * d - day of month (no leading zero) + * dd - day of month (two digit) + * o - day of year (no leading zeros) + * oo - day of year (three digit) + * D - day name short + * DD - day name long + * m - month of year (no leading zero) + * mm - month of year (two digit) + * M - month name short + * MM - month name long + * y - year (two digit) + * yy - year (four digit) + * @ - Unix timestamp (ms since 01/01/1970) + * ! - Windows ticks (100ns since 01/01/0001) + * "..." - literal text + * '' - single quote + * + * @param format string - the desired format of the date + * @param date Date - the date value to format + * @param settings Object - attributes include: + * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + * dayNames string[7] - names of the days from Sunday (optional) + * monthNamesShort string[12] - abbreviated names of the months (optional) + * monthNames string[12] - names of the months (optional) + * @return string - the date in the above format + */ + formatDate: function (format, date, settings) { + if (!date) { + return ""; + } + + var iFormat, + dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort, + dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames, + monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort, + monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames, + // Check whether a format character is doubled + lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); + if (matches) { + iFormat++; + } + return matches; + }, + // Format a number, with leading zero if necessary + formatNumber = function(match, value, len) { + var num = "" + value; + if (lookAhead(match)) { + while (num.length < len) { + num = "0" + num; + } + } + return num; + }, + // Format a name, short or long as requested + formatName = function(match, value, shortNames, longNames) { + return (lookAhead(match) ? longNames[value] : shortNames[value]); + }, + output = "", + literal = false; + + if (date) { + for (iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === "'" && !lookAhead("'")) { + literal = false; + } else { + output += format.charAt(iFormat); + } + } else { + switch (format.charAt(iFormat)) { + case "d": + output += formatNumber("d", date.getDate(), 2); + break; + case "D": + output += formatName("D", date.getDay(), dayNamesShort, dayNames); + break; + case "o": + output += formatNumber("o", + Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3); + break; + case "m": + output += formatNumber("m", date.getMonth() + 1, 2); + break; + case "M": + output += formatName("M", date.getMonth(), monthNamesShort, monthNames); + break; + case "y": + output += (lookAhead("y") ? date.getFullYear() : + (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100); + break; + case "@": + output += date.getTime(); + break; + case "!": + output += date.getTime() * 10000 + this._ticksTo1970; + break; + case "'": + if (lookAhead("'")) { + output += "'"; + } else { + literal = true; + } + break; + default: + output += format.charAt(iFormat); + } + } + } + } + return output; + }, + + /* Extract all possible characters from the date format. */ + _possibleChars: function (format) { + var iFormat, + chars = "", + literal = false, + // Check whether a format character is doubled + lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); + if (matches) { + iFormat++; + } + return matches; + }; + + for (iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === "'" && !lookAhead("'")) { + literal = false; + } else { + chars += format.charAt(iFormat); + } + } else { + switch (format.charAt(iFormat)) { + case "d": case "m": case "y": case "@": + chars += "0123456789"; + break; + case "D": case "M": + return null; // Accept anything + case "'": + if (lookAhead("'")) { + chars += "'"; + } else { + literal = true; + } + break; + default: + chars += format.charAt(iFormat); + } + } + } + return chars; + }, + + /* Get a setting value, defaulting if necessary. */ + _get: function(inst, name) { + return inst.settings[name] !== undefined ? + inst.settings[name] : this._defaults[name]; + }, + + /* Parse existing date and initialise date picker. */ + _setDateFromField: function(inst, noDefault) { + if (inst.input.val() === inst.lastVal) { + return; + } + + var dateFormat = this._get(inst, "dateFormat"), + dates = inst.lastVal = inst.input ? inst.input.val() : null, + defaultDate = this._getDefaultDate(inst), + date = defaultDate, + settings = this._getFormatConfig(inst); + + try { + date = this.parseDate(dateFormat, dates, settings) || defaultDate; + } catch (event) { + dates = (noDefault ? "" : dates); + } + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + inst.currentDay = (dates ? date.getDate() : 0); + inst.currentMonth = (dates ? date.getMonth() : 0); + inst.currentYear = (dates ? date.getFullYear() : 0); + this._adjustInstDate(inst); + }, + + /* Retrieve the default date shown on opening. */ + _getDefaultDate: function(inst) { + return this._restrictMinMax(inst, + this._determineDate(inst, this._get(inst, "defaultDate"), new Date())); + }, + + /* A date may be specified as an exact value or a relative one. */ + _determineDate: function(inst, date, defaultDate) { + var offsetNumeric = function(offset) { + var date = new Date(); + date.setDate(date.getDate() + offset); + return date; + }, + offsetString = function(offset) { + try { + return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"), + offset, $.datepicker._getFormatConfig(inst)); + } + catch (e) { + // Ignore + } + + var date = (offset.toLowerCase().match(/^c/) ? + $.datepicker._getDate(inst) : null) || new Date(), + year = date.getFullYear(), + month = date.getMonth(), + day = date.getDate(), + pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g, + matches = pattern.exec(offset); + + while (matches) { + switch (matches[2] || "d") { + case "d" : case "D" : + day += parseInt(matches[1],10); break; + case "w" : case "W" : + day += parseInt(matches[1],10) * 7; break; + case "m" : case "M" : + month += parseInt(matches[1],10); + day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); + break; + case "y": case "Y" : + year += parseInt(matches[1],10); + day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); + break; + } + matches = pattern.exec(offset); + } + return new Date(year, month, day); + }, + newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) : + (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime())))); + + newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate); + if (newDate) { + newDate.setHours(0); + newDate.setMinutes(0); + newDate.setSeconds(0); + newDate.setMilliseconds(0); + } + return this._daylightSavingAdjust(newDate); + }, + + /* Handle switch to/from daylight saving. + * Hours may be non-zero on daylight saving cut-over: + * > 12 when midnight changeover, but then cannot generate + * midnight datetime, so jump to 1AM, otherwise reset. + * @param date (Date) the date to check + * @return (Date) the corrected date + */ + _daylightSavingAdjust: function(date) { + if (!date) { + return null; + } + date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); + return date; + }, + + /* Set the date(s) directly. */ + _setDate: function(inst, date, noChange) { + var clear = !date, + origMonth = inst.selectedMonth, + origYear = inst.selectedYear, + newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date())); + + inst.selectedDay = inst.currentDay = newDate.getDate(); + inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth(); + inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear(); + if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) { + this._notifyChange(inst); + } + this._adjustInstDate(inst); + if (inst.input) { + inst.input.val(clear ? "" : this._formatDate(inst)); + } + }, + + /* Retrieve the date(s) directly. */ + _getDate: function(inst) { + var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null : + this._daylightSavingAdjust(new Date( + inst.currentYear, inst.currentMonth, inst.currentDay))); + return startDate; + }, + + /* Attach the onxxx handlers. These are declared statically so + * they work with static code transformers like Caja. + */ + _attachHandlers: function(inst) { + var stepMonths = this._get(inst, "stepMonths"), + id = "#" + inst.id.replace( /\\\\/g, "\\" ); + inst.dpDiv.find("[data-handler]").map(function () { + var handler = { + prev: function () { + $.datepicker._adjustDate(id, -stepMonths, "M"); + }, + next: function () { + $.datepicker._adjustDate(id, +stepMonths, "M"); + }, + hide: function () { + $.datepicker._hideDatepicker(); + }, + today: function () { + $.datepicker._gotoToday(id); + }, + selectDay: function () { + $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this); + return false; + }, + selectMonth: function () { + $.datepicker._selectMonthYear(id, this, "M"); + return false; + }, + selectYear: function () { + $.datepicker._selectMonthYear(id, this, "Y"); + return false; + } + }; + $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]); + }); + }, + + /* Generate the HTML for the current state of the date picker. */ + _generateHTML: function(inst) { + var maxDraw, prevText, prev, nextText, next, currentText, gotoDate, + controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin, + monthNames, monthNamesShort, beforeShowDay, showOtherMonths, + selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate, + cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows, + printDate, dRow, tbody, daySettings, otherMonth, unselectable, + tempDate = new Date(), + today = this._daylightSavingAdjust( + new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time + isRTL = this._get(inst, "isRTL"), + showButtonPanel = this._get(inst, "showButtonPanel"), + hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"), + navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"), + numMonths = this._getNumberOfMonths(inst), + showCurrentAtPos = this._get(inst, "showCurrentAtPos"), + stepMonths = this._get(inst, "stepMonths"), + isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1), + currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) : + new Date(inst.currentYear, inst.currentMonth, inst.currentDay))), + minDate = this._getMinMaxDate(inst, "min"), + maxDate = this._getMinMaxDate(inst, "max"), + drawMonth = inst.drawMonth - showCurrentAtPos, + drawYear = inst.drawYear; + + if (drawMonth < 0) { + drawMonth += 12; + drawYear--; + } + if (maxDate) { + maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(), + maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate())); + maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw); + while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) { + drawMonth--; + if (drawMonth < 0) { + drawMonth = 11; + drawYear--; + } + } + } + inst.drawMonth = drawMonth; + inst.drawYear = drawYear; + + prevText = this._get(inst, "prevText"); + prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText, + this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)), + this._getFormatConfig(inst))); + + prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? + "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" + + " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" : + (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+ prevText +"'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>")); + + nextText = this._get(inst, "nextText"); + nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText, + this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)), + this._getFormatConfig(inst))); + + next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? + "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" + + " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" : + (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+ nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>")); + + currentText = this._get(inst, "currentText"); + gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today); + currentText = (!navigationAsDateFormat ? currentText : + this.formatDate(currentText, gotoDate, this._getFormatConfig(inst))); + + controls = (!inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" + + this._get(inst, "closeText") + "</button>" : ""); + + buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") + + (this._isInRange(inst, gotoDate) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" + + ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : ""; + + firstDay = parseInt(this._get(inst, "firstDay"),10); + firstDay = (isNaN(firstDay) ? 0 : firstDay); + + showWeek = this._get(inst, "showWeek"); + dayNames = this._get(inst, "dayNames"); + dayNamesMin = this._get(inst, "dayNamesMin"); + monthNames = this._get(inst, "monthNames"); + monthNamesShort = this._get(inst, "monthNamesShort"); + beforeShowDay = this._get(inst, "beforeShowDay"); + showOtherMonths = this._get(inst, "showOtherMonths"); + selectOtherMonths = this._get(inst, "selectOtherMonths"); + defaultDate = this._getDefaultDate(inst); + html = ""; + dow; + for (row = 0; row < numMonths[0]; row++) { + group = ""; + this.maxRows = 4; + for (col = 0; col < numMonths[1]; col++) { + selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay)); + cornerClass = " ui-corner-all"; + calender = ""; + if (isMultiMonth) { + calender += "<div class='ui-datepicker-group"; + if (numMonths[1] > 1) { + switch (col) { + case 0: calender += " ui-datepicker-group-first"; + cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break; + case numMonths[1]-1: calender += " ui-datepicker-group-last"; + cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break; + default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break; + } + } + calender += "'>"; + } + calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" + + (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") + + (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") + + this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, + row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers + "</div><table class='ui-datepicker-calendar'><thead>" + + "<tr>"; + thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : ""); + for (dow = 0; dow < 7; dow++) { // days of the week + day = (dow + firstDay) % 7; + thead += "<th scope='col'" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" + + "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>"; + } + calender += thead + "</tr></thead><tbody>"; + daysInMonth = this._getDaysInMonth(drawYear, drawMonth); + if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) { + inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); + } + leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; + curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate + numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043) + this.maxRows = numRows; + printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); + for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows + calender += "<tr>"; + tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" + + this._get(inst, "calculateWeek")(printDate) + "</td>"); + for (dow = 0; dow < 7; dow++) { // create date picker days + daySettings = (beforeShowDay ? + beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]); + otherMonth = (printDate.getMonth() !== drawMonth); + unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] || + (minDate && printDate < minDate) || (maxDate && printDate > maxDate); + tbody += "<td class='" + + ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends + (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months + ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key + (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ? + // or defaultDate is current printedDate and defaultDate is selectedDate + " " + this._dayOverClass : "") + // highlight selected day + (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days + (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates + (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day + (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different) + ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "'") + "'" : "") + // cell title + (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions + (otherMonth && !showOtherMonths ? " " : // display for other months + (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" + + (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") + + (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day + (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months + "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date + printDate.setDate(printDate.getDate() + 1); + printDate = this._daylightSavingAdjust(printDate); + } + calender += tbody + "</tr>"; + } + drawMonth++; + if (drawMonth > 11) { + drawMonth = 0; + drawYear++; + } + calender += "</tbody></table>" + (isMultiMonth ? "</div>" + + ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : ""); + group += calender; + } + html += group; + } + html += buttonPanel; + inst._keyEvent = false; + return html; + }, + + /* Generate the month and year header. */ + _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, + secondary, monthNames, monthNamesShort) { + + var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear, + changeMonth = this._get(inst, "changeMonth"), + changeYear = this._get(inst, "changeYear"), + showMonthAfterYear = this._get(inst, "showMonthAfterYear"), + html = "<div class='ui-datepicker-title'>", + monthHtml = ""; + + // month selection + if (secondary || !changeMonth) { + monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>"; + } else { + inMinYear = (minDate && minDate.getFullYear() === drawYear); + inMaxYear = (maxDate && maxDate.getFullYear() === drawYear); + monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>"; + for ( month = 0; month < 12; month++) { + if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) { + monthHtml += "<option value='" + month + "'" + + (month === drawMonth ? " selected='selected'" : "") + + ">" + monthNamesShort[month] + "</option>"; + } + } + monthHtml += "</select>"; + } + + if (!showMonthAfterYear) { + html += monthHtml + (secondary || !(changeMonth && changeYear) ? " " : ""); + } + + // year selection + if ( !inst.yearshtml ) { + inst.yearshtml = ""; + if (secondary || !changeYear) { + html += "<span class='ui-datepicker-year'>" + drawYear + "</span>"; + } else { + // determine range of years to display + years = this._get(inst, "yearRange").split(":"); + thisYear = new Date().getFullYear(); + determineYear = function(value) { + var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) : + (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) : + parseInt(value, 10))); + return (isNaN(year) ? thisYear : year); + }; + year = determineYear(years[0]); + endYear = Math.max(year, determineYear(years[1] || "")); + year = (minDate ? Math.max(year, minDate.getFullYear()) : year); + endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); + inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>"; + for (; year <= endYear; year++) { + inst.yearshtml += "<option value='" + year + "'" + + (year === drawYear ? " selected='selected'" : "") + + ">" + year + "</option>"; + } + inst.yearshtml += "</select>"; + + html += inst.yearshtml; + inst.yearshtml = null; + } + } + + html += this._get(inst, "yearSuffix"); + if (showMonthAfterYear) { + html += (secondary || !(changeMonth && changeYear) ? " " : "") + monthHtml; + } + html += "</div>"; // Close datepicker_header + return html; + }, + + /* Adjust one of the date sub-fields. */ + _adjustInstDate: function(inst, offset, period) { + var year = inst.drawYear + (period === "Y" ? offset : 0), + month = inst.drawMonth + (period === "M" ? offset : 0), + day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0), + date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day))); + + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + if (period === "M" || period === "Y") { + this._notifyChange(inst); + } + }, + + /* Ensure a date is within any min/max bounds. */ + _restrictMinMax: function(inst, date) { + var minDate = this._getMinMaxDate(inst, "min"), + maxDate = this._getMinMaxDate(inst, "max"), + newDate = (minDate && date < minDate ? minDate : date); + return (maxDate && newDate > maxDate ? maxDate : newDate); + }, + + /* Notify change of month/year. */ + _notifyChange: function(inst) { + var onChange = this._get(inst, "onChangeMonthYear"); + if (onChange) { + onChange.apply((inst.input ? inst.input[0] : null), + [inst.selectedYear, inst.selectedMonth + 1, inst]); + } + }, + + /* Determine the number of months to show. */ + _getNumberOfMonths: function(inst) { + var numMonths = this._get(inst, "numberOfMonths"); + return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths)); + }, + + /* Determine the current maximum date - ensure no time components are set. */ + _getMinMaxDate: function(inst, minMax) { + return this._determineDate(inst, this._get(inst, minMax + "Date"), null); + }, + + /* Find the number of days in a given month. */ + _getDaysInMonth: function(year, month) { + return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate(); + }, + + /* Find the day of the week of the first of a month. */ + _getFirstDayOfMonth: function(year, month) { + return new Date(year, month, 1).getDay(); + }, + + /* Determines if we should allow a "next/prev" month display change. */ + _canAdjustMonth: function(inst, offset, curYear, curMonth) { + var numMonths = this._getNumberOfMonths(inst), + date = this._daylightSavingAdjust(new Date(curYear, + curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1)); + + if (offset < 0) { + date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); + } + return this._isInRange(inst, date); + }, + + /* Is the given date in the accepted range? */ + _isInRange: function(inst, date) { + var yearSplit, currentYear, + minDate = this._getMinMaxDate(inst, "min"), + maxDate = this._getMinMaxDate(inst, "max"), + minYear = null, + maxYear = null, + years = this._get(inst, "yearRange"); + if (years){ + yearSplit = years.split(":"); + currentYear = new Date().getFullYear(); + minYear = parseInt(yearSplit[0], 10); + maxYear = parseInt(yearSplit[1], 10); + if ( yearSplit[0].match(/[+\-].*/) ) { + minYear += currentYear; + } + if ( yearSplit[1].match(/[+\-].*/) ) { + maxYear += currentYear; + } + } + + return ((!minDate || date.getTime() >= minDate.getTime()) && + (!maxDate || date.getTime() <= maxDate.getTime()) && + (!minYear || date.getFullYear() >= minYear) && + (!maxYear || date.getFullYear() <= maxYear)); + }, + + /* Provide the configuration settings for formatting/parsing. */ + _getFormatConfig: function(inst) { + var shortYearCutoff = this._get(inst, "shortYearCutoff"); + shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff : + new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); + return {shortYearCutoff: shortYearCutoff, + dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"), + monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")}; + }, + + /* Format the given date for display. */ + _formatDate: function(inst, day, month, year) { + if (!day) { + inst.currentDay = inst.selectedDay; + inst.currentMonth = inst.selectedMonth; + inst.currentYear = inst.selectedYear; + } + var date = (day ? (typeof day === "object" ? day : + this._daylightSavingAdjust(new Date(year, month, day))) : + this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); + return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst)); + } +}); + +/* + * Bind hover events for datepicker elements. + * Done via delegate so the binding only occurs once in the lifetime of the parent div. + * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. + */ +function datepicker_bindHover(dpDiv) { + var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a"; + return dpDiv.delegate(selector, "mouseout", function() { + $(this).removeClass("ui-state-hover"); + if (this.className.indexOf("ui-datepicker-prev") !== -1) { + $(this).removeClass("ui-datepicker-prev-hover"); + } + if (this.className.indexOf("ui-datepicker-next") !== -1) { + $(this).removeClass("ui-datepicker-next-hover"); + } + }) + .delegate( selector, "mouseover", datepicker_handleMouseover ); +} + +function datepicker_handleMouseover() { + if (!$.datepicker._isDisabledDatepicker( datepicker_instActive.inline? datepicker_instActive.dpDiv.parent()[0] : datepicker_instActive.input[0])) { + $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"); + $(this).addClass("ui-state-hover"); + if (this.className.indexOf("ui-datepicker-prev") !== -1) { + $(this).addClass("ui-datepicker-prev-hover"); + } + if (this.className.indexOf("ui-datepicker-next") !== -1) { + $(this).addClass("ui-datepicker-next-hover"); + } + } +} + +/* jQuery extend now ignores nulls! */ +function datepicker_extendRemove(target, props) { + $.extend(target, props); + for (var name in props) { + if (props[name] == null) { + target[name] = props[name]; + } + } + return target; +} + +/* Invoke the datepicker functionality. + @param options string - a command, optionally followed by additional parameters or + Object - settings for attaching new datepicker functionality + @return jQuery object */ +$.fn.datepicker = function(options){ + + /* Verify an empty collection wasn't passed - Fixes #6976 */ + if ( !this.length ) { + return this; + } + + /* Initialise the date picker. */ + if (!$.datepicker.initialized) { + $(document).mousedown($.datepicker._checkExternalClick); + $.datepicker.initialized = true; + } + + /* Append datepicker main container to body if not exist. */ + if ($("#"+$.datepicker._mainDivId).length === 0) { + $("body").append($.datepicker.dpDiv); + } + + var otherArgs = Array.prototype.slice.call(arguments, 1); + if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) { + return $.datepicker["_" + options + "Datepicker"]. + apply($.datepicker, [this[0]].concat(otherArgs)); + } + if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") { + return $.datepicker["_" + options + "Datepicker"]. + apply($.datepicker, [this[0]].concat(otherArgs)); + } + return this.each(function() { + typeof options === "string" ? + $.datepicker["_" + options + "Datepicker"]. + apply($.datepicker, [this].concat(otherArgs)) : + $.datepicker._attachDatepicker(this, options); + }); +}; + +$.datepicker = new Datepicker(); // singleton instance +$.datepicker.initialized = false; +$.datepicker.uuid = new Date().getTime(); +$.datepicker.version = "1.11.4"; + +var datepicker = $.datepicker; + + +/*! + * jQuery UI Draggable 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/draggable/ + */ + + +$.widget("ui.draggable", $.ui.mouse, { + version: "1.11.4", + widgetEventPrefix: "drag", + options: { + addClasses: true, + appendTo: "parent", + axis: false, + connectToSortable: false, + containment: false, + cursor: "auto", + cursorAt: false, + grid: false, + handle: false, + helper: "original", + iframeFix: false, + opacity: false, + refreshPositions: false, + revert: false, + revertDuration: 500, + scope: "default", + scroll: true, + scrollSensitivity: 20, + scrollSpeed: 20, + snap: false, + snapMode: "both", + snapTolerance: 20, + stack: false, + zIndex: false, + + // callbacks + drag: null, + start: null, + stop: null + }, + _create: function() { + + if ( this.options.helper === "original" ) { + this._setPositionRelative(); + } + if (this.options.addClasses){ + this.element.addClass("ui-draggable"); + } + if (this.options.disabled){ + this.element.addClass("ui-draggable-disabled"); + } + this._setHandleClassName(); + + this._mouseInit(); + }, + + _setOption: function( key, value ) { + this._super( key, value ); + if ( key === "handle" ) { + this._removeHandleClassName(); + this._setHandleClassName(); + } + }, + + _destroy: function() { + if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) { + this.destroyOnClear = true; + return; + } + this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" ); + this._removeHandleClassName(); + this._mouseDestroy(); + }, + + _mouseCapture: function(event) { + var o = this.options; + + this._blurActiveElement( event ); + + // among others, prevent a drag on a resizable-handle + if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) { + return false; + } + + //Quit if we're not on a valid handle + this.handle = this._getHandle(event); + if (!this.handle) { + return false; + } + + this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix ); + + return true; + + }, + + _blockFrames: function( selector ) { + this.iframeBlocks = this.document.find( selector ).map(function() { + var iframe = $( this ); + + return $( "<div>" ) + .css( "position", "absolute" ) + .appendTo( iframe.parent() ) + .outerWidth( iframe.outerWidth() ) + .outerHeight( iframe.outerHeight() ) + .offset( iframe.offset() )[ 0 ]; + }); + }, + + _unblockFrames: function() { + if ( this.iframeBlocks ) { + this.iframeBlocks.remove(); + delete this.iframeBlocks; + } + }, + + _blurActiveElement: function( event ) { + var document = this.document[ 0 ]; + + // Only need to blur if the event occurred on the draggable itself, see #10527 + if ( !this.handleElement.is( event.target ) ) { + return; + } + + // support: IE9 + // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe> + try { + + // Support: IE9, IE10 + // If the <body> is blurred, IE will switch windows, see #9520 + if ( document.activeElement && document.activeElement.nodeName.toLowerCase() !== "body" ) { + + // Blur any element that currently has focus, see #4261 + $( document.activeElement ).blur(); + } + } catch ( error ) {} + }, + + _mouseStart: function(event) { + + var o = this.options; + + //Create and append the visible helper + this.helper = this._createHelper(event); + + this.helper.addClass("ui-draggable-dragging"); + + //Cache the helper size + this._cacheHelperProportions(); + + //If ddmanager is used for droppables, set the global draggable + if ($.ui.ddmanager) { + $.ui.ddmanager.current = this; + } + + /* + * - Position generation - + * This block generates everything position related - it's the core of draggables. + */ + + //Cache the margins of the original element + this._cacheMargins(); + + //Store the helper's css position + this.cssPosition = this.helper.css( "position" ); + this.scrollParent = this.helper.scrollParent( true ); + this.offsetParent = this.helper.offsetParent(); + this.hasFixedAncestor = this.helper.parents().filter(function() { + return $( this ).css( "position" ) === "fixed"; + }).length > 0; + + //The element's absolute position on the page minus margins + this.positionAbs = this.element.offset(); + this._refreshOffsets( event ); + + //Generate the original position + this.originalPosition = this.position = this._generatePosition( event, false ); + this.originalPageX = event.pageX; + this.originalPageY = event.pageY; + + //Adjust the mouse offset relative to the helper if "cursorAt" is supplied + (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); + + //Set a containment if given in the options + this._setContainment(); + + //Trigger event + callbacks + if (this._trigger("start", event) === false) { + this._clear(); + return false; + } + + //Recache the helper size + this._cacheHelperProportions(); + + //Prepare the droppable offsets + if ($.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(this, event); + } + + // Reset helper's right/bottom css if they're set and set explicit width/height instead + // as this prevents resizing of elements with right/bottom set (see #7772) + this._normalizeRightBottom(); + + this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position + + //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) + if ( $.ui.ddmanager ) { + $.ui.ddmanager.dragStart(this, event); + } + + return true; + }, + + _refreshOffsets: function( event ) { + this.offset = { + top: this.positionAbs.top - this.margins.top, + left: this.positionAbs.left - this.margins.left, + scroll: false, + parent: this._getParentOffset(), + relative: this._getRelativeOffset() + }; + + this.offset.click = { + left: event.pageX - this.offset.left, + top: event.pageY - this.offset.top + }; + }, + + _mouseDrag: function(event, noPropagation) { + // reset any necessary cached properties (see #5009) + if ( this.hasFixedAncestor ) { + this.offset.parent = this._getParentOffset(); + } + + //Compute the helpers position + this.position = this._generatePosition( event, true ); + this.positionAbs = this._convertPositionTo("absolute"); + + //Call plugins and callbacks and use the resulting position if something is returned + if (!noPropagation) { + var ui = this._uiHash(); + if (this._trigger("drag", event, ui) === false) { + this._mouseUp({}); + return false; + } + this.position = ui.position; + } + + this.helper[ 0 ].style.left = this.position.left + "px"; + this.helper[ 0 ].style.top = this.position.top + "px"; + + if ($.ui.ddmanager) { + $.ui.ddmanager.drag(this, event); + } + + return false; + }, + + _mouseStop: function(event) { + + //If we are using droppables, inform the manager about the drop + var that = this, + dropped = false; + if ($.ui.ddmanager && !this.options.dropBehaviour) { + dropped = $.ui.ddmanager.drop(this, event); + } + + //if a drop comes from outside (a sortable) + if (this.dropped) { + dropped = this.dropped; + this.dropped = false; + } + + if ((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { + $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { + if (that._trigger("stop", event) !== false) { + that._clear(); + } + }); + } else { + if (this._trigger("stop", event) !== false) { + this._clear(); + } + } + + return false; + }, + + _mouseUp: function( event ) { + this._unblockFrames(); + + //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003) + if ( $.ui.ddmanager ) { + $.ui.ddmanager.dragStop(this, event); + } + + // Only need to focus if the event occurred on the draggable itself, see #10527 + if ( this.handleElement.is( event.target ) ) { + // The interaction is over; whether or not the click resulted in a drag, focus the element + this.element.focus(); + } + + return $.ui.mouse.prototype._mouseUp.call(this, event); + }, + + cancel: function() { + + if (this.helper.is(".ui-draggable-dragging")) { + this._mouseUp({}); + } else { + this._clear(); + } + + return this; + + }, + + _getHandle: function(event) { + return this.options.handle ? + !!$( event.target ).closest( this.element.find( this.options.handle ) ).length : + true; + }, + + _setHandleClassName: function() { + this.handleElement = this.options.handle ? + this.element.find( this.options.handle ) : this.element; + this.handleElement.addClass( "ui-draggable-handle" ); + }, + + _removeHandleClassName: function() { + this.handleElement.removeClass( "ui-draggable-handle" ); + }, + + _createHelper: function(event) { + + var o = this.options, + helperIsFunction = $.isFunction( o.helper ), + helper = helperIsFunction ? + $( o.helper.apply( this.element[ 0 ], [ event ] ) ) : + ( o.helper === "clone" ? + this.element.clone().removeAttr( "id" ) : + this.element ); + + if (!helper.parents("body").length) { + helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo)); + } + + // http://bugs.jqueryui.com/ticket/9446 + // a helper function can return the original element + // which wouldn't have been set to relative in _create + if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) { + this._setPositionRelative(); + } + + if (helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) { + helper.css("position", "absolute"); + } + + return helper; + + }, + + _setPositionRelative: function() { + if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) { + this.element[ 0 ].style.position = "relative"; + } + }, + + _adjustOffsetFromHelper: function(obj) { + if (typeof obj === "string") { + obj = obj.split(" "); + } + if ($.isArray(obj)) { + obj = { left: +obj[0], top: +obj[1] || 0 }; + } + if ("left" in obj) { + this.offset.click.left = obj.left + this.margins.left; + } + if ("right" in obj) { + this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; + } + if ("top" in obj) { + this.offset.click.top = obj.top + this.margins.top; + } + if ("bottom" in obj) { + this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; + } + }, + + _isRootNode: function( element ) { + return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ]; + }, + + _getParentOffset: function() { + + //Get the offsetParent and cache its position + var po = this.offsetParent.offset(), + document = this.document[ 0 ]; + + // This is a special case where we need to modify a offset calculated on start, since the following happened: + // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent + // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that + // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag + if (this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { + po.left += this.scrollParent.scrollLeft(); + po.top += this.scrollParent.scrollTop(); + } + + if ( this._isRootNode( this.offsetParent[ 0 ] ) ) { + po = { top: 0, left: 0 }; + } + + return { + top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"), 10) || 0), + left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"), 10) || 0) + }; + + }, + + _getRelativeOffset: function() { + if ( this.cssPosition !== "relative" ) { + return { top: 0, left: 0 }; + } + + var p = this.element.position(), + scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ); + + return { + top: p.top - ( parseInt(this.helper.css( "top" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ), + left: p.left - ( parseInt(this.helper.css( "left" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 ) + }; + + }, + + _cacheMargins: function() { + this.margins = { + left: (parseInt(this.element.css("marginLeft"), 10) || 0), + top: (parseInt(this.element.css("marginTop"), 10) || 0), + right: (parseInt(this.element.css("marginRight"), 10) || 0), + bottom: (parseInt(this.element.css("marginBottom"), 10) || 0) + }; + }, + + _cacheHelperProportions: function() { + this.helperProportions = { + width: this.helper.outerWidth(), + height: this.helper.outerHeight() + }; + }, + + _setContainment: function() { + + var isUserScrollable, c, ce, + o = this.options, + document = this.document[ 0 ]; + + this.relativeContainer = null; + + if ( !o.containment ) { + this.containment = null; + return; + } + + if ( o.containment === "window" ) { + this.containment = [ + $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left, + $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top, + $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left, + $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top + ]; + return; + } + + if ( o.containment === "document") { + this.containment = [ + 0, + 0, + $( document ).width() - this.helperProportions.width - this.margins.left, + ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top + ]; + return; + } + + if ( o.containment.constructor === Array ) { + this.containment = o.containment; + return; + } + + if ( o.containment === "parent" ) { + o.containment = this.helper[ 0 ].parentNode; + } + + c = $( o.containment ); + ce = c[ 0 ]; + + if ( !ce ) { + return; + } + + isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) ); + + this.containment = [ + ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ), + ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ), + ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - + ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - + ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - + this.helperProportions.width - + this.margins.left - + this.margins.right, + ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - + ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - + ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - + this.helperProportions.height - + this.margins.top - + this.margins.bottom + ]; + this.relativeContainer = c; + }, + + _convertPositionTo: function(d, pos) { + + if (!pos) { + pos = this.position; + } + + var mod = d === "absolute" ? 1 : -1, + scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ); + + return { + top: ( + pos.top + // The absolute mouse position + this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod) + ), + left: ( + pos.left + // The absolute mouse position + this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod) + ) + }; + + }, + + _generatePosition: function( event, constrainPosition ) { + + var containment, co, top, left, + o = this.options, + scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ), + pageX = event.pageX, + pageY = event.pageY; + + // Cache the scroll + if ( !scrollIsRootNode || !this.offset.scroll ) { + this.offset.scroll = { + top: this.scrollParent.scrollTop(), + left: this.scrollParent.scrollLeft() + }; + } + + /* + * - Position constraining - + * Constrain the position to a mix of grid, containment. + */ + + // If we are not dragging yet, we won't check for options + if ( constrainPosition ) { + if ( this.containment ) { + if ( this.relativeContainer ){ + co = this.relativeContainer.offset(); + containment = [ + this.containment[ 0 ] + co.left, + this.containment[ 1 ] + co.top, + this.containment[ 2 ] + co.left, + this.containment[ 3 ] + co.top + ]; + } else { + containment = this.containment; + } + + if (event.pageX - this.offset.click.left < containment[0]) { + pageX = containment[0] + this.offset.click.left; + } + if (event.pageY - this.offset.click.top < containment[1]) { + pageY = containment[1] + this.offset.click.top; + } + if (event.pageX - this.offset.click.left > containment[2]) { + pageX = containment[2] + this.offset.click.left; + } + if (event.pageY - this.offset.click.top > containment[3]) { + pageY = containment[3] + this.offset.click.top; + } + } + + if (o.grid) { + //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950) + top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; + pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + + left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; + pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + } + + if ( o.axis === "y" ) { + pageX = this.originalPageX; + } + + if ( o.axis === "x" ) { + pageY = this.originalPageY; + } + } + + return { + top: ( + pageY - // The absolute mouse position + this.offset.click.top - // Click offset (relative to the element) + this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top + // The offsetParent's offset without borders (offset + border) + ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) + ), + left: ( + pageX - // The absolute mouse position + this.offset.click.left - // Click offset (relative to the element) + this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left + // The offsetParent's offset without borders (offset + border) + ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) + ) + }; + + }, + + _clear: function() { + this.helper.removeClass("ui-draggable-dragging"); + if (this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) { + this.helper.remove(); + } + this.helper = null; + this.cancelHelperRemoval = false; + if ( this.destroyOnClear ) { + this.destroy(); + } + }, + + _normalizeRightBottom: function() { + if ( this.options.axis !== "y" && this.helper.css( "right" ) !== "auto" ) { + this.helper.width( this.helper.width() ); + this.helper.css( "right", "auto" ); + } + if ( this.options.axis !== "x" && this.helper.css( "bottom" ) !== "auto" ) { + this.helper.height( this.helper.height() ); + this.helper.css( "bottom", "auto" ); + } + }, + + // From now on bulk stuff - mainly helpers + + _trigger: function( type, event, ui ) { + ui = ui || this._uiHash(); + $.ui.plugin.call( this, type, [ event, ui, this ], true ); + + // Absolute position and offset (see #6884 ) have to be recalculated after plugins + if ( /^(drag|start|stop)/.test( type ) ) { + this.positionAbs = this._convertPositionTo( "absolute" ); + ui.offset = this.positionAbs; + } + return $.Widget.prototype._trigger.call( this, type, event, ui ); + }, + + plugins: {}, + + _uiHash: function() { + return { + helper: this.helper, + position: this.position, + originalPosition: this.originalPosition, + offset: this.positionAbs + }; + } + +}); + +$.ui.plugin.add( "draggable", "connectToSortable", { + start: function( event, ui, draggable ) { + var uiSortable = $.extend( {}, ui, { + item: draggable.element + }); + + draggable.sortables = []; + $( draggable.options.connectToSortable ).each(function() { + var sortable = $( this ).sortable( "instance" ); + + if ( sortable && !sortable.options.disabled ) { + draggable.sortables.push( sortable ); + + // refreshPositions is called at drag start to refresh the containerCache + // which is used in drag. This ensures it's initialized and synchronized + // with any changes that might have happened on the page since initialization. + sortable.refreshPositions(); + sortable._trigger("activate", event, uiSortable); + } + }); + }, + stop: function( event, ui, draggable ) { + var uiSortable = $.extend( {}, ui, { + item: draggable.element + }); + + draggable.cancelHelperRemoval = false; + + $.each( draggable.sortables, function() { + var sortable = this; + + if ( sortable.isOver ) { + sortable.isOver = 0; + + // Allow this sortable to handle removing the helper + draggable.cancelHelperRemoval = true; + sortable.cancelHelperRemoval = false; + + // Use _storedCSS To restore properties in the sortable, + // as this also handles revert (#9675) since the draggable + // may have modified them in unexpected ways (#8809) + sortable._storedCSS = { + position: sortable.placeholder.css( "position" ), + top: sortable.placeholder.css( "top" ), + left: sortable.placeholder.css( "left" ) + }; + + sortable._mouseStop(event); + + // Once drag has ended, the sortable should return to using + // its original helper, not the shared helper from draggable + sortable.options.helper = sortable.options._helper; + } else { + // Prevent this Sortable from removing the helper. + // However, don't set the draggable to remove the helper + // either as another connected Sortable may yet handle the removal. + sortable.cancelHelperRemoval = true; + + sortable._trigger( "deactivate", event, uiSortable ); + } + }); + }, + drag: function( event, ui, draggable ) { + $.each( draggable.sortables, function() { + var innermostIntersecting = false, + sortable = this; + + // Copy over variables that sortable's _intersectsWith uses + sortable.positionAbs = draggable.positionAbs; + sortable.helperProportions = draggable.helperProportions; + sortable.offset.click = draggable.offset.click; + + if ( sortable._intersectsWith( sortable.containerCache ) ) { + innermostIntersecting = true; + + $.each( draggable.sortables, function() { + // Copy over variables that sortable's _intersectsWith uses + this.positionAbs = draggable.positionAbs; + this.helperProportions = draggable.helperProportions; + this.offset.click = draggable.offset.click; + + if ( this !== sortable && + this._intersectsWith( this.containerCache ) && + $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) { + innermostIntersecting = false; + } + + return innermostIntersecting; + }); + } + + if ( innermostIntersecting ) { + // If it intersects, we use a little isOver variable and set it once, + // so that the move-in stuff gets fired only once. + if ( !sortable.isOver ) { + sortable.isOver = 1; + + // Store draggable's parent in case we need to reappend to it later. + draggable._parent = ui.helper.parent(); + + sortable.currentItem = ui.helper + .appendTo( sortable.element ) + .data( "ui-sortable-item", true ); + + // Store helper option to later restore it + sortable.options._helper = sortable.options.helper; + + sortable.options.helper = function() { + return ui.helper[ 0 ]; + }; + + // Fire the start events of the sortable with our passed browser event, + // and our own helper (so it doesn't create a new one) + event.target = sortable.currentItem[ 0 ]; + sortable._mouseCapture( event, true ); + sortable._mouseStart( event, true, true ); + + // Because the browser event is way off the new appended portlet, + // modify necessary variables to reflect the changes + sortable.offset.click.top = draggable.offset.click.top; + sortable.offset.click.left = draggable.offset.click.left; + sortable.offset.parent.left -= draggable.offset.parent.left - + sortable.offset.parent.left; + sortable.offset.parent.top -= draggable.offset.parent.top - + sortable.offset.parent.top; + + draggable._trigger( "toSortable", event ); + + // Inform draggable that the helper is in a valid drop zone, + // used solely in the revert option to handle "valid/invalid". + draggable.dropped = sortable.element; + + // Need to refreshPositions of all sortables in the case that + // adding to one sortable changes the location of the other sortables (#9675) + $.each( draggable.sortables, function() { + this.refreshPositions(); + }); + + // hack so receive/update callbacks work (mostly) + draggable.currentItem = draggable.element; + sortable.fromOutside = draggable; + } + + if ( sortable.currentItem ) { + sortable._mouseDrag( event ); + // Copy the sortable's position because the draggable's can potentially reflect + // a relative position, while sortable is always absolute, which the dragged + // element has now become. (#8809) + ui.position = sortable.position; + } + } else { + // If it doesn't intersect with the sortable, and it intersected before, + // we fake the drag stop of the sortable, but make sure it doesn't remove + // the helper by using cancelHelperRemoval. + if ( sortable.isOver ) { + + sortable.isOver = 0; + sortable.cancelHelperRemoval = true; + + // Calling sortable's mouseStop would trigger a revert, + // so revert must be temporarily false until after mouseStop is called. + sortable.options._revert = sortable.options.revert; + sortable.options.revert = false; + + sortable._trigger( "out", event, sortable._uiHash( sortable ) ); + sortable._mouseStop( event, true ); + + // restore sortable behaviors that were modfied + // when the draggable entered the sortable area (#9481) + sortable.options.revert = sortable.options._revert; + sortable.options.helper = sortable.options._helper; + + if ( sortable.placeholder ) { + sortable.placeholder.remove(); + } + + // Restore and recalculate the draggable's offset considering the sortable + // may have modified them in unexpected ways. (#8809, #10669) + ui.helper.appendTo( draggable._parent ); + draggable._refreshOffsets( event ); + ui.position = draggable._generatePosition( event, true ); + + draggable._trigger( "fromSortable", event ); + + // Inform draggable that the helper is no longer in a valid drop zone + draggable.dropped = false; + + // Need to refreshPositions of all sortables just in case removing + // from one sortable changes the location of other sortables (#9675) + $.each( draggable.sortables, function() { + this.refreshPositions(); + }); + } + } + }); + } +}); + +$.ui.plugin.add("draggable", "cursor", { + start: function( event, ui, instance ) { + var t = $( "body" ), + o = instance.options; + + if (t.css("cursor")) { + o._cursor = t.css("cursor"); + } + t.css("cursor", o.cursor); + }, + stop: function( event, ui, instance ) { + var o = instance.options; + if (o._cursor) { + $("body").css("cursor", o._cursor); + } + } +}); + +$.ui.plugin.add("draggable", "opacity", { + start: function( event, ui, instance ) { + var t = $( ui.helper ), + o = instance.options; + if (t.css("opacity")) { + o._opacity = t.css("opacity"); + } + t.css("opacity", o.opacity); + }, + stop: function( event, ui, instance ) { + var o = instance.options; + if (o._opacity) { + $(ui.helper).css("opacity", o._opacity); + } + } +}); + +$.ui.plugin.add("draggable", "scroll", { + start: function( event, ui, i ) { + if ( !i.scrollParentNotHidden ) { + i.scrollParentNotHidden = i.helper.scrollParent( false ); + } + + if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] && i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) { + i.overflowOffset = i.scrollParentNotHidden.offset(); + } + }, + drag: function( event, ui, i ) { + + var o = i.options, + scrolled = false, + scrollParent = i.scrollParentNotHidden[ 0 ], + document = i.document[ 0 ]; + + if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) { + if ( !o.axis || o.axis !== "x" ) { + if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY < o.scrollSensitivity ) { + scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed; + } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) { + scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed; + } + } + + if ( !o.axis || o.axis !== "y" ) { + if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX < o.scrollSensitivity ) { + scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed; + } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) { + scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed; + } + } + + } else { + + if (!o.axis || o.axis !== "x") { + if (event.pageY - $(document).scrollTop() < o.scrollSensitivity) { + scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); + } else if ($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { + scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + } + } + + if (!o.axis || o.axis !== "y") { + if (event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { + scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); + } else if ($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { + scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + } + } + + } + + if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(i, event); + } + + } +}); + +$.ui.plugin.add("draggable", "snap", { + start: function( event, ui, i ) { + + var o = i.options; + + i.snapElements = []; + + $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() { + var $t = $(this), + $o = $t.offset(); + if (this !== i.element[0]) { + i.snapElements.push({ + item: this, + width: $t.outerWidth(), height: $t.outerHeight(), + top: $o.top, left: $o.left + }); + } + }); + + }, + drag: function( event, ui, inst ) { + + var ts, bs, ls, rs, l, r, t, b, i, first, + o = inst.options, + d = o.snapTolerance, + x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, + y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; + + for (i = inst.snapElements.length - 1; i >= 0; i--){ + + l = inst.snapElements[i].left - inst.margins.left; + r = l + inst.snapElements[i].width; + t = inst.snapElements[i].top - inst.margins.top; + b = t + inst.snapElements[i].height; + + if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) { + if (inst.snapElements[i].snapping) { + (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + } + inst.snapElements[i].snapping = false; + continue; + } + + if (o.snapMode !== "inner") { + ts = Math.abs(t - y2) <= d; + bs = Math.abs(b - y1) <= d; + ls = Math.abs(l - x2) <= d; + rs = Math.abs(r - x1) <= d; + if (ts) { + ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top; + } + if (bs) { + ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top; + } + if (ls) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left; + } + if (rs) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left; + } + } + + first = (ts || bs || ls || rs); + + if (o.snapMode !== "outer") { + ts = Math.abs(t - y1) <= d; + bs = Math.abs(b - y2) <= d; + ls = Math.abs(l - x1) <= d; + rs = Math.abs(r - x2) <= d; + if (ts) { + ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top; + } + if (bs) { + ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top; + } + if (ls) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left; + } + if (rs) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left; + } + } + + if (!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) { + (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + } + inst.snapElements[i].snapping = (ts || bs || ls || rs || first); + + } + + } +}); + +$.ui.plugin.add("draggable", "stack", { + start: function( event, ui, instance ) { + var min, + o = instance.options, + group = $.makeArray($(o.stack)).sort(function(a, b) { + return (parseInt($(a).css("zIndex"), 10) || 0) - (parseInt($(b).css("zIndex"), 10) || 0); + }); + + if (!group.length) { return; } + + min = parseInt($(group[0]).css("zIndex"), 10) || 0; + $(group).each(function(i) { + $(this).css("zIndex", min + i); + }); + this.css("zIndex", (min + group.length)); + } +}); + +$.ui.plugin.add("draggable", "zIndex", { + start: function( event, ui, instance ) { + var t = $( ui.helper ), + o = instance.options; + + if (t.css("zIndex")) { + o._zIndex = t.css("zIndex"); + } + t.css("zIndex", o.zIndex); + }, + stop: function( event, ui, instance ) { + var o = instance.options; + + if (o._zIndex) { + $(ui.helper).css("zIndex", o._zIndex); + } + } +}); + +var draggable = $.ui.draggable; + + +/*! + * jQuery UI Resizable 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/resizable/ + */ + + +$.widget("ui.resizable", $.ui.mouse, { + version: "1.11.4", + widgetEventPrefix: "resize", + options: { + alsoResize: false, + animate: false, + animateDuration: "slow", + animateEasing: "swing", + aspectRatio: false, + autoHide: false, + containment: false, + ghost: false, + grid: false, + handles: "e,s,se", + helper: false, + maxHeight: null, + maxWidth: null, + minHeight: 10, + minWidth: 10, + // See #7960 + zIndex: 90, + + // callbacks + resize: null, + start: null, + stop: null + }, + + _num: function( value ) { + return parseInt( value, 10 ) || 0; + }, + + _isNumber: function( value ) { + return !isNaN( parseInt( value, 10 ) ); + }, + + _hasScroll: function( el, a ) { + + if ( $( el ).css( "overflow" ) === "hidden") { + return false; + } + + var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", + has = false; + + if ( el[ scroll ] > 0 ) { + return true; + } + + // TODO: determine which cases actually cause this to happen + // if the element doesn't have the scroll set, see if it's possible to + // set the scroll + el[ scroll ] = 1; + has = ( el[ scroll ] > 0 ); + el[ scroll ] = 0; + return has; + }, + + _create: function() { + + var n, i, handle, axis, hname, + that = this, + o = this.options; + this.element.addClass("ui-resizable"); + + $.extend(this, { + _aspectRatio: !!(o.aspectRatio), + aspectRatio: o.aspectRatio, + originalElement: this.element, + _proportionallyResizeElements: [], + _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null + }); + + // Wrap the element if it cannot hold child nodes + if (this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)) { + + this.element.wrap( + $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({ + position: this.element.css("position"), + width: this.element.outerWidth(), + height: this.element.outerHeight(), + top: this.element.css("top"), + left: this.element.css("left") + }) + ); + + this.element = this.element.parent().data( + "ui-resizable", this.element.resizable( "instance" ) + ); + + this.elementIsWrapper = true; + + this.element.css({ + marginLeft: this.originalElement.css("marginLeft"), + marginTop: this.originalElement.css("marginTop"), + marginRight: this.originalElement.css("marginRight"), + marginBottom: this.originalElement.css("marginBottom") + }); + this.originalElement.css({ + marginLeft: 0, + marginTop: 0, + marginRight: 0, + marginBottom: 0 + }); + // support: Safari + // Prevent Safari textarea resize + this.originalResizeStyle = this.originalElement.css("resize"); + this.originalElement.css("resize", "none"); + + this._proportionallyResizeElements.push( this.originalElement.css({ + position: "static", + zoom: 1, + display: "block" + }) ); + + // support: IE9 + // avoid IE jump (hard set the margin) + this.originalElement.css({ margin: this.originalElement.css("margin") }); + + this._proportionallyResize(); + } + + this.handles = o.handles || + ( !$(".ui-resizable-handle", this.element).length ? + "e,s,se" : { + n: ".ui-resizable-n", + e: ".ui-resizable-e", + s: ".ui-resizable-s", + w: ".ui-resizable-w", + se: ".ui-resizable-se", + sw: ".ui-resizable-sw", + ne: ".ui-resizable-ne", + nw: ".ui-resizable-nw" + } ); + + this._handles = $(); + if ( this.handles.constructor === String ) { + + if ( this.handles === "all") { + this.handles = "n,e,s,w,se,sw,ne,nw"; + } + + n = this.handles.split(","); + this.handles = {}; + + for (i = 0; i < n.length; i++) { + + handle = $.trim(n[i]); + hname = "ui-resizable-" + handle; + axis = $("<div class='ui-resizable-handle " + hname + "'></div>"); + + axis.css({ zIndex: o.zIndex }); + + // TODO : What's going on here? + if ("se" === handle) { + axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se"); + } + + this.handles[handle] = ".ui-resizable-" + handle; + this.element.append(axis); + } + + } + + this._renderAxis = function(target) { + + var i, axis, padPos, padWrapper; + + target = target || this.element; + + for (i in this.handles) { + + if (this.handles[i].constructor === String) { + this.handles[i] = this.element.children( this.handles[ i ] ).first().show(); + } else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) { + this.handles[ i ] = $( this.handles[ i ] ); + this._on( this.handles[ i ], { "mousedown": that._mouseDown }); + } + + if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)) { + + axis = $(this.handles[i], this.element); + + padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); + + padPos = [ "padding", + /ne|nw|n/.test(i) ? "Top" : + /se|sw|s/.test(i) ? "Bottom" : + /^e$/.test(i) ? "Right" : "Left" ].join(""); + + target.css(padPos, padWrapper); + + this._proportionallyResize(); + } + + this._handles = this._handles.add( this.handles[ i ] ); + } + }; + + // TODO: make renderAxis a prototype function + this._renderAxis(this.element); + + this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) ); + this._handles.disableSelection(); + + this._handles.mouseover(function() { + if (!that.resizing) { + if (this.className) { + axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); + } + that.axis = axis && axis[1] ? axis[1] : "se"; + } + }); + + if (o.autoHide) { + this._handles.hide(); + $(this.element) + .addClass("ui-resizable-autohide") + .mouseenter(function() { + if (o.disabled) { + return; + } + $(this).removeClass("ui-resizable-autohide"); + that._handles.show(); + }) + .mouseleave(function() { + if (o.disabled) { + return; + } + if (!that.resizing) { + $(this).addClass("ui-resizable-autohide"); + that._handles.hide(); + } + }); + } + + this._mouseInit(); + }, + + _destroy: function() { + + this._mouseDestroy(); + + var wrapper, + _destroy = function(exp) { + $(exp) + .removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") + .removeData("resizable") + .removeData("ui-resizable") + .unbind(".resizable") + .find(".ui-resizable-handle") + .remove(); + }; + + // TODO: Unwrap at same DOM position + if (this.elementIsWrapper) { + _destroy(this.element); + wrapper = this.element; + this.originalElement.css({ + position: wrapper.css("position"), + width: wrapper.outerWidth(), + height: wrapper.outerHeight(), + top: wrapper.css("top"), + left: wrapper.css("left") + }).insertAfter( wrapper ); + wrapper.remove(); + } + + this.originalElement.css("resize", this.originalResizeStyle); + _destroy(this.originalElement); + + return this; + }, + + _mouseCapture: function(event) { + var i, handle, + capture = false; + + for (i in this.handles) { + handle = $(this.handles[i])[0]; + if (handle === event.target || $.contains(handle, event.target)) { + capture = true; + } + } + + return !this.options.disabled && capture; + }, + + _mouseStart: function(event) { + + var curleft, curtop, cursor, + o = this.options, + el = this.element; + + this.resizing = true; + + this._renderProxy(); + + curleft = this._num(this.helper.css("left")); + curtop = this._num(this.helper.css("top")); + + if (o.containment) { + curleft += $(o.containment).scrollLeft() || 0; + curtop += $(o.containment).scrollTop() || 0; + } + + this.offset = this.helper.offset(); + this.position = { left: curleft, top: curtop }; + + this.size = this._helper ? { + width: this.helper.width(), + height: this.helper.height() + } : { + width: el.width(), + height: el.height() + }; + + this.originalSize = this._helper ? { + width: el.outerWidth(), + height: el.outerHeight() + } : { + width: el.width(), + height: el.height() + }; + + this.sizeDiff = { + width: el.outerWidth() - el.width(), + height: el.outerHeight() - el.height() + }; + + this.originalPosition = { left: curleft, top: curtop }; + this.originalMousePosition = { left: event.pageX, top: event.pageY }; + + this.aspectRatio = (typeof o.aspectRatio === "number") ? + o.aspectRatio : + ((this.originalSize.width / this.originalSize.height) || 1); + + cursor = $(".ui-resizable-" + this.axis).css("cursor"); + $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor); + + el.addClass("ui-resizable-resizing"); + this._propagate("start", event); + return true; + }, + + _mouseDrag: function(event) { + + var data, props, + smp = this.originalMousePosition, + a = this.axis, + dx = (event.pageX - smp.left) || 0, + dy = (event.pageY - smp.top) || 0, + trigger = this._change[a]; + + this._updatePrevProperties(); + + if (!trigger) { + return false; + } + + data = trigger.apply(this, [ event, dx, dy ]); + + this._updateVirtualBoundaries(event.shiftKey); + if (this._aspectRatio || event.shiftKey) { + data = this._updateRatio(data, event); + } + + data = this._respectSize(data, event); + + this._updateCache(data); + + this._propagate("resize", event); + + props = this._applyChanges(); + + if ( !this._helper && this._proportionallyResizeElements.length ) { + this._proportionallyResize(); + } + + if ( !$.isEmptyObject( props ) ) { + this._updatePrevProperties(); + this._trigger( "resize", event, this.ui() ); + this._applyChanges(); + } + + return false; + }, + + _mouseStop: function(event) { + + this.resizing = false; + var pr, ista, soffseth, soffsetw, s, left, top, + o = this.options, that = this; + + if (this._helper) { + + pr = this._proportionallyResizeElements; + ista = pr.length && (/textarea/i).test(pr[0].nodeName); + soffseth = ista && this._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height; + soffsetw = ista ? 0 : that.sizeDiff.width; + + s = { + width: (that.helper.width() - soffsetw), + height: (that.helper.height() - soffseth) + }; + left = (parseInt(that.element.css("left"), 10) + + (that.position.left - that.originalPosition.left)) || null; + top = (parseInt(that.element.css("top"), 10) + + (that.position.top - that.originalPosition.top)) || null; + + if (!o.animate) { + this.element.css($.extend(s, { top: top, left: left })); + } + + that.helper.height(that.size.height); + that.helper.width(that.size.width); + + if (this._helper && !o.animate) { + this._proportionallyResize(); + } + } + + $("body").css("cursor", "auto"); + + this.element.removeClass("ui-resizable-resizing"); + + this._propagate("stop", event); + + if (this._helper) { + this.helper.remove(); + } + + return false; + + }, + + _updatePrevProperties: function() { + this.prevPosition = { + top: this.position.top, + left: this.position.left + }; + this.prevSize = { + width: this.size.width, + height: this.size.height + }; + }, + + _applyChanges: function() { + var props = {}; + + if ( this.position.top !== this.prevPosition.top ) { + props.top = this.position.top + "px"; + } + if ( this.position.left !== this.prevPosition.left ) { + props.left = this.position.left + "px"; + } + if ( this.size.width !== this.prevSize.width ) { + props.width = this.size.width + "px"; + } + if ( this.size.height !== this.prevSize.height ) { + props.height = this.size.height + "px"; + } + + this.helper.css( props ); + + return props; + }, + + _updateVirtualBoundaries: function(forceAspectRatio) { + var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b, + o = this.options; + + b = { + minWidth: this._isNumber(o.minWidth) ? o.minWidth : 0, + maxWidth: this._isNumber(o.maxWidth) ? o.maxWidth : Infinity, + minHeight: this._isNumber(o.minHeight) ? o.minHeight : 0, + maxHeight: this._isNumber(o.maxHeight) ? o.maxHeight : Infinity + }; + + if (this._aspectRatio || forceAspectRatio) { + pMinWidth = b.minHeight * this.aspectRatio; + pMinHeight = b.minWidth / this.aspectRatio; + pMaxWidth = b.maxHeight * this.aspectRatio; + pMaxHeight = b.maxWidth / this.aspectRatio; + + if (pMinWidth > b.minWidth) { + b.minWidth = pMinWidth; + } + if (pMinHeight > b.minHeight) { + b.minHeight = pMinHeight; + } + if (pMaxWidth < b.maxWidth) { + b.maxWidth = pMaxWidth; + } + if (pMaxHeight < b.maxHeight) { + b.maxHeight = pMaxHeight; + } + } + this._vBoundaries = b; + }, + + _updateCache: function(data) { + this.offset = this.helper.offset(); + if (this._isNumber(data.left)) { + this.position.left = data.left; + } + if (this._isNumber(data.top)) { + this.position.top = data.top; + } + if (this._isNumber(data.height)) { + this.size.height = data.height; + } + if (this._isNumber(data.width)) { + this.size.width = data.width; + } + }, + + _updateRatio: function( data ) { + + var cpos = this.position, + csize = this.size, + a = this.axis; + + if (this._isNumber(data.height)) { + data.width = (data.height * this.aspectRatio); + } else if (this._isNumber(data.width)) { + data.height = (data.width / this.aspectRatio); + } + + if (a === "sw") { + data.left = cpos.left + (csize.width - data.width); + data.top = null; + } + if (a === "nw") { + data.top = cpos.top + (csize.height - data.height); + data.left = cpos.left + (csize.width - data.width); + } + + return data; + }, + + _respectSize: function( data ) { + + var o = this._vBoundaries, + a = this.axis, + ismaxw = this._isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), + ismaxh = this._isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), + isminw = this._isNumber(data.width) && o.minWidth && (o.minWidth > data.width), + isminh = this._isNumber(data.height) && o.minHeight && (o.minHeight > data.height), + dw = this.originalPosition.left + this.originalSize.width, + dh = this.position.top + this.size.height, + cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); + if (isminw) { + data.width = o.minWidth; + } + if (isminh) { + data.height = o.minHeight; + } + if (ismaxw) { + data.width = o.maxWidth; + } + if (ismaxh) { + data.height = o.maxHeight; + } + + if (isminw && cw) { + data.left = dw - o.minWidth; + } + if (ismaxw && cw) { + data.left = dw - o.maxWidth; + } + if (isminh && ch) { + data.top = dh - o.minHeight; + } + if (ismaxh && ch) { + data.top = dh - o.maxHeight; + } + + // Fixing jump error on top/left - bug #2330 + if (!data.width && !data.height && !data.left && data.top) { + data.top = null; + } else if (!data.width && !data.height && !data.top && data.left) { + data.left = null; + } + + return data; + }, + + _getPaddingPlusBorderDimensions: function( element ) { + var i = 0, + widths = [], + borders = [ + element.css( "borderTopWidth" ), + element.css( "borderRightWidth" ), + element.css( "borderBottomWidth" ), + element.css( "borderLeftWidth" ) + ], + paddings = [ + element.css( "paddingTop" ), + element.css( "paddingRight" ), + element.css( "paddingBottom" ), + element.css( "paddingLeft" ) + ]; + + for ( ; i < 4; i++ ) { + widths[ i ] = ( parseInt( borders[ i ], 10 ) || 0 ); + widths[ i ] += ( parseInt( paddings[ i ], 10 ) || 0 ); + } + + return { + height: widths[ 0 ] + widths[ 2 ], + width: widths[ 1 ] + widths[ 3 ] + }; + }, + + _proportionallyResize: function() { + + if (!this._proportionallyResizeElements.length) { + return; + } + + var prel, + i = 0, + element = this.helper || this.element; + + for ( ; i < this._proportionallyResizeElements.length; i++) { + + prel = this._proportionallyResizeElements[i]; + + // TODO: Seems like a bug to cache this.outerDimensions + // considering that we are in a loop. + if (!this.outerDimensions) { + this.outerDimensions = this._getPaddingPlusBorderDimensions( prel ); + } + + prel.css({ + height: (element.height() - this.outerDimensions.height) || 0, + width: (element.width() - this.outerDimensions.width) || 0 + }); + + } + + }, + + _renderProxy: function() { + + var el = this.element, o = this.options; + this.elementOffset = el.offset(); + + if (this._helper) { + + this.helper = this.helper || $("<div style='overflow:hidden;'></div>"); + + this.helper.addClass(this._helper).css({ + width: this.element.outerWidth() - 1, + height: this.element.outerHeight() - 1, + position: "absolute", + left: this.elementOffset.left + "px", + top: this.elementOffset.top + "px", + zIndex: ++o.zIndex //TODO: Don't modify option + }); + + this.helper + .appendTo("body") + .disableSelection(); + + } else { + this.helper = this.element; + } + + }, + + _change: { + e: function(event, dx) { + return { width: this.originalSize.width + dx }; + }, + w: function(event, dx) { + var cs = this.originalSize, sp = this.originalPosition; + return { left: sp.left + dx, width: cs.width - dx }; + }, + n: function(event, dx, dy) { + var cs = this.originalSize, sp = this.originalPosition; + return { top: sp.top + dy, height: cs.height - dy }; + }, + s: function(event, dx, dy) { + return { height: this.originalSize.height + dy }; + }, + se: function(event, dx, dy) { + return $.extend(this._change.s.apply(this, arguments), + this._change.e.apply(this, [ event, dx, dy ])); + }, + sw: function(event, dx, dy) { + return $.extend(this._change.s.apply(this, arguments), + this._change.w.apply(this, [ event, dx, dy ])); + }, + ne: function(event, dx, dy) { + return $.extend(this._change.n.apply(this, arguments), + this._change.e.apply(this, [ event, dx, dy ])); + }, + nw: function(event, dx, dy) { + return $.extend(this._change.n.apply(this, arguments), + this._change.w.apply(this, [ event, dx, dy ])); + } + }, + + _propagate: function(n, event) { + $.ui.plugin.call(this, n, [ event, this.ui() ]); + (n !== "resize" && this._trigger(n, event, this.ui())); + }, + + plugins: {}, + + ui: function() { + return { + originalElement: this.originalElement, + element: this.element, + helper: this.helper, + position: this.position, + size: this.size, + originalSize: this.originalSize, + originalPosition: this.originalPosition + }; + } + +}); + +/* + * Resizable Extensions + */ + +$.ui.plugin.add("resizable", "animate", { + + stop: function( event ) { + var that = $(this).resizable( "instance" ), + o = that.options, + pr = that._proportionallyResizeElements, + ista = pr.length && (/textarea/i).test(pr[0].nodeName), + soffseth = ista && that._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height, + soffsetw = ista ? 0 : that.sizeDiff.width, + style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) }, + left = (parseInt(that.element.css("left"), 10) + + (that.position.left - that.originalPosition.left)) || null, + top = (parseInt(that.element.css("top"), 10) + + (that.position.top - that.originalPosition.top)) || null; + + that.element.animate( + $.extend(style, top && left ? { top: top, left: left } : {}), { + duration: o.animateDuration, + easing: o.animateEasing, + step: function() { + + var data = { + width: parseInt(that.element.css("width"), 10), + height: parseInt(that.element.css("height"), 10), + top: parseInt(that.element.css("top"), 10), + left: parseInt(that.element.css("left"), 10) + }; + + if (pr && pr.length) { + $(pr[0]).css({ width: data.width, height: data.height }); + } + + // propagating resize, and updating values for each animation step + that._updateCache(data); + that._propagate("resize", event); + + } + } + ); + } + +}); + +$.ui.plugin.add( "resizable", "containment", { + + start: function() { + var element, p, co, ch, cw, width, height, + that = $( this ).resizable( "instance" ), + o = that.options, + el = that.element, + oc = o.containment, + ce = ( oc instanceof $ ) ? oc.get( 0 ) : ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc; + + if ( !ce ) { + return; + } + + that.containerElement = $( ce ); + + if ( /document/.test( oc ) || oc === document ) { + that.containerOffset = { + left: 0, + top: 0 + }; + that.containerPosition = { + left: 0, + top: 0 + }; + + that.parentData = { + element: $( document ), + left: 0, + top: 0, + width: $( document ).width(), + height: $( document ).height() || document.body.parentNode.scrollHeight + }; + } else { + element = $( ce ); + p = []; + $([ "Top", "Right", "Left", "Bottom" ]).each(function( i, name ) { + p[ i ] = that._num( element.css( "padding" + name ) ); + }); + + that.containerOffset = element.offset(); + that.containerPosition = element.position(); + that.containerSize = { + height: ( element.innerHeight() - p[ 3 ] ), + width: ( element.innerWidth() - p[ 1 ] ) + }; + + co = that.containerOffset; + ch = that.containerSize.height; + cw = that.containerSize.width; + width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw ); + height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ; + + that.parentData = { + element: ce, + left: co.left, + top: co.top, + width: width, + height: height + }; + } + }, + + resize: function( event ) { + var woset, hoset, isParent, isOffsetRelative, + that = $( this ).resizable( "instance" ), + o = that.options, + co = that.containerOffset, + cp = that.position, + pRatio = that._aspectRatio || event.shiftKey, + cop = { + top: 0, + left: 0 + }, + ce = that.containerElement, + continueResize = true; + + if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) { + cop = co; + } + + if ( cp.left < ( that._helper ? co.left : 0 ) ) { + that.size.width = that.size.width + + ( that._helper ? + ( that.position.left - co.left ) : + ( that.position.left - cop.left ) ); + + if ( pRatio ) { + that.size.height = that.size.width / that.aspectRatio; + continueResize = false; + } + that.position.left = o.helper ? co.left : 0; + } + + if ( cp.top < ( that._helper ? co.top : 0 ) ) { + that.size.height = that.size.height + + ( that._helper ? + ( that.position.top - co.top ) : + that.position.top ); + + if ( pRatio ) { + that.size.width = that.size.height * that.aspectRatio; + continueResize = false; + } + that.position.top = that._helper ? co.top : 0; + } + + isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 ); + isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) ); + + if ( isParent && isOffsetRelative ) { + that.offset.left = that.parentData.left + that.position.left; + that.offset.top = that.parentData.top + that.position.top; + } else { + that.offset.left = that.element.offset().left; + that.offset.top = that.element.offset().top; + } + + woset = Math.abs( that.sizeDiff.width + + (that._helper ? + that.offset.left - cop.left : + (that.offset.left - co.left)) ); + + hoset = Math.abs( that.sizeDiff.height + + (that._helper ? + that.offset.top - cop.top : + (that.offset.top - co.top)) ); + + if ( woset + that.size.width >= that.parentData.width ) { + that.size.width = that.parentData.width - woset; + if ( pRatio ) { + that.size.height = that.size.width / that.aspectRatio; + continueResize = false; + } + } + + if ( hoset + that.size.height >= that.parentData.height ) { + that.size.height = that.parentData.height - hoset; + if ( pRatio ) { + that.size.width = that.size.height * that.aspectRatio; + continueResize = false; + } + } + + if ( !continueResize ) { + that.position.left = that.prevPosition.left; + that.position.top = that.prevPosition.top; + that.size.width = that.prevSize.width; + that.size.height = that.prevSize.height; + } + }, + + stop: function() { + var that = $( this ).resizable( "instance" ), + o = that.options, + co = that.containerOffset, + cop = that.containerPosition, + ce = that.containerElement, + helper = $( that.helper ), + ho = helper.offset(), + w = helper.outerWidth() - that.sizeDiff.width, + h = helper.outerHeight() - that.sizeDiff.height; + + if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) { + $( this ).css({ + left: ho.left - cop.left - co.left, + width: w, + height: h + }); + } + + if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) { + $( this ).css({ + left: ho.left - cop.left - co.left, + width: w, + height: h + }); + } + } +}); + +$.ui.plugin.add("resizable", "alsoResize", { + + start: function() { + var that = $(this).resizable( "instance" ), + o = that.options; + + $(o.alsoResize).each(function() { + var el = $(this); + el.data("ui-resizable-alsoresize", { + width: parseInt(el.width(), 10), height: parseInt(el.height(), 10), + left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10) + }); + }); + }, + + resize: function(event, ui) { + var that = $(this).resizable( "instance" ), + o = that.options, + os = that.originalSize, + op = that.originalPosition, + delta = { + height: (that.size.height - os.height) || 0, + width: (that.size.width - os.width) || 0, + top: (that.position.top - op.top) || 0, + left: (that.position.left - op.left) || 0 + }; + + $(o.alsoResize).each(function() { + var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {}, + css = el.parents(ui.originalElement[0]).length ? + [ "width", "height" ] : + [ "width", "height", "top", "left" ]; + + $.each(css, function(i, prop) { + var sum = (start[prop] || 0) + (delta[prop] || 0); + if (sum && sum >= 0) { + style[prop] = sum || null; + } + }); + + el.css(style); + }); + }, + + stop: function() { + $(this).removeData("resizable-alsoresize"); + } +}); + +$.ui.plugin.add("resizable", "ghost", { + + start: function() { + + var that = $(this).resizable( "instance" ), o = that.options, cs = that.size; + + that.ghost = that.originalElement.clone(); + that.ghost + .css({ + opacity: 0.25, + display: "block", + position: "relative", + height: cs.height, + width: cs.width, + margin: 0, + left: 0, + top: 0 + }) + .addClass("ui-resizable-ghost") + .addClass(typeof o.ghost === "string" ? o.ghost : ""); + + that.ghost.appendTo(that.helper); + + }, + + resize: function() { + var that = $(this).resizable( "instance" ); + if (that.ghost) { + that.ghost.css({ + position: "relative", + height: that.size.height, + width: that.size.width + }); + } + }, + + stop: function() { + var that = $(this).resizable( "instance" ); + if (that.ghost && that.helper) { + that.helper.get(0).removeChild(that.ghost.get(0)); + } + } + +}); + +$.ui.plugin.add("resizable", "grid", { + + resize: function() { + var outerDimensions, + that = $(this).resizable( "instance" ), + o = that.options, + cs = that.size, + os = that.originalSize, + op = that.originalPosition, + a = that.axis, + grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid, + gridX = (grid[0] || 1), + gridY = (grid[1] || 1), + ox = Math.round((cs.width - os.width) / gridX) * gridX, + oy = Math.round((cs.height - os.height) / gridY) * gridY, + newWidth = os.width + ox, + newHeight = os.height + oy, + isMaxWidth = o.maxWidth && (o.maxWidth < newWidth), + isMaxHeight = o.maxHeight && (o.maxHeight < newHeight), + isMinWidth = o.minWidth && (o.minWidth > newWidth), + isMinHeight = o.minHeight && (o.minHeight > newHeight); + + o.grid = grid; + + if (isMinWidth) { + newWidth += gridX; + } + if (isMinHeight) { + newHeight += gridY; + } + if (isMaxWidth) { + newWidth -= gridX; + } + if (isMaxHeight) { + newHeight -= gridY; + } + + if (/^(se|s|e)$/.test(a)) { + that.size.width = newWidth; + that.size.height = newHeight; + } else if (/^(ne)$/.test(a)) { + that.size.width = newWidth; + that.size.height = newHeight; + that.position.top = op.top - oy; + } else if (/^(sw)$/.test(a)) { + that.size.width = newWidth; + that.size.height = newHeight; + that.position.left = op.left - ox; + } else { + if ( newHeight - gridY <= 0 || newWidth - gridX <= 0) { + outerDimensions = that._getPaddingPlusBorderDimensions( this ); + } + + if ( newHeight - gridY > 0 ) { + that.size.height = newHeight; + that.position.top = op.top - oy; + } else { + newHeight = gridY - outerDimensions.height; + that.size.height = newHeight; + that.position.top = op.top + os.height - newHeight; + } + if ( newWidth - gridX > 0 ) { + that.size.width = newWidth; + that.position.left = op.left - ox; + } else { + newWidth = gridX - outerDimensions.width; + that.size.width = newWidth; + that.position.left = op.left + os.width - newWidth; + } + } + } + +}); + +var resizable = $.ui.resizable; + + +/*! + * jQuery UI Dialog 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/dialog/ + */ + + +var dialog = $.widget( "ui.dialog", { + version: "1.11.4", + options: { + appendTo: "body", + autoOpen: true, + buttons: [], + closeOnEscape: true, + closeText: "Close", + dialogClass: "", + draggable: true, + hide: null, + height: "auto", + maxHeight: null, + maxWidth: null, + minHeight: 150, + minWidth: 150, + modal: false, + position: { + my: "center", + at: "center", + of: window, + collision: "fit", + // Ensure the titlebar is always visible + using: function( pos ) { + var topOffset = $( this ).css( pos ).offset().top; + if ( topOffset < 0 ) { + $( this ).css( "top", pos.top - topOffset ); + } + } + }, + resizable: true, + show: null, + title: null, + width: 300, + + // callbacks + beforeClose: null, + close: null, + drag: null, + dragStart: null, + dragStop: null, + focus: null, + open: null, + resize: null, + resizeStart: null, + resizeStop: null + }, + + sizeRelatedOptions: { + buttons: true, + height: true, + maxHeight: true, + maxWidth: true, + minHeight: true, + minWidth: true, + width: true + }, + + resizableRelatedOptions: { + maxHeight: true, + maxWidth: true, + minHeight: true, + minWidth: true + }, + + _create: function() { + this.originalCss = { + display: this.element[ 0 ].style.display, + width: this.element[ 0 ].style.width, + minHeight: this.element[ 0 ].style.minHeight, + maxHeight: this.element[ 0 ].style.maxHeight, + height: this.element[ 0 ].style.height + }; + this.originalPosition = { + parent: this.element.parent(), + index: this.element.parent().children().index( this.element ) + }; + this.originalTitle = this.element.attr( "title" ); + this.options.title = this.options.title || this.originalTitle; + + this._createWrapper(); + + this.element + .show() + .removeAttr( "title" ) + .addClass( "ui-dialog-content ui-widget-content" ) + .appendTo( this.uiDialog ); + + this._createTitlebar(); + this._createButtonPane(); + + if ( this.options.draggable && $.fn.draggable ) { + this._makeDraggable(); + } + if ( this.options.resizable && $.fn.resizable ) { + this._makeResizable(); + } + + this._isOpen = false; + + this._trackFocus(); + }, + + _init: function() { + if ( this.options.autoOpen ) { + this.open(); + } + }, + + _appendTo: function() { + var element = this.options.appendTo; + if ( element && (element.jquery || element.nodeType) ) { + return $( element ); + } + return this.document.find( element || "body" ).eq( 0 ); + }, + + _destroy: function() { + var next, + originalPosition = this.originalPosition; + + this._untrackInstance(); + this._destroyOverlay(); + + this.element + .removeUniqueId() + .removeClass( "ui-dialog-content ui-widget-content" ) + .css( this.originalCss ) + // Without detaching first, the following becomes really slow + .detach(); + + this.uiDialog.stop( true, true ).remove(); + + if ( this.originalTitle ) { + this.element.attr( "title", this.originalTitle ); + } + + next = originalPosition.parent.children().eq( originalPosition.index ); + // Don't try to place the dialog next to itself (#8613) + if ( next.length && next[ 0 ] !== this.element[ 0 ] ) { + next.before( this.element ); + } else { + originalPosition.parent.append( this.element ); + } + }, + + widget: function() { + return this.uiDialog; + }, + + disable: $.noop, + enable: $.noop, + + close: function( event ) { + var activeElement, + that = this; + + if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) { + return; + } + + this._isOpen = false; + this._focusedElement = null; + this._destroyOverlay(); + this._untrackInstance(); + + if ( !this.opener.filter( ":focusable" ).focus().length ) { + + // support: IE9 + // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe> + try { + activeElement = this.document[ 0 ].activeElement; + + // Support: IE9, IE10 + // If the <body> is blurred, IE will switch windows, see #4520 + if ( activeElement && activeElement.nodeName.toLowerCase() !== "body" ) { + + // Hiding a focused element doesn't trigger blur in WebKit + // so in case we have nothing to focus on, explicitly blur the active element + // https://bugs.webkit.org/show_bug.cgi?id=47182 + $( activeElement ).blur(); + } + } catch ( error ) {} + } + + this._hide( this.uiDialog, this.options.hide, function() { + that._trigger( "close", event ); + }); + }, + + isOpen: function() { + return this._isOpen; + }, + + moveToTop: function() { + this._moveToTop(); + }, + + _moveToTop: function( event, silent ) { + var moved = false, + zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map(function() { + return +$( this ).css( "z-index" ); + }).get(), + zIndexMax = Math.max.apply( null, zIndices ); + + if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) { + this.uiDialog.css( "z-index", zIndexMax + 1 ); + moved = true; + } + + if ( moved && !silent ) { + this._trigger( "focus", event ); + } + return moved; + }, + + open: function() { + var that = this; + if ( this._isOpen ) { + if ( this._moveToTop() ) { + this._focusTabbable(); + } + return; + } + + this._isOpen = true; + this.opener = $( this.document[ 0 ].activeElement ); + + this._size(); + this._position(); + this._createOverlay(); + this._moveToTop( null, true ); + + // Ensure the overlay is moved to the top with the dialog, but only when + // opening. The overlay shouldn't move after the dialog is open so that + // modeless dialogs opened after the modal dialog stack properly. + if ( this.overlay ) { + this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 ); + } + + this._show( this.uiDialog, this.options.show, function() { + that._focusTabbable(); + that._trigger( "focus" ); + }); + + // Track the dialog immediately upon openening in case a focus event + // somehow occurs outside of the dialog before an element inside the + // dialog is focused (#10152) + this._makeFocusTarget(); + + this._trigger( "open" ); + }, + + _focusTabbable: function() { + // Set focus to the first match: + // 1. An element that was focused previously + // 2. First element inside the dialog matching [autofocus] + // 3. Tabbable element inside the content element + // 4. Tabbable element inside the buttonpane + // 5. The close button + // 6. The dialog itself + var hasFocus = this._focusedElement; + if ( !hasFocus ) { + hasFocus = this.element.find( "[autofocus]" ); + } + if ( !hasFocus.length ) { + hasFocus = this.element.find( ":tabbable" ); + } + if ( !hasFocus.length ) { + hasFocus = this.uiDialogButtonPane.find( ":tabbable" ); + } + if ( !hasFocus.length ) { + hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" ); + } + if ( !hasFocus.length ) { + hasFocus = this.uiDialog; + } + hasFocus.eq( 0 ).focus(); + }, + + _keepFocus: function( event ) { + function checkFocus() { + var activeElement = this.document[0].activeElement, + isActive = this.uiDialog[0] === activeElement || + $.contains( this.uiDialog[0], activeElement ); + if ( !isActive ) { + this._focusTabbable(); + } + } + event.preventDefault(); + checkFocus.call( this ); + // support: IE + // IE <= 8 doesn't prevent moving focus even with event.preventDefault() + // so we check again later + this._delay( checkFocus ); + }, + + _createWrapper: function() { + this.uiDialog = $("<div>") + .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " + + this.options.dialogClass ) + .hide() + .attr({ + // Setting tabIndex makes the div focusable + tabIndex: -1, + role: "dialog" + }) + .appendTo( this._appendTo() ); + + this._on( this.uiDialog, { + keydown: function( event ) { + if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && + event.keyCode === $.ui.keyCode.ESCAPE ) { + event.preventDefault(); + this.close( event ); + return; + } + + // prevent tabbing out of dialogs + if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) { + return; + } + var tabbables = this.uiDialog.find( ":tabbable" ), + first = tabbables.filter( ":first" ), + last = tabbables.filter( ":last" ); + + if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) { + this._delay(function() { + first.focus(); + }); + event.preventDefault(); + } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) { + this._delay(function() { + last.focus(); + }); + event.preventDefault(); + } + }, + mousedown: function( event ) { + if ( this._moveToTop( event ) ) { + this._focusTabbable(); + } + } + }); + + // We assume that any existing aria-describedby attribute means + // that the dialog content is marked up properly + // otherwise we brute force the content as the description + if ( !this.element.find( "[aria-describedby]" ).length ) { + this.uiDialog.attr({ + "aria-describedby": this.element.uniqueId().attr( "id" ) + }); + } + }, + + _createTitlebar: function() { + var uiDialogTitle; + + this.uiDialogTitlebar = $( "<div>" ) + .addClass( "ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix" ) + .prependTo( this.uiDialog ); + this._on( this.uiDialogTitlebar, { + mousedown: function( event ) { + // Don't prevent click on close button (#8838) + // Focusing a dialog that is partially scrolled out of view + // causes the browser to scroll it into view, preventing the click event + if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) { + // Dialog isn't getting focus when dragging (#8063) + this.uiDialog.focus(); + } + } + }); + + // support: IE + // Use type="button" to prevent enter keypresses in textboxes from closing the + // dialog in IE (#9312) + this.uiDialogTitlebarClose = $( "<button type='button'></button>" ) + .button({ + label: this.options.closeText, + icons: { + primary: "ui-icon-closethick" + }, + text: false + }) + .addClass( "ui-dialog-titlebar-close" ) + .appendTo( this.uiDialogTitlebar ); + this._on( this.uiDialogTitlebarClose, { + click: function( event ) { + event.preventDefault(); + this.close( event ); + } + }); + + uiDialogTitle = $( "<span>" ) + .uniqueId() + .addClass( "ui-dialog-title" ) + .prependTo( this.uiDialogTitlebar ); + this._title( uiDialogTitle ); + + this.uiDialog.attr({ + "aria-labelledby": uiDialogTitle.attr( "id" ) + }); + }, + + _title: function( title ) { + if ( !this.options.title ) { + title.html( " " ); + } + title.text( this.options.title ); + }, + + _createButtonPane: function() { + this.uiDialogButtonPane = $( "<div>" ) + .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" ); + + this.uiButtonSet = $( "<div>" ) + .addClass( "ui-dialog-buttonset" ) + .appendTo( this.uiDialogButtonPane ); + + this._createButtons(); + }, + + _createButtons: function() { + var that = this, + buttons = this.options.buttons; + + // if we already have a button pane, remove it + this.uiDialogButtonPane.remove(); + this.uiButtonSet.empty(); + + if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) { + this.uiDialog.removeClass( "ui-dialog-buttons" ); + return; + } + + $.each( buttons, function( name, props ) { + var click, buttonOptions; + props = $.isFunction( props ) ? + { click: props, text: name } : + props; + // Default to a non-submitting button + props = $.extend( { type: "button" }, props ); + // Change the context for the click callback to be the main element + click = props.click; + props.click = function() { + click.apply( that.element[ 0 ], arguments ); + }; + buttonOptions = { + icons: props.icons, + text: props.showText + }; + delete props.icons; + delete props.showText; + $( "<button></button>", props ) + .button( buttonOptions ) + .appendTo( that.uiButtonSet ); + }); + this.uiDialog.addClass( "ui-dialog-buttons" ); + this.uiDialogButtonPane.appendTo( this.uiDialog ); + }, + + _makeDraggable: function() { + var that = this, + options = this.options; + + function filteredUi( ui ) { + return { + position: ui.position, + offset: ui.offset + }; + } + + this.uiDialog.draggable({ + cancel: ".ui-dialog-content, .ui-dialog-titlebar-close", + handle: ".ui-dialog-titlebar", + containment: "document", + start: function( event, ui ) { + $( this ).addClass( "ui-dialog-dragging" ); + that._blockFrames(); + that._trigger( "dragStart", event, filteredUi( ui ) ); + }, + drag: function( event, ui ) { + that._trigger( "drag", event, filteredUi( ui ) ); + }, + stop: function( event, ui ) { + var left = ui.offset.left - that.document.scrollLeft(), + top = ui.offset.top - that.document.scrollTop(); + + options.position = { + my: "left top", + at: "left" + (left >= 0 ? "+" : "") + left + " " + + "top" + (top >= 0 ? "+" : "") + top, + of: that.window + }; + $( this ).removeClass( "ui-dialog-dragging" ); + that._unblockFrames(); + that._trigger( "dragStop", event, filteredUi( ui ) ); + } + }); + }, + + _makeResizable: function() { + var that = this, + options = this.options, + handles = options.resizable, + // .ui-resizable has position: relative defined in the stylesheet + // but dialogs have to use absolute or fixed positioning + position = this.uiDialog.css("position"), + resizeHandles = typeof handles === "string" ? + handles : + "n,e,s,w,se,sw,ne,nw"; + + function filteredUi( ui ) { + return { + originalPosition: ui.originalPosition, + originalSize: ui.originalSize, + position: ui.position, + size: ui.size + }; + } + + this.uiDialog.resizable({ + cancel: ".ui-dialog-content", + containment: "document", + alsoResize: this.element, + maxWidth: options.maxWidth, + maxHeight: options.maxHeight, + minWidth: options.minWidth, + minHeight: this._minHeight(), + handles: resizeHandles, + start: function( event, ui ) { + $( this ).addClass( "ui-dialog-resizing" ); + that._blockFrames(); + that._trigger( "resizeStart", event, filteredUi( ui ) ); + }, + resize: function( event, ui ) { + that._trigger( "resize", event, filteredUi( ui ) ); + }, + stop: function( event, ui ) { + var offset = that.uiDialog.offset(), + left = offset.left - that.document.scrollLeft(), + top = offset.top - that.document.scrollTop(); + + options.height = that.uiDialog.height(); + options.width = that.uiDialog.width(); + options.position = { + my: "left top", + at: "left" + (left >= 0 ? "+" : "") + left + " " + + "top" + (top >= 0 ? "+" : "") + top, + of: that.window + }; + $( this ).removeClass( "ui-dialog-resizing" ); + that._unblockFrames(); + that._trigger( "resizeStop", event, filteredUi( ui ) ); + } + }) + .css( "position", position ); + }, + + _trackFocus: function() { + this._on( this.widget(), { + focusin: function( event ) { + this._makeFocusTarget(); + this._focusedElement = $( event.target ); + } + }); + }, + + _makeFocusTarget: function() { + this._untrackInstance(); + this._trackingInstances().unshift( this ); + }, + + _untrackInstance: function() { + var instances = this._trackingInstances(), + exists = $.inArray( this, instances ); + if ( exists !== -1 ) { + instances.splice( exists, 1 ); + } + }, + + _trackingInstances: function() { + var instances = this.document.data( "ui-dialog-instances" ); + if ( !instances ) { + instances = []; + this.document.data( "ui-dialog-instances", instances ); + } + return instances; + }, + + _minHeight: function() { + var options = this.options; + + return options.height === "auto" ? + options.minHeight : + Math.min( options.minHeight, options.height ); + }, + + _position: function() { + // Need to show the dialog to get the actual offset in the position plugin + var isVisible = this.uiDialog.is( ":visible" ); + if ( !isVisible ) { + this.uiDialog.show(); + } + this.uiDialog.position( this.options.position ); + if ( !isVisible ) { + this.uiDialog.hide(); + } + }, + + _setOptions: function( options ) { + var that = this, + resize = false, + resizableOptions = {}; + + $.each( options, function( key, value ) { + that._setOption( key, value ); + + if ( key in that.sizeRelatedOptions ) { + resize = true; + } + if ( key in that.resizableRelatedOptions ) { + resizableOptions[ key ] = value; + } + }); + + if ( resize ) { + this._size(); + this._position(); + } + if ( this.uiDialog.is( ":data(ui-resizable)" ) ) { + this.uiDialog.resizable( "option", resizableOptions ); + } + }, + + _setOption: function( key, value ) { + var isDraggable, isResizable, + uiDialog = this.uiDialog; + + if ( key === "dialogClass" ) { + uiDialog + .removeClass( this.options.dialogClass ) + .addClass( value ); + } + + if ( key === "disabled" ) { + return; + } + + this._super( key, value ); + + if ( key === "appendTo" ) { + this.uiDialog.appendTo( this._appendTo() ); + } + + if ( key === "buttons" ) { + this._createButtons(); + } + + if ( key === "closeText" ) { + this.uiDialogTitlebarClose.button({ + // Ensure that we always pass a string + label: "" + value + }); + } + + if ( key === "draggable" ) { + isDraggable = uiDialog.is( ":data(ui-draggable)" ); + if ( isDraggable && !value ) { + uiDialog.draggable( "destroy" ); + } + + if ( !isDraggable && value ) { + this._makeDraggable(); + } + } + + if ( key === "position" ) { + this._position(); + } + + if ( key === "resizable" ) { + // currently resizable, becoming non-resizable + isResizable = uiDialog.is( ":data(ui-resizable)" ); + if ( isResizable && !value ) { + uiDialog.resizable( "destroy" ); + } + + // currently resizable, changing handles + if ( isResizable && typeof value === "string" ) { + uiDialog.resizable( "option", "handles", value ); + } + + // currently non-resizable, becoming resizable + if ( !isResizable && value !== false ) { + this._makeResizable(); + } + } + + if ( key === "title" ) { + this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) ); + } + }, + + _size: function() { + // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content + // divs will both have width and height set, so we need to reset them + var nonContentHeight, minContentHeight, maxContentHeight, + options = this.options; + + // Reset content sizing + this.element.show().css({ + width: "auto", + minHeight: 0, + maxHeight: "none", + height: 0 + }); + + if ( options.minWidth > options.width ) { + options.width = options.minWidth; + } + + // reset wrapper sizing + // determine the height of all the non-content elements + nonContentHeight = this.uiDialog.css({ + height: "auto", + width: options.width + }) + .outerHeight(); + minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); + maxContentHeight = typeof options.maxHeight === "number" ? + Math.max( 0, options.maxHeight - nonContentHeight ) : + "none"; + + if ( options.height === "auto" ) { + this.element.css({ + minHeight: minContentHeight, + maxHeight: maxContentHeight, + height: "auto" + }); + } else { + this.element.height( Math.max( 0, options.height - nonContentHeight ) ); + } + + if ( this.uiDialog.is( ":data(ui-resizable)" ) ) { + this.uiDialog.resizable( "option", "minHeight", this._minHeight() ); + } + }, + + _blockFrames: function() { + this.iframeBlocks = this.document.find( "iframe" ).map(function() { + var iframe = $( this ); + + return $( "<div>" ) + .css({ + position: "absolute", + width: iframe.outerWidth(), + height: iframe.outerHeight() + }) + .appendTo( iframe.parent() ) + .offset( iframe.offset() )[0]; + }); + }, + + _unblockFrames: function() { + if ( this.iframeBlocks ) { + this.iframeBlocks.remove(); + delete this.iframeBlocks; + } + }, + + _allowInteraction: function( event ) { + if ( $( event.target ).closest( ".ui-dialog" ).length ) { + return true; + } + + // TODO: Remove hack when datepicker implements + // the .ui-front logic (#8989) + return !!$( event.target ).closest( ".ui-datepicker" ).length; + }, + + _createOverlay: function() { + if ( !this.options.modal ) { + return; + } + + // We use a delay in case the overlay is created from an + // event that we're going to be cancelling (#2804) + var isOpening = true; + this._delay(function() { + isOpening = false; + }); + + if ( !this.document.data( "ui-dialog-overlays" ) ) { + + // Prevent use of anchors and inputs + // Using _on() for an event handler shared across many instances is + // safe because the dialogs stack and must be closed in reverse order + this._on( this.document, { + focusin: function( event ) { + if ( isOpening ) { + return; + } + + if ( !this._allowInteraction( event ) ) { + event.preventDefault(); + this._trackingInstances()[ 0 ]._focusTabbable(); + } + } + }); + } + + this.overlay = $( "<div>" ) + .addClass( "ui-widget-overlay ui-front" ) + .appendTo( this._appendTo() ); + this._on( this.overlay, { + mousedown: "_keepFocus" + }); + this.document.data( "ui-dialog-overlays", + (this.document.data( "ui-dialog-overlays" ) || 0) + 1 ); + }, + + _destroyOverlay: function() { + if ( !this.options.modal ) { + return; + } + + if ( this.overlay ) { + var overlays = this.document.data( "ui-dialog-overlays" ) - 1; + + if ( !overlays ) { + this.document + .unbind( "focusin" ) + .removeData( "ui-dialog-overlays" ); + } else { + this.document.data( "ui-dialog-overlays", overlays ); + } + + this.overlay.remove(); + this.overlay = null; + } + } +}); + + +/*! + * jQuery UI Droppable 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/droppable/ + */ + + +$.widget( "ui.droppable", { + version: "1.11.4", + widgetEventPrefix: "drop", + options: { + accept: "*", + activeClass: false, + addClasses: true, + greedy: false, + hoverClass: false, + scope: "default", + tolerance: "intersect", + + // callbacks + activate: null, + deactivate: null, + drop: null, + out: null, + over: null + }, + _create: function() { + + var proportions, + o = this.options, + accept = o.accept; + + this.isover = false; + this.isout = true; + + this.accept = $.isFunction( accept ) ? accept : function( d ) { + return d.is( accept ); + }; + + this.proportions = function( /* valueToWrite */ ) { + if ( arguments.length ) { + // Store the droppable's proportions + proportions = arguments[ 0 ]; + } else { + // Retrieve or derive the droppable's proportions + return proportions ? + proportions : + proportions = { + width: this.element[ 0 ].offsetWidth, + height: this.element[ 0 ].offsetHeight + }; + } + }; + + this._addToManager( o.scope ); + + o.addClasses && this.element.addClass( "ui-droppable" ); + + }, + + _addToManager: function( scope ) { + // Add the reference and positions to the manager + $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || []; + $.ui.ddmanager.droppables[ scope ].push( this ); + }, + + _splice: function( drop ) { + var i = 0; + for ( ; i < drop.length; i++ ) { + if ( drop[ i ] === this ) { + drop.splice( i, 1 ); + } + } + }, + + _destroy: function() { + var drop = $.ui.ddmanager.droppables[ this.options.scope ]; + + this._splice( drop ); + + this.element.removeClass( "ui-droppable ui-droppable-disabled" ); + }, + + _setOption: function( key, value ) { + + if ( key === "accept" ) { + this.accept = $.isFunction( value ) ? value : function( d ) { + return d.is( value ); + }; + } else if ( key === "scope" ) { + var drop = $.ui.ddmanager.droppables[ this.options.scope ]; + + this._splice( drop ); + this._addToManager( value ); + } + + this._super( key, value ); + }, + + _activate: function( event ) { + var draggable = $.ui.ddmanager.current; + if ( this.options.activeClass ) { + this.element.addClass( this.options.activeClass ); + } + if ( draggable ){ + this._trigger( "activate", event, this.ui( draggable ) ); + } + }, + + _deactivate: function( event ) { + var draggable = $.ui.ddmanager.current; + if ( this.options.activeClass ) { + this.element.removeClass( this.options.activeClass ); + } + if ( draggable ){ + this._trigger( "deactivate", event, this.ui( draggable ) ); + } + }, + + _over: function( event ) { + + var draggable = $.ui.ddmanager.current; + + // Bail if draggable and droppable are same element + if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) { + return; + } + + if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) { + if ( this.options.hoverClass ) { + this.element.addClass( this.options.hoverClass ); + } + this._trigger( "over", event, this.ui( draggable ) ); + } + + }, + + _out: function( event ) { + + var draggable = $.ui.ddmanager.current; + + // Bail if draggable and droppable are same element + if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) { + return; + } + + if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) { + if ( this.options.hoverClass ) { + this.element.removeClass( this.options.hoverClass ); + } + this._trigger( "out", event, this.ui( draggable ) ); + } + + }, + + _drop: function( event, custom ) { + + var draggable = custom || $.ui.ddmanager.current, + childrenIntersection = false; + + // Bail if draggable and droppable are same element + if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) { + return false; + } + + this.element.find( ":data(ui-droppable)" ).not( ".ui-draggable-dragging" ).each(function() { + var inst = $( this ).droppable( "instance" ); + if ( + inst.options.greedy && + !inst.options.disabled && + inst.options.scope === draggable.options.scope && + inst.accept.call( inst.element[ 0 ], ( draggable.currentItem || draggable.element ) ) && + $.ui.intersect( draggable, $.extend( inst, { offset: inst.element.offset() } ), inst.options.tolerance, event ) + ) { childrenIntersection = true; return false; } + }); + if ( childrenIntersection ) { + return false; + } + + if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) { + if ( this.options.activeClass ) { + this.element.removeClass( this.options.activeClass ); + } + if ( this.options.hoverClass ) { + this.element.removeClass( this.options.hoverClass ); + } + this._trigger( "drop", event, this.ui( draggable ) ); + return this.element; + } + + return false; + + }, + + ui: function( c ) { + return { + draggable: ( c.currentItem || c.element ), + helper: c.helper, + position: c.position, + offset: c.positionAbs + }; + } + +}); + +$.ui.intersect = (function() { + function isOverAxis( x, reference, size ) { + return ( x >= reference ) && ( x < ( reference + size ) ); + } + + return function( draggable, droppable, toleranceMode, event ) { + + if ( !droppable.offset ) { + return false; + } + + var x1 = ( draggable.positionAbs || draggable.position.absolute ).left + draggable.margins.left, + y1 = ( draggable.positionAbs || draggable.position.absolute ).top + draggable.margins.top, + x2 = x1 + draggable.helperProportions.width, + y2 = y1 + draggable.helperProportions.height, + l = droppable.offset.left, + t = droppable.offset.top, + r = l + droppable.proportions().width, + b = t + droppable.proportions().height; + + switch ( toleranceMode ) { + case "fit": + return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b ); + case "intersect": + return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half + x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half + t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half + y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half + case "pointer": + return isOverAxis( event.pageY, t, droppable.proportions().height ) && isOverAxis( event.pageX, l, droppable.proportions().width ); + case "touch": + return ( + ( y1 >= t && y1 <= b ) || // Top edge touching + ( y2 >= t && y2 <= b ) || // Bottom edge touching + ( y1 < t && y2 > b ) // Surrounded vertically + ) && ( + ( x1 >= l && x1 <= r ) || // Left edge touching + ( x2 >= l && x2 <= r ) || // Right edge touching + ( x1 < l && x2 > r ) // Surrounded horizontally + ); + default: + return false; + } + }; +})(); + +/* + This manager tracks offsets of draggables and droppables +*/ +$.ui.ddmanager = { + current: null, + droppables: { "default": [] }, + prepareOffsets: function( t, event ) { + + var i, j, + m = $.ui.ddmanager.droppables[ t.options.scope ] || [], + type = event ? event.type : null, // workaround for #2317 + list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack(); + + droppablesLoop: for ( i = 0; i < m.length; i++ ) { + + // No disabled and non-accepted + if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], ( t.currentItem || t.element ) ) ) ) { + continue; + } + + // Filter out elements in the current dragged item + for ( j = 0; j < list.length; j++ ) { + if ( list[ j ] === m[ i ].element[ 0 ] ) { + m[ i ].proportions().height = 0; + continue droppablesLoop; + } + } + + m[ i ].visible = m[ i ].element.css( "display" ) !== "none"; + if ( !m[ i ].visible ) { + continue; + } + + // Activate the droppable if used directly from draggables + if ( type === "mousedown" ) { + m[ i ]._activate.call( m[ i ], event ); + } + + m[ i ].offset = m[ i ].element.offset(); + m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth, height: m[ i ].element[ 0 ].offsetHeight }); + + } + + }, + drop: function( draggable, event ) { + + var dropped = false; + // Create a copy of the droppables in case the list changes during the drop (#9116) + $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() { + + if ( !this.options ) { + return; + } + if ( !this.options.disabled && this.visible && $.ui.intersect( draggable, this, this.options.tolerance, event ) ) { + dropped = this._drop.call( this, event ) || dropped; + } + + if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) { + this.isout = true; + this.isover = false; + this._deactivate.call( this, event ); + } + + }); + return dropped; + + }, + dragStart: function( draggable, event ) { + // Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003) + draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() { + if ( !draggable.options.refreshPositions ) { + $.ui.ddmanager.prepareOffsets( draggable, event ); + } + }); + }, + drag: function( draggable, event ) { + + // If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. + if ( draggable.options.refreshPositions ) { + $.ui.ddmanager.prepareOffsets( draggable, event ); + } + + // Run through all droppables and check their positions based on specific tolerance options + $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() { + + if ( this.options.disabled || this.greedyChild || !this.visible ) { + return; + } + + var parentInstance, scope, parent, + intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ), + c = !intersects && this.isover ? "isout" : ( intersects && !this.isover ? "isover" : null ); + if ( !c ) { + return; + } + + if ( this.options.greedy ) { + // find droppable parents with same scope + scope = this.options.scope; + parent = this.element.parents( ":data(ui-droppable)" ).filter(function() { + return $( this ).droppable( "instance" ).options.scope === scope; + }); + + if ( parent.length ) { + parentInstance = $( parent[ 0 ] ).droppable( "instance" ); + parentInstance.greedyChild = ( c === "isover" ); + } + } + + // we just moved into a greedy child + if ( parentInstance && c === "isover" ) { + parentInstance.isover = false; + parentInstance.isout = true; + parentInstance._out.call( parentInstance, event ); + } + + this[ c ] = true; + this[c === "isout" ? "isover" : "isout"] = false; + this[c === "isover" ? "_over" : "_out"].call( this, event ); + + // we just moved out of a greedy child + if ( parentInstance && c === "isout" ) { + parentInstance.isout = false; + parentInstance.isover = true; + parentInstance._over.call( parentInstance, event ); + } + }); + + }, + dragStop: function( draggable, event ) { + draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" ); + // Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003) + if ( !draggable.options.refreshPositions ) { + $.ui.ddmanager.prepareOffsets( draggable, event ); + } + } +}; + +var droppable = $.ui.droppable; + + +/*! + * jQuery UI Effects 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/category/effects-core/ + */ + + +var dataSpace = "ui-effects-", + + // Create a local jQuery because jQuery Color relies on it and the + // global may not exist with AMD and a custom build (#10199) + jQuery = $; + +$.effects = { + effect: {} +}; + +/*! + * jQuery Color Animations v2.1.2 + * https://github.com/jquery/jquery-color + * + * Copyright 2014 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * Date: Wed Jan 16 08:47:09 2013 -0600 + */ +(function( jQuery, undefined ) { + + var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor", + + // plusequals test for += 100 -= 100 + rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, + // a set of RE's that can match strings and generate color tuples. + stringParsers = [ { + re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + parse: function( execResult ) { + return [ + execResult[ 1 ], + execResult[ 2 ], + execResult[ 3 ], + execResult[ 4 ] + ]; + } + }, { + re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + parse: function( execResult ) { + return [ + execResult[ 1 ] * 2.55, + execResult[ 2 ] * 2.55, + execResult[ 3 ] * 2.55, + execResult[ 4 ] + ]; + } + }, { + // this regex ignores A-F because it's compared against an already lowercased string + re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/, + parse: function( execResult ) { + return [ + parseInt( execResult[ 1 ], 16 ), + parseInt( execResult[ 2 ], 16 ), + parseInt( execResult[ 3 ], 16 ) + ]; + } + }, { + // this regex ignores A-F because it's compared against an already lowercased string + re: /#([a-f0-9])([a-f0-9])([a-f0-9])/, + parse: function( execResult ) { + return [ + parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), + parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), + parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ) + ]; + } + }, { + re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + space: "hsla", + parse: function( execResult ) { + return [ + execResult[ 1 ], + execResult[ 2 ] / 100, + execResult[ 3 ] / 100, + execResult[ 4 ] + ]; + } + } ], + + // jQuery.Color( ) + color = jQuery.Color = function( color, green, blue, alpha ) { + return new jQuery.Color.fn.parse( color, green, blue, alpha ); + }, + spaces = { + rgba: { + props: { + red: { + idx: 0, + type: "byte" + }, + green: { + idx: 1, + type: "byte" + }, + blue: { + idx: 2, + type: "byte" + } + } + }, + + hsla: { + props: { + hue: { + idx: 0, + type: "degrees" + }, + saturation: { + idx: 1, + type: "percent" + }, + lightness: { + idx: 2, + type: "percent" + } + } + } + }, + propTypes = { + "byte": { + floor: true, + max: 255 + }, + "percent": { + max: 1 + }, + "degrees": { + mod: 360, + floor: true + } + }, + support = color.support = {}, + + // element for support tests + supportElem = jQuery( "<p>" )[ 0 ], + + // colors = jQuery.Color.names + colors, + + // local aliases of functions called often + each = jQuery.each; + +// determine rgba support immediately +supportElem.style.cssText = "background-color:rgba(1,1,1,.5)"; +support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1; + +// define cache name and alpha properties +// for rgba and hsla spaces +each( spaces, function( spaceName, space ) { + space.cache = "_" + spaceName; + space.props.alpha = { + idx: 3, + type: "percent", + def: 1 + }; +}); + +function clamp( value, prop, allowEmpty ) { + var type = propTypes[ prop.type ] || {}; + + if ( value == null ) { + return (allowEmpty || !prop.def) ? null : prop.def; + } + + // ~~ is an short way of doing floor for positive numbers + value = type.floor ? ~~value : parseFloat( value ); + + // IE will pass in empty strings as value for alpha, + // which will hit this case + if ( isNaN( value ) ) { + return prop.def; + } + + if ( type.mod ) { + // we add mod before modding to make sure that negatives values + // get converted properly: -10 -> 350 + return (value + type.mod) % type.mod; + } + + // for now all property types without mod have min and max + return 0 > value ? 0 : type.max < value ? type.max : value; +} + +function stringParse( string ) { + var inst = color(), + rgba = inst._rgba = []; + + string = string.toLowerCase(); + + each( stringParsers, function( i, parser ) { + var parsed, + match = parser.re.exec( string ), + values = match && parser.parse( match ), + spaceName = parser.space || "rgba"; + + if ( values ) { + parsed = inst[ spaceName ]( values ); + + // if this was an rgba parse the assignment might happen twice + // oh well.... + inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ]; + rgba = inst._rgba = parsed._rgba; + + // exit each( stringParsers ) here because we matched + return false; + } + }); + + // Found a stringParser that handled it + if ( rgba.length ) { + + // if this came from a parsed string, force "transparent" when alpha is 0 + // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) + if ( rgba.join() === "0,0,0,0" ) { + jQuery.extend( rgba, colors.transparent ); + } + return inst; + } + + // named colors + return colors[ string ]; +} + +color.fn = jQuery.extend( color.prototype, { + parse: function( red, green, blue, alpha ) { + if ( red === undefined ) { + this._rgba = [ null, null, null, null ]; + return this; + } + if ( red.jquery || red.nodeType ) { + red = jQuery( red ).css( green ); + green = undefined; + } + + var inst = this, + type = jQuery.type( red ), + rgba = this._rgba = []; + + // more than 1 argument specified - assume ( red, green, blue, alpha ) + if ( green !== undefined ) { + red = [ red, green, blue, alpha ]; + type = "array"; + } + + if ( type === "string" ) { + return this.parse( stringParse( red ) || colors._default ); + } + + if ( type === "array" ) { + each( spaces.rgba.props, function( key, prop ) { + rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); + }); + return this; + } + + if ( type === "object" ) { + if ( red instanceof color ) { + each( spaces, function( spaceName, space ) { + if ( red[ space.cache ] ) { + inst[ space.cache ] = red[ space.cache ].slice(); + } + }); + } else { + each( spaces, function( spaceName, space ) { + var cache = space.cache; + each( space.props, function( key, prop ) { + + // if the cache doesn't exist, and we know how to convert + if ( !inst[ cache ] && space.to ) { + + // if the value was null, we don't need to copy it + // if the key was alpha, we don't need to copy it either + if ( key === "alpha" || red[ key ] == null ) { + return; + } + inst[ cache ] = space.to( inst._rgba ); + } + + // this is the only case where we allow nulls for ALL properties. + // call clamp with alwaysAllowEmpty + inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); + }); + + // everything defined but alpha? + if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) { + // use the default of 1 + inst[ cache ][ 3 ] = 1; + if ( space.from ) { + inst._rgba = space.from( inst[ cache ] ); + } + } + }); + } + return this; + } + }, + is: function( compare ) { + var is = color( compare ), + same = true, + inst = this; + + each( spaces, function( _, space ) { + var localCache, + isCache = is[ space.cache ]; + if (isCache) { + localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || []; + each( space.props, function( _, prop ) { + if ( isCache[ prop.idx ] != null ) { + same = ( isCache[ prop.idx ] === localCache[ prop.idx ] ); + return same; + } + }); + } + return same; + }); + return same; + }, + _space: function() { + var used = [], + inst = this; + each( spaces, function( spaceName, space ) { + if ( inst[ space.cache ] ) { + used.push( spaceName ); + } + }); + return used.pop(); + }, + transition: function( other, distance ) { + var end = color( other ), + spaceName = end._space(), + space = spaces[ spaceName ], + startColor = this.alpha() === 0 ? color( "transparent" ) : this, + start = startColor[ space.cache ] || space.to( startColor._rgba ), + result = start.slice(); + + end = end[ space.cache ]; + each( space.props, function( key, prop ) { + var index = prop.idx, + startValue = start[ index ], + endValue = end[ index ], + type = propTypes[ prop.type ] || {}; + + // if null, don't override start value + if ( endValue === null ) { + return; + } + // if null - use end + if ( startValue === null ) { + result[ index ] = endValue; + } else { + if ( type.mod ) { + if ( endValue - startValue > type.mod / 2 ) { + startValue += type.mod; + } else if ( startValue - endValue > type.mod / 2 ) { + startValue -= type.mod; + } + } + result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); + } + }); + return this[ spaceName ]( result ); + }, + blend: function( opaque ) { + // if we are already opaque - return ourself + if ( this._rgba[ 3 ] === 1 ) { + return this; + } + + var rgb = this._rgba.slice(), + a = rgb.pop(), + blend = color( opaque )._rgba; + + return color( jQuery.map( rgb, function( v, i ) { + return ( 1 - a ) * blend[ i ] + a * v; + })); + }, + toRgbaString: function() { + var prefix = "rgba(", + rgba = jQuery.map( this._rgba, function( v, i ) { + return v == null ? ( i > 2 ? 1 : 0 ) : v; + }); + + if ( rgba[ 3 ] === 1 ) { + rgba.pop(); + prefix = "rgb("; + } + + return prefix + rgba.join() + ")"; + }, + toHslaString: function() { + var prefix = "hsla(", + hsla = jQuery.map( this.hsla(), function( v, i ) { + if ( v == null ) { + v = i > 2 ? 1 : 0; + } + + // catch 1 and 2 + if ( i && i < 3 ) { + v = Math.round( v * 100 ) + "%"; + } + return v; + }); + + if ( hsla[ 3 ] === 1 ) { + hsla.pop(); + prefix = "hsl("; + } + return prefix + hsla.join() + ")"; + }, + toHexString: function( includeAlpha ) { + var rgba = this._rgba.slice(), + alpha = rgba.pop(); + + if ( includeAlpha ) { + rgba.push( ~~( alpha * 255 ) ); + } + + return "#" + jQuery.map( rgba, function( v ) { + + // default to 0 when nulls exist + v = ( v || 0 ).toString( 16 ); + return v.length === 1 ? "0" + v : v; + }).join(""); + }, + toString: function() { + return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString(); + } +}); +color.fn.parse.prototype = color.fn; + +// hsla conversions adapted from: +// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021 + +function hue2rgb( p, q, h ) { + h = ( h + 1 ) % 1; + if ( h * 6 < 1 ) { + return p + ( q - p ) * h * 6; + } + if ( h * 2 < 1) { + return q; + } + if ( h * 3 < 2 ) { + return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6; + } + return p; +} + +spaces.hsla.to = function( rgba ) { + if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { + return [ null, null, null, rgba[ 3 ] ]; + } + var r = rgba[ 0 ] / 255, + g = rgba[ 1 ] / 255, + b = rgba[ 2 ] / 255, + a = rgba[ 3 ], + max = Math.max( r, g, b ), + min = Math.min( r, g, b ), + diff = max - min, + add = max + min, + l = add * 0.5, + h, s; + + if ( min === max ) { + h = 0; + } else if ( r === max ) { + h = ( 60 * ( g - b ) / diff ) + 360; + } else if ( g === max ) { + h = ( 60 * ( b - r ) / diff ) + 120; + } else { + h = ( 60 * ( r - g ) / diff ) + 240; + } + + // chroma (diff) == 0 means greyscale which, by definition, saturation = 0% + // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add) + if ( diff === 0 ) { + s = 0; + } else if ( l <= 0.5 ) { + s = diff / add; + } else { + s = diff / ( 2 - add ); + } + return [ Math.round(h) % 360, s, l, a == null ? 1 : a ]; +}; + +spaces.hsla.from = function( hsla ) { + if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { + return [ null, null, null, hsla[ 3 ] ]; + } + var h = hsla[ 0 ] / 360, + s = hsla[ 1 ], + l = hsla[ 2 ], + a = hsla[ 3 ], + q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, + p = 2 * l - q; + + return [ + Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), + Math.round( hue2rgb( p, q, h ) * 255 ), + Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), + a + ]; +}; + +each( spaces, function( spaceName, space ) { + var props = space.props, + cache = space.cache, + to = space.to, + from = space.from; + + // makes rgba() and hsla() + color.fn[ spaceName ] = function( value ) { + + // generate a cache for this space if it doesn't exist + if ( to && !this[ cache ] ) { + this[ cache ] = to( this._rgba ); + } + if ( value === undefined ) { + return this[ cache ].slice(); + } + + var ret, + type = jQuery.type( value ), + arr = ( type === "array" || type === "object" ) ? value : arguments, + local = this[ cache ].slice(); + + each( props, function( key, prop ) { + var val = arr[ type === "object" ? key : prop.idx ]; + if ( val == null ) { + val = local[ prop.idx ]; + } + local[ prop.idx ] = clamp( val, prop ); + }); + + if ( from ) { + ret = color( from( local ) ); + ret[ cache ] = local; + return ret; + } else { + return color( local ); + } + }; + + // makes red() green() blue() alpha() hue() saturation() lightness() + each( props, function( key, prop ) { + // alpha is included in more than one space + if ( color.fn[ key ] ) { + return; + } + color.fn[ key ] = function( value ) { + var vtype = jQuery.type( value ), + fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ), + local = this[ fn ](), + cur = local[ prop.idx ], + match; + + if ( vtype === "undefined" ) { + return cur; + } + + if ( vtype === "function" ) { + value = value.call( this, cur ); + vtype = jQuery.type( value ); + } + if ( value == null && prop.empty ) { + return this; + } + if ( vtype === "string" ) { + match = rplusequals.exec( value ); + if ( match ) { + value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); + } + } + local[ prop.idx ] = value; + return this[ fn ]( local ); + }; + }); +}); + +// add cssHook and .fx.step function for each named hook. +// accept a space separated string of properties +color.hook = function( hook ) { + var hooks = hook.split( " " ); + each( hooks, function( i, hook ) { + jQuery.cssHooks[ hook ] = { + set: function( elem, value ) { + var parsed, curElem, + backgroundColor = ""; + + if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) { + value = color( parsed || value ); + if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { + curElem = hook === "backgroundColor" ? elem.parentNode : elem; + while ( + (backgroundColor === "" || backgroundColor === "transparent") && + curElem && curElem.style + ) { + try { + backgroundColor = jQuery.css( curElem, "backgroundColor" ); + curElem = curElem.parentNode; + } catch ( e ) { + } + } + + value = value.blend( backgroundColor && backgroundColor !== "transparent" ? + backgroundColor : + "_default" ); + } + + value = value.toRgbaString(); + } + try { + elem.style[ hook ] = value; + } catch ( e ) { + // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit' + } + } + }; + jQuery.fx.step[ hook ] = function( fx ) { + if ( !fx.colorInit ) { + fx.start = color( fx.elem, hook ); + fx.end = color( fx.end ); + fx.colorInit = true; + } + jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); + }; + }); + +}; + +color.hook( stepHooks ); + +jQuery.cssHooks.borderColor = { + expand: function( value ) { + var expanded = {}; + + each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) { + expanded[ "border" + part + "Color" ] = value; + }); + return expanded; + } +}; + +// Basic color names only. +// Usage of any of the other color names requires adding yourself or including +// jquery.color.svg-names.js. +colors = jQuery.Color.names = { + // 4.1. Basic color keywords + aqua: "#00ffff", + black: "#000000", + blue: "#0000ff", + fuchsia: "#ff00ff", + gray: "#808080", + green: "#008000", + lime: "#00ff00", + maroon: "#800000", + navy: "#000080", + olive: "#808000", + purple: "#800080", + red: "#ff0000", + silver: "#c0c0c0", + teal: "#008080", + white: "#ffffff", + yellow: "#ffff00", + + // 4.2.3. "transparent" color keyword + transparent: [ null, null, null, 0 ], + + _default: "#ffffff" +}; + +})( jQuery ); + +/******************************************************************************/ +/****************************** CLASS ANIMATIONS ******************************/ +/******************************************************************************/ +(function() { + +var classAnimationActions = [ "add", "remove", "toggle" ], + shorthandStyles = { + border: 1, + borderBottom: 1, + borderColor: 1, + borderLeft: 1, + borderRight: 1, + borderTop: 1, + borderWidth: 1, + margin: 1, + padding: 1 + }; + +$.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) { + $.fx.step[ prop ] = function( fx ) { + if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) { + jQuery.style( fx.elem, prop, fx.end ); + fx.setAttr = true; + } + }; +}); + +function getElementStyles( elem ) { + var key, len, + style = elem.ownerDocument.defaultView ? + elem.ownerDocument.defaultView.getComputedStyle( elem, null ) : + elem.currentStyle, + styles = {}; + + if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) { + len = style.length; + while ( len-- ) { + key = style[ len ]; + if ( typeof style[ key ] === "string" ) { + styles[ $.camelCase( key ) ] = style[ key ]; + } + } + // support: Opera, IE <9 + } else { + for ( key in style ) { + if ( typeof style[ key ] === "string" ) { + styles[ key ] = style[ key ]; + } + } + } + + return styles; +} + +function styleDifference( oldStyle, newStyle ) { + var diff = {}, + name, value; + + for ( name in newStyle ) { + value = newStyle[ name ]; + if ( oldStyle[ name ] !== value ) { + if ( !shorthandStyles[ name ] ) { + if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) { + diff[ name ] = value; + } + } + } + } + + return diff; +} + +// support: jQuery <1.8 +if ( !$.fn.addBack ) { + $.fn.addBack = function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + }; +} + +$.effects.animateClass = function( value, duration, easing, callback ) { + var o = $.speed( duration, easing, callback ); + + return this.queue( function() { + var animated = $( this ), + baseClass = animated.attr( "class" ) || "", + applyClassChange, + allAnimations = o.children ? animated.find( "*" ).addBack() : animated; + + // map the animated objects to store the original styles. + allAnimations = allAnimations.map(function() { + var el = $( this ); + return { + el: el, + start: getElementStyles( this ) + }; + }); + + // apply class change + applyClassChange = function() { + $.each( classAnimationActions, function(i, action) { + if ( value[ action ] ) { + animated[ action + "Class" ]( value[ action ] ); + } + }); + }; + applyClassChange(); + + // map all animated objects again - calculate new styles and diff + allAnimations = allAnimations.map(function() { + this.end = getElementStyles( this.el[ 0 ] ); + this.diff = styleDifference( this.start, this.end ); + return this; + }); + + // apply original class + animated.attr( "class", baseClass ); + + // map all animated objects again - this time collecting a promise + allAnimations = allAnimations.map(function() { + var styleInfo = this, + dfd = $.Deferred(), + opts = $.extend({}, o, { + queue: false, + complete: function() { + dfd.resolve( styleInfo ); + } + }); + + this.el.animate( this.diff, opts ); + return dfd.promise(); + }); + + // once all animations have completed: + $.when.apply( $, allAnimations.get() ).done(function() { + + // set the final class + applyClassChange(); + + // for each animated element, + // clear all css properties that were animated + $.each( arguments, function() { + var el = this.el; + $.each( this.diff, function(key) { + el.css( key, "" ); + }); + }); + + // this is guarnteed to be there if you use jQuery.speed() + // it also handles dequeuing the next anim... + o.complete.call( animated[ 0 ] ); + }); + }); +}; + +$.fn.extend({ + addClass: (function( orig ) { + return function( classNames, speed, easing, callback ) { + return speed ? + $.effects.animateClass.call( this, + { add: classNames }, speed, easing, callback ) : + orig.apply( this, arguments ); + }; + })( $.fn.addClass ), + + removeClass: (function( orig ) { + return function( classNames, speed, easing, callback ) { + return arguments.length > 1 ? + $.effects.animateClass.call( this, + { remove: classNames }, speed, easing, callback ) : + orig.apply( this, arguments ); + }; + })( $.fn.removeClass ), + + toggleClass: (function( orig ) { + return function( classNames, force, speed, easing, callback ) { + if ( typeof force === "boolean" || force === undefined ) { + if ( !speed ) { + // without speed parameter + return orig.apply( this, arguments ); + } else { + return $.effects.animateClass.call( this, + (force ? { add: classNames } : { remove: classNames }), + speed, easing, callback ); + } + } else { + // without force parameter + return $.effects.animateClass.call( this, + { toggle: classNames }, force, speed, easing ); + } + }; + })( $.fn.toggleClass ), + + switchClass: function( remove, add, speed, easing, callback) { + return $.effects.animateClass.call( this, { + add: add, + remove: remove + }, speed, easing, callback ); + } +}); + +})(); + +/******************************************************************************/ +/*********************************** EFFECTS **********************************/ +/******************************************************************************/ + +(function() { + +$.extend( $.effects, { + version: "1.11.4", + + // Saves a set of properties in a data storage + save: function( element, set ) { + for ( var i = 0; i < set.length; i++ ) { + if ( set[ i ] !== null ) { + element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] ); + } + } + }, + + // Restores a set of previously saved properties from a data storage + restore: function( element, set ) { + var val, i; + for ( i = 0; i < set.length; i++ ) { + if ( set[ i ] !== null ) { + val = element.data( dataSpace + set[ i ] ); + // support: jQuery 1.6.2 + // http://bugs.jquery.com/ticket/9917 + // jQuery 1.6.2 incorrectly returns undefined for any falsy value. + // We can't differentiate between "" and 0 here, so we just assume + // empty string since it's likely to be a more common value... + if ( val === undefined ) { + val = ""; + } + element.css( set[ i ], val ); + } + } + }, + + setMode: function( el, mode ) { + if (mode === "toggle") { + mode = el.is( ":hidden" ) ? "show" : "hide"; + } + return mode; + }, + + // Translates a [top,left] array into a baseline value + // this should be a little more flexible in the future to handle a string & hash + getBaseline: function( origin, original ) { + var y, x; + switch ( origin[ 0 ] ) { + case "top": y = 0; break; + case "middle": y = 0.5; break; + case "bottom": y = 1; break; + default: y = origin[ 0 ] / original.height; + } + switch ( origin[ 1 ] ) { + case "left": x = 0; break; + case "center": x = 0.5; break; + case "right": x = 1; break; + default: x = origin[ 1 ] / original.width; + } + return { + x: x, + y: y + }; + }, + + // Wraps the element around a wrapper that copies position properties + createWrapper: function( element ) { + + // if the element is already wrapped, return it + if ( element.parent().is( ".ui-effects-wrapper" )) { + return element.parent(); + } + + // wrap the element + var props = { + width: element.outerWidth(true), + height: element.outerHeight(true), + "float": element.css( "float" ) + }, + wrapper = $( "<div></div>" ) + .addClass( "ui-effects-wrapper" ) + .css({ + fontSize: "100%", + background: "transparent", + border: "none", + margin: 0, + padding: 0 + }), + // Store the size in case width/height are defined in % - Fixes #5245 + size = { + width: element.width(), + height: element.height() + }, + active = document.activeElement; + + // support: Firefox + // Firefox incorrectly exposes anonymous content + // https://bugzilla.mozilla.org/show_bug.cgi?id=561664 + try { + active.id; + } catch ( e ) { + active = document.body; + } + + element.wrap( wrapper ); + + // Fixes #7595 - Elements lose focus when wrapped. + if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { + $( active ).focus(); + } + + wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element + + // transfer positioning properties to the wrapper + if ( element.css( "position" ) === "static" ) { + wrapper.css({ position: "relative" }); + element.css({ position: "relative" }); + } else { + $.extend( props, { + position: element.css( "position" ), + zIndex: element.css( "z-index" ) + }); + $.each([ "top", "left", "bottom", "right" ], function(i, pos) { + props[ pos ] = element.css( pos ); + if ( isNaN( parseInt( props[ pos ], 10 ) ) ) { + props[ pos ] = "auto"; + } + }); + element.css({ + position: "relative", + top: 0, + left: 0, + right: "auto", + bottom: "auto" + }); + } + element.css(size); + + return wrapper.css( props ).show(); + }, + + removeWrapper: function( element ) { + var active = document.activeElement; + + if ( element.parent().is( ".ui-effects-wrapper" ) ) { + element.parent().replaceWith( element ); + + // Fixes #7595 - Elements lose focus when wrapped. + if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { + $( active ).focus(); + } + } + + return element; + }, + + setTransition: function( element, list, factor, value ) { + value = value || {}; + $.each( list, function( i, x ) { + var unit = element.cssUnit( x ); + if ( unit[ 0 ] > 0 ) { + value[ x ] = unit[ 0 ] * factor + unit[ 1 ]; + } + }); + return value; + } +}); + +// return an effect options object for the given parameters: +function _normalizeArguments( effect, options, speed, callback ) { + + // allow passing all options as the first parameter + if ( $.isPlainObject( effect ) ) { + options = effect; + effect = effect.effect; + } + + // convert to an object + effect = { effect: effect }; + + // catch (effect, null, ...) + if ( options == null ) { + options = {}; + } + + // catch (effect, callback) + if ( $.isFunction( options ) ) { + callback = options; + speed = null; + options = {}; + } + + // catch (effect, speed, ?) + if ( typeof options === "number" || $.fx.speeds[ options ] ) { + callback = speed; + speed = options; + options = {}; + } + + // catch (effect, options, callback) + if ( $.isFunction( speed ) ) { + callback = speed; + speed = null; + } + + // add options to effect + if ( options ) { + $.extend( effect, options ); + } + + speed = speed || options.duration; + effect.duration = $.fx.off ? 0 : + typeof speed === "number" ? speed : + speed in $.fx.speeds ? $.fx.speeds[ speed ] : + $.fx.speeds._default; + + effect.complete = callback || options.complete; + + return effect; +} + +function standardAnimationOption( option ) { + // Valid standard speeds (nothing, number, named speed) + if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) { + return true; + } + + // Invalid strings - treat as "normal" speed + if ( typeof option === "string" && !$.effects.effect[ option ] ) { + return true; + } + + // Complete callback + if ( $.isFunction( option ) ) { + return true; + } + + // Options hash (but not naming an effect) + if ( typeof option === "object" && !option.effect ) { + return true; + } + + // Didn't match any standard API + return false; +} + +$.fn.extend({ + effect: function( /* effect, options, speed, callback */ ) { + var args = _normalizeArguments.apply( this, arguments ), + mode = args.mode, + queue = args.queue, + effectMethod = $.effects.effect[ args.effect ]; + + if ( $.fx.off || !effectMethod ) { + // delegate to the original method (e.g., .show()) if possible + if ( mode ) { + return this[ mode ]( args.duration, args.complete ); + } else { + return this.each( function() { + if ( args.complete ) { + args.complete.call( this ); + } + }); + } + } + + function run( next ) { + var elem = $( this ), + complete = args.complete, + mode = args.mode; + + function done() { + if ( $.isFunction( complete ) ) { + complete.call( elem[0] ); + } + if ( $.isFunction( next ) ) { + next(); + } + } + + // If the element already has the correct final state, delegate to + // the core methods so the internal tracking of "olddisplay" works. + if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) { + elem[ mode ](); + done(); + } else { + effectMethod.call( elem[0], args, done ); + } + } + + return queue === false ? this.each( run ) : this.queue( queue || "fx", run ); + }, + + show: (function( orig ) { + return function( option ) { + if ( standardAnimationOption( option ) ) { + return orig.apply( this, arguments ); + } else { + var args = _normalizeArguments.apply( this, arguments ); + args.mode = "show"; + return this.effect.call( this, args ); + } + }; + })( $.fn.show ), + + hide: (function( orig ) { + return function( option ) { + if ( standardAnimationOption( option ) ) { + return orig.apply( this, arguments ); + } else { + var args = _normalizeArguments.apply( this, arguments ); + args.mode = "hide"; + return this.effect.call( this, args ); + } + }; + })( $.fn.hide ), + + toggle: (function( orig ) { + return function( option ) { + if ( standardAnimationOption( option ) || typeof option === "boolean" ) { + return orig.apply( this, arguments ); + } else { + var args = _normalizeArguments.apply( this, arguments ); + args.mode = "toggle"; + return this.effect.call( this, args ); + } + }; + })( $.fn.toggle ), + + // helper functions + cssUnit: function(key) { + var style = this.css( key ), + val = []; + + $.each( [ "em", "px", "%", "pt" ], function( i, unit ) { + if ( style.indexOf( unit ) > 0 ) { + val = [ parseFloat( style ), unit ]; + } + }); + return val; + } +}); + +})(); + +/******************************************************************************/ +/*********************************** EASING ***********************************/ +/******************************************************************************/ + +(function() { + +// based on easing equations from Robert Penner (http://www.robertpenner.com/easing) + +var baseEasings = {}; + +$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) { + baseEasings[ name ] = function( p ) { + return Math.pow( p, i + 2 ); + }; +}); + +$.extend( baseEasings, { + Sine: function( p ) { + return 1 - Math.cos( p * Math.PI / 2 ); + }, + Circ: function( p ) { + return 1 - Math.sqrt( 1 - p * p ); + }, + Elastic: function( p ) { + return p === 0 || p === 1 ? p : + -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 ); + }, + Back: function( p ) { + return p * p * ( 3 * p - 2 ); + }, + Bounce: function( p ) { + var pow2, + bounce = 4; + + while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {} + return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 ); + } +}); + +$.each( baseEasings, function( name, easeIn ) { + $.easing[ "easeIn" + name ] = easeIn; + $.easing[ "easeOut" + name ] = function( p ) { + return 1 - easeIn( 1 - p ); + }; + $.easing[ "easeInOut" + name ] = function( p ) { + return p < 0.5 ? + easeIn( p * 2 ) / 2 : + 1 - easeIn( p * -2 + 2 ) / 2; + }; +}); + +})(); + +var effect = $.effects; + + +/*! + * jQuery UI Effects Blind 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/blind-effect/ + */ + + +var effectBlind = $.effects.effect.blind = function( o, done ) { + // Create element + var el = $( this ), + rvertical = /up|down|vertical/, + rpositivemotion = /up|left|vertical|horizontal/, + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + mode = $.effects.setMode( el, o.mode || "hide" ), + direction = o.direction || "up", + vertical = rvertical.test( direction ), + ref = vertical ? "height" : "width", + ref2 = vertical ? "top" : "left", + motion = rpositivemotion.test( direction ), + animation = {}, + show = mode === "show", + wrapper, distance, margin; + + // if already wrapped, the wrapper's properties are my property. #6245 + if ( el.parent().is( ".ui-effects-wrapper" ) ) { + $.effects.save( el.parent(), props ); + } else { + $.effects.save( el, props ); + } + el.show(); + wrapper = $.effects.createWrapper( el ).css({ + overflow: "hidden" + }); + + distance = wrapper[ ref ](); + margin = parseFloat( wrapper.css( ref2 ) ) || 0; + + animation[ ref ] = show ? distance : 0; + if ( !motion ) { + el + .css( vertical ? "bottom" : "right", 0 ) + .css( vertical ? "top" : "left", "auto" ) + .css({ position: "absolute" }); + + animation[ ref2 ] = show ? margin : distance + margin; + } + + // start at 0 if we are showing + if ( show ) { + wrapper.css( ref, 0 ); + if ( !motion ) { + wrapper.css( ref2, margin + distance ); + } + } + + // Animate + wrapper.animate( animation, { + duration: o.duration, + easing: o.easing, + queue: false, + complete: function() { + if ( mode === "hide" ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + } + }); +}; + + +/*! + * jQuery UI Effects Bounce 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/bounce-effect/ + */ + + +var effectBounce = $.effects.effect.bounce = function( o, done ) { + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + + // defaults: + mode = $.effects.setMode( el, o.mode || "effect" ), + hide = mode === "hide", + show = mode === "show", + direction = o.direction || "up", + distance = o.distance, + times = o.times || 5, + + // number of internal animations + anims = times * 2 + ( show || hide ? 1 : 0 ), + speed = o.duration / anims, + easing = o.easing, + + // utility: + ref = ( direction === "up" || direction === "down" ) ? "top" : "left", + motion = ( direction === "up" || direction === "left" ), + i, + upAnim, + downAnim, + + // we will need to re-assemble the queue to stack our animations in place + queue = el.queue(), + queuelen = queue.length; + + // Avoid touching opacity to prevent clearType and PNG issues in IE + if ( show || hide ) { + props.push( "opacity" ); + } + + $.effects.save( el, props ); + el.show(); + $.effects.createWrapper( el ); // Create Wrapper + + // default distance for the BIGGEST bounce is the outer Distance / 3 + if ( !distance ) { + distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3; + } + + if ( show ) { + downAnim = { opacity: 1 }; + downAnim[ ref ] = 0; + + // if we are showing, force opacity 0 and set the initial position + // then do the "first" animation + el.css( "opacity", 0 ) + .css( ref, motion ? -distance * 2 : distance * 2 ) + .animate( downAnim, speed, easing ); + } + + // start at the smallest distance if we are hiding + if ( hide ) { + distance = distance / Math.pow( 2, times - 1 ); + } + + downAnim = {}; + downAnim[ ref ] = 0; + // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here + for ( i = 0; i < times; i++ ) { + upAnim = {}; + upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; + + el.animate( upAnim, speed, easing ) + .animate( downAnim, speed, easing ); + + distance = hide ? distance * 2 : distance / 2; + } + + // Last Bounce when Hiding + if ( hide ) { + upAnim = { opacity: 0 }; + upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; + + el.animate( upAnim, speed, easing ); + } + + el.queue(function() { + if ( hide ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + }); + + // inject all the animations we just queued to be first in line (after "inprogress") + if ( queuelen > 1) { + queue.splice.apply( queue, + [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); + } + el.dequeue(); + +}; + + +/*! + * jQuery UI Effects Clip 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/clip-effect/ + */ + + +var effectClip = $.effects.effect.clip = function( o, done ) { + // Create element + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + mode = $.effects.setMode( el, o.mode || "hide" ), + show = mode === "show", + direction = o.direction || "vertical", + vert = direction === "vertical", + size = vert ? "height" : "width", + position = vert ? "top" : "left", + animation = {}, + wrapper, animate, distance; + + // Save & Show + $.effects.save( el, props ); + el.show(); + + // Create Wrapper + wrapper = $.effects.createWrapper( el ).css({ + overflow: "hidden" + }); + animate = ( el[0].tagName === "IMG" ) ? wrapper : el; + distance = animate[ size ](); + + // Shift + if ( show ) { + animate.css( size, 0 ); + animate.css( position, distance / 2 ); + } + + // Create Animation Object: + animation[ size ] = show ? distance : 0; + animation[ position ] = show ? 0 : distance / 2; + + // Animate + animate.animate( animation, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: function() { + if ( !show ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + } + }); + +}; + + +/*! + * jQuery UI Effects Drop 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/drop-effect/ + */ + + +var effectDrop = $.effects.effect.drop = function( o, done ) { + + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ], + mode = $.effects.setMode( el, o.mode || "hide" ), + show = mode === "show", + direction = o.direction || "left", + ref = ( direction === "up" || direction === "down" ) ? "top" : "left", + motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg", + animation = { + opacity: show ? 1 : 0 + }, + distance; + + // Adjust + $.effects.save( el, props ); + el.show(); + $.effects.createWrapper( el ); + + distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2; + + if ( show ) { + el + .css( "opacity", 0 ) + .css( ref, motion === "pos" ? -distance : distance ); + } + + // Animation + animation[ ref ] = ( show ? + ( motion === "pos" ? "+=" : "-=" ) : + ( motion === "pos" ? "-=" : "+=" ) ) + + distance; + + // Animate + el.animate( animation, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: function() { + if ( mode === "hide" ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + } + }); +}; + + +/*! + * jQuery UI Effects Explode 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/explode-effect/ + */ + + +var effectExplode = $.effects.effect.explode = function( o, done ) { + + var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3, + cells = rows, + el = $( this ), + mode = $.effects.setMode( el, o.mode || "hide" ), + show = mode === "show", + + // show and then visibility:hidden the element before calculating offset + offset = el.show().css( "visibility", "hidden" ).offset(), + + // width and height of a piece + width = Math.ceil( el.outerWidth() / cells ), + height = Math.ceil( el.outerHeight() / rows ), + pieces = [], + + // loop + i, j, left, top, mx, my; + + // children animate complete: + function childComplete() { + pieces.push( this ); + if ( pieces.length === rows * cells ) { + animComplete(); + } + } + + // clone the element for each row and cell. + for ( i = 0; i < rows ; i++ ) { // ===> + top = offset.top + i * height; + my = i - ( rows - 1 ) / 2 ; + + for ( j = 0; j < cells ; j++ ) { // ||| + left = offset.left + j * width; + mx = j - ( cells - 1 ) / 2 ; + + // Create a clone of the now hidden main element that will be absolute positioned + // within a wrapper div off the -left and -top equal to size of our pieces + el + .clone() + .appendTo( "body" ) + .wrap( "<div></div>" ) + .css({ + position: "absolute", + visibility: "visible", + left: -j * width, + top: -i * height + }) + + // select the wrapper - make it overflow: hidden and absolute positioned based on + // where the original was located +left and +top equal to the size of pieces + .parent() + .addClass( "ui-effects-explode" ) + .css({ + position: "absolute", + overflow: "hidden", + width: width, + height: height, + left: left + ( show ? mx * width : 0 ), + top: top + ( show ? my * height : 0 ), + opacity: show ? 0 : 1 + }).animate({ + left: left + ( show ? 0 : mx * width ), + top: top + ( show ? 0 : my * height ), + opacity: show ? 1 : 0 + }, o.duration || 500, o.easing, childComplete ); + } + } + + function animComplete() { + el.css({ + visibility: "visible" + }); + $( pieces ).remove(); + if ( !show ) { + el.hide(); + } + done(); + } +}; + + +/*! + * jQuery UI Effects Fade 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/fade-effect/ + */ + + +var effectFade = $.effects.effect.fade = function( o, done ) { + var el = $( this ), + mode = $.effects.setMode( el, o.mode || "toggle" ); + + el.animate({ + opacity: mode + }, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: done + }); +}; + + +/*! + * jQuery UI Effects Fold 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/fold-effect/ + */ + + +var effectFold = $.effects.effect.fold = function( o, done ) { + + // Create element + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + mode = $.effects.setMode( el, o.mode || "hide" ), + show = mode === "show", + hide = mode === "hide", + size = o.size || 15, + percent = /([0-9]+)%/.exec( size ), + horizFirst = !!o.horizFirst, + widthFirst = show !== horizFirst, + ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ], + duration = o.duration / 2, + wrapper, distance, + animation1 = {}, + animation2 = {}; + + $.effects.save( el, props ); + el.show(); + + // Create Wrapper + wrapper = $.effects.createWrapper( el ).css({ + overflow: "hidden" + }); + distance = widthFirst ? + [ wrapper.width(), wrapper.height() ] : + [ wrapper.height(), wrapper.width() ]; + + if ( percent ) { + size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ]; + } + if ( show ) { + wrapper.css( horizFirst ? { + height: 0, + width: size + } : { + height: size, + width: 0 + }); + } + + // Animation + animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size; + animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0; + + // Animate + wrapper + .animate( animation1, duration, o.easing ) + .animate( animation2, duration, o.easing, function() { + if ( hide ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + }); + +}; + + +/*! + * jQuery UI Effects Highlight 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/highlight-effect/ + */ + + +var effectHighlight = $.effects.effect.highlight = function( o, done ) { + var elem = $( this ), + props = [ "backgroundImage", "backgroundColor", "opacity" ], + mode = $.effects.setMode( elem, o.mode || "show" ), + animation = { + backgroundColor: elem.css( "backgroundColor" ) + }; + + if (mode === "hide") { + animation.opacity = 0; + } + + $.effects.save( elem, props ); + + elem + .show() + .css({ + backgroundImage: "none", + backgroundColor: o.color || "#ffff99" + }) + .animate( animation, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: function() { + if ( mode === "hide" ) { + elem.hide(); + } + $.effects.restore( elem, props ); + done(); + } + }); +}; + + +/*! + * jQuery UI Effects Size 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/size-effect/ + */ + + +var effectSize = $.effects.effect.size = function( o, done ) { + + // Create element + var original, baseline, factor, + el = $( this ), + props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ], + + // Always restore + props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ], + + // Copy for children + props2 = [ "width", "height", "overflow" ], + cProps = [ "fontSize" ], + vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ], + hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ], + + // Set options + mode = $.effects.setMode( el, o.mode || "effect" ), + restore = o.restore || mode !== "effect", + scale = o.scale || "both", + origin = o.origin || [ "middle", "center" ], + position = el.css( "position" ), + props = restore ? props0 : props1, + zero = { + height: 0, + width: 0, + outerHeight: 0, + outerWidth: 0 + }; + + if ( mode === "show" ) { + el.show(); + } + original = { + height: el.height(), + width: el.width(), + outerHeight: el.outerHeight(), + outerWidth: el.outerWidth() + }; + + if ( o.mode === "toggle" && mode === "show" ) { + el.from = o.to || zero; + el.to = o.from || original; + } else { + el.from = o.from || ( mode === "show" ? zero : original ); + el.to = o.to || ( mode === "hide" ? zero : original ); + } + + // Set scaling factor + factor = { + from: { + y: el.from.height / original.height, + x: el.from.width / original.width + }, + to: { + y: el.to.height / original.height, + x: el.to.width / original.width + } + }; + + // Scale the css box + if ( scale === "box" || scale === "both" ) { + + // Vertical props scaling + if ( factor.from.y !== factor.to.y ) { + props = props.concat( vProps ); + el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from ); + el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to ); + } + + // Horizontal props scaling + if ( factor.from.x !== factor.to.x ) { + props = props.concat( hProps ); + el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from ); + el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to ); + } + } + + // Scale the content + if ( scale === "content" || scale === "both" ) { + + // Vertical props scaling + if ( factor.from.y !== factor.to.y ) { + props = props.concat( cProps ).concat( props2 ); + el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from ); + el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to ); + } + } + + $.effects.save( el, props ); + el.show(); + $.effects.createWrapper( el ); + el.css( "overflow", "hidden" ).css( el.from ); + + // Adjust + if (origin) { // Calculate baseline shifts + baseline = $.effects.getBaseline( origin, original ); + el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y; + el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x; + el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y; + el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x; + } + el.css( el.from ); // set top & left + + // Animate + if ( scale === "content" || scale === "both" ) { // Scale the children + + // Add margins/font-size + vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps); + hProps = hProps.concat([ "marginLeft", "marginRight" ]); + props2 = props0.concat(vProps).concat(hProps); + + el.find( "*[width]" ).each( function() { + var child = $( this ), + c_original = { + height: child.height(), + width: child.width(), + outerHeight: child.outerHeight(), + outerWidth: child.outerWidth() + }; + if (restore) { + $.effects.save(child, props2); + } + + child.from = { + height: c_original.height * factor.from.y, + width: c_original.width * factor.from.x, + outerHeight: c_original.outerHeight * factor.from.y, + outerWidth: c_original.outerWidth * factor.from.x + }; + child.to = { + height: c_original.height * factor.to.y, + width: c_original.width * factor.to.x, + outerHeight: c_original.height * factor.to.y, + outerWidth: c_original.width * factor.to.x + }; + + // Vertical props scaling + if ( factor.from.y !== factor.to.y ) { + child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from ); + child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to ); + } + + // Horizontal props scaling + if ( factor.from.x !== factor.to.x ) { + child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from ); + child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to ); + } + + // Animate children + child.css( child.from ); + child.animate( child.to, o.duration, o.easing, function() { + + // Restore children + if ( restore ) { + $.effects.restore( child, props2 ); + } + }); + }); + } + + // Animate + el.animate( el.to, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: function() { + if ( el.to.opacity === 0 ) { + el.css( "opacity", el.from.opacity ); + } + if ( mode === "hide" ) { + el.hide(); + } + $.effects.restore( el, props ); + if ( !restore ) { + + // we need to calculate our new positioning based on the scaling + if ( position === "static" ) { + el.css({ + position: "relative", + top: el.to.top, + left: el.to.left + }); + } else { + $.each([ "top", "left" ], function( idx, pos ) { + el.css( pos, function( _, str ) { + var val = parseInt( str, 10 ), + toRef = idx ? el.to.left : el.to.top; + + // if original was "auto", recalculate the new value from wrapper + if ( str === "auto" ) { + return toRef + "px"; + } + + return val + toRef + "px"; + }); + }); + } + } + + $.effects.removeWrapper( el ); + done(); + } + }); + +}; + + +/*! + * jQuery UI Effects Scale 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/scale-effect/ + */ + + +var effectScale = $.effects.effect.scale = function( o, done ) { + + // Create element + var el = $( this ), + options = $.extend( true, {}, o ), + mode = $.effects.setMode( el, o.mode || "effect" ), + percent = parseInt( o.percent, 10 ) || + ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ), + direction = o.direction || "both", + origin = o.origin, + original = { + height: el.height(), + width: el.width(), + outerHeight: el.outerHeight(), + outerWidth: el.outerWidth() + }, + factor = { + y: direction !== "horizontal" ? (percent / 100) : 1, + x: direction !== "vertical" ? (percent / 100) : 1 + }; + + // We are going to pass this effect to the size effect: + options.effect = "size"; + options.queue = false; + options.complete = done; + + // Set default origin and restore for show/hide + if ( mode !== "effect" ) { + options.origin = origin || [ "middle", "center" ]; + options.restore = true; + } + + options.from = o.from || ( mode === "show" ? { + height: 0, + width: 0, + outerHeight: 0, + outerWidth: 0 + } : original ); + options.to = { + height: original.height * factor.y, + width: original.width * factor.x, + outerHeight: original.outerHeight * factor.y, + outerWidth: original.outerWidth * factor.x + }; + + // Fade option to support puff + if ( options.fade ) { + if ( mode === "show" ) { + options.from.opacity = 0; + options.to.opacity = 1; + } + if ( mode === "hide" ) { + options.from.opacity = 1; + options.to.opacity = 0; + } + } + + // Animate + el.effect( options ); + +}; + + +/*! + * jQuery UI Effects Puff 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/puff-effect/ + */ + + +var effectPuff = $.effects.effect.puff = function( o, done ) { + var elem = $( this ), + mode = $.effects.setMode( elem, o.mode || "hide" ), + hide = mode === "hide", + percent = parseInt( o.percent, 10 ) || 150, + factor = percent / 100, + original = { + height: elem.height(), + width: elem.width(), + outerHeight: elem.outerHeight(), + outerWidth: elem.outerWidth() + }; + + $.extend( o, { + effect: "scale", + queue: false, + fade: true, + mode: mode, + complete: done, + percent: hide ? percent : 100, + from: hide ? + original : + { + height: original.height * factor, + width: original.width * factor, + outerHeight: original.outerHeight * factor, + outerWidth: original.outerWidth * factor + } + }); + + elem.effect( o ); +}; + + +/*! + * jQuery UI Effects Pulsate 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/pulsate-effect/ + */ + + +var effectPulsate = $.effects.effect.pulsate = function( o, done ) { + var elem = $( this ), + mode = $.effects.setMode( elem, o.mode || "show" ), + show = mode === "show", + hide = mode === "hide", + showhide = ( show || mode === "hide" ), + + // showing or hiding leaves of the "last" animation + anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ), + duration = o.duration / anims, + animateTo = 0, + queue = elem.queue(), + queuelen = queue.length, + i; + + if ( show || !elem.is(":visible")) { + elem.css( "opacity", 0 ).show(); + animateTo = 1; + } + + // anims - 1 opacity "toggles" + for ( i = 1; i < anims; i++ ) { + elem.animate({ + opacity: animateTo + }, duration, o.easing ); + animateTo = 1 - animateTo; + } + + elem.animate({ + opacity: animateTo + }, duration, o.easing); + + elem.queue(function() { + if ( hide ) { + elem.hide(); + } + done(); + }); + + // We just queued up "anims" animations, we need to put them next in the queue + if ( queuelen > 1 ) { + queue.splice.apply( queue, + [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); + } + elem.dequeue(); +}; + + +/*! + * jQuery UI Effects Shake 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/shake-effect/ + */ + + +var effectShake = $.effects.effect.shake = function( o, done ) { + + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + mode = $.effects.setMode( el, o.mode || "effect" ), + direction = o.direction || "left", + distance = o.distance || 20, + times = o.times || 3, + anims = times * 2 + 1, + speed = Math.round( o.duration / anims ), + ref = (direction === "up" || direction === "down") ? "top" : "left", + positiveMotion = (direction === "up" || direction === "left"), + animation = {}, + animation1 = {}, + animation2 = {}, + i, + + // we will need to re-assemble the queue to stack our animations in place + queue = el.queue(), + queuelen = queue.length; + + $.effects.save( el, props ); + el.show(); + $.effects.createWrapper( el ); + + // Animation + animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance; + animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2; + animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2; + + // Animate + el.animate( animation, speed, o.easing ); + + // Shakes + for ( i = 1; i < times; i++ ) { + el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing ); + } + el + .animate( animation1, speed, o.easing ) + .animate( animation, speed / 2, o.easing ) + .queue(function() { + if ( mode === "hide" ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + }); + + // inject all the animations we just queued to be first in line (after "inprogress") + if ( queuelen > 1) { + queue.splice.apply( queue, + [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); + } + el.dequeue(); + +}; + + +/*! + * jQuery UI Effects Slide 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/slide-effect/ + */ + + +var effectSlide = $.effects.effect.slide = function( o, done ) { + + // Create element + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "width", "height" ], + mode = $.effects.setMode( el, o.mode || "show" ), + show = mode === "show", + direction = o.direction || "left", + ref = (direction === "up" || direction === "down") ? "top" : "left", + positiveMotion = (direction === "up" || direction === "left"), + distance, + animation = {}; + + // Adjust + $.effects.save( el, props ); + el.show(); + distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ); + + $.effects.createWrapper( el ).css({ + overflow: "hidden" + }); + + if ( show ) { + el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance ); + } + + // Animation + animation[ ref ] = ( show ? + ( positiveMotion ? "+=" : "-=") : + ( positiveMotion ? "-=" : "+=")) + + distance; + + // Animate + el.animate( animation, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: function() { + if ( mode === "hide" ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + } + }); +}; + + +/*! + * jQuery UI Effects Transfer 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/transfer-effect/ + */ + + +var effectTransfer = $.effects.effect.transfer = function( o, done ) { + var elem = $( this ), + target = $( o.to ), + targetFixed = target.css( "position" ) === "fixed", + body = $("body"), + fixTop = targetFixed ? body.scrollTop() : 0, + fixLeft = targetFixed ? body.scrollLeft() : 0, + endPosition = target.offset(), + animation = { + top: endPosition.top - fixTop, + left: endPosition.left - fixLeft, + height: target.innerHeight(), + width: target.innerWidth() + }, + startPosition = elem.offset(), + transfer = $( "<div class='ui-effects-transfer'></div>" ) + .appendTo( document.body ) + .addClass( o.className ) + .css({ + top: startPosition.top - fixTop, + left: startPosition.left - fixLeft, + height: elem.innerHeight(), + width: elem.innerWidth(), + position: targetFixed ? "fixed" : "absolute" + }) + .animate( animation, o.duration, o.easing, function() { + transfer.remove(); + done(); + }); +}; + + +/*! + * jQuery UI Progressbar 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/progressbar/ + */ + + +var progressbar = $.widget( "ui.progressbar", { + version: "1.11.4", + options: { + max: 100, + value: 0, + + change: null, + complete: null + }, + + min: 0, + + _create: function() { + // Constrain initial value + this.oldValue = this.options.value = this._constrainedValue(); + + this.element + .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) + .attr({ + // Only set static values, aria-valuenow and aria-valuemax are + // set inside _refreshValue() + role: "progressbar", + "aria-valuemin": this.min + }); + + this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" ) + .appendTo( this.element ); + + this._refreshValue(); + }, + + _destroy: function() { + this.element + .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) + .removeAttr( "role" ) + .removeAttr( "aria-valuemin" ) + .removeAttr( "aria-valuemax" ) + .removeAttr( "aria-valuenow" ); + + this.valueDiv.remove(); + }, + + value: function( newValue ) { + if ( newValue === undefined ) { + return this.options.value; + } + + this.options.value = this._constrainedValue( newValue ); + this._refreshValue(); + }, + + _constrainedValue: function( newValue ) { + if ( newValue === undefined ) { + newValue = this.options.value; + } + + this.indeterminate = newValue === false; + + // sanitize value + if ( typeof newValue !== "number" ) { + newValue = 0; + } + + return this.indeterminate ? false : + Math.min( this.options.max, Math.max( this.min, newValue ) ); + }, + + _setOptions: function( options ) { + // Ensure "value" option is set after other values (like max) + var value = options.value; + delete options.value; + + this._super( options ); + + this.options.value = this._constrainedValue( value ); + this._refreshValue(); + }, + + _setOption: function( key, value ) { + if ( key === "max" ) { + // Don't allow a max less than min + value = Math.max( this.min, value ); + } + if ( key === "disabled" ) { + this.element + .toggleClass( "ui-state-disabled", !!value ) + .attr( "aria-disabled", value ); + } + this._super( key, value ); + }, + + _percentage: function() { + return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min ); + }, + + _refreshValue: function() { + var value = this.options.value, + percentage = this._percentage(); + + this.valueDiv + .toggle( this.indeterminate || value > this.min ) + .toggleClass( "ui-corner-right", value === this.options.max ) + .width( percentage.toFixed(0) + "%" ); + + this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate ); + + if ( this.indeterminate ) { + this.element.removeAttr( "aria-valuenow" ); + if ( !this.overlayDiv ) { + this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv ); + } + } else { + this.element.attr({ + "aria-valuemax": this.options.max, + "aria-valuenow": value + }); + if ( this.overlayDiv ) { + this.overlayDiv.remove(); + this.overlayDiv = null; + } + } + + if ( this.oldValue !== value ) { + this.oldValue = value; + this._trigger( "change" ); + } + if ( value === this.options.max ) { + this._trigger( "complete" ); + } + } +}); + + +/*! + * jQuery UI Selectable 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/selectable/ + */ + + +var selectable = $.widget("ui.selectable", $.ui.mouse, { + version: "1.11.4", + options: { + appendTo: "body", + autoRefresh: true, + distance: 0, + filter: "*", + tolerance: "touch", + + // callbacks + selected: null, + selecting: null, + start: null, + stop: null, + unselected: null, + unselecting: null + }, + _create: function() { + var selectees, + that = this; + + this.element.addClass("ui-selectable"); + + this.dragged = false; + + // cache selectee children based on filter + this.refresh = function() { + selectees = $(that.options.filter, that.element[0]); + selectees.addClass("ui-selectee"); + selectees.each(function() { + var $this = $(this), + pos = $this.offset(); + $.data(this, "selectable-item", { + element: this, + $element: $this, + left: pos.left, + top: pos.top, + right: pos.left + $this.outerWidth(), + bottom: pos.top + $this.outerHeight(), + startselected: false, + selected: $this.hasClass("ui-selected"), + selecting: $this.hasClass("ui-selecting"), + unselecting: $this.hasClass("ui-unselecting") + }); + }); + }; + this.refresh(); + + this.selectees = selectees.addClass("ui-selectee"); + + this._mouseInit(); + + this.helper = $("<div class='ui-selectable-helper'></div>"); + }, + + _destroy: function() { + this.selectees + .removeClass("ui-selectee") + .removeData("selectable-item"); + this.element + .removeClass("ui-selectable ui-selectable-disabled"); + this._mouseDestroy(); + }, + + _mouseStart: function(event) { + var that = this, + options = this.options; + + this.opos = [ event.pageX, event.pageY ]; + + if (this.options.disabled) { + return; + } + + this.selectees = $(options.filter, this.element[0]); + + this._trigger("start", event); + + $(options.appendTo).append(this.helper); + // position helper (lasso) + this.helper.css({ + "left": event.pageX, + "top": event.pageY, + "width": 0, + "height": 0 + }); + + if (options.autoRefresh) { + this.refresh(); + } + + this.selectees.filter(".ui-selected").each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.startselected = true; + if (!event.metaKey && !event.ctrlKey) { + selectee.$element.removeClass("ui-selected"); + selectee.selected = false; + selectee.$element.addClass("ui-unselecting"); + selectee.unselecting = true; + // selectable UNSELECTING callback + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + }); + + $(event.target).parents().addBack().each(function() { + var doSelect, + selectee = $.data(this, "selectable-item"); + if (selectee) { + doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected"); + selectee.$element + .removeClass(doSelect ? "ui-unselecting" : "ui-selected") + .addClass(doSelect ? "ui-selecting" : "ui-unselecting"); + selectee.unselecting = !doSelect; + selectee.selecting = doSelect; + selectee.selected = doSelect; + // selectable (UN)SELECTING callback + if (doSelect) { + that._trigger("selecting", event, { + selecting: selectee.element + }); + } else { + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + return false; + } + }); + + }, + + _mouseDrag: function(event) { + + this.dragged = true; + + if (this.options.disabled) { + return; + } + + var tmp, + that = this, + options = this.options, + x1 = this.opos[0], + y1 = this.opos[1], + x2 = event.pageX, + y2 = event.pageY; + + if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; } + if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; } + this.helper.css({ left: x1, top: y1, width: x2 - x1, height: y2 - y1 }); + + this.selectees.each(function() { + var selectee = $.data(this, "selectable-item"), + hit = false; + + //prevent helper from being selected if appendTo: selectable + if (!selectee || selectee.element === that.element[0]) { + return; + } + + if (options.tolerance === "touch") { + hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); + } else if (options.tolerance === "fit") { + hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); + } + + if (hit) { + // SELECT + if (selectee.selected) { + selectee.$element.removeClass("ui-selected"); + selectee.selected = false; + } + if (selectee.unselecting) { + selectee.$element.removeClass("ui-unselecting"); + selectee.unselecting = false; + } + if (!selectee.selecting) { + selectee.$element.addClass("ui-selecting"); + selectee.selecting = true; + // selectable SELECTING callback + that._trigger("selecting", event, { + selecting: selectee.element + }); + } + } else { + // UNSELECT + if (selectee.selecting) { + if ((event.metaKey || event.ctrlKey) && selectee.startselected) { + selectee.$element.removeClass("ui-selecting"); + selectee.selecting = false; + selectee.$element.addClass("ui-selected"); + selectee.selected = true; + } else { + selectee.$element.removeClass("ui-selecting"); + selectee.selecting = false; + if (selectee.startselected) { + selectee.$element.addClass("ui-unselecting"); + selectee.unselecting = true; + } + // selectable UNSELECTING callback + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + } + if (selectee.selected) { + if (!event.metaKey && !event.ctrlKey && !selectee.startselected) { + selectee.$element.removeClass("ui-selected"); + selectee.selected = false; + + selectee.$element.addClass("ui-unselecting"); + selectee.unselecting = true; + // selectable UNSELECTING callback + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + } + } + }); + + return false; + }, + + _mouseStop: function(event) { + var that = this; + + this.dragged = false; + + $(".ui-unselecting", this.element[0]).each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.$element.removeClass("ui-unselecting"); + selectee.unselecting = false; + selectee.startselected = false; + that._trigger("unselected", event, { + unselected: selectee.element + }); + }); + $(".ui-selecting", this.element[0]).each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.$element.removeClass("ui-selecting").addClass("ui-selected"); + selectee.selecting = false; + selectee.selected = true; + selectee.startselected = true; + that._trigger("selected", event, { + selected: selectee.element + }); + }); + this._trigger("stop", event); + + this.helper.remove(); + + return false; + } + +}); + + +/*! + * jQuery UI Selectmenu 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/selectmenu + */ + + +var selectmenu = $.widget( "ui.selectmenu", { + version: "1.11.4", + defaultElement: "<select>", + options: { + appendTo: null, + disabled: null, + icons: { + button: "ui-icon-triangle-1-s" + }, + position: { + my: "left top", + at: "left bottom", + collision: "none" + }, + width: null, + + // callbacks + change: null, + close: null, + focus: null, + open: null, + select: null + }, + + _create: function() { + var selectmenuId = this.element.uniqueId().attr( "id" ); + this.ids = { + element: selectmenuId, + button: selectmenuId + "-button", + menu: selectmenuId + "-menu" + }; + + this._drawButton(); + this._drawMenu(); + + if ( this.options.disabled ) { + this.disable(); + } + }, + + _drawButton: function() { + var that = this; + + // Associate existing label with the new button + this.label = $( "label[for='" + this.ids.element + "']" ).attr( "for", this.ids.button ); + this._on( this.label, { + click: function( event ) { + this.button.focus(); + event.preventDefault(); + } + }); + + // Hide original select element + this.element.hide(); + + // Create button + this.button = $( "<span>", { + "class": "ui-selectmenu-button ui-widget ui-state-default ui-corner-all", + tabindex: this.options.disabled ? -1 : 0, + id: this.ids.button, + role: "combobox", + "aria-expanded": "false", + "aria-autocomplete": "list", + "aria-owns": this.ids.menu, + "aria-haspopup": "true" + }) + .insertAfter( this.element ); + + $( "<span>", { + "class": "ui-icon " + this.options.icons.button + }) + .prependTo( this.button ); + + this.buttonText = $( "<span>", { + "class": "ui-selectmenu-text" + }) + .appendTo( this.button ); + + this._setText( this.buttonText, this.element.find( "option:selected" ).text() ); + this._resizeButton(); + + this._on( this.button, this._buttonEvents ); + this.button.one( "focusin", function() { + + // Delay rendering the menu items until the button receives focus. + // The menu may have already been rendered via a programmatic open. + if ( !that.menuItems ) { + that._refreshMenu(); + } + }); + this._hoverable( this.button ); + this._focusable( this.button ); + }, + + _drawMenu: function() { + var that = this; + + // Create menu + this.menu = $( "<ul>", { + "aria-hidden": "true", + "aria-labelledby": this.ids.button, + id: this.ids.menu + }); + + // Wrap menu + this.menuWrap = $( "<div>", { + "class": "ui-selectmenu-menu ui-front" + }) + .append( this.menu ) + .appendTo( this._appendTo() ); + + // Initialize menu widget + this.menuInstance = this.menu + .menu({ + role: "listbox", + select: function( event, ui ) { + event.preventDefault(); + + // support: IE8 + // If the item was selected via a click, the text selection + // will be destroyed in IE + that._setSelection(); + + that._select( ui.item.data( "ui-selectmenu-item" ), event ); + }, + focus: function( event, ui ) { + var item = ui.item.data( "ui-selectmenu-item" ); + + // Prevent inital focus from firing and check if its a newly focused item + if ( that.focusIndex != null && item.index !== that.focusIndex ) { + that._trigger( "focus", event, { item: item } ); + if ( !that.isOpen ) { + that._select( item, event ); + } + } + that.focusIndex = item.index; + + that.button.attr( "aria-activedescendant", + that.menuItems.eq( item.index ).attr( "id" ) ); + } + }) + .menu( "instance" ); + + // Adjust menu styles to dropdown + this.menu + .addClass( "ui-corner-bottom" ) + .removeClass( "ui-corner-all" ); + + // Don't close the menu on mouseleave + this.menuInstance._off( this.menu, "mouseleave" ); + + // Cancel the menu's collapseAll on document click + this.menuInstance._closeOnDocumentClick = function() { + return false; + }; + + // Selects often contain empty items, but never contain dividers + this.menuInstance._isDivider = function() { + return false; + }; + }, + + refresh: function() { + this._refreshMenu(); + this._setText( this.buttonText, this._getSelectedItem().text() ); + if ( !this.options.width ) { + this._resizeButton(); + } + }, + + _refreshMenu: function() { + this.menu.empty(); + + var item, + options = this.element.find( "option" ); + + if ( !options.length ) { + return; + } + + this._parseOptions( options ); + this._renderMenu( this.menu, this.items ); + + this.menuInstance.refresh(); + this.menuItems = this.menu.find( "li" ).not( ".ui-selectmenu-optgroup" ); + + item = this._getSelectedItem(); + + // Update the menu to have the correct item focused + this.menuInstance.focus( null, item ); + this._setAria( item.data( "ui-selectmenu-item" ) ); + + // Set disabled state + this._setOption( "disabled", this.element.prop( "disabled" ) ); + }, + + open: function( event ) { + if ( this.options.disabled ) { + return; + } + + // If this is the first time the menu is being opened, render the items + if ( !this.menuItems ) { + this._refreshMenu(); + } else { + + // Menu clears focus on close, reset focus to selected item + this.menu.find( ".ui-state-focus" ).removeClass( "ui-state-focus" ); + this.menuInstance.focus( null, this._getSelectedItem() ); + } + + this.isOpen = true; + this._toggleAttr(); + this._resizeMenu(); + this._position(); + + this._on( this.document, this._documentClick ); + + this._trigger( "open", event ); + }, + + _position: function() { + this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) ); + }, + + close: function( event ) { + if ( !this.isOpen ) { + return; + } + + this.isOpen = false; + this._toggleAttr(); + + this.range = null; + this._off( this.document ); + + this._trigger( "close", event ); + }, + + widget: function() { + return this.button; + }, + + menuWidget: function() { + return this.menu; + }, + + _renderMenu: function( ul, items ) { + var that = this, + currentOptgroup = ""; + + $.each( items, function( index, item ) { + if ( item.optgroup !== currentOptgroup ) { + $( "<li>", { + "class": "ui-selectmenu-optgroup ui-menu-divider" + + ( item.element.parent( "optgroup" ).prop( "disabled" ) ? + " ui-state-disabled" : + "" ), + text: item.optgroup + }) + .appendTo( ul ); + + currentOptgroup = item.optgroup; + } + + that._renderItemData( ul, item ); + }); + }, + + _renderItemData: function( ul, item ) { + return this._renderItem( ul, item ).data( "ui-selectmenu-item", item ); + }, + + _renderItem: function( ul, item ) { + var li = $( "<li>" ); + + if ( item.disabled ) { + li.addClass( "ui-state-disabled" ); + } + this._setText( li, item.label ); + + return li.appendTo( ul ); + }, + + _setText: function( element, value ) { + if ( value ) { + element.text( value ); + } else { + element.html( " " ); + } + }, + + _move: function( direction, event ) { + var item, next, + filter = ".ui-menu-item"; + + if ( this.isOpen ) { + item = this.menuItems.eq( this.focusIndex ); + } else { + item = this.menuItems.eq( this.element[ 0 ].selectedIndex ); + filter += ":not(.ui-state-disabled)"; + } + + if ( direction === "first" || direction === "last" ) { + next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 ); + } else { + next = item[ direction + "All" ]( filter ).eq( 0 ); + } + + if ( next.length ) { + this.menuInstance.focus( event, next ); + } + }, + + _getSelectedItem: function() { + return this.menuItems.eq( this.element[ 0 ].selectedIndex ); + }, + + _toggle: function( event ) { + this[ this.isOpen ? "close" : "open" ]( event ); + }, + + _setSelection: function() { + var selection; + + if ( !this.range ) { + return; + } + + if ( window.getSelection ) { + selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange( this.range ); + + // support: IE8 + } else { + this.range.select(); + } + + // support: IE + // Setting the text selection kills the button focus in IE, but + // restoring the focus doesn't kill the selection. + this.button.focus(); + }, + + _documentClick: { + mousedown: function( event ) { + if ( !this.isOpen ) { + return; + } + + if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" + this.ids.button ).length ) { + this.close( event ); + } + } + }, + + _buttonEvents: { + + // Prevent text selection from being reset when interacting with the selectmenu (#10144) + mousedown: function() { + var selection; + + if ( window.getSelection ) { + selection = window.getSelection(); + if ( selection.rangeCount ) { + this.range = selection.getRangeAt( 0 ); + } + + // support: IE8 + } else { + this.range = document.selection.createRange(); + } + }, + + click: function( event ) { + this._setSelection(); + this._toggle( event ); + }, + + keydown: function( event ) { + var preventDefault = true; + switch ( event.keyCode ) { + case $.ui.keyCode.TAB: + case $.ui.keyCode.ESCAPE: + this.close( event ); + preventDefault = false; + break; + case $.ui.keyCode.ENTER: + if ( this.isOpen ) { + this._selectFocusedItem( event ); + } + break; + case $.ui.keyCode.UP: + if ( event.altKey ) { + this._toggle( event ); + } else { + this._move( "prev", event ); + } + break; + case $.ui.keyCode.DOWN: + if ( event.altKey ) { + this._toggle( event ); + } else { + this._move( "next", event ); + } + break; + case $.ui.keyCode.SPACE: + if ( this.isOpen ) { + this._selectFocusedItem( event ); + } else { + this._toggle( event ); + } + break; + case $.ui.keyCode.LEFT: + this._move( "prev", event ); + break; + case $.ui.keyCode.RIGHT: + this._move( "next", event ); + break; + case $.ui.keyCode.HOME: + case $.ui.keyCode.PAGE_UP: + this._move( "first", event ); + break; + case $.ui.keyCode.END: + case $.ui.keyCode.PAGE_DOWN: + this._move( "last", event ); + break; + default: + this.menu.trigger( event ); + preventDefault = false; + } + + if ( preventDefault ) { + event.preventDefault(); + } + } + }, + + _selectFocusedItem: function( event ) { + var item = this.menuItems.eq( this.focusIndex ); + if ( !item.hasClass( "ui-state-disabled" ) ) { + this._select( item.data( "ui-selectmenu-item" ), event ); + } + }, + + _select: function( item, event ) { + var oldIndex = this.element[ 0 ].selectedIndex; + + // Change native select element + this.element[ 0 ].selectedIndex = item.index; + this._setText( this.buttonText, item.label ); + this._setAria( item ); + this._trigger( "select", event, { item: item } ); + + if ( item.index !== oldIndex ) { + this._trigger( "change", event, { item: item } ); + } + + this.close( event ); + }, + + _setAria: function( item ) { + var id = this.menuItems.eq( item.index ).attr( "id" ); + + this.button.attr({ + "aria-labelledby": id, + "aria-activedescendant": id + }); + this.menu.attr( "aria-activedescendant", id ); + }, + + _setOption: function( key, value ) { + if ( key === "icons" ) { + this.button.find( "span.ui-icon" ) + .removeClass( this.options.icons.button ) + .addClass( value.button ); + } + + this._super( key, value ); + + if ( key === "appendTo" ) { + this.menuWrap.appendTo( this._appendTo() ); + } + + if ( key === "disabled" ) { + this.menuInstance.option( "disabled", value ); + this.button + .toggleClass( "ui-state-disabled", value ) + .attr( "aria-disabled", value ); + + this.element.prop( "disabled", value ); + if ( value ) { + this.button.attr( "tabindex", -1 ); + this.close(); + } else { + this.button.attr( "tabindex", 0 ); + } + } + + if ( key === "width" ) { + this._resizeButton(); + } + }, + + _appendTo: function() { + var element = this.options.appendTo; + + if ( element ) { + element = element.jquery || element.nodeType ? + $( element ) : + this.document.find( element ).eq( 0 ); + } + + if ( !element || !element[ 0 ] ) { + element = this.element.closest( ".ui-front" ); + } + + if ( !element.length ) { + element = this.document[ 0 ].body; + } + + return element; + }, + + _toggleAttr: function() { + this.button + .toggleClass( "ui-corner-top", this.isOpen ) + .toggleClass( "ui-corner-all", !this.isOpen ) + .attr( "aria-expanded", this.isOpen ); + this.menuWrap.toggleClass( "ui-selectmenu-open", this.isOpen ); + this.menu.attr( "aria-hidden", !this.isOpen ); + }, + + _resizeButton: function() { + var width = this.options.width; + + if ( !width ) { + width = this.element.show().outerWidth(); + this.element.hide(); + } + + this.button.outerWidth( width ); + }, + + _resizeMenu: function() { + this.menu.outerWidth( Math.max( + this.button.outerWidth(), + + // support: IE10 + // IE10 wraps long text (possibly a rounding bug) + // so we add 1px to avoid the wrapping + this.menu.width( "" ).outerWidth() + 1 + ) ); + }, + + _getCreateOptions: function() { + return { disabled: this.element.prop( "disabled" ) }; + }, + + _parseOptions: function( options ) { + var data = []; + options.each(function( index, item ) { + var option = $( item ), + optgroup = option.parent( "optgroup" ); + data.push({ + element: option, + index: index, + value: option.val(), + label: option.text(), + optgroup: optgroup.attr( "label" ) || "", + disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" ) + }); + }); + this.items = data; + }, + + _destroy: function() { + this.menuWrap.remove(); + this.button.remove(); + this.element.show(); + this.element.removeUniqueId(); + this.label.attr( "for", this.ids.element ); + } +}); + + +/*! + * jQuery UI Slider 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/slider/ + */ + + +var slider = $.widget( "ui.slider", $.ui.mouse, { + version: "1.11.4", + widgetEventPrefix: "slide", + + options: { + animate: false, + distance: 0, + max: 100, + min: 0, + orientation: "horizontal", + range: false, + step: 1, + value: 0, + values: null, + + // callbacks + change: null, + slide: null, + start: null, + stop: null + }, + + // number of pages in a slider + // (how many times can you page up/down to go through the whole range) + numPages: 5, + + _create: function() { + this._keySliding = false; + this._mouseSliding = false; + this._animateOff = true; + this._handleIndex = null; + this._detectOrientation(); + this._mouseInit(); + this._calculateNewMax(); + + this.element + .addClass( "ui-slider" + + " ui-slider-" + this.orientation + + " ui-widget" + + " ui-widget-content" + + " ui-corner-all"); + + this._refresh(); + this._setOption( "disabled", this.options.disabled ); + + this._animateOff = false; + }, + + _refresh: function() { + this._createRange(); + this._createHandles(); + this._setupEvents(); + this._refreshValue(); + }, + + _createHandles: function() { + var i, handleCount, + options = this.options, + existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ), + handle = "<span class='ui-slider-handle ui-state-default ui-corner-all' tabindex='0'></span>", + handles = []; + + handleCount = ( options.values && options.values.length ) || 1; + + if ( existingHandles.length > handleCount ) { + existingHandles.slice( handleCount ).remove(); + existingHandles = existingHandles.slice( 0, handleCount ); + } + + for ( i = existingHandles.length; i < handleCount; i++ ) { + handles.push( handle ); + } + + this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) ); + + this.handle = this.handles.eq( 0 ); + + this.handles.each(function( i ) { + $( this ).data( "ui-slider-handle-index", i ); + }); + }, + + _createRange: function() { + var options = this.options, + classes = ""; + + if ( options.range ) { + if ( options.range === true ) { + if ( !options.values ) { + options.values = [ this._valueMin(), this._valueMin() ]; + } else if ( options.values.length && options.values.length !== 2 ) { + options.values = [ options.values[0], options.values[0] ]; + } else if ( $.isArray( options.values ) ) { + options.values = options.values.slice(0); + } + } + + if ( !this.range || !this.range.length ) { + this.range = $( "<div></div>" ) + .appendTo( this.element ); + + classes = "ui-slider-range" + + // note: this isn't the most fittingly semantic framework class for this element, + // but worked best visually with a variety of themes + " ui-widget-header ui-corner-all"; + } else { + this.range.removeClass( "ui-slider-range-min ui-slider-range-max" ) + // Handle range switching from true to min/max + .css({ + "left": "", + "bottom": "" + }); + } + + this.range.addClass( classes + + ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) ); + } else { + if ( this.range ) { + this.range.remove(); + } + this.range = null; + } + }, + + _setupEvents: function() { + this._off( this.handles ); + this._on( this.handles, this._handleEvents ); + this._hoverable( this.handles ); + this._focusable( this.handles ); + }, + + _destroy: function() { + this.handles.remove(); + if ( this.range ) { + this.range.remove(); + } + + this.element + .removeClass( "ui-slider" + + " ui-slider-horizontal" + + " ui-slider-vertical" + + " ui-widget" + + " ui-widget-content" + + " ui-corner-all" ); + + this._mouseDestroy(); + }, + + _mouseCapture: function( event ) { + var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle, + that = this, + o = this.options; + + if ( o.disabled ) { + return false; + } + + this.elementSize = { + width: this.element.outerWidth(), + height: this.element.outerHeight() + }; + this.elementOffset = this.element.offset(); + + position = { x: event.pageX, y: event.pageY }; + normValue = this._normValueFromMouse( position ); + distance = this._valueMax() - this._valueMin() + 1; + this.handles.each(function( i ) { + var thisDistance = Math.abs( normValue - that.values(i) ); + if (( distance > thisDistance ) || + ( distance === thisDistance && + (i === that._lastChangedValue || that.values(i) === o.min ))) { + distance = thisDistance; + closestHandle = $( this ); + index = i; + } + }); + + allowed = this._start( event, index ); + if ( allowed === false ) { + return false; + } + this._mouseSliding = true; + + this._handleIndex = index; + + closestHandle + .addClass( "ui-state-active" ) + .focus(); + + offset = closestHandle.offset(); + mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" ); + this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { + left: event.pageX - offset.left - ( closestHandle.width() / 2 ), + top: event.pageY - offset.top - + ( closestHandle.height() / 2 ) - + ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) - + ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) + + ( parseInt( closestHandle.css("marginTop"), 10 ) || 0) + }; + + if ( !this.handles.hasClass( "ui-state-hover" ) ) { + this._slide( event, index, normValue ); + } + this._animateOff = true; + return true; + }, + + _mouseStart: function() { + return true; + }, + + _mouseDrag: function( event ) { + var position = { x: event.pageX, y: event.pageY }, + normValue = this._normValueFromMouse( position ); + + this._slide( event, this._handleIndex, normValue ); + + return false; + }, + + _mouseStop: function( event ) { + this.handles.removeClass( "ui-state-active" ); + this._mouseSliding = false; + + this._stop( event, this._handleIndex ); + this._change( event, this._handleIndex ); + + this._handleIndex = null; + this._clickOffset = null; + this._animateOff = false; + + return false; + }, + + _detectOrientation: function() { + this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; + }, + + _normValueFromMouse: function( position ) { + var pixelTotal, + pixelMouse, + percentMouse, + valueTotal, + valueMouse; + + if ( this.orientation === "horizontal" ) { + pixelTotal = this.elementSize.width; + pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 ); + } else { + pixelTotal = this.elementSize.height; + pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 ); + } + + percentMouse = ( pixelMouse / pixelTotal ); + if ( percentMouse > 1 ) { + percentMouse = 1; + } + if ( percentMouse < 0 ) { + percentMouse = 0; + } + if ( this.orientation === "vertical" ) { + percentMouse = 1 - percentMouse; + } + + valueTotal = this._valueMax() - this._valueMin(); + valueMouse = this._valueMin() + percentMouse * valueTotal; + + return this._trimAlignValue( valueMouse ); + }, + + _start: function( event, index ) { + var uiHash = { + handle: this.handles[ index ], + value: this.value() + }; + if ( this.options.values && this.options.values.length ) { + uiHash.value = this.values( index ); + uiHash.values = this.values(); + } + return this._trigger( "start", event, uiHash ); + }, + + _slide: function( event, index, newVal ) { + var otherVal, + newValues, + allowed; + + if ( this.options.values && this.options.values.length ) { + otherVal = this.values( index ? 0 : 1 ); + + if ( ( this.options.values.length === 2 && this.options.range === true ) && + ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) ) + ) { + newVal = otherVal; + } + + if ( newVal !== this.values( index ) ) { + newValues = this.values(); + newValues[ index ] = newVal; + // A slide can be canceled by returning false from the slide callback + allowed = this._trigger( "slide", event, { + handle: this.handles[ index ], + value: newVal, + values: newValues + } ); + otherVal = this.values( index ? 0 : 1 ); + if ( allowed !== false ) { + this.values( index, newVal ); + } + } + } else { + if ( newVal !== this.value() ) { + // A slide can be canceled by returning false from the slide callback + allowed = this._trigger( "slide", event, { + handle: this.handles[ index ], + value: newVal + } ); + if ( allowed !== false ) { + this.value( newVal ); + } + } + } + }, + + _stop: function( event, index ) { + var uiHash = { + handle: this.handles[ index ], + value: this.value() + }; + if ( this.options.values && this.options.values.length ) { + uiHash.value = this.values( index ); + uiHash.values = this.values(); + } + + this._trigger( "stop", event, uiHash ); + }, + + _change: function( event, index ) { + if ( !this._keySliding && !this._mouseSliding ) { + var uiHash = { + handle: this.handles[ index ], + value: this.value() + }; + if ( this.options.values && this.options.values.length ) { + uiHash.value = this.values( index ); + uiHash.values = this.values(); + } + + //store the last changed value index for reference when handles overlap + this._lastChangedValue = index; + + this._trigger( "change", event, uiHash ); + } + }, + + value: function( newValue ) { + if ( arguments.length ) { + this.options.value = this._trimAlignValue( newValue ); + this._refreshValue(); + this._change( null, 0 ); + return; + } + + return this._value(); + }, + + values: function( index, newValue ) { + var vals, + newValues, + i; + + if ( arguments.length > 1 ) { + this.options.values[ index ] = this._trimAlignValue( newValue ); + this._refreshValue(); + this._change( null, index ); + return; + } + + if ( arguments.length ) { + if ( $.isArray( arguments[ 0 ] ) ) { + vals = this.options.values; + newValues = arguments[ 0 ]; + for ( i = 0; i < vals.length; i += 1 ) { + vals[ i ] = this._trimAlignValue( newValues[ i ] ); + this._change( null, i ); + } + this._refreshValue(); + } else { + if ( this.options.values && this.options.values.length ) { + return this._values( index ); + } else { + return this.value(); + } + } + } else { + return this._values(); + } + }, + + _setOption: function( key, value ) { + var i, + valsLength = 0; + + if ( key === "range" && this.options.range === true ) { + if ( value === "min" ) { + this.options.value = this._values( 0 ); + this.options.values = null; + } else if ( value === "max" ) { + this.options.value = this._values( this.options.values.length - 1 ); + this.options.values = null; + } + } + + if ( $.isArray( this.options.values ) ) { + valsLength = this.options.values.length; + } + + if ( key === "disabled" ) { + this.element.toggleClass( "ui-state-disabled", !!value ); + } + + this._super( key, value ); + + switch ( key ) { + case "orientation": + this._detectOrientation(); + this.element + .removeClass( "ui-slider-horizontal ui-slider-vertical" ) + .addClass( "ui-slider-" + this.orientation ); + this._refreshValue(); + + // Reset positioning from previous orientation + this.handles.css( value === "horizontal" ? "bottom" : "left", "" ); + break; + case "value": + this._animateOff = true; + this._refreshValue(); + this._change( null, 0 ); + this._animateOff = false; + break; + case "values": + this._animateOff = true; + this._refreshValue(); + for ( i = 0; i < valsLength; i += 1 ) { + this._change( null, i ); + } + this._animateOff = false; + break; + case "step": + case "min": + case "max": + this._animateOff = true; + this._calculateNewMax(); + this._refreshValue(); + this._animateOff = false; + break; + case "range": + this._animateOff = true; + this._refresh(); + this._animateOff = false; + break; + } + }, + + //internal value getter + // _value() returns value trimmed by min and max, aligned by step + _value: function() { + var val = this.options.value; + val = this._trimAlignValue( val ); + + return val; + }, + + //internal values getter + // _values() returns array of values trimmed by min and max, aligned by step + // _values( index ) returns single value trimmed by min and max, aligned by step + _values: function( index ) { + var val, + vals, + i; + + if ( arguments.length ) { + val = this.options.values[ index ]; + val = this._trimAlignValue( val ); + + return val; + } else if ( this.options.values && this.options.values.length ) { + // .slice() creates a copy of the array + // this copy gets trimmed by min and max and then returned + vals = this.options.values.slice(); + for ( i = 0; i < vals.length; i += 1) { + vals[ i ] = this._trimAlignValue( vals[ i ] ); + } + + return vals; + } else { + return []; + } + }, + + // returns the step-aligned value that val is closest to, between (inclusive) min and max + _trimAlignValue: function( val ) { + if ( val <= this._valueMin() ) { + return this._valueMin(); + } + if ( val >= this._valueMax() ) { + return this._valueMax(); + } + var step = ( this.options.step > 0 ) ? this.options.step : 1, + valModStep = (val - this._valueMin()) % step, + alignValue = val - valModStep; + + if ( Math.abs(valModStep) * 2 >= step ) { + alignValue += ( valModStep > 0 ) ? step : ( -step ); + } + + // Since JavaScript has problems with large floats, round + // the final value to 5 digits after the decimal point (see #4124) + return parseFloat( alignValue.toFixed(5) ); + }, + + _calculateNewMax: function() { + var max = this.options.max, + min = this._valueMin(), + step = this.options.step, + aboveMin = Math.floor( ( +( max - min ).toFixed( this._precision() ) ) / step ) * step; + max = aboveMin + min; + this.max = parseFloat( max.toFixed( this._precision() ) ); + }, + + _precision: function() { + var precision = this._precisionOf( this.options.step ); + if ( this.options.min !== null ) { + precision = Math.max( precision, this._precisionOf( this.options.min ) ); + } + return precision; + }, + + _precisionOf: function( num ) { + var str = num.toString(), + decimal = str.indexOf( "." ); + return decimal === -1 ? 0 : str.length - decimal - 1; + }, + + _valueMin: function() { + return this.options.min; + }, + + _valueMax: function() { + return this.max; + }, + + _refreshValue: function() { + var lastValPercent, valPercent, value, valueMin, valueMax, + oRange = this.options.range, + o = this.options, + that = this, + animate = ( !this._animateOff ) ? o.animate : false, + _set = {}; + + if ( this.options.values && this.options.values.length ) { + this.handles.each(function( i ) { + valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100; + _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; + $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); + if ( that.options.range === true ) { + if ( that.orientation === "horizontal" ) { + if ( i === 0 ) { + that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate ); + } + if ( i === 1 ) { + that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); + } + } else { + if ( i === 0 ) { + that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate ); + } + if ( i === 1 ) { + that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); + } + } + } + lastValPercent = valPercent; + }); + } else { + value = this.value(); + valueMin = this._valueMin(); + valueMax = this._valueMax(); + valPercent = ( valueMax !== valueMin ) ? + ( value - valueMin ) / ( valueMax - valueMin ) * 100 : + 0; + _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; + this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); + + if ( oRange === "min" && this.orientation === "horizontal" ) { + this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate ); + } + if ( oRange === "max" && this.orientation === "horizontal" ) { + this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); + } + if ( oRange === "min" && this.orientation === "vertical" ) { + this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate ); + } + if ( oRange === "max" && this.orientation === "vertical" ) { + this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); + } + } + }, + + _handleEvents: { + keydown: function( event ) { + var allowed, curVal, newVal, step, + index = $( event.target ).data( "ui-slider-handle-index" ); + + switch ( event.keyCode ) { + case $.ui.keyCode.HOME: + case $.ui.keyCode.END: + case $.ui.keyCode.PAGE_UP: + case $.ui.keyCode.PAGE_DOWN: + case $.ui.keyCode.UP: + case $.ui.keyCode.RIGHT: + case $.ui.keyCode.DOWN: + case $.ui.keyCode.LEFT: + event.preventDefault(); + if ( !this._keySliding ) { + this._keySliding = true; + $( event.target ).addClass( "ui-state-active" ); + allowed = this._start( event, index ); + if ( allowed === false ) { + return; + } + } + break; + } + + step = this.options.step; + if ( this.options.values && this.options.values.length ) { + curVal = newVal = this.values( index ); + } else { + curVal = newVal = this.value(); + } + + switch ( event.keyCode ) { + case $.ui.keyCode.HOME: + newVal = this._valueMin(); + break; + case $.ui.keyCode.END: + newVal = this._valueMax(); + break; + case $.ui.keyCode.PAGE_UP: + newVal = this._trimAlignValue( + curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages ) + ); + break; + case $.ui.keyCode.PAGE_DOWN: + newVal = this._trimAlignValue( + curVal - ( (this._valueMax() - this._valueMin()) / this.numPages ) ); + break; + case $.ui.keyCode.UP: + case $.ui.keyCode.RIGHT: + if ( curVal === this._valueMax() ) { + return; + } + newVal = this._trimAlignValue( curVal + step ); + break; + case $.ui.keyCode.DOWN: + case $.ui.keyCode.LEFT: + if ( curVal === this._valueMin() ) { + return; + } + newVal = this._trimAlignValue( curVal - step ); + break; + } + + this._slide( event, index, newVal ); + }, + keyup: function( event ) { + var index = $( event.target ).data( "ui-slider-handle-index" ); + + if ( this._keySliding ) { + this._keySliding = false; + this._stop( event, index ); + this._change( event, index ); + $( event.target ).removeClass( "ui-state-active" ); + } + } + } +}); + + +/*! + * jQuery UI Sortable 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/sortable/ + */ + + +var sortable = $.widget("ui.sortable", $.ui.mouse, { + version: "1.11.4", + widgetEventPrefix: "sort", + ready: false, + options: { + appendTo: "parent", + axis: false, + connectWith: false, + containment: false, + cursor: "auto", + cursorAt: false, + dropOnEmpty: true, + forcePlaceholderSize: false, + forceHelperSize: false, + grid: false, + handle: false, + helper: "original", + items: "> *", + opacity: false, + placeholder: false, + revert: false, + scroll: true, + scrollSensitivity: 20, + scrollSpeed: 20, + scope: "default", + tolerance: "intersect", + zIndex: 1000, + + // callbacks + activate: null, + beforeStop: null, + change: null, + deactivate: null, + out: null, + over: null, + receive: null, + remove: null, + sort: null, + start: null, + stop: null, + update: null + }, + + _isOverAxis: function( x, reference, size ) { + return ( x >= reference ) && ( x < ( reference + size ) ); + }, + + _isFloating: function( item ) { + return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display")); + }, + + _create: function() { + this.containerCache = {}; + this.element.addClass("ui-sortable"); + + //Get the items + this.refresh(); + + //Let's determine the parent's offset + this.offset = this.element.offset(); + + //Initialize mouse events for interaction + this._mouseInit(); + + this._setHandleClassName(); + + //We're ready to go + this.ready = true; + + }, + + _setOption: function( key, value ) { + this._super( key, value ); + + if ( key === "handle" ) { + this._setHandleClassName(); + } + }, + + _setHandleClassName: function() { + this.element.find( ".ui-sortable-handle" ).removeClass( "ui-sortable-handle" ); + $.each( this.items, function() { + ( this.instance.options.handle ? + this.item.find( this.instance.options.handle ) : this.item ) + .addClass( "ui-sortable-handle" ); + }); + }, + + _destroy: function() { + this.element + .removeClass( "ui-sortable ui-sortable-disabled" ) + .find( ".ui-sortable-handle" ) + .removeClass( "ui-sortable-handle" ); + this._mouseDestroy(); + + for ( var i = this.items.length - 1; i >= 0; i-- ) { + this.items[i].item.removeData(this.widgetName + "-item"); + } + + return this; + }, + + _mouseCapture: function(event, overrideHandle) { + var currentItem = null, + validHandle = false, + that = this; + + if (this.reverting) { + return false; + } + + if(this.options.disabled || this.options.type === "static") { + return false; + } + + //We have to refresh the items data once first + this._refreshItems(event); + + //Find out if the clicked node (or one of its parents) is a actual item in this.items + $(event.target).parents().each(function() { + if($.data(this, that.widgetName + "-item") === that) { + currentItem = $(this); + return false; + } + }); + if($.data(event.target, that.widgetName + "-item") === that) { + currentItem = $(event.target); + } + + if(!currentItem) { + return false; + } + if(this.options.handle && !overrideHandle) { + $(this.options.handle, currentItem).find("*").addBack().each(function() { + if(this === event.target) { + validHandle = true; + } + }); + if(!validHandle) { + return false; + } + } + + this.currentItem = currentItem; + this._removeCurrentsFromItems(); + return true; + + }, + + _mouseStart: function(event, overrideHandle, noActivation) { + + var i, body, + o = this.options; + + this.currentContainer = this; + + //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture + this.refreshPositions(); + + //Create and append the visible helper + this.helper = this._createHelper(event); + + //Cache the helper size + this._cacheHelperProportions(); + + /* + * - Position generation - + * This block generates everything position related - it's the core of draggables. + */ + + //Cache the margins of the original element + this._cacheMargins(); + + //Get the next scrolling parent + this.scrollParent = this.helper.scrollParent(); + + //The element's absolute position on the page minus margins + this.offset = this.currentItem.offset(); + this.offset = { + top: this.offset.top - this.margins.top, + left: this.offset.left - this.margins.left + }; + + $.extend(this.offset, { + click: { //Where the click happened, relative to the element + left: event.pageX - this.offset.left, + top: event.pageY - this.offset.top + }, + parent: this._getParentOffset(), + relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper + }); + + // Only after we got the offset, we can change the helper's position to absolute + // TODO: Still need to figure out a way to make relative sorting possible + this.helper.css("position", "absolute"); + this.cssPosition = this.helper.css("position"); + + //Generate the original position + this.originalPosition = this._generatePosition(event); + this.originalPageX = event.pageX; + this.originalPageY = event.pageY; + + //Adjust the mouse offset relative to the helper if "cursorAt" is supplied + (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); + + //Cache the former DOM position + this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; + + //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way + if(this.helper[0] !== this.currentItem[0]) { + this.currentItem.hide(); + } + + //Create the placeholder + this._createPlaceholder(); + + //Set a containment if given in the options + if(o.containment) { + this._setContainment(); + } + + if( o.cursor && o.cursor !== "auto" ) { // cursor option + body = this.document.find( "body" ); + + // support: IE + this.storedCursor = body.css( "cursor" ); + body.css( "cursor", o.cursor ); + + this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body ); + } + + if(o.opacity) { // opacity option + if (this.helper.css("opacity")) { + this._storedOpacity = this.helper.css("opacity"); + } + this.helper.css("opacity", o.opacity); + } + + if(o.zIndex) { // zIndex option + if (this.helper.css("zIndex")) { + this._storedZIndex = this.helper.css("zIndex"); + } + this.helper.css("zIndex", o.zIndex); + } + + //Prepare scrolling + if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") { + this.overflowOffset = this.scrollParent.offset(); + } + + //Call callbacks + this._trigger("start", event, this._uiHash()); + + //Recache the helper size + if(!this._preserveHelperProportions) { + this._cacheHelperProportions(); + } + + + //Post "activate" events to possible containers + if( !noActivation ) { + for ( i = this.containers.length - 1; i >= 0; i-- ) { + this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); + } + } + + //Prepare possible droppables + if($.ui.ddmanager) { + $.ui.ddmanager.current = this; + } + + if ($.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(this, event); + } + + this.dragging = true; + + this.helper.addClass("ui-sortable-helper"); + this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position + return true; + + }, + + _mouseDrag: function(event) { + var i, item, itemElement, intersection, + o = this.options, + scrolled = false; + + //Compute the helpers position + this.position = this._generatePosition(event); + this.positionAbs = this._convertPositionTo("absolute"); + + if (!this.lastPositionAbs) { + this.lastPositionAbs = this.positionAbs; + } + + //Do scrolling + if(this.options.scroll) { + if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") { + + if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { + this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; + } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) { + this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; + } + + if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { + this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; + } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) { + this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; + } + + } else { + + if(event.pageY - this.document.scrollTop() < o.scrollSensitivity) { + scrolled = this.document.scrollTop(this.document.scrollTop() - o.scrollSpeed); + } else if(this.window.height() - (event.pageY - this.document.scrollTop()) < o.scrollSensitivity) { + scrolled = this.document.scrollTop(this.document.scrollTop() + o.scrollSpeed); + } + + if(event.pageX - this.document.scrollLeft() < o.scrollSensitivity) { + scrolled = this.document.scrollLeft(this.document.scrollLeft() - o.scrollSpeed); + } else if(this.window.width() - (event.pageX - this.document.scrollLeft()) < o.scrollSensitivity) { + scrolled = this.document.scrollLeft(this.document.scrollLeft() + o.scrollSpeed); + } + + } + + if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(this, event); + } + } + + //Regenerate the absolute position used for position checks + this.positionAbs = this._convertPositionTo("absolute"); + + //Set the helper position + if(!this.options.axis || this.options.axis !== "y") { + this.helper[0].style.left = this.position.left+"px"; + } + if(!this.options.axis || this.options.axis !== "x") { + this.helper[0].style.top = this.position.top+"px"; + } + + //Rearrange + for (i = this.items.length - 1; i >= 0; i--) { + + //Cache variables and intersection, continue if no intersection + item = this.items[i]; + itemElement = item.item[0]; + intersection = this._intersectsWithPointer(item); + if (!intersection) { + continue; + } + + // Only put the placeholder inside the current Container, skip all + // items from other containers. This works because when moving + // an item from one container to another the + // currentContainer is switched before the placeholder is moved. + // + // Without this, moving items in "sub-sortables" can cause + // the placeholder to jitter between the outer and inner container. + if (item.instance !== this.currentContainer) { + continue; + } + + // cannot intersect with itself + // no useless actions that have been done before + // no action if the item moved is the parent of the item checked + if (itemElement !== this.currentItem[0] && + this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && + !$.contains(this.placeholder[0], itemElement) && + (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) + ) { + + this.direction = intersection === 1 ? "down" : "up"; + + if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { + this._rearrange(event, item); + } else { + break; + } + + this._trigger("change", event, this._uiHash()); + break; + } + } + + //Post events to containers + this._contactContainers(event); + + //Interconnect with droppables + if($.ui.ddmanager) { + $.ui.ddmanager.drag(this, event); + } + + //Call callbacks + this._trigger("sort", event, this._uiHash()); + + this.lastPositionAbs = this.positionAbs; + return false; + + }, + + _mouseStop: function(event, noPropagation) { + + if(!event) { + return; + } + + //If we are using droppables, inform the manager about the drop + if ($.ui.ddmanager && !this.options.dropBehaviour) { + $.ui.ddmanager.drop(this, event); + } + + if(this.options.revert) { + var that = this, + cur = this.placeholder.offset(), + axis = this.options.axis, + animation = {}; + + if ( !axis || axis === "x" ) { + animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollLeft); + } + if ( !axis || axis === "y" ) { + animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollTop); + } + this.reverting = true; + $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() { + that._clear(event); + }); + } else { + this._clear(event, noPropagation); + } + + return false; + + }, + + cancel: function() { + + if(this.dragging) { + + this._mouseUp({ target: null }); + + if(this.options.helper === "original") { + this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); + } else { + this.currentItem.show(); + } + + //Post deactivating events to containers + for (var i = this.containers.length - 1; i >= 0; i--){ + this.containers[i]._trigger("deactivate", null, this._uiHash(this)); + if(this.containers[i].containerCache.over) { + this.containers[i]._trigger("out", null, this._uiHash(this)); + this.containers[i].containerCache.over = 0; + } + } + + } + + if (this.placeholder) { + //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! + if(this.placeholder[0].parentNode) { + this.placeholder[0].parentNode.removeChild(this.placeholder[0]); + } + if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) { + this.helper.remove(); + } + + $.extend(this, { + helper: null, + dragging: false, + reverting: false, + _noFinalSort: null + }); + + if(this.domPosition.prev) { + $(this.domPosition.prev).after(this.currentItem); + } else { + $(this.domPosition.parent).prepend(this.currentItem); + } + } + + return this; + + }, + + serialize: function(o) { + + var items = this._getItemsAsjQuery(o && o.connected), + str = []; + o = o || {}; + + $(items).each(function() { + var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/)); + if (res) { + str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2])); + } + }); + + if(!str.length && o.key) { + str.push(o.key + "="); + } + + return str.join("&"); + + }, + + toArray: function(o) { + + var items = this._getItemsAsjQuery(o && o.connected), + ret = []; + + o = o || {}; + + items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); }); + return ret; + + }, + + /* Be careful with the following core functions */ + _intersectsWith: function(item) { + + var x1 = this.positionAbs.left, + x2 = x1 + this.helperProportions.width, + y1 = this.positionAbs.top, + y2 = y1 + this.helperProportions.height, + l = item.left, + r = l + item.width, + t = item.top, + b = t + item.height, + dyClick = this.offset.click.top, + dxClick = this.offset.click.left, + isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ), + isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ), + isOverElement = isOverElementHeight && isOverElementWidth; + + if ( this.options.tolerance === "pointer" || + this.options.forcePointerForContainers || + (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"]) + ) { + return isOverElement; + } else { + + return (l < x1 + (this.helperProportions.width / 2) && // Right Half + x2 - (this.helperProportions.width / 2) < r && // Left Half + t < y1 + (this.helperProportions.height / 2) && // Bottom Half + y2 - (this.helperProportions.height / 2) < b ); // Top Half + + } + }, + + _intersectsWithPointer: function(item) { + + var isOverElementHeight = (this.options.axis === "x") || this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), + isOverElementWidth = (this.options.axis === "y") || this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), + isOverElement = isOverElementHeight && isOverElementWidth, + verticalDirection = this._getDragVerticalDirection(), + horizontalDirection = this._getDragHorizontalDirection(); + + if (!isOverElement) { + return false; + } + + return this.floating ? + ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 ) + : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) ); + + }, + + _intersectsWithSides: function(item) { + + var isOverBottomHalf = this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), + isOverRightHalf = this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), + verticalDirection = this._getDragVerticalDirection(), + horizontalDirection = this._getDragHorizontalDirection(); + + if (this.floating && horizontalDirection) { + return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf)); + } else { + return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf)); + } + + }, + + _getDragVerticalDirection: function() { + var delta = this.positionAbs.top - this.lastPositionAbs.top; + return delta !== 0 && (delta > 0 ? "down" : "up"); + }, + + _getDragHorizontalDirection: function() { + var delta = this.positionAbs.left - this.lastPositionAbs.left; + return delta !== 0 && (delta > 0 ? "right" : "left"); + }, + + refresh: function(event) { + this._refreshItems(event); + this._setHandleClassName(); + this.refreshPositions(); + return this; + }, + + _connectWith: function() { + var options = this.options; + return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith; + }, + + _getItemsAsjQuery: function(connected) { + + var i, j, cur, inst, + items = [], + queries = [], + connectWith = this._connectWith(); + + if(connectWith && connected) { + for (i = connectWith.length - 1; i >= 0; i--){ + cur = $(connectWith[i], this.document[0]); + for ( j = cur.length - 1; j >= 0; j--){ + inst = $.data(cur[j], this.widgetFullName); + if(inst && inst !== this && !inst.options.disabled) { + queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]); + } + } + } + } + + queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]); + + function addItems() { + items.push( this ); + } + for (i = queries.length - 1; i >= 0; i--){ + queries[i][0].each( addItems ); + } + + return $(items); + + }, + + _removeCurrentsFromItems: function() { + + var list = this.currentItem.find(":data(" + this.widgetName + "-item)"); + + this.items = $.grep(this.items, function (item) { + for (var j=0; j < list.length; j++) { + if(list[j] === item.item[0]) { + return false; + } + } + return true; + }); + + }, + + _refreshItems: function(event) { + + this.items = []; + this.containers = [this]; + + var i, j, cur, inst, targetData, _queries, item, queriesLength, + items = this.items, + queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]], + connectWith = this._connectWith(); + + if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down + for (i = connectWith.length - 1; i >= 0; i--){ + cur = $(connectWith[i], this.document[0]); + for (j = cur.length - 1; j >= 0; j--){ + inst = $.data(cur[j], this.widgetFullName); + if(inst && inst !== this && !inst.options.disabled) { + queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); + this.containers.push(inst); + } + } + } + } + + for (i = queries.length - 1; i >= 0; i--) { + targetData = queries[i][1]; + _queries = queries[i][0]; + + for (j=0, queriesLength = _queries.length; j < queriesLength; j++) { + item = $(_queries[j]); + + item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager) + + items.push({ + item: item, + instance: targetData, + width: 0, height: 0, + left: 0, top: 0 + }); + } + } + + }, + + refreshPositions: function(fast) { + + // Determine whether items are being displayed horizontally + this.floating = this.items.length ? + this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) : + false; + + //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change + if(this.offsetParent && this.helper) { + this.offset.parent = this._getParentOffset(); + } + + var i, item, t, p; + + for (i = this.items.length - 1; i >= 0; i--){ + item = this.items[i]; + + //We ignore calculating positions of all connected containers when we're not over them + if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) { + continue; + } + + t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; + + if (!fast) { + item.width = t.outerWidth(); + item.height = t.outerHeight(); + } + + p = t.offset(); + item.left = p.left; + item.top = p.top; + } + + if(this.options.custom && this.options.custom.refreshContainers) { + this.options.custom.refreshContainers.call(this); + } else { + for (i = this.containers.length - 1; i >= 0; i--){ + p = this.containers[i].element.offset(); + this.containers[i].containerCache.left = p.left; + this.containers[i].containerCache.top = p.top; + this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); + this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); + } + } + + return this; + }, + + _createPlaceholder: function(that) { + that = that || this; + var className, + o = that.options; + + if(!o.placeholder || o.placeholder.constructor === String) { + className = o.placeholder; + o.placeholder = { + element: function() { + + var nodeName = that.currentItem[0].nodeName.toLowerCase(), + element = $( "<" + nodeName + ">", that.document[0] ) + .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") + .removeClass("ui-sortable-helper"); + + if ( nodeName === "tbody" ) { + that._createTrPlaceholder( + that.currentItem.find( "tr" ).eq( 0 ), + $( "<tr>", that.document[ 0 ] ).appendTo( element ) + ); + } else if ( nodeName === "tr" ) { + that._createTrPlaceholder( that.currentItem, element ); + } else if ( nodeName === "img" ) { + element.attr( "src", that.currentItem.attr( "src" ) ); + } + + if ( !className ) { + element.css( "visibility", "hidden" ); + } + + return element; + }, + update: function(container, p) { + + // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that + // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified + if(className && !o.forcePlaceholderSize) { + return; + } + + //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item + if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); } + if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); } + } + }; + } + + //Create the placeholder + that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem)); + + //Append it after the actual current item + that.currentItem.after(that.placeholder); + + //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) + o.placeholder.update(that, that.placeholder); + + }, + + _createTrPlaceholder: function( sourceTr, targetTr ) { + var that = this; + + sourceTr.children().each(function() { + $( "<td> </td>", that.document[ 0 ] ) + .attr( "colspan", $( this ).attr( "colspan" ) || 1 ) + .appendTo( targetTr ); + }); + }, + + _contactContainers: function(event) { + var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, floating, axis, + innermostContainer = null, + innermostIndex = null; + + // get innermost container that intersects with item + for (i = this.containers.length - 1; i >= 0; i--) { + + // never consider a container that's located within the item itself + if($.contains(this.currentItem[0], this.containers[i].element[0])) { + continue; + } + + if(this._intersectsWith(this.containers[i].containerCache)) { + + // if we've already found a container and it's more "inner" than this, then continue + if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) { + continue; + } + + innermostContainer = this.containers[i]; + innermostIndex = i; + + } else { + // container doesn't intersect. trigger "out" event if necessary + if(this.containers[i].containerCache.over) { + this.containers[i]._trigger("out", event, this._uiHash(this)); + this.containers[i].containerCache.over = 0; + } + } + + } + + // if no intersecting containers found, return + if(!innermostContainer) { + return; + } + + // move the item into the container if it's not there already + if(this.containers.length === 1) { + if (!this.containers[innermostIndex].containerCache.over) { + this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); + this.containers[innermostIndex].containerCache.over = 1; + } + } else { + + //When entering a new container, we will find the item with the least distance and append our item near it + dist = 10000; + itemWithLeastDistance = null; + floating = innermostContainer.floating || this._isFloating(this.currentItem); + posProperty = floating ? "left" : "top"; + sizeProperty = floating ? "width" : "height"; + axis = floating ? "clientX" : "clientY"; + + for (j = this.items.length - 1; j >= 0; j--) { + if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) { + continue; + } + if(this.items[j].item[0] === this.currentItem[0]) { + continue; + } + + cur = this.items[j].item.offset()[posProperty]; + nearBottom = false; + if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) { + nearBottom = true; + } + + if ( Math.abs( event[ axis ] - cur ) < dist ) { + dist = Math.abs( event[ axis ] - cur ); + itemWithLeastDistance = this.items[ j ]; + this.direction = nearBottom ? "up": "down"; + } + } + + //Check if dropOnEmpty is enabled + if(!itemWithLeastDistance && !this.options.dropOnEmpty) { + return; + } + + if(this.currentContainer === this.containers[innermostIndex]) { + if ( !this.currentContainer.containerCache.over ) { + this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() ); + this.currentContainer.containerCache.over = 1; + } + return; + } + + itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); + this._trigger("change", event, this._uiHash()); + this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); + this.currentContainer = this.containers[innermostIndex]; + + //Update the placeholder + this.options.placeholder.update(this.currentContainer, this.placeholder); + + this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); + this.containers[innermostIndex].containerCache.over = 1; + } + + + }, + + _createHelper: function(event) { + + var o = this.options, + helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem); + + //Add the helper to the DOM if that didn't happen already + if(!helper.parents("body").length) { + $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); + } + + if(helper[0] === this.currentItem[0]) { + this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; + } + + if(!helper[0].style.width || o.forceHelperSize) { + helper.width(this.currentItem.width()); + } + if(!helper[0].style.height || o.forceHelperSize) { + helper.height(this.currentItem.height()); + } + + return helper; + + }, + + _adjustOffsetFromHelper: function(obj) { + if (typeof obj === "string") { + obj = obj.split(" "); + } + if ($.isArray(obj)) { + obj = {left: +obj[0], top: +obj[1] || 0}; + } + if ("left" in obj) { + this.offset.click.left = obj.left + this.margins.left; + } + if ("right" in obj) { + this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; + } + if ("top" in obj) { + this.offset.click.top = obj.top + this.margins.top; + } + if ("bottom" in obj) { + this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; + } + }, + + _getParentOffset: function() { + + + //Get the offsetParent and cache its position + this.offsetParent = this.helper.offsetParent(); + var po = this.offsetParent.offset(); + + // This is a special case where we need to modify a offset calculated on start, since the following happened: + // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent + // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that + // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag + if(this.cssPosition === "absolute" && this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) { + po.left += this.scrollParent.scrollLeft(); + po.top += this.scrollParent.scrollTop(); + } + + // This needs to be actually done for all browsers, since pageX/pageY includes this information + // with an ugly IE fix + if( this.offsetParent[0] === this.document[0].body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { + po = { top: 0, left: 0 }; + } + + return { + top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), + left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) + }; + + }, + + _getRelativeOffset: function() { + + if(this.cssPosition === "relative") { + var p = this.currentItem.position(); + return { + top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), + left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() + }; + } else { + return { top: 0, left: 0 }; + } + + }, + + _cacheMargins: function() { + this.margins = { + left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), + top: (parseInt(this.currentItem.css("marginTop"),10) || 0) + }; + }, + + _cacheHelperProportions: function() { + this.helperProportions = { + width: this.helper.outerWidth(), + height: this.helper.outerHeight() + }; + }, + + _setContainment: function() { + + var ce, co, over, + o = this.options; + if(o.containment === "parent") { + o.containment = this.helper[0].parentNode; + } + if(o.containment === "document" || o.containment === "window") { + this.containment = [ + 0 - this.offset.relative.left - this.offset.parent.left, + 0 - this.offset.relative.top - this.offset.parent.top, + o.containment === "document" ? this.document.width() : this.window.width() - this.helperProportions.width - this.margins.left, + (o.containment === "document" ? this.document.width() : this.window.height() || this.document[0].body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top + ]; + } + + if(!(/^(document|window|parent)$/).test(o.containment)) { + ce = $(o.containment)[0]; + co = $(o.containment).offset(); + over = ($(ce).css("overflow") !== "hidden"); + + this.containment = [ + co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, + co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, + co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, + co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top + ]; + } + + }, + + _convertPositionTo: function(d, pos) { + + if(!pos) { + pos = this.position; + } + var mod = d === "absolute" ? 1 : -1, + scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, + scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + return { + top: ( + pos.top + // The absolute mouse position + this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) + ), + left: ( + pos.left + // The absolute mouse position + this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) + ) + }; + + }, + + _generatePosition: function(event) { + + var top, left, + o = this.options, + pageX = event.pageX, + pageY = event.pageY, + scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + // This is another very weird special case that only happens for relative elements: + // 1. If the css position is relative + // 2. and the scroll parent is the document or similar to the offset parent + // we have to refresh the relative offset during the scroll so there are no jumps + if(this.cssPosition === "relative" && !(this.scrollParent[0] !== this.document[0] && this.scrollParent[0] !== this.offsetParent[0])) { + this.offset.relative = this._getRelativeOffset(); + } + + /* + * - Position constraining - + * Constrain the position to a mix of grid, containment. + */ + + if(this.originalPosition) { //If we are not dragging yet, we won't check for options + + if(this.containment) { + if(event.pageX - this.offset.click.left < this.containment[0]) { + pageX = this.containment[0] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top < this.containment[1]) { + pageY = this.containment[1] + this.offset.click.top; + } + if(event.pageX - this.offset.click.left > this.containment[2]) { + pageX = this.containment[2] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top > this.containment[3]) { + pageY = this.containment[3] + this.offset.click.top; + } + } + + if(o.grid) { + top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; + pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + + left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; + pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + } + + } + + return { + top: ( + pageY - // The absolute mouse position + this.offset.click.top - // Click offset (relative to the element) + this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top + // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) + ), + left: ( + pageX - // The absolute mouse position + this.offset.click.left - // Click offset (relative to the element) + this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left + // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) + ) + }; + + }, + + _rearrange: function(event, i, a, hardRefresh) { + + a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling)); + + //Various things done here to improve the performance: + // 1. we create a setTimeout, that calls refreshPositions + // 2. on the instance, we have a counter variable, that get's higher after every append + // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same + // 4. this lets only the last addition to the timeout stack through + this.counter = this.counter ? ++this.counter : 1; + var counter = this.counter; + + this._delay(function() { + if(counter === this.counter) { + this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove + } + }); + + }, + + _clear: function(event, noPropagation) { + + this.reverting = false; + // We delay all events that have to be triggered to after the point where the placeholder has been removed and + // everything else normalized again + var i, + delayedTriggers = []; + + // We first have to update the dom position of the actual currentItem + // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) + if(!this._noFinalSort && this.currentItem.parent().length) { + this.placeholder.before(this.currentItem); + } + this._noFinalSort = null; + + if(this.helper[0] === this.currentItem[0]) { + for(i in this._storedCSS) { + if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") { + this._storedCSS[i] = ""; + } + } + this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); + } else { + this.currentItem.show(); + } + + if(this.fromOutside && !noPropagation) { + delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); + } + if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) { + delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed + } + + // Check if the items Container has Changed and trigger appropriate + // events. + if (this !== this.currentContainer) { + if(!noPropagation) { + delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); + delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); + delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); + } + } + + + //Post events to containers + function delayEvent( type, instance, container ) { + return function( event ) { + container._trigger( type, event, instance._uiHash( instance ) ); + }; + } + for (i = this.containers.length - 1; i >= 0; i--){ + if (!noPropagation) { + delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) ); + } + if(this.containers[i].containerCache.over) { + delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) ); + this.containers[i].containerCache.over = 0; + } + } + + //Do what was originally in plugins + if ( this.storedCursor ) { + this.document.find( "body" ).css( "cursor", this.storedCursor ); + this.storedStylesheet.remove(); + } + if(this._storedOpacity) { + this.helper.css("opacity", this._storedOpacity); + } + if(this._storedZIndex) { + this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex); + } + + this.dragging = false; + + if(!noPropagation) { + this._trigger("beforeStop", event, this._uiHash()); + } + + //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! + this.placeholder[0].parentNode.removeChild(this.placeholder[0]); + + if ( !this.cancelHelperRemoval ) { + if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) { + this.helper.remove(); + } + this.helper = null; + } + + if(!noPropagation) { + for (i=0; i < delayedTriggers.length; i++) { + delayedTriggers[i].call(this, event); + } //Trigger all delayed events + this._trigger("stop", event, this._uiHash()); + } + + this.fromOutside = false; + return !this.cancelHelperRemoval; + + }, + + _trigger: function() { + if ($.Widget.prototype._trigger.apply(this, arguments) === false) { + this.cancel(); + } + }, + + _uiHash: function(_inst) { + var inst = _inst || this; + return { + helper: inst.helper, + placeholder: inst.placeholder || $([]), + position: inst.position, + originalPosition: inst.originalPosition, + offset: inst.positionAbs, + item: inst.currentItem, + sender: _inst ? _inst.element : null + }; + } + +}); + + +/*! + * jQuery UI Spinner 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/spinner/ + */ + + +function spinner_modifier( fn ) { + return function() { + var previous = this.element.val(); + fn.apply( this, arguments ); + this._refresh(); + if ( previous !== this.element.val() ) { + this._trigger( "change" ); + } + }; +} + +var spinner = $.widget( "ui.spinner", { + version: "1.11.4", + defaultElement: "<input>", + widgetEventPrefix: "spin", + options: { + culture: null, + icons: { + down: "ui-icon-triangle-1-s", + up: "ui-icon-triangle-1-n" + }, + incremental: true, + max: null, + min: null, + numberFormat: null, + page: 10, + step: 1, + + change: null, + spin: null, + start: null, + stop: null + }, + + _create: function() { + // handle string values that need to be parsed + this._setOption( "max", this.options.max ); + this._setOption( "min", this.options.min ); + this._setOption( "step", this.options.step ); + + // Only format if there is a value, prevents the field from being marked + // as invalid in Firefox, see #9573. + if ( this.value() !== "" ) { + // Format the value, but don't constrain. + this._value( this.element.val(), true ); + } + + this._draw(); + this._on( this._events ); + this._refresh(); + + // turning off autocomplete prevents the browser from remembering the + // value when navigating through history, so we re-enable autocomplete + // if the page is unloaded before the widget is destroyed. #7790 + this._on( this.window, { + beforeunload: function() { + this.element.removeAttr( "autocomplete" ); + } + }); + }, + + _getCreateOptions: function() { + var options = {}, + element = this.element; + + $.each( [ "min", "max", "step" ], function( i, option ) { + var value = element.attr( option ); + if ( value !== undefined && value.length ) { + options[ option ] = value; + } + }); + + return options; + }, + + _events: { + keydown: function( event ) { + if ( this._start( event ) && this._keydown( event ) ) { + event.preventDefault(); + } + }, + keyup: "_stop", + focus: function() { + this.previous = this.element.val(); + }, + blur: function( event ) { + if ( this.cancelBlur ) { + delete this.cancelBlur; + return; + } + + this._stop(); + this._refresh(); + if ( this.previous !== this.element.val() ) { + this._trigger( "change", event ); + } + }, + mousewheel: function( event, delta ) { + if ( !delta ) { + return; + } + if ( !this.spinning && !this._start( event ) ) { + return false; + } + + this._spin( (delta > 0 ? 1 : -1) * this.options.step, event ); + clearTimeout( this.mousewheelTimer ); + this.mousewheelTimer = this._delay(function() { + if ( this.spinning ) { + this._stop( event ); + } + }, 100 ); + event.preventDefault(); + }, + "mousedown .ui-spinner-button": function( event ) { + var previous; + + // We never want the buttons to have focus; whenever the user is + // interacting with the spinner, the focus should be on the input. + // If the input is focused then this.previous is properly set from + // when the input first received focus. If the input is not focused + // then we need to set this.previous based on the value before spinning. + previous = this.element[0] === this.document[0].activeElement ? + this.previous : this.element.val(); + function checkFocus() { + var isActive = this.element[0] === this.document[0].activeElement; + if ( !isActive ) { + this.element.focus(); + this.previous = previous; + // support: IE + // IE sets focus asynchronously, so we need to check if focus + // moved off of the input because the user clicked on the button. + this._delay(function() { + this.previous = previous; + }); + } + } + + // ensure focus is on (or stays on) the text field + event.preventDefault(); + checkFocus.call( this ); + + // support: IE + // IE doesn't prevent moving focus even with event.preventDefault() + // so we set a flag to know when we should ignore the blur event + // and check (again) if focus moved off of the input. + this.cancelBlur = true; + this._delay(function() { + delete this.cancelBlur; + checkFocus.call( this ); + }); + + if ( this._start( event ) === false ) { + return; + } + + this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event ); + }, + "mouseup .ui-spinner-button": "_stop", + "mouseenter .ui-spinner-button": function( event ) { + // button will add ui-state-active if mouse was down while mouseleave and kept down + if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) { + return; + } + + if ( this._start( event ) === false ) { + return false; + } + this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event ); + }, + // TODO: do we really want to consider this a stop? + // shouldn't we just stop the repeater and wait until mouseup before + // we trigger the stop event? + "mouseleave .ui-spinner-button": "_stop" + }, + + _draw: function() { + var uiSpinner = this.uiSpinner = this.element + .addClass( "ui-spinner-input" ) + .attr( "autocomplete", "off" ) + .wrap( this._uiSpinnerHtml() ) + .parent() + // add buttons + .append( this._buttonHtml() ); + + this.element.attr( "role", "spinbutton" ); + + // button bindings + this.buttons = uiSpinner.find( ".ui-spinner-button" ) + .attr( "tabIndex", -1 ) + .button() + .removeClass( "ui-corner-all" ); + + // IE 6 doesn't understand height: 50% for the buttons + // unless the wrapper has an explicit height + if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) && + uiSpinner.height() > 0 ) { + uiSpinner.height( uiSpinner.height() ); + } + + // disable spinner if element was already disabled + if ( this.options.disabled ) { + this.disable(); + } + }, + + _keydown: function( event ) { + var options = this.options, + keyCode = $.ui.keyCode; + + switch ( event.keyCode ) { + case keyCode.UP: + this._repeat( null, 1, event ); + return true; + case keyCode.DOWN: + this._repeat( null, -1, event ); + return true; + case keyCode.PAGE_UP: + this._repeat( null, options.page, event ); + return true; + case keyCode.PAGE_DOWN: + this._repeat( null, -options.page, event ); + return true; + } + + return false; + }, + + _uiSpinnerHtml: function() { + return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>"; + }, + + _buttonHtml: function() { + return "" + + "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" + + "<span class='ui-icon " + this.options.icons.up + "'>▲</span>" + + "</a>" + + "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" + + "<span class='ui-icon " + this.options.icons.down + "'>▼</span>" + + "</a>"; + }, + + _start: function( event ) { + if ( !this.spinning && this._trigger( "start", event ) === false ) { + return false; + } + + if ( !this.counter ) { + this.counter = 1; + } + this.spinning = true; + return true; + }, + + _repeat: function( i, steps, event ) { + i = i || 500; + + clearTimeout( this.timer ); + this.timer = this._delay(function() { + this._repeat( 40, steps, event ); + }, i ); + + this._spin( steps * this.options.step, event ); + }, + + _spin: function( step, event ) { + var value = this.value() || 0; + + if ( !this.counter ) { + this.counter = 1; + } + + value = this._adjustValue( value + step * this._increment( this.counter ) ); + + if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) { + this._value( value ); + this.counter++; + } + }, + + _increment: function( i ) { + var incremental = this.options.incremental; + + if ( incremental ) { + return $.isFunction( incremental ) ? + incremental( i ) : + Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 ); + } + + return 1; + }, + + _precision: function() { + var precision = this._precisionOf( this.options.step ); + if ( this.options.min !== null ) { + precision = Math.max( precision, this._precisionOf( this.options.min ) ); + } + return precision; + }, + + _precisionOf: function( num ) { + var str = num.toString(), + decimal = str.indexOf( "." ); + return decimal === -1 ? 0 : str.length - decimal - 1; + }, + + _adjustValue: function( value ) { + var base, aboveMin, + options = this.options; + + // make sure we're at a valid step + // - find out where we are relative to the base (min or 0) + base = options.min !== null ? options.min : 0; + aboveMin = value - base; + // - round to the nearest step + aboveMin = Math.round(aboveMin / options.step) * options.step; + // - rounding is based on 0, so adjust back to our base + value = base + aboveMin; + + // fix precision from bad JS floating point math + value = parseFloat( value.toFixed( this._precision() ) ); + + // clamp the value + if ( options.max !== null && value > options.max) { + return options.max; + } + if ( options.min !== null && value < options.min ) { + return options.min; + } + + return value; + }, + + _stop: function( event ) { + if ( !this.spinning ) { + return; + } + + clearTimeout( this.timer ); + clearTimeout( this.mousewheelTimer ); + this.counter = 0; + this.spinning = false; + this._trigger( "stop", event ); + }, + + _setOption: function( key, value ) { + if ( key === "culture" || key === "numberFormat" ) { + var prevValue = this._parse( this.element.val() ); + this.options[ key ] = value; + this.element.val( this._format( prevValue ) ); + return; + } + + if ( key === "max" || key === "min" || key === "step" ) { + if ( typeof value === "string" ) { + value = this._parse( value ); + } + } + if ( key === "icons" ) { + this.buttons.first().find( ".ui-icon" ) + .removeClass( this.options.icons.up ) + .addClass( value.up ); + this.buttons.last().find( ".ui-icon" ) + .removeClass( this.options.icons.down ) + .addClass( value.down ); + } + + this._super( key, value ); + + if ( key === "disabled" ) { + this.widget().toggleClass( "ui-state-disabled", !!value ); + this.element.prop( "disabled", !!value ); + this.buttons.button( value ? "disable" : "enable" ); + } + }, + + _setOptions: spinner_modifier(function( options ) { + this._super( options ); + }), + + _parse: function( val ) { + if ( typeof val === "string" && val !== "" ) { + val = window.Globalize && this.options.numberFormat ? + Globalize.parseFloat( val, 10, this.options.culture ) : +val; + } + return val === "" || isNaN( val ) ? null : val; + }, + + _format: function( value ) { + if ( value === "" ) { + return ""; + } + return window.Globalize && this.options.numberFormat ? + Globalize.format( value, this.options.numberFormat, this.options.culture ) : + value; + }, + + _refresh: function() { + this.element.attr({ + "aria-valuemin": this.options.min, + "aria-valuemax": this.options.max, + // TODO: what should we do with values that can't be parsed? + "aria-valuenow": this._parse( this.element.val() ) + }); + }, + + isValid: function() { + var value = this.value(); + + // null is invalid + if ( value === null ) { + return false; + } + + // if value gets adjusted, it's invalid + return value === this._adjustValue( value ); + }, + + // update the value without triggering change + _value: function( value, allowAny ) { + var parsed; + if ( value !== "" ) { + parsed = this._parse( value ); + if ( parsed !== null ) { + if ( !allowAny ) { + parsed = this._adjustValue( parsed ); + } + value = this._format( parsed ); + } + } + this.element.val( value ); + this._refresh(); + }, + + _destroy: function() { + this.element + .removeClass( "ui-spinner-input" ) + .prop( "disabled", false ) + .removeAttr( "autocomplete" ) + .removeAttr( "role" ) + .removeAttr( "aria-valuemin" ) + .removeAttr( "aria-valuemax" ) + .removeAttr( "aria-valuenow" ); + this.uiSpinner.replaceWith( this.element ); + }, + + stepUp: spinner_modifier(function( steps ) { + this._stepUp( steps ); + }), + _stepUp: function( steps ) { + if ( this._start() ) { + this._spin( (steps || 1) * this.options.step ); + this._stop(); + } + }, + + stepDown: spinner_modifier(function( steps ) { + this._stepDown( steps ); + }), + _stepDown: function( steps ) { + if ( this._start() ) { + this._spin( (steps || 1) * -this.options.step ); + this._stop(); + } + }, + + pageUp: spinner_modifier(function( pages ) { + this._stepUp( (pages || 1) * this.options.page ); + }), + + pageDown: spinner_modifier(function( pages ) { + this._stepDown( (pages || 1) * this.options.page ); + }), + + value: function( newVal ) { + if ( !arguments.length ) { + return this._parse( this.element.val() ); + } + spinner_modifier( this._value ).call( this, newVal ); + }, + + widget: function() { + return this.uiSpinner; + } +}); + + +/*! + * jQuery UI Tabs 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/tabs/ + */ + + +var tabs = $.widget( "ui.tabs", { + version: "1.11.4", + delay: 300, + options: { + active: null, + collapsible: false, + event: "click", + heightStyle: "content", + hide: null, + show: null, + + // callbacks + activate: null, + beforeActivate: null, + beforeLoad: null, + load: null + }, + + _isLocal: (function() { + var rhash = /#.*$/; + + return function( anchor ) { + var anchorUrl, locationUrl; + + // support: IE7 + // IE7 doesn't normalize the href property when set via script (#9317) + anchor = anchor.cloneNode( false ); + + anchorUrl = anchor.href.replace( rhash, "" ); + locationUrl = location.href.replace( rhash, "" ); + + // decoding may throw an error if the URL isn't UTF-8 (#9518) + try { + anchorUrl = decodeURIComponent( anchorUrl ); + } catch ( error ) {} + try { + locationUrl = decodeURIComponent( locationUrl ); + } catch ( error ) {} + + return anchor.hash.length > 1 && anchorUrl === locationUrl; + }; + })(), + + _create: function() { + var that = this, + options = this.options; + + this.running = false; + + this.element + .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" ) + .toggleClass( "ui-tabs-collapsible", options.collapsible ); + + this._processTabs(); + options.active = this._initialActive(); + + // Take disabling tabs via class attribute from HTML + // into account and update option properly. + if ( $.isArray( options.disabled ) ) { + options.disabled = $.unique( options.disabled.concat( + $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) { + return that.tabs.index( li ); + }) + ) ).sort(); + } + + // check for length avoids error when initializing empty list + if ( this.options.active !== false && this.anchors.length ) { + this.active = this._findActive( options.active ); + } else { + this.active = $(); + } + + this._refresh(); + + if ( this.active.length ) { + this.load( options.active ); + } + }, + + _initialActive: function() { + var active = this.options.active, + collapsible = this.options.collapsible, + locationHash = location.hash.substring( 1 ); + + if ( active === null ) { + // check the fragment identifier in the URL + if ( locationHash ) { + this.tabs.each(function( i, tab ) { + if ( $( tab ).attr( "aria-controls" ) === locationHash ) { + active = i; + return false; + } + }); + } + + // check for a tab marked active via a class + if ( active === null ) { + active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) ); + } + + // no active tab, set to false + if ( active === null || active === -1 ) { + active = this.tabs.length ? 0 : false; + } + } + + // handle numbers: negative, out of range + if ( active !== false ) { + active = this.tabs.index( this.tabs.eq( active ) ); + if ( active === -1 ) { + active = collapsible ? false : 0; + } + } + + // don't allow collapsible: false and active: false + if ( !collapsible && active === false && this.anchors.length ) { + active = 0; + } + + return active; + }, + + _getCreateEventData: function() { + return { + tab: this.active, + panel: !this.active.length ? $() : this._getPanelForTab( this.active ) + }; + }, + + _tabKeydown: function( event ) { + var focusedTab = $( this.document[0].activeElement ).closest( "li" ), + selectedIndex = this.tabs.index( focusedTab ), + goingForward = true; + + if ( this._handlePageNav( event ) ) { + return; + } + + switch ( event.keyCode ) { + case $.ui.keyCode.RIGHT: + case $.ui.keyCode.DOWN: + selectedIndex++; + break; + case $.ui.keyCode.UP: + case $.ui.keyCode.LEFT: + goingForward = false; + selectedIndex--; + break; + case $.ui.keyCode.END: + selectedIndex = this.anchors.length - 1; + break; + case $.ui.keyCode.HOME: + selectedIndex = 0; + break; + case $.ui.keyCode.SPACE: + // Activate only, no collapsing + event.preventDefault(); + clearTimeout( this.activating ); + this._activate( selectedIndex ); + return; + case $.ui.keyCode.ENTER: + // Toggle (cancel delayed activation, allow collapsing) + event.preventDefault(); + clearTimeout( this.activating ); + // Determine if we should collapse or activate + this._activate( selectedIndex === this.options.active ? false : selectedIndex ); + return; + default: + return; + } + + // Focus the appropriate tab, based on which key was pressed + event.preventDefault(); + clearTimeout( this.activating ); + selectedIndex = this._focusNextTab( selectedIndex, goingForward ); + + // Navigating with control/command key will prevent automatic activation + if ( !event.ctrlKey && !event.metaKey ) { + + // Update aria-selected immediately so that AT think the tab is already selected. + // Otherwise AT may confuse the user by stating that they need to activate the tab, + // but the tab will already be activated by the time the announcement finishes. + focusedTab.attr( "aria-selected", "false" ); + this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" ); + + this.activating = this._delay(function() { + this.option( "active", selectedIndex ); + }, this.delay ); + } + }, + + _panelKeydown: function( event ) { + if ( this._handlePageNav( event ) ) { + return; + } + + // Ctrl+up moves focus to the current tab + if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) { + event.preventDefault(); + this.active.focus(); + } + }, + + // Alt+page up/down moves focus to the previous/next tab (and activates) + _handlePageNav: function( event ) { + if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) { + this._activate( this._focusNextTab( this.options.active - 1, false ) ); + return true; + } + if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) { + this._activate( this._focusNextTab( this.options.active + 1, true ) ); + return true; + } + }, + + _findNextTab: function( index, goingForward ) { + var lastTabIndex = this.tabs.length - 1; + + function constrain() { + if ( index > lastTabIndex ) { + index = 0; + } + if ( index < 0 ) { + index = lastTabIndex; + } + return index; + } + + while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) { + index = goingForward ? index + 1 : index - 1; + } + + return index; + }, + + _focusNextTab: function( index, goingForward ) { + index = this._findNextTab( index, goingForward ); + this.tabs.eq( index ).focus(); + return index; + }, + + _setOption: function( key, value ) { + if ( key === "active" ) { + // _activate() will handle invalid values and update this.options + this._activate( value ); + return; + } + + if ( key === "disabled" ) { + // don't use the widget factory's disabled handling + this._setupDisabled( value ); + return; + } + + this._super( key, value); + + if ( key === "collapsible" ) { + this.element.toggleClass( "ui-tabs-collapsible", value ); + // Setting collapsible: false while collapsed; open first panel + if ( !value && this.options.active === false ) { + this._activate( 0 ); + } + } + + if ( key === "event" ) { + this._setupEvents( value ); + } + + if ( key === "heightStyle" ) { + this._setupHeightStyle( value ); + } + }, + + _sanitizeSelector: function( hash ) { + return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : ""; + }, + + refresh: function() { + var options = this.options, + lis = this.tablist.children( ":has(a[href])" ); + + // get disabled tabs from class attribute from HTML + // this will get converted to a boolean if needed in _refresh() + options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) { + return lis.index( tab ); + }); + + this._processTabs(); + + // was collapsed or no tabs + if ( options.active === false || !this.anchors.length ) { + options.active = false; + this.active = $(); + // was active, but active tab is gone + } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) { + // all remaining tabs are disabled + if ( this.tabs.length === options.disabled.length ) { + options.active = false; + this.active = $(); + // activate previous tab + } else { + this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) ); + } + // was active, active tab still exists + } else { + // make sure active index is correct + options.active = this.tabs.index( this.active ); + } + + this._refresh(); + }, + + _refresh: function() { + this._setupDisabled( this.options.disabled ); + this._setupEvents( this.options.event ); + this._setupHeightStyle( this.options.heightStyle ); + + this.tabs.not( this.active ).attr({ + "aria-selected": "false", + "aria-expanded": "false", + tabIndex: -1 + }); + this.panels.not( this._getPanelForTab( this.active ) ) + .hide() + .attr({ + "aria-hidden": "true" + }); + + // Make sure one tab is in the tab order + if ( !this.active.length ) { + this.tabs.eq( 0 ).attr( "tabIndex", 0 ); + } else { + this.active + .addClass( "ui-tabs-active ui-state-active" ) + .attr({ + "aria-selected": "true", + "aria-expanded": "true", + tabIndex: 0 + }); + this._getPanelForTab( this.active ) + .show() + .attr({ + "aria-hidden": "false" + }); + } + }, + + _processTabs: function() { + var that = this, + prevTabs = this.tabs, + prevAnchors = this.anchors, + prevPanels = this.panels; + + this.tablist = this._getList() + .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ) + .attr( "role", "tablist" ) + + // Prevent users from focusing disabled tabs via click + .delegate( "> li", "mousedown" + this.eventNamespace, function( event ) { + if ( $( this ).is( ".ui-state-disabled" ) ) { + event.preventDefault(); + } + }) + + // support: IE <9 + // Preventing the default action in mousedown doesn't prevent IE + // from focusing the element, so if the anchor gets focused, blur. + // We don't have to worry about focusing the previously focused + // element since clicking on a non-focusable element should focus + // the body anyway. + .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() { + if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) { + this.blur(); + } + }); + + this.tabs = this.tablist.find( "> li:has(a[href])" ) + .addClass( "ui-state-default ui-corner-top" ) + .attr({ + role: "tab", + tabIndex: -1 + }); + + this.anchors = this.tabs.map(function() { + return $( "a", this )[ 0 ]; + }) + .addClass( "ui-tabs-anchor" ) + .attr({ + role: "presentation", + tabIndex: -1 + }); + + this.panels = $(); + + this.anchors.each(function( i, anchor ) { + var selector, panel, panelId, + anchorId = $( anchor ).uniqueId().attr( "id" ), + tab = $( anchor ).closest( "li" ), + originalAriaControls = tab.attr( "aria-controls" ); + + // inline tab + if ( that._isLocal( anchor ) ) { + selector = anchor.hash; + panelId = selector.substring( 1 ); + panel = that.element.find( that._sanitizeSelector( selector ) ); + // remote tab + } else { + // If the tab doesn't already have aria-controls, + // generate an id by using a throw-away element + panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id; + selector = "#" + panelId; + panel = that.element.find( selector ); + if ( !panel.length ) { + panel = that._createPanel( panelId ); + panel.insertAfter( that.panels[ i - 1 ] || that.tablist ); + } + panel.attr( "aria-live", "polite" ); + } + + if ( panel.length) { + that.panels = that.panels.add( panel ); + } + if ( originalAriaControls ) { + tab.data( "ui-tabs-aria-controls", originalAriaControls ); + } + tab.attr({ + "aria-controls": panelId, + "aria-labelledby": anchorId + }); + panel.attr( "aria-labelledby", anchorId ); + }); + + this.panels + .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) + .attr( "role", "tabpanel" ); + + // Avoid memory leaks (#10056) + if ( prevTabs ) { + this._off( prevTabs.not( this.tabs ) ); + this._off( prevAnchors.not( this.anchors ) ); + this._off( prevPanels.not( this.panels ) ); + } + }, + + // allow overriding how to find the list for rare usage scenarios (#7715) + _getList: function() { + return this.tablist || this.element.find( "ol,ul" ).eq( 0 ); + }, + + _createPanel: function( id ) { + return $( "<div>" ) + .attr( "id", id ) + .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) + .data( "ui-tabs-destroy", true ); + }, + + _setupDisabled: function( disabled ) { + if ( $.isArray( disabled ) ) { + if ( !disabled.length ) { + disabled = false; + } else if ( disabled.length === this.anchors.length ) { + disabled = true; + } + } + + // disable tabs + for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) { + if ( disabled === true || $.inArray( i, disabled ) !== -1 ) { + $( li ) + .addClass( "ui-state-disabled" ) + .attr( "aria-disabled", "true" ); + } else { + $( li ) + .removeClass( "ui-state-disabled" ) + .removeAttr( "aria-disabled" ); + } + } + + this.options.disabled = disabled; + }, + + _setupEvents: function( event ) { + var events = {}; + if ( event ) { + $.each( event.split(" "), function( index, eventName ) { + events[ eventName ] = "_eventHandler"; + }); + } + + this._off( this.anchors.add( this.tabs ).add( this.panels ) ); + // Always prevent the default action, even when disabled + this._on( true, this.anchors, { + click: function( event ) { + event.preventDefault(); + } + }); + this._on( this.anchors, events ); + this._on( this.tabs, { keydown: "_tabKeydown" } ); + this._on( this.panels, { keydown: "_panelKeydown" } ); + + this._focusable( this.tabs ); + this._hoverable( this.tabs ); + }, + + _setupHeightStyle: function( heightStyle ) { + var maxHeight, + parent = this.element.parent(); + + if ( heightStyle === "fill" ) { + maxHeight = parent.height(); + maxHeight -= this.element.outerHeight() - this.element.height(); + + this.element.siblings( ":visible" ).each(function() { + var elem = $( this ), + position = elem.css( "position" ); + + if ( position === "absolute" || position === "fixed" ) { + return; + } + maxHeight -= elem.outerHeight( true ); + }); + + this.element.children().not( this.panels ).each(function() { + maxHeight -= $( this ).outerHeight( true ); + }); + + this.panels.each(function() { + $( this ).height( Math.max( 0, maxHeight - + $( this ).innerHeight() + $( this ).height() ) ); + }) + .css( "overflow", "auto" ); + } else if ( heightStyle === "auto" ) { + maxHeight = 0; + this.panels.each(function() { + maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() ); + }).height( maxHeight ); + } + }, + + _eventHandler: function( event ) { + var options = this.options, + active = this.active, + anchor = $( event.currentTarget ), + tab = anchor.closest( "li" ), + clickedIsActive = tab[ 0 ] === active[ 0 ], + collapsing = clickedIsActive && options.collapsible, + toShow = collapsing ? $() : this._getPanelForTab( tab ), + toHide = !active.length ? $() : this._getPanelForTab( active ), + eventData = { + oldTab: active, + oldPanel: toHide, + newTab: collapsing ? $() : tab, + newPanel: toShow + }; + + event.preventDefault(); + + if ( tab.hasClass( "ui-state-disabled" ) || + // tab is already loading + tab.hasClass( "ui-tabs-loading" ) || + // can't switch durning an animation + this.running || + // click on active header, but not collapsible + ( clickedIsActive && !options.collapsible ) || + // allow canceling activation + ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { + return; + } + + options.active = collapsing ? false : this.tabs.index( tab ); + + this.active = clickedIsActive ? $() : tab; + if ( this.xhr ) { + this.xhr.abort(); + } + + if ( !toHide.length && !toShow.length ) { + $.error( "jQuery UI Tabs: Mismatching fragment identifier." ); + } + + if ( toShow.length ) { + this.load( this.tabs.index( tab ), event ); + } + this._toggle( event, eventData ); + }, + + // handles show/hide for selecting tabs + _toggle: function( event, eventData ) { + var that = this, + toShow = eventData.newPanel, + toHide = eventData.oldPanel; + + this.running = true; + + function complete() { + that.running = false; + that._trigger( "activate", event, eventData ); + } + + function show() { + eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" ); + + if ( toShow.length && that.options.show ) { + that._show( toShow, that.options.show, complete ); + } else { + toShow.show(); + complete(); + } + } + + // start out by hiding, then showing, then completing + if ( toHide.length && this.options.hide ) { + this._hide( toHide, this.options.hide, function() { + eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); + show(); + }); + } else { + eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); + toHide.hide(); + show(); + } + + toHide.attr( "aria-hidden", "true" ); + eventData.oldTab.attr({ + "aria-selected": "false", + "aria-expanded": "false" + }); + // If we're switching tabs, remove the old tab from the tab order. + // If we're opening from collapsed state, remove the previous tab from the tab order. + // If we're collapsing, then keep the collapsing tab in the tab order. + if ( toShow.length && toHide.length ) { + eventData.oldTab.attr( "tabIndex", -1 ); + } else if ( toShow.length ) { + this.tabs.filter(function() { + return $( this ).attr( "tabIndex" ) === 0; + }) + .attr( "tabIndex", -1 ); + } + + toShow.attr( "aria-hidden", "false" ); + eventData.newTab.attr({ + "aria-selected": "true", + "aria-expanded": "true", + tabIndex: 0 + }); + }, + + _activate: function( index ) { + var anchor, + active = this._findActive( index ); + + // trying to activate the already active panel + if ( active[ 0 ] === this.active[ 0 ] ) { + return; + } + + // trying to collapse, simulate a click on the current active header + if ( !active.length ) { + active = this.active; + } + + anchor = active.find( ".ui-tabs-anchor" )[ 0 ]; + this._eventHandler({ + target: anchor, + currentTarget: anchor, + preventDefault: $.noop + }); + }, + + _findActive: function( index ) { + return index === false ? $() : this.tabs.eq( index ); + }, + + _getIndex: function( index ) { + // meta-function to give users option to provide a href string instead of a numerical index. + if ( typeof index === "string" ) { + index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) ); + } + + return index; + }, + + _destroy: function() { + if ( this.xhr ) { + this.xhr.abort(); + } + + this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" ); + + this.tablist + .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ) + .removeAttr( "role" ); + + this.anchors + .removeClass( "ui-tabs-anchor" ) + .removeAttr( "role" ) + .removeAttr( "tabIndex" ) + .removeUniqueId(); + + this.tablist.unbind( this.eventNamespace ); + + this.tabs.add( this.panels ).each(function() { + if ( $.data( this, "ui-tabs-destroy" ) ) { + $( this ).remove(); + } else { + $( this ) + .removeClass( "ui-state-default ui-state-active ui-state-disabled " + + "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" ) + .removeAttr( "tabIndex" ) + .removeAttr( "aria-live" ) + .removeAttr( "aria-busy" ) + .removeAttr( "aria-selected" ) + .removeAttr( "aria-labelledby" ) + .removeAttr( "aria-hidden" ) + .removeAttr( "aria-expanded" ) + .removeAttr( "role" ); + } + }); + + this.tabs.each(function() { + var li = $( this ), + prev = li.data( "ui-tabs-aria-controls" ); + if ( prev ) { + li + .attr( "aria-controls", prev ) + .removeData( "ui-tabs-aria-controls" ); + } else { + li.removeAttr( "aria-controls" ); + } + }); + + this.panels.show(); + + if ( this.options.heightStyle !== "content" ) { + this.panels.css( "height", "" ); + } + }, + + enable: function( index ) { + var disabled = this.options.disabled; + if ( disabled === false ) { + return; + } + + if ( index === undefined ) { + disabled = false; + } else { + index = this._getIndex( index ); + if ( $.isArray( disabled ) ) { + disabled = $.map( disabled, function( num ) { + return num !== index ? num : null; + }); + } else { + disabled = $.map( this.tabs, function( li, num ) { + return num !== index ? num : null; + }); + } + } + this._setupDisabled( disabled ); + }, + + disable: function( index ) { + var disabled = this.options.disabled; + if ( disabled === true ) { + return; + } + + if ( index === undefined ) { + disabled = true; + } else { + index = this._getIndex( index ); + if ( $.inArray( index, disabled ) !== -1 ) { + return; + } + if ( $.isArray( disabled ) ) { + disabled = $.merge( [ index ], disabled ).sort(); + } else { + disabled = [ index ]; + } + } + this._setupDisabled( disabled ); + }, + + load: function( index, event ) { + index = this._getIndex( index ); + var that = this, + tab = this.tabs.eq( index ), + anchor = tab.find( ".ui-tabs-anchor" ), + panel = this._getPanelForTab( tab ), + eventData = { + tab: tab, + panel: panel + }, + complete = function( jqXHR, status ) { + if ( status === "abort" ) { + that.panels.stop( false, true ); + } + + tab.removeClass( "ui-tabs-loading" ); + panel.removeAttr( "aria-busy" ); + + if ( jqXHR === that.xhr ) { + delete that.xhr; + } + }; + + // not remote + if ( this._isLocal( anchor[ 0 ] ) ) { + return; + } + + this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) ); + + // support: jQuery <1.8 + // jQuery <1.8 returns false if the request is canceled in beforeSend, + // but as of 1.8, $.ajax() always returns a jqXHR object. + if ( this.xhr && this.xhr.statusText !== "canceled" ) { + tab.addClass( "ui-tabs-loading" ); + panel.attr( "aria-busy", "true" ); + + this.xhr + .done(function( response, status, jqXHR ) { + // support: jQuery <1.8 + // http://bugs.jquery.com/ticket/11778 + setTimeout(function() { + panel.html( response ); + that._trigger( "load", event, eventData ); + + complete( jqXHR, status ); + }, 1 ); + }) + .fail(function( jqXHR, status ) { + // support: jQuery <1.8 + // http://bugs.jquery.com/ticket/11778 + setTimeout(function() { + complete( jqXHR, status ); + }, 1 ); + }); + } + }, + + _ajaxSettings: function( anchor, event, eventData ) { + var that = this; + return { + url: anchor.attr( "href" ), + beforeSend: function( jqXHR, settings ) { + return that._trigger( "beforeLoad", event, + $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) ); + } + }; + }, + + _getPanelForTab: function( tab ) { + var id = $( tab ).attr( "aria-controls" ); + return this.element.find( this._sanitizeSelector( "#" + id ) ); + } +}); + + +/*! + * jQuery UI Tooltip 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/tooltip/ + */ + + +var tooltip = $.widget( "ui.tooltip", { + version: "1.11.4", + options: { + content: function() { + // support: IE<9, Opera in jQuery <1.7 + // .text() can't accept undefined, so coerce to a string + var title = $( this ).attr( "title" ) || ""; + // Escape title, since we're going from an attribute to raw HTML + return $( "<a>" ).text( title ).html(); + }, + hide: true, + // Disabled elements have inconsistent behavior across browsers (#8661) + items: "[title]:not([disabled])", + position: { + my: "left top+15", + at: "left bottom", + collision: "flipfit flip" + }, + show: true, + tooltipClass: null, + track: false, + + // callbacks + close: null, + open: null + }, + + _addDescribedBy: function( elem, id ) { + var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ); + describedby.push( id ); + elem + .data( "ui-tooltip-id", id ) + .attr( "aria-describedby", $.trim( describedby.join( " " ) ) ); + }, + + _removeDescribedBy: function( elem ) { + var id = elem.data( "ui-tooltip-id" ), + describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ), + index = $.inArray( id, describedby ); + + if ( index !== -1 ) { + describedby.splice( index, 1 ); + } + + elem.removeData( "ui-tooltip-id" ); + describedby = $.trim( describedby.join( " " ) ); + if ( describedby ) { + elem.attr( "aria-describedby", describedby ); + } else { + elem.removeAttr( "aria-describedby" ); + } + }, + + _create: function() { + this._on({ + mouseover: "open", + focusin: "open" + }); + + // IDs of generated tooltips, needed for destroy + this.tooltips = {}; + + // IDs of parent tooltips where we removed the title attribute + this.parents = {}; + + if ( this.options.disabled ) { + this._disable(); + } + + // Append the aria-live region so tooltips announce correctly + this.liveRegion = $( "<div>" ) + .attr({ + role: "log", + "aria-live": "assertive", + "aria-relevant": "additions" + }) + .addClass( "ui-helper-hidden-accessible" ) + .appendTo( this.document[ 0 ].body ); + }, + + _setOption: function( key, value ) { + var that = this; + + if ( key === "disabled" ) { + this[ value ? "_disable" : "_enable" ](); + this.options[ key ] = value; + // disable element style changes + return; + } + + this._super( key, value ); + + if ( key === "content" ) { + $.each( this.tooltips, function( id, tooltipData ) { + that._updateContent( tooltipData.element ); + }); + } + }, + + _disable: function() { + var that = this; + + // close open tooltips + $.each( this.tooltips, function( id, tooltipData ) { + var event = $.Event( "blur" ); + event.target = event.currentTarget = tooltipData.element[ 0 ]; + that.close( event, true ); + }); + + // remove title attributes to prevent native tooltips + this.element.find( this.options.items ).addBack().each(function() { + var element = $( this ); + if ( element.is( "[title]" ) ) { + element + .data( "ui-tooltip-title", element.attr( "title" ) ) + .removeAttr( "title" ); + } + }); + }, + + _enable: function() { + // restore title attributes + this.element.find( this.options.items ).addBack().each(function() { + var element = $( this ); + if ( element.data( "ui-tooltip-title" ) ) { + element.attr( "title", element.data( "ui-tooltip-title" ) ); + } + }); + }, + + open: function( event ) { + var that = this, + target = $( event ? event.target : this.element ) + // we need closest here due to mouseover bubbling, + // but always pointing at the same event target + .closest( this.options.items ); + + // No element to show a tooltip for or the tooltip is already open + if ( !target.length || target.data( "ui-tooltip-id" ) ) { + return; + } + + if ( target.attr( "title" ) ) { + target.data( "ui-tooltip-title", target.attr( "title" ) ); + } + + target.data( "ui-tooltip-open", true ); + + // kill parent tooltips, custom or native, for hover + if ( event && event.type === "mouseover" ) { + target.parents().each(function() { + var parent = $( this ), + blurEvent; + if ( parent.data( "ui-tooltip-open" ) ) { + blurEvent = $.Event( "blur" ); + blurEvent.target = blurEvent.currentTarget = this; + that.close( blurEvent, true ); + } + if ( parent.attr( "title" ) ) { + parent.uniqueId(); + that.parents[ this.id ] = { + element: this, + title: parent.attr( "title" ) + }; + parent.attr( "title", "" ); + } + }); + } + + this._registerCloseHandlers( event, target ); + this._updateContent( target, event ); + }, + + _updateContent: function( target, event ) { + var content, + contentOption = this.options.content, + that = this, + eventType = event ? event.type : null; + + if ( typeof contentOption === "string" ) { + return this._open( event, target, contentOption ); + } + + content = contentOption.call( target[0], function( response ) { + + // IE may instantly serve a cached response for ajax requests + // delay this call to _open so the other call to _open runs first + that._delay(function() { + + // Ignore async response if tooltip was closed already + if ( !target.data( "ui-tooltip-open" ) ) { + return; + } + + // jQuery creates a special event for focusin when it doesn't + // exist natively. To improve performance, the native event + // object is reused and the type is changed. Therefore, we can't + // rely on the type being correct after the event finished + // bubbling, so we set it back to the previous value. (#8740) + if ( event ) { + event.type = eventType; + } + this._open( event, target, response ); + }); + }); + if ( content ) { + this._open( event, target, content ); + } + }, + + _open: function( event, target, content ) { + var tooltipData, tooltip, delayedShow, a11yContent, + positionOption = $.extend( {}, this.options.position ); + + if ( !content ) { + return; + } + + // Content can be updated multiple times. If the tooltip already + // exists, then just update the content and bail. + tooltipData = this._find( target ); + if ( tooltipData ) { + tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content ); + return; + } + + // if we have a title, clear it to prevent the native tooltip + // we have to check first to avoid defining a title if none exists + // (we don't want to cause an element to start matching [title]) + // + // We use removeAttr only for key events, to allow IE to export the correct + // accessible attributes. For mouse events, set to empty string to avoid + // native tooltip showing up (happens only when removing inside mouseover). + if ( target.is( "[title]" ) ) { + if ( event && event.type === "mouseover" ) { + target.attr( "title", "" ); + } else { + target.removeAttr( "title" ); + } + } + + tooltipData = this._tooltip( target ); + tooltip = tooltipData.tooltip; + this._addDescribedBy( target, tooltip.attr( "id" ) ); + tooltip.find( ".ui-tooltip-content" ).html( content ); + + // Support: Voiceover on OS X, JAWS on IE <= 9 + // JAWS announces deletions even when aria-relevant="additions" + // Voiceover will sometimes re-read the entire log region's contents from the beginning + this.liveRegion.children().hide(); + if ( content.clone ) { + a11yContent = content.clone(); + a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" ); + } else { + a11yContent = content; + } + $( "<div>" ).html( a11yContent ).appendTo( this.liveRegion ); + + function position( event ) { + positionOption.of = event; + if ( tooltip.is( ":hidden" ) ) { + return; + } + tooltip.position( positionOption ); + } + if ( this.options.track && event && /^mouse/.test( event.type ) ) { + this._on( this.document, { + mousemove: position + }); + // trigger once to override element-relative positioning + position( event ); + } else { + tooltip.position( $.extend({ + of: target + }, this.options.position ) ); + } + + tooltip.hide(); + + this._show( tooltip, this.options.show ); + // Handle tracking tooltips that are shown with a delay (#8644). As soon + // as the tooltip is visible, position the tooltip using the most recent + // event. + if ( this.options.show && this.options.show.delay ) { + delayedShow = this.delayedShow = setInterval(function() { + if ( tooltip.is( ":visible" ) ) { + position( positionOption.of ); + clearInterval( delayedShow ); + } + }, $.fx.interval ); + } + + this._trigger( "open", event, { tooltip: tooltip } ); + }, + + _registerCloseHandlers: function( event, target ) { + var events = { + keyup: function( event ) { + if ( event.keyCode === $.ui.keyCode.ESCAPE ) { + var fakeEvent = $.Event(event); + fakeEvent.currentTarget = target[0]; + this.close( fakeEvent, true ); + } + } + }; + + // Only bind remove handler for delegated targets. Non-delegated + // tooltips will handle this in destroy. + if ( target[ 0 ] !== this.element[ 0 ] ) { + events.remove = function() { + this._removeTooltip( this._find( target ).tooltip ); + }; + } + + if ( !event || event.type === "mouseover" ) { + events.mouseleave = "close"; + } + if ( !event || event.type === "focusin" ) { + events.focusout = "close"; + } + this._on( true, target, events ); + }, + + close: function( event ) { + var tooltip, + that = this, + target = $( event ? event.currentTarget : this.element ), + tooltipData = this._find( target ); + + // The tooltip may already be closed + if ( !tooltipData ) { + + // We set ui-tooltip-open immediately upon open (in open()), but only set the + // additional data once there's actually content to show (in _open()). So even if the + // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in + // the period between open() and _open(). + target.removeData( "ui-tooltip-open" ); + return; + } + + tooltip = tooltipData.tooltip; + + // disabling closes the tooltip, so we need to track when we're closing + // to avoid an infinite loop in case the tooltip becomes disabled on close + if ( tooltipData.closing ) { + return; + } + + // Clear the interval for delayed tracking tooltips + clearInterval( this.delayedShow ); + + // only set title if we had one before (see comment in _open()) + // If the title attribute has changed since open(), don't restore + if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) { + target.attr( "title", target.data( "ui-tooltip-title" ) ); + } + + this._removeDescribedBy( target ); + + tooltipData.hiding = true; + tooltip.stop( true ); + this._hide( tooltip, this.options.hide, function() { + that._removeTooltip( $( this ) ); + }); + + target.removeData( "ui-tooltip-open" ); + this._off( target, "mouseleave focusout keyup" ); + + // Remove 'remove' binding only on delegated targets + if ( target[ 0 ] !== this.element[ 0 ] ) { + this._off( target, "remove" ); + } + this._off( this.document, "mousemove" ); + + if ( event && event.type === "mouseleave" ) { + $.each( this.parents, function( id, parent ) { + $( parent.element ).attr( "title", parent.title ); + delete that.parents[ id ]; + }); + } + + tooltipData.closing = true; + this._trigger( "close", event, { tooltip: tooltip } ); + if ( !tooltipData.hiding ) { + tooltipData.closing = false; + } + }, + + _tooltip: function( element ) { + var tooltip = $( "<div>" ) + .attr( "role", "tooltip" ) + .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " + + ( this.options.tooltipClass || "" ) ), + id = tooltip.uniqueId().attr( "id" ); + + $( "<div>" ) + .addClass( "ui-tooltip-content" ) + .appendTo( tooltip ); + + tooltip.appendTo( this.document[0].body ); + + return this.tooltips[ id ] = { + element: element, + tooltip: tooltip + }; + }, + + _find: function( target ) { + var id = target.data( "ui-tooltip-id" ); + return id ? this.tooltips[ id ] : null; + }, + + _removeTooltip: function( tooltip ) { + tooltip.remove(); + delete this.tooltips[ tooltip.attr( "id" ) ]; + }, + + _destroy: function() { + var that = this; + + // close open tooltips + $.each( this.tooltips, function( id, tooltipData ) { + // Delegate to close method to handle common cleanup + var event = $.Event( "blur" ), + element = tooltipData.element; + event.target = event.currentTarget = element[ 0 ]; + that.close( event, true ); + + // Remove immediately; destroying an open tooltip doesn't use the + // hide animation + $( "#" + id ).remove(); + + // Restore the title + if ( element.data( "ui-tooltip-title" ) ) { + // If the title attribute has changed since open(), don't restore + if ( !element.attr( "title" ) ) { + element.attr( "title", element.data( "ui-tooltip-title" ) ); + } + element.removeData( "ui-tooltip-title" ); + } + }); + this.liveRegion.remove(); + } +}); + + + +})); \ No newline at end of file -- GitLab