add fancytree js, recode overview in js-area using fancytree

first steps to new class clFileList to build different directory tree views
Dieser Commit ist enthalten in:
o.pinke 2021-06-28 15:13:56 +02:00
Ursprung 6a2da6de31
Commit 7724016e9c
52 geänderte Dateien mit 33827 neuen und 826 gelöschten Zeilen

Datei anzeigen

@ -0,0 +1,15 @@
<?php
/**
*
*/
defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
class cGuiPage {
public function __construct($sPageName, $sPluginName = '', $sSubMenu = '') {
}
}

Datei anzeigen

@ -234,9 +234,9 @@ function fileEdit($filename, $sCode, $path) {
*/
function getFileContent($filename, $path) {
$sCode = cFileHandler::read($path . $filename);
if (!empty($sCode)) {
$sCode = mb_convert_encoding($sCode, 'UTF-8', 'OLD-ENCODING');
}
if (!empty($sCode)) {
$sCode = mb_convert_encoding($sCode, 'UTF-8', 'OLD-ENCODING');
}
return $sCode;
}
@ -313,7 +313,7 @@ function renameFile($sOldFile, $sNewFile, $path) {
* @return (void|bool) Either validation result or nothing (depends on second parameter)
*/
function fileValidateFilename($filename, $notifyAndExitOnFailure = true) {
if (preg_match('/[^a-z0-9._-]/i', $filename)) {
// validation failure...
if ($notifyAndExitOnFailure == true) {

Datei anzeigen

@ -419,13 +419,7 @@ function getLanguageNamesByClient($client) {
}
function set_magic_quotes_gpc(&$code) {
global $cfg;
if (!$cfg['simulate_magic_quotes']) {
if (get_magic_quotes_gpc() == 0) {
$code = addslashes($code);
}
}
}
/**

Datei anzeigen

@ -43,7 +43,7 @@ if (!isset($HTTP_POST_VARS) && isset($_POST)) {
}
}
if (!isset($_REQUEST) || (isset($cfg['simulate_magic_quotes']) && $cfg['simulate_magic_quotes'])) {
if (!isset($_REQUEST)) {
/* Register post,get and cookie variables into $_REQUEST */
$_REQUEST = array_merge($_GET, $_POST, $_COOKIE);
}

Datei-Diff unterdrückt, da er zu groß ist Diff laden

Datei anzeigen

@ -1,4 +1,5 @@
<?php
/**
* Project:
* Contenido Content Management System
@ -28,9 +29,8 @@
* }}
*
*/
if(!defined('CON_FRAMEWORK')) {
die('Illegal call');
if (!defined('CON_FRAMEWORK')) {
die('Illegal call');
}
cInclude("external", "edit_area/class.edit_area.php");
@ -45,32 +45,29 @@ $page = new cPage;
$tpl->reset();
if (!$perm->have_perm_area_action($area, $action))
{
if (!$perm->have_perm_area_action($area, $action)) {
$notification->displayNotification("error", i18n("Permission denied"));
} else if (!(int) $client > 0) {
#if there is no client selected, display empty page
$page->render();
#if there is no client selected, display empty page
$page->render();
} else {
$path = $cfgClient[$client]["tpl"]["path"];
$sTempFilename = stripslashes($_REQUEST['tmp_file']);
$sTempFilename = stripslashes($_REQUEST['tmp_file']);
$sOrigFileName = $sTempFilename;
if (getFileType($_REQUEST['file']) != $sFileType AND strlen(stripslashes(trim($_REQUEST['file']))) > 0)
{
$sFilename .= stripslashes($_REQUEST['file']).".$sFileType";
} else
{
$sFilename .= stripslashes($_REQUEST['file']);
if (getFileType($_REQUEST['file']) != $sFileType AND strlen(stripslashes(trim($_REQUEST['file']))) > 0) {
$sFilename .= stripslashes($_REQUEST['file']) . ".$sFileType";
} else {
$sFilename .= stripslashes($_REQUEST['file']);
}
if (stripslashes($_REQUEST['file'])) {
$sReloadScript = "<script type=\"text/javascript\">
var left_bottom = parent.parent.frames['left'].frames['left_bottom'];
if (left_bottom) {
var href = left_bottom.location.href;
href = href.replace(/&file[^&]*/, '');
left_bottom.location.href = href+'&file='+'".$sFilename."';
left_bottom.location.href = href+'&file='+'" . $sFilename . "';
}
</script>";
} else {
@ -78,121 +75,106 @@ if (!$perm->have_perm_area_action($area, $action))
}
// Content Type is template
$sTypeContent = "templates";
$aFileInfo = getFileInformation ($client, $sTempFilename, $sTypeContent, $db);
# create new file
if ( $_REQUEST['action'] == $sActionCreate AND $_REQUEST['status'] == 'send')
{
$sTempFilename = $sFilename;
createFile($sFilename, $path);
$bEdit = fileEdit($sFilename, $_REQUEST['code'], $path);
$sTypeContent = "templates";
$aFileInfo = getFileInformation($client, $sTempFilename, $sTypeContent, $db);
# create new file
if ($_REQUEST['action'] == $sActionCreate AND $_REQUEST['status'] == 'send') {
$sTempFilename = $sFilename;
createFile($sFilename, $path);
$bEdit = fileEdit($sFilename, $_REQUEST['code'], $path);
$sReloadScript .= "<script type=\"text/javascript\">
var right_top = top.content.right.right_top;
if (right_top) {
var href = '".$sess->url("main.php?area=$area&frame=3&file=$sTempFilename")."';
var href = '" . $sess->url("main.php?area=$area&frame=3&file=$sTempFilename") . "';
right_top.location.href = href;
}
</script>";
updateFileInformation($client, $sFilename, 'templates', $auth->auth['uid'], $_REQUEST['description'], $db);
}
# edit selected file
if ( $_REQUEST['action'] == $sActionEdit AND $_REQUEST['status'] == 'send')
{
if ($sFilename != $sTempFilename)
{
$sTempFilename = renameFile($sTempFilename, $sFilename, $path);
# edit selected file
if ($_REQUEST['action'] == $sActionEdit AND $_REQUEST['status'] == 'send') {
if ($sFilename != $sTempFilename) {
$sTempFilename = renameFile($sTempFilename, $sFilename, $path);
$sReloadScript .= "<script type=\"text/javascript\">
var right_top = top.content.right.right_top;
if (right_top) {
var href = '".$sess->url("main.php?area=$area&frame=3&file=$sTempFilename")."';
var href = '" . $sess->url("main.php?area=$area&frame=3&file=$sTempFilename") . "';
right_top.location.href = href;
}
</script>";
} else
{
$sTempFilename = $sFilename;
}
updateFileInformation($client, $sOrigFileName, 'templates', $auth->auth['uid'], $_REQUEST['description'], $db, $sFilename);
/**
* START TRACK VERSION
**/
$sTypeContent = "templates";
if((count($aFileInfo) == 0) || ((int)$aFileInfo["idsfi"] == 0)) {
$aFileInfo = getFileInformation ($client, $sTempFilename, $sTypeContent, $db);
} else {
$sTempFilename = $sFilename;
}
updateFileInformation($client, $sOrigFileName, 'templates', $auth->auth['uid'], $_REQUEST['description'], $db, $sFilename);
/**
* START TRACK VERSION
* */
$sTypeContent = "templates";
if ((count($aFileInfo) == 0) || ((int) $aFileInfo["idsfi"] == 0)) {
$aFileInfo = getFileInformation($client, $sTempFilename, $sTypeContent, $db);
$aFileInfo['description'] = '';
}
if((count($aFileInfo) > 0) && ($aFileInfo["idsfi"] !="")) {
$oVersion = new VersionFile($aFileInfo["idsfi"], $aFileInfo, $sFilename, $sTypeContent, $cfg, $cfgClient, $db, $client, $area, $frame, $sOrigFileName);
// Create new Layout Version in cms/version/css/ folder
$oVersion->createNewVersion();
}
/**
* END TRACK VERSION
**/
$bEdit = fileEdit($sFilename, $_REQUEST['code'], $path);
}
# generate edit form
if (isset($_REQUEST['action']))
{
$sAction = ($bEdit) ? $sActionEdit : $_REQUEST['action'];
if ($_REQUEST['action'] == $sActionEdit)
{
$sCode = getFileContent($sFilename, $path);
} else
{
$sCode = stripslashes($_REQUEST['code']); # stripslashes is required here in case of creating a new file
}
/* Try to validate html */
if (getEffectiveSetting("layout", "htmlvalidator", "true") == "true" && $sCode !== "")
{
$v = new cHTMLValidator;
$v->validate($sCode);
$msg = "";
if ((count($aFileInfo) > 0) && ($aFileInfo["idsfi"] != "")) {
$oVersion = new VersionFile($aFileInfo["idsfi"], $aFileInfo, $sFilename, $sTypeContent, $cfg, $cfgClient, $db, $client, $area, $frame, $sOrigFileName);
// Create new Layout Version in cms/version/css/ folder
$oVersion->createNewVersion();
}
/**
* END TRACK VERSION
* */
$bEdit = fileEdit($sFilename, $_REQUEST['code'], $path);
}
foreach ($v->missingNodes as $value)
{
$idqualifier = "";
# generate edit form
if (isset($_REQUEST['action'])) {
$sAction = ($bEdit) ? $sActionEdit : $_REQUEST['action'];
if ($_REQUEST['action'] == $sActionEdit) {
$sCode = getFileContent($sFilename, $path);
} else {
$sCode = $_REQUEST['code']; # stripslashes is required here in case of creating a new file
}
/* Try to validate html */
if (getEffectiveSetting("layout", "htmlvalidator", "true") == "true" && $sCode !== "") {
$v = new cHTMLValidator;
$v->validate($sCode);
$msg = "";
foreach ($v->missingNodes as $value) {
$idqualifier = "";
$attr = array();
if ($value["name"] != "") {
$attr["name"] = "name '" . $value["name"] . "'";
}
if ($value["id"] != "") {
$attr["id"] = "id '" . $value["id"] . "'";
}
$idqualifier = implode(", ", $attr);
if ($idqualifier != "") {
$idqualifier = "($idqualifier)";
}
$msg .= sprintf(i18n("Tag '%s' %s has no end tag (start tag is on line %s char %s)"), $value["tag"], $idqualifier, $value["line"], $value["char"]) . "<br />";
}
if ($msg != "") {
$notis = $notification->returnNotification("warning", $msg) . "<br />";
}
}
$attr = array();
if ($value["name"] != "")
{
$attr["name"] = "name '".$value["name"]."'";
}
if ($value["id"] != "")
{
$attr["id"] = "id '".$value["id"]."'";
}
$idqualifier = implode(", ",$attr);
if ($idqualifier != "")
{
$idqualifier = "($idqualifier)";
}
$msg .= sprintf(i18n("Tag '%s' %s has no end tag (start tag is on line %s char %s)"), $value["tag"], $idqualifier, $value["line"],$value["char"]) . "<br />";
}
if ($msg != "")
{
$notis = $notification->returnNotification("warning", $msg) . "<br />";
}
}
$aFileInfo = getFileInformation($client, $sTempFilename, $sTypeContent, $db);
$form = new UI_Table_Form("file_editor");
$form->addHeader(i18n("Edit file"));
$form->setWidth("100%");
@ -201,28 +183,26 @@ if (!$perm->have_perm_area_action($area, $action))
$form->setVar("frame", $frame);
$form->setVar("status", 'send');
$form->setVar("tmp_file", $sTempFilename);
$tb_name = new cHTMLTextbox("file", $sFilename, 60);
$ta_code = new cHTMLTextarea("code", clHtmlSpecialChars($sCode), 100, 35, "code");
$descr = new cHTMLTextarea("description", clHtmlSpecialChars($aFileInfo["description"]), 100, 5);
$descr = new cHTMLTextarea("description", clHtmlSpecialChars($aFileInfo["description"]), 100, 5);
$ta_code->setStyle("font-family: monospace;width: 100%;");
$descr->setStyle("font-family: monospace;width: 100%;");
$ta_code->updateAttributes(array("wrap" => getEffectiveSetting('html_editor', 'wrap', 'off')));
$form->add(i18n("Name"),$tb_name);
$form->add(i18n("Name"), $tb_name);
$form->add(i18n("Description"), $descr->render());
$form->add(i18n("Code"),$ta_code);
$form->add(i18n("Code"), $ta_code);
$page->setContent($notis . $form->render());
$oEditArea = new EditArea('code', 'html', substr(strtolower($belang), 0, 2), true, $cfg);
$page->addScript('editarea', $oEditArea->renderScript());
$page->addScript('reload', $sReloadScript);
$page->render();
}
$page->addScript('reload', $sReloadScript);
$page->render();
}
}
?>

Datei anzeigen

@ -140,7 +140,7 @@ if (!$perm->have_perm_area_action($area, $action)) {
if ($_REQUEST['action'] == $sActionEdit) {
$sCode = getFileContent($sFilename, $path);
} else {
$sCode = stripslashes($_REQUEST['code']); # stripslashes is required here in case of creating a new file
$sCode = $_REQUEST['code']; # stripslashes is required here in case of creating a new file
}
$form = new UI_Table_Form("file_editor");

Datei anzeigen

@ -1,161 +1,120 @@
<?php
/**
* Project:
* Contenido Content Management System
*
* Description:
* Display files from specified directory
*
* Requirements:
* @con_php_req 5.0
*
*
* @package Contenido Backend includes
* @version 1.0.2
* @author Olaf Niemann, Willi Mann
* @copyright four for business AG <www.4fb.de>
* @license http://www.contenido.org/license/LIZENZ.txt
* @link http://www.4fb.de
* @link http://www.contenido.org
* @since file available since contenido release <= 4.6
*
* {@internal
* created 2003-04-20
* modified 2008-06-27, Frederic Schneider, add security fix
*
* $Id$:
* }}
*
*/
if(!defined('CON_FRAMEWORK')) {
die('Illegal call');
if (!defined('CON_FRAMEWORK')) {
die('Illegal call');
}
cInclude("includes", "functions.file.php");
class clFileList {
$tpl->reset();
protected $_sPath;
protected $_mFileExt;
protected $_iScanDepth;
protected $_aDirItems;
protected $_bWritable;
protected $_oTpl;
if (!(int) $client > 0) {
#if there is no client selected, display empty page
$oPage = new cPage;
$oPage->render();
return;
}
$path = $cfgClient[$client]["js"]["path"];
$sFileType = "js";
$sSession = $sess->id;
$sArea = 'js';
$sActionDelete = 'js_delete';
$sActionEdit = 'js_edit';
$sScriptTemplate = '
<script type="text/javascript" src="scripts/rowMark.js"></script>
<script type="text/javascript" src="scripts/general.js"></script>
<script type="text/javascript" src="scripts/messageBox.js.php?contenido='.$sSession.'"></script>
<script type="text/javascript">
/* Create messageBox instance */
box = new messageBox("", "", "", 0, 0);
function deleteFile(file)
{
url = "main.php?area='.$sArea.'";
url += "&action='.$sActionDelete.'";
url += "&frame=2";
url += "&delfile=" + file;
url += "&contenido='.$sSession.'";
window.location.href = url;
parent.parent.frames["right"].frames["right_bottom"].location.href = "main.php?area='.$sArea.'&frame=4&contenido='.$sSession.'";
}
</script>';
$tpl->set('s', 'JAVASCRIPT', $sScriptTemplate);
# delete file
if ($action == $sActionDelete)
{
if (!strrchr($_REQUEST['delfile'], "/"))
{
if (file_exists($path.$_REQUEST['delfile']))
{
unlink($path.$_REQUEST['delfile']);
removeFileInformation($client, $_REQUEST['delfile'], 'js', $db);
public function __construct($sPath, $mFileExt = null) {
if(!empty($mFileExt) && is_string($mFileExt)) {
$mFileExt = [strtolower($mFileExt)];
}
$this->_sPath = $sPath;
$this->_mFileExt = $mFileExt;
$this->_iScanDepth = 3;
$this->_oTpl = new Template();
}
}
if ($handle = opendir($path))
{
$aFiles = array();
while ($file = readdir($handle))
{
if(substr($file, (strlen($file) - (strlen($sFileType) + 1)), (strlen($sFileType) + 1)) == ".$sFileType" AND is_readable($path.$file))
{
$aFiles[] = $file;
}elseif (substr($file, (strlen($file) - (strlen($sFileType) + 1)), (strlen($sFileType) + 1)) == ".$sFileType" AND !is_readable($path.$file))
{
$notification->displayNotification("error", $file." ".i18n("is not readable!"));
public function scanDir() {
if (empty($this->_sPath) || !is_readable($this->_sPath)) {
return false;
}
}
closedir($handle);
// display files
if (is_array($aFiles))
{
sort($aFiles);
foreach ($aFiles as $filename)
{
$bgcolor = ( is_int($tpl->dyn_cnt / 2) ) ? $cfg["color"]["table_light"] : $cfg["color"]["table_dark"];
$tpl->set('d', 'BGCOLOR', $bgcolor);
$tmp_mstr = '<a class=\"action\" href="javascript:conMultiLink(\'%s\', \'%s\', \'%s\', \'%s\')" title="%s" alt="%s">%s</a>';
$html_filename = sprintf($tmp_mstr, 'right_top',
$sess->url("main.php?area=$area&frame=3&file=$filename"),
'right_bottom',
$sess->url("main.php?area=$area&frame=4&action=$sActionEdit&file=$filename&tmp_file=$filename"),
$filename, $filename, clHtmlSpecialChars($filename));
$this->_bWritable = (!is_writable($this->_sPath)) ? true : false;
$tpl->set('d', 'FILENAME', $html_filename);
$delTitle = i18n("Delete File");
$delDescr = sprintf(i18n("Do you really want to delete the following file:<br><br>%s<br>"),$filename);
if ($perm->have_perm_area_action('style', $sActionDelete))
{
$tpl->set('d', 'DELETE', '<a title="'.$delTitle.'" href="javascript://" onclick="box.confirm(\''.$delTitle.'\', \''.$delDescr.'\', \'deleteFile(\\\''.$filename.'\\\')\')"><img src="'.$cfg['path']['images'].'delete.gif" border="0" title="'.$delTitle.'"></a>');
}else
{
$tpl->set('d', 'DELETE', '');
}
if (stripslashes($_REQUEST['file']) == $filename) {
$tpl->set('d', 'ID', 'id="marked"');
$this->_aDirItems = $this->_assetsMap($this->_sPath, $this->_iScanDepth);
asort($this->_aDirItems, SORT_STRING | SORT_FLAG_CASE | SORT_NATURAL);
}
public function renderList($sTpl = null, $bReturn = false) {
global $sess, $area;
$sList = '<ul id="treeData" style="display: none;">'."\n";
foreach($this->_aDirItems as $key => $item) {
if(is_array($item)) {
$sList .= $this->_getSubItems($key, $item,$this->_sPath);
} else {
$tpl->set('d', 'ID', '');
$sAddClass = (is_writable($this->_sPath.$item))?'':' notwritable';
$sList .= '<li class="file'.$sAddClass.'" data-filepath="'.$item.'">'.$item.'</li>'."\n";
}
$tpl->next();
}
}
$sList .= '</ul>'."\n";
$this->_oTpl->set('s', 'item_list', $sList);
$this->_oTpl->set('s', 'multilink1', $sess->url("main.php?area=$area&frame=3&file=\${file}"));
$this->_oTpl->set('s', 'multilink2', $sess->url("main.php?area=$area&frame=4&action=js_edit&file=\${file}&tmp_file=\${file}"));
$this->_oTpl->generate(cRegistry::getConfigValue('path', 'contenido') . cRegistry::getConfigValue('path', 'templates') . "html5/file_list.html", $bReturn);
}
}else
{
if ((int) $client > 0) {
$notification->displayNotification("error", i18n("Directory is not existing or readable!")."<br>$path");
}
protected function _getSubItems($sName, $aItems, $sPathToItem) {
$sPathToItem = $sPathToItem.$sName.DIRECTORY_SEPARATOR;
$sItemListEntry = '<li class="folder directory">'.$sName."\n\t";
if(is_array($aItems) && count($aItems) >0) {
$sItemListEntry .= '<ul data-filepath="'.$sPathToItem.'">'."\n\t";
foreach($aItems as $key=>$item) {
if(is_array($item)) {
$sItemListEntry .= $this->_getSubItems($key, $item, $sPathToItem);
} else {
$sAddClass = (is_writable($sPathToItem.$item))?'':' notwritable';
$sItemListEntry .= '<li class="file'.$sAddClass.'" data-filepath="'. str_replace($this->_sPath, '', $sPathToItem.$item).'">'.$item.'</li>'."\n";
}
}
$sItemListEntry .= '</ul>'."\n";
}
$sItemListEntry .= '</li>'."\n";
return $sItemListEntry;
}
protected function _assetsMap($source_dir, $directory_depth = 0, $hidden = false) {
if ($fp = @opendir($source_dir)) {
$filedata = array();
$new_depth = $directory_depth - 1;
$source_dir = rtrim($source_dir, '/') . '/';
while (FALSE !== ($file = readdir($fp))) {
// Remove '.', '..', and hidden files [optional]
if (!trim($file, '.') OR ($hidden == false && $file[0] == '.')) {
continue;
}
if (($directory_depth < 1 OR $new_depth > 0) && is_dir($source_dir . $file)) {
$aTmp = $this->_assetsMap($source_dir . $file . '/', $new_depth, $hidden);
if(!empty($aTmp)) {
asort($aTmp, SORT_STRING | SORT_FLAG_CASE | SORT_NATURAL);
$filedata[$file] = $aTmp;
}
unset($aTmp);
} else {
$sFileExt = strtolower(pathinfo($file, PATHINFO_EXTENSION));
if(!empty($this->_mFileExt) && in_array($sFileExt, $this->_mFileExt)) {
$filedata[] = $file;
}
}
}
closedir($fp);
return $filedata;
}
echo 'can not open dir';
return FALSE;
}
}
$tpl->generate($cfg['path']['templates'] . $cfg['templates']['files_overview']);
$oDirList = new clFileList($cfgClient[$client]["js"]["path"], 'js');
$oDirList->scanDir();
?>
$oDirList->renderList();

Datei anzeigen

@ -158,7 +158,7 @@ if (!$perm->have_perm_area_action($area, $action)) {
if ($_REQUEST['action'] == $sActionEdit) {
$sCode = getFileContent($sFilename, $path);
} else {
$sCode = stripslashes($_REQUEST['code']); # stripslashes is required here in case of creating a new file
$sCode = $_REQUEST['code']; # stripslashes is required here in case of creating a new file
}
$aFileInfo = getFileInformation($client, $sTempFilename, "css", $db);

Datei anzeigen

@ -0,0 +1,21 @@
Copyright 2008-2021 Martin Wendt,
https://wwWendt.de/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Datei-Diff unterdrückt, da er zu groß ist Diff laden

Dateidiff unterdrückt, weil mindestens eine Zeile zu lang ist

Dateidiff unterdrückt, weil mindestens eine Zeile zu lang ist

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 648 B

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 412 B

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 309 B

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 536 B

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 618 B

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 620 B

Datei anzeigen

@ -0,0 +1,256 @@
// jQuery Context Menu Plugin
//
// Version 1.01 customized version (see comment below)
//
// Cory S.N. LaViska
// A Beautiful Site (http://abeautifulsite.net/)
//
// More info: http://abeautifulsite.net/2008/09/jquery-context-menu-plugin/
//
// Terms of Use
//
// This plugin is dual-licensed under the GNU General Public License
// and the MIT License and is copyright A Beautiful Site, LLC.
//
// 2011-02-17 Martin Wendt:
// Changed stopPropagation() to preventDefault() in order to make it
// work with Dynatree drag'n'drop.
// See http://code.google.com/p/dynatree/issues/detail?id=174
// 2012-09-27 Martin Wendt:
// fixed position in a fancy layout
// 2013-05-09 Martin Wendt:
// Added polyfil for $.browser (fixes compatibility with jQuery 1.9)
//
if(jQuery)( function() {
/* Check browser version, since $.browser was removed in jQuery 1.9 */
function _checkBrowser(){
var matched, browser;
function uaMatch( ua ) {
ua = ua.toLowerCase();
var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
/(webkit)[ \/]([\w.]+)/.exec( ua ) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
/(msie) ([\w.]+)/.exec( ua ) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
[];
return {
browser: match[ 1 ] || "",
version: match[ 2 ] || "0"
};
}
matched = uaMatch( navigator.userAgent );
browser = {};
if ( matched.browser ) {
browser[ matched.browser ] = true;
browser.version = matched.version;
}
if ( browser.chrome ) {
browser.webkit = true;
} else if ( browser.webkit ) {
browser.safari = true;
}
return browser;
}
var BROWSER = jQuery.browser || _checkBrowser();
$.extend($.fn, {
contextMenu: function(o, callback) {
// Defaults
if( o.menu == undefined ) return false;
if( o.inSpeed == undefined ) o.inSpeed = 150;
if( o.outSpeed == undefined ) o.outSpeed = 75;
// 0 needs to be -1 for expected results (no fade)
if( o.inSpeed == 0 ) o.inSpeed = -1;
if( o.outSpeed == 0 ) o.outSpeed = -1;
// Loop each context menu
$(this).each( function() {
var el = $(this);
var offset = $(el).offset();
// Add contextMenu class
$('#' + o.menu).addClass('contextMenu');
// Simulate a true right click
$(this).mousedown( function(e) {
var evt = e;
// evt.stopPropagation();
evt.preventDefault();
$(this).mouseup( function(e) {
// e.stopPropagation();
e.preventDefault();
var srcElement = $(this);
$(this).unbind('mouseup');
if( evt.button == 2 ) {
// Hide context menus that may be showing
$(".contextMenu").hide();
// Get this context menu
var menu = $('#' + o.menu);
if( $(el).hasClass('disabled') ) return false;
// Detect mouse position
var d = {}, x, y;
if( self.innerHeight ) {
d.pageYOffset = self.pageYOffset;
d.pageXOffset = self.pageXOffset;
d.innerHeight = self.innerHeight;
d.innerWidth = self.innerWidth;
} else if( document.documentElement &&
document.documentElement.clientHeight ) {
d.pageYOffset = document.documentElement.scrollTop;
d.pageXOffset = document.documentElement.scrollLeft;
d.innerHeight = document.documentElement.clientHeight;
d.innerWidth = document.documentElement.clientWidth;
} else if( document.body ) {
d.pageYOffset = document.body.scrollTop;
d.pageXOffset = document.body.scrollLeft;
d.innerHeight = document.body.clientHeight;
d.innerWidth = document.body.clientWidth;
}
(e.pageX) ? x = e.pageX : x = e.clientX + d.scrollLeft;
(e.pageY) ? y = e.pageY : y = e.clientY + d.scrollTop;
// Show the menu
$(document).unbind('click');
// MW: fixed position in a fancy layout
// $(menu).css({ top: y, left: x }).fadeIn(o.inSpeed);
$(menu).fadeIn(o.inSpeed).offset({ top: y, left: x }); // must be visible, before calling offset()
// Hover events
$(menu).find('A').mouseover( function() {
$(menu).find('LI.hover').removeClass('hover');
$(this).parent().addClass('hover');
}).mouseout( function() {
$(menu).find('LI.hover').removeClass('hover');
});
// Keyboard
$(document).keypress( function(e) {
switch( e.keyCode ) {
case 38: // up
if( $(menu).find('LI.hover').size() == 0 ) {
$(menu).find('LI:last').addClass('hover');
} else {
$(menu).find('LI.hover').removeClass('hover').prevAll('LI:not(.disabled)').eq(0).addClass('hover');
if( $(menu).find('LI.hover').size() == 0 ) $(menu).find('LI:last').addClass('hover');
}
break;
case 40: // down
if( $(menu).find('LI.hover').size() == 0 ) {
$(menu).find('LI:first').addClass('hover');
} else {
$(menu).find('LI.hover').removeClass('hover').nextAll('LI:not(.disabled)').eq(0).addClass('hover');
if( $(menu).find('LI.hover').size() == 0 ) $(menu).find('LI:first').addClass('hover');
}
break;
case 13: // enter
$(menu).find('LI.hover A').trigger('click');
break;
case 27: // esc
$(document).trigger('click');
break
}
});
// When items are selected
$('#' + o.menu).find('A').unbind('click');
$('#' + o.menu).find('LI:not(.disabled) A').click( function() {
$(document).unbind('click').unbind('keypress');
$(".contextMenu").hide();
// Callback
if( callback ) callback( $(this).attr('href').substr(1), $(srcElement), {x: x - offset.left, y: y - offset.top, docX: x, docY: y} );
return false;
});
// Hide bindings
setTimeout( function() { // Delay for Mozilla
$(document).click( function() {
$(document).unbind('click').unbind('keypress');
$(menu).fadeOut(o.outSpeed);
return false;
});
}, 0);
}
});
});
// Disable text selection
if( BROWSER.mozilla ) {
$('#' + o.menu).each( function() { $(this).css({ 'MozUserSelect' : 'none' }); });
} else if( BROWSER.msie ) {
$('#' + o.menu).each( function() { $(this).bind('selectstart.disableTextSelect', function() { return false; }); });
} else {
$('#' + o.menu).each(function() { $(this).bind('mousedown.disableTextSelect', function() { return false; }); });
}
// Disable browser context menu (requires both selectors to work in IE/Safari + FF/Chrome)
$(el).add($('UL.contextMenu')).bind('contextmenu', function() { return false; });
});
return $(this);
},
// Disable context menu items on the fly
disableContextMenuItems: function(o) {
if( o == undefined ) {
// Disable all
$(this).find('LI').addClass('disabled');
return( $(this) );
}
$(this).each( function() {
if( o != undefined ) {
var d = o.split(',');
for( var i = 0; i < d.length; i++ ) {
$(this).find('A[href="' + d[i] + '"]').parent().addClass('disabled');
}
}
});
return( $(this) );
},
// Enable context menu items on the fly
enableContextMenuItems: function(o) {
if( o == undefined ) {
// Enable all
$(this).find('LI.disabled').removeClass('disabled');
return( $(this) );
}
$(this).each( function() {
if( o != undefined ) {
var d = o.split(',');
for( var i = 0; i < d.length; i++ ) {
$(this).find('A[href="' + d[i] + '"]').parent().removeClass('disabled');
}
}
});
return( $(this) );
},
// Disable context menu(s)
disableContextMenu: function() {
$(this).each( function() {
$(this).addClass('disabled');
});
return( $(this) );
},
// Enable context menu(s)
enableContextMenu: function() {
$(this).each( function() {
$(this).removeClass('disabled');
});
return( $(this) );
},
// Destroy context menu(s)
destroyContextMenu: function() {
// Destroy specified context menus
$(this).each( function() {
// Disable action
$(this).unbind('mousedown').unbind('mouseup');
});
return( $(this) );
}
});
})(jQuery);

Datei anzeigen

@ -0,0 +1,62 @@
/* Generic context menu styles */
.contextMenu {
position: absolute;
width: 120px;
z-index: 99999;
border: solid 1px #CCC;
background: #EEE;
padding: 0px;
margin: 0px;
display: none;
}
.contextMenu LI {
list-style: none;
padding: 0px;
margin: 0px;
}
.contextMenu A {
color: #333;
text-decoration: none;
display: block;
line-height: 20px;
height: 20px;
background-position: 6px center;
background-repeat: no-repeat;
outline: none;
padding: 1px 5px;
padding-left: 28px;
}
.contextMenu LI.hover A {
color: #FFF;
background-color: #3399FF;
}
.contextMenu LI.disabled A {
color: #AAA;
cursor: default;
}
.contextMenu LI.hover.disabled A {
background-color: transparent;
}
.contextMenu LI.separator {
border-top: solid 1px #CCC;
}
/*
Adding Icons
You can add icons to the context menu by adding
classes to the respective LI element(s)
*/
.contextMenu LI.edit A { background-image: url(images/page_white_edit.png); }
.contextMenu LI.cut A { background-image: url(images/cut.png); }
.contextMenu LI.copy A { background-image: url(images/page_white_copy.png); }
.contextMenu LI.paste A { background-image: url(images/page_white_paste.png); }
.contextMenu LI.delete A { background-image: url(images/page_white_delete.png); }
.contextMenu LI.quit A { background-image: url(images/door.png); }

Datei anzeigen

@ -0,0 +1,718 @@
/*!
* jquery.fancytree.ariagrid.js
*
* Support ARIA compliant markup and keyboard navigation for tree grids with
* embedded input controls.
* (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/)
*
* @requires ext-table
*
* Copyright (c) 2008-2021, Martin Wendt (https://wwWendt.de)
*
* Released under the MIT license
* https://github.com/mar10/fancytree/wiki/LicenseInfo
*
* @version 2.38.0
* @date 2021-02-09T20:03:49Z
*/
(function(factory) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define([
"jquery",
"./jquery.fancytree",
"./jquery.fancytree.table",
], factory);
} else if (typeof module === "object" && module.exports) {
// Node/CommonJS
require("./jquery.fancytree.table"); // core + table
module.exports = factory(require("jquery"));
} else {
// Browser globals
factory(jQuery);
}
})(function($) {
"use strict";
/*******************************************************************************
* Private functions and variables
*/
// Allow these navigation keys even when input controls are focused
var FT = $.ui.fancytree,
clsFancytreeActiveCell = "fancytree-active-cell",
clsFancytreeCellMode = "fancytree-cell-mode",
clsFancytreeCellNavMode = "fancytree-cell-nav-mode",
VALID_MODES = ["allow", "force", "start", "off"],
// Define which keys are handled by embedded <input> control, and should
// *not* be passed to tree navigation handler in cell-edit mode:
INPUT_KEYS = {
text: ["left", "right", "home", "end", "backspace"],
number: ["up", "down", "left", "right", "home", "end", "backspace"],
checkbox: [],
link: [],
radiobutton: ["up", "down"],
"select-one": ["up", "down"],
"select-multiple": ["up", "down"],
},
NAV_KEYS = ["up", "down", "left", "right", "home", "end"];
/* Set aria-activedescendant on container to active cell's ID (generate one if required).*/
function setActiveDescendant(tree, $target) {
var id = $target ? $target.uniqueId().attr("id") : "";
tree.$container.attr("aria-activedescendant", id);
}
/* 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(tree, $target, keyCode) {
var nextNode,
node,
navMap = { "ctrl+home": "first", "ctrl+end": "last" },
$td = $target.closest("td"),
$tr = $td.parent(),
treeOpts = tree.options,
colIdx = getColIdx($tr, $td),
$tdNext = null;
keyCode = navMap[keyCode] || keyCode;
switch (keyCode) {
case "left":
$tdNext = treeOpts.rtl ? $td.next() : $td.prev();
break;
case "right":
$tdNext = treeOpts.rtl ? $td.prev() : $td.next();
break;
case "up":
case "down":
case "ctrl+home":
case "ctrl+end":
node = $tr[0].ftnode;
nextNode = tree.findRelatedNode(node, keyCode);
if (nextNode) {
nextNode.makeVisible();
nextNode.setActive();
$tdNext = findTdAtColIdx($(nextNode.tr), colIdx);
}
break;
case "home":
$tdNext = treeOpts.rtl
? $tr.children("td").last()
: $tr.children("td").first();
break;
case "end":
$tdNext = treeOpts.rtl
? $tr.children("td").first()
: $tr.children("td").last();
break;
}
return $tdNext && $tdNext.length ? $tdNext : null;
}
/* Return a descriptive string of the current mode. */
function getGridNavMode(tree) {
if (tree.$activeTd) {
return tree.forceNavMode ? "cell-nav" : "cell-edit";
}
return "row";
}
/* .*/
function activateEmbeddedLink($td) {
// $td.find( "a" )[ 0 ].click(); // does not work (always)?
// $td.find( "a" ).click();
var event = document.createEvent("MouseEvent"),
a = $td.find("a")[0]; // document.getElementById('nameOfID');
event = new CustomEvent("click");
a.dispatchEvent(event);
}
/**
* [ext-ariagrid] Set active cell and activate cell-nav or cell-edit mode if needed.
* Pass $td=null to enter row-mode.
*
* See also FancytreeNode#setActive(flag, {cell: idx})
*
* @param {jQuery | Element | integer} [$td]
* @param {Event|null} [orgEvent=null]
* @alias Fancytree#activateCell
* @requires jquery.fancytree.ariagrid.js
* @since 2.23
*/
$.ui.fancytree._FancytreeClass.prototype.activateCell = function(
$td,
orgEvent
) {
var colIdx,
$input,
$tr,
res,
tree = this,
$prevTd = this.$activeTd || null,
newNode = $td ? FT.getNode($td) : null,
prevNode = $prevTd ? FT.getNode($prevTd) : null,
anyNode = newNode || prevNode,
$prevTr = $prevTd ? $prevTd.closest("tr") : null;
anyNode.debug(
"activateCell(" +
($prevTd ? $prevTd.text() : "null") +
") -> " +
($td ? $td.text() : "OFF")
);
// Make available as event
if ($td) {
FT.assert($td.length, "Invalid active cell");
colIdx = getColIdx($(newNode.tr), $td);
res = this._triggerNodeEvent("activateCell", newNode, orgEvent, {
activeTd: tree.$activeTd,
colIdx: colIdx,
mode: null, // editMode ? "cell-edit" : "cell-nav"
});
if (res === false) {
return false;
}
this.$container.addClass(clsFancytreeCellMode);
this.$container.toggleClass(
clsFancytreeCellNavMode,
!!this.forceNavMode
);
$tr = $td.closest("tr");
if ($prevTd) {
// cell-mode => cell-mode
if ($prevTd.is($td)) {
return;
}
$prevTd
.removeAttr("tabindex")
.removeClass(clsFancytreeActiveCell);
if (!$prevTr.is($tr)) {
// We are moving to a different row: only the inputs in the
// active row should be tabbable
$prevTr.find(">td :input,a").attr("tabindex", "-1");
}
}
$tr.find(">td :input:enabled,a").attr("tabindex", "0");
newNode.setActive();
$td.addClass(clsFancytreeActiveCell);
this.$activeTd = $td;
$input = $td.find(":input:enabled,a");
this.debug("Focus input", $input);
if ($input.length) {
$input.focus();
setActiveDescendant(this, $input);
} else {
$td.attr("tabindex", "-1").focus();
setActiveDescendant(this, $td);
}
} else {
res = this._triggerNodeEvent("activateCell", prevNode, orgEvent, {
activeTd: null,
colIdx: null,
mode: "row",
});
if (res === false) {
return false;
}
// $td == null: switch back to row-mode
this.$container.removeClass(
clsFancytreeCellMode + " " + clsFancytreeCellNavMode
);
// console.log("activateCell: set row-mode for " + this.activeNode, $prevTd);
if ($prevTd) {
// cell-mode => row-mode
$prevTd
.removeAttr("tabindex")
.removeClass(clsFancytreeActiveCell);
// In row-mode, only embedded inputs of the active row are tabbable
$prevTr
.find("td")
.blur() // we need to blur first, because otherwise the focus frame is not reliably removed(?)
.removeAttr("tabindex");
$prevTr.find(">td :input,a").attr("tabindex", "-1");
this.$activeTd = null;
// The cell lost focus, but the tree still needs to capture keys:
this.activeNode.setFocus();
setActiveDescendant(this, $tr);
} else {
// row-mode => row-mode (nothing to do)
}
}
};
/*******************************************************************************
* Extension code
*/
$.ui.fancytree.registerExtension({
name: "ariagrid",
version: "2.38.0",
// Default options for this extension.
options: {
// Internal behavior flags
activateCellOnDoubelclick: true,
cellFocus: "allow",
// TODO: use a global tree option `name` or `title` instead?:
label: "Tree Grid", // Added as `aria-label` attribute
},
treeInit: function(ctx) {
var tree = ctx.tree,
treeOpts = ctx.options,
opts = treeOpts.ariagrid;
// ariagrid requires the table extension to be loaded before itself
if (tree.ext.grid) {
this._requireExtension("grid", true, true);
} else {
this._requireExtension("table", true, true);
}
if (!treeOpts.aria) {
$.error("ext-ariagrid requires `aria: true`");
}
if ($.inArray(opts.cellFocus, VALID_MODES) < 0) {
$.error("Invalid `cellFocus` option");
}
this._superApply(arguments);
// The combination of $activeTd and forceNavMode determines the current
// navigation mode:
this.$activeTd = null; // active cell (null in row-mode)
this.forceNavMode = true;
this.$container
.addClass("fancytree-ext-ariagrid")
.toggleClass(clsFancytreeCellNavMode, !!this.forceNavMode)
.attr("aria-label", "" + opts.label);
this.$container
.find("thead > tr > th")
.attr("role", "columnheader");
// Store table options for easier evaluation of default actions
// depending of active cell column
this.nodeColumnIdx = treeOpts.table.nodeColumnIdx;
this.checkboxColumnIdx = treeOpts.table.checkboxColumnIdx;
if (this.checkboxColumnIdx == null) {
this.checkboxColumnIdx = this.nodeColumnIdx;
}
this.$container
.on("focusin", function(event) {
// Activate node if embedded input gets focus (due to a click)
var node = FT.getNode(event.target),
$td = $(event.target).closest("td");
// tree.debug( "focusin: " + ( node ? node.title : "null" ) +
// ", target: " + ( $td ? $td.text() : null ) +
// ", node was active: " + ( node && node.isActive() ) +
// ", last cell: " + ( tree.$activeTd ? tree.$activeTd.text() : null ) );
// tree.debug( "focusin: target", event.target );
// TODO: add ":input" as delegate filter instead of testing here
if (
node &&
!$td.is(tree.$activeTd) &&
$(event.target).is(":input")
) {
node.debug("Activate cell on INPUT focus event");
tree.activateCell($td);
}
})
.on("fancytreeinit", function(event, data) {
if (
opts.cellFocus === "start" ||
opts.cellFocus === "force"
) {
tree.debug("Enforce cell-mode on init");
tree.debug(
"init",
tree.getActiveNode() || tree.getFirstChild()
);
(
tree.getActiveNode() || tree.getFirstChild()
).setActive(true, { cell: tree.nodeColumnIdx });
tree.debug(
"init2",
tree.getActiveNode() || tree.getFirstChild()
);
}
})
.on("fancytreefocustree", function(event, data) {
// Enforce cell-mode when container gets focus
if (opts.cellFocus === "force" && !tree.$activeTd) {
var node = tree.getActiveNode() || tree.getFirstChild();
tree.debug("Enforce cell-mode on focusTree event");
node.setActive(true, { cell: 0 });
}
})
// .on("fancytreeupdateviewport", function(event, data) {
// tree.debug(event.type, data);
// })
.on("fancytreebeforeupdateviewport", function(event, data) {
// When scrolling, the TR may be re-used by another node, so the
// active cell marker an
// tree.debug(event.type, data);
if (tree.viewport && tree.$activeTd) {
tree.info("Cancel cell-mode due to scroll event.");
tree.activateCell(null);
}
});
},
nodeClick: function(ctx) {
var targetType = ctx.targetType,
tree = ctx.tree,
node = ctx.node,
event = ctx.originalEvent,
$target = $(event.target),
$td = $target.closest("td");
tree.debug(
"nodeClick: node: " +
(node ? node.title : "null") +
", targetType: " +
targetType +
", target: " +
($td.length ? $td.text() : null) +
", node was active: " +
(node && node.isActive()) +
", last cell: " +
(tree.$activeTd ? tree.$activeTd.text() : null)
);
if (tree.$activeTd) {
// If already in cell-mode, activate new cell
tree.activateCell($td);
if ($target.is(":input")) {
return;
} else if (
$target.is(".fancytree-checkbox") ||
$target.is(".fancytree-expander")
) {
return this._superApply(arguments);
}
return false;
}
return this._superApply(arguments);
},
nodeDblclick: function(ctx) {
var tree = ctx.tree,
treeOpts = ctx.options,
opts = treeOpts.ariagrid,
event = ctx.originalEvent,
$td = $(event.target).closest("td");
// console.log("nodeDblclick", tree.$activeTd, ctx.options.ariagrid.cellFocus)
if (
opts.activateCellOnDoubelclick &&
!tree.$activeTd &&
opts.cellFocus === "allow"
) {
// If in row-mode, activate new cell
tree.activateCell($td);
return false;
}
return this._superApply(arguments);
},
nodeRenderStatus: function(ctx) {
// Set classes for current status
var res,
node = ctx.node,
$tr = $(node.tr);
res = this._super(ctx);
if (node.parent) {
$tr.attr("aria-level", node.getLevel())
.attr("aria-setsize", node.parent.children.length)
.attr("aria-posinset", node.getIndex() + 1);
// 2018-06-24: not required according to
// https://github.com/w3c/aria-practices/issues/132#issuecomment-397698250
// if ( $tr.is( ":hidden" ) ) {
// $tr.attr( "aria-hidden", true );
// } else {
// $tr.removeAttr( "aria-hidden" );
// }
// this.debug("nodeRenderStatus: " + this.$activeTd + ", " + $tr.attr("aria-expanded"));
// In cell-mode, move aria-expanded attribute from TR to first child TD
if (this.$activeTd && $tr.attr("aria-expanded") != null) {
$tr.remove("aria-expanded");
$tr.find("td")
.eq(this.nodeColumnIdx)
.attr("aria-expanded", node.isExpanded());
} else {
$tr.find("td")
.eq(this.nodeColumnIdx)
.removeAttr("aria-expanded");
}
}
return res;
},
nodeSetActive: function(ctx, flag, callOpts) {
var $td,
node = ctx.node,
tree = ctx.tree,
$tr = $(node.tr);
flag = flag !== false;
node.debug("nodeSetActive(" + flag + ")", callOpts);
// Support custom `cell` option
if (flag && callOpts && callOpts.cell != null) {
// `cell` may be a col-index, <td>, or `$(td)`
if (typeof callOpts.cell === "number") {
$td = findTdAtColIdx($tr, callOpts.cell);
} else {
$td = $(callOpts.cell);
}
tree.activateCell($td);
return;
}
// tree.debug( "nodeSetActive: activeNode " + this.activeNode );
return this._superApply(arguments);
},
nodeKeydown: function(ctx) {
var handleKeys,
inputType,
res,
$td,
$embeddedCheckbox = null,
tree = ctx.tree,
node = ctx.node,
treeOpts = ctx.options,
opts = treeOpts.ariagrid,
event = ctx.originalEvent,
eventString = FT.eventToString(event),
$target = $(event.target),
$activeTd = this.$activeTd,
$activeTr = $activeTd ? $activeTd.closest("tr") : null,
colIdx = $activeTd ? getColIdx($activeTr, $activeTd) : -1,
forceNav =
$activeTd &&
tree.forceNavMode &&
$.inArray(eventString, NAV_KEYS) >= 0;
if (opts.cellFocus === "off") {
return this._superApply(arguments);
}
if ($target.is(":input:enabled")) {
inputType = $target.prop("type");
} else if ($target.is("a")) {
inputType = "link";
}
if ($activeTd && $activeTd.find(":checkbox:enabled").length === 1) {
$embeddedCheckbox = $activeTd.find(":checkbox:enabled");
inputType = "checkbox";
}
tree.debug(
"nodeKeydown(" +
eventString +
"), activeTd: '" +
($activeTd && $activeTd.text()) +
"', inputType: " +
inputType
);
if (inputType && eventString !== "esc" && !forceNav) {
handleKeys = INPUT_KEYS[inputType];
if (handleKeys && $.inArray(eventString, handleKeys) >= 0) {
return; // Let input control handle the key
}
}
switch (eventString) {
case "right":
if ($activeTd) {
// Cell mode: move to neighbour (stop on right border)
$td = findNeighbourTd(tree, $activeTd, eventString);
if ($td) {
tree.activateCell($td);
}
} else if (
node &&
!node.isExpanded() &&
node.hasChildren() !== false
) {
// Row mode and current node can be expanded:
// default handling will expand.
break;
} else {
// Row mode: switch to cell-mode
$td = $(node.tr)
.find(">td")
.first();
tree.activateCell($td);
}
return false; // no default handling
case "left":
case "home":
case "end":
case "ctrl+home":
case "ctrl+end":
case "up":
case "down":
if ($activeTd) {
// Cell mode: move to neighbour
$td = findNeighbourTd(tree, $activeTd, eventString);
// Note: $td may be null if we move outside bounds. In this case
// we switch back to row-mode (i.e. call activateCell(null) ).
if (!$td && "left right".indexOf(eventString) < 0) {
// Only switch to row-mode if left/right hits the bounds
return false;
}
if ($td || opts.cellFocus !== "force") {
tree.activateCell($td);
}
return false;
}
break;
case "esc":
if ($activeTd && !tree.forceNavMode) {
// Switch from cell-edit-mode to cell-nav-mode
// $target.closest( "td" ).focus();
tree.forceNavMode = true;
tree.debug("Enter cell-nav-mode");
tree.$container.toggleClass(
clsFancytreeCellNavMode,
!!tree.forceNavMode
);
return false;
} else if ($activeTd && opts.cellFocus !== "force") {
// Switch back from cell-mode to row-mode
tree.activateCell(null);
return false;
}
// tree.$container.toggleClass( clsFancytreeCellNavMode, !!tree.forceNavMode );
break;
case "return":
// Let user override the default action.
// This event is triggered in row-mode and cell-mode
res = tree._triggerNodeEvent(
"defaultGridAction",
node,
event,
{
activeTd: tree.$activeTd ? tree.$activeTd[0] : null,
colIdx: colIdx,
mode: getGridNavMode(tree),
}
);
if (res === false) {
return false;
}
// Implement default actions (for cell-mode only).
if ($activeTd) {
// Apply 'default action' for embedded cell control
if (colIdx === this.nodeColumnIdx) {
node.toggleExpanded();
} else if (colIdx === this.checkboxColumnIdx) {
// TODO: only in checkbox mode!
node.toggleSelected();
} else if ($embeddedCheckbox) {
// Embedded checkboxes are always toggled (ignoring `autoFocusInput`)
$embeddedCheckbox.prop(
"checked",
!$embeddedCheckbox.prop("checked")
);
} else if (tree.forceNavMode && $target.is(":input")) {
tree.forceNavMode = false;
tree.$container.removeClass(
clsFancytreeCellNavMode
);
tree.debug("enable cell-edit-mode");
} else if ($activeTd.find("a").length === 1) {
activateEmbeddedLink($activeTd);
}
} else {
// ENTER in row-mode: Switch from row-mode to cell-mode
// TODO: it was also suggested to expand/collapse instead
// https://github.com/w3c/aria-practices/issues/132#issuecomment-407634891
$td = $(node.tr)
.find(">td")
.nth(this.nodeColumnIdx);
tree.activateCell($td);
}
return false; // no default handling
case "space":
if ($activeTd) {
if (colIdx === this.checkboxColumnIdx) {
node.toggleSelected();
} else if ($embeddedCheckbox) {
$embeddedCheckbox.prop(
"checked",
!$embeddedCheckbox.prop("checked")
);
}
return false; // no default handling
}
break;
default:
// Allow to focus input by typing alphanum keys
}
return this._superApply(arguments);
},
treeSetOption: function(ctx, key, value) {
var tree = ctx.tree,
opts = tree.options.ariagrid;
if (key === "ariagrid") {
// User called `$().fancytree("option", "ariagrid.SUBKEY", VALUE)`
if (value.cellFocus !== opts.cellFocus) {
if ($.inArray(value.cellFocus, VALID_MODES) < 0) {
$.error("Invalid `cellFocus` option");
}
// TODO: fix current focus and mode
}
}
return this._superApply(arguments);
},
});
// Value returned by `require('jquery.fancytree..')`
return $.ui.fancytree;
}); // End of closure

Datei anzeigen

@ -0,0 +1,239 @@
// Extending Fancytree
// ===================
//
// See also the [live demo](https://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-2021, Martin Wendt (https://wwWendt.de)
*
* Released under the MIT license
* https://github.com/mar10/fancytree/wiki/LicenseInfo
*
* @version 2.38.0
* @date 2021-02-09T20:03:49Z
*/
// To keep the global namespace clean, we wrap everything in a closure.
// The UMD wrapper pattern defines the dependencies on jQuery and the
// Fancytree core module, and makes sure that we can use the `require()`
// syntax with package loaders.
(function(factory) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define(["jquery", "./jquery.fancytree"], factory);
} else if (typeof module === "object" && module.exports) {
// Node/CommonJS
require("./jquery.fancytree");
module.exports = factory(require("jquery"));
} else {
// Browser globals
factory(jQuery);
}
})(function($) {
// 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 /eslint compliance.
// But for this sample, we want to allow unused variables for demonstration purpose.
/*eslint-disable no-unused-vars */
// Adding methods
// --------------
// New member functions can be added to the `Fancytree` class.
// This function will be available for every tree instance:
//
// var tree = $.ui.fancytree.getTree("#tree");
// 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,span.fancytree-custom-icon",
node.span
)
);
}
$badge.text(count);
} else {
$badge.remove();
}
if (extOpts.deep && !node.isTopLevel() && !node.isRootNode()) {
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](https://wwWendt.de/tech/fancytree/demo/sample-ext-childcounter.html)):
//
// <script src="../src/jquery.fancytree.js"></script>
// <script src="../src/jquery.fancytree.childcounter.js"></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: "2.38.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](https://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](https://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
// We use `_super()` instead of `_superApply()` here, since it is a little bit
// more performant when called often
this._super(ctx, title);
// Append a counter badge
if (
(count || !extOpts.hideZeros) &&
(!node.isExpanded() || !extOpts.hideExpanded)
) {
$(
"span.fancytree-icon,span.fancytree-custom-icon",
node.span
).append(
$("<span class='fancytree-childcounter'/>").text(count)
);
}
},
// Overload the `setExpanded` hook, so the counters are updated
nodeSetExpanded: function(ctx, flag, callOpts) {
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
});
// Value returned by `require('jquery.fancytree..')`
return $.ui.fancytree;
}); // End of closure

Datei anzeigen

@ -0,0 +1,514 @@
/*!
*
* 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-2021, Martin Wendt (https://wwWendt.de)
*
* Released under the MIT license
* https://github.com/mar10/fancytree/wiki/LicenseInfo
*
* @version 2.38.0
* @date 2021-02-09T20:03:49Z
*/
(function(factory) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define(["jquery", "./jquery.fancytree"], factory);
} else if (typeof module === "object" && module.exports) {
// Node/CommonJS
require("./jquery.fancytree");
module.exports = factory(require("jquery"));
} else {
// Browser globals
factory(jQuery);
}
})(function($) {
"use strict";
/*******************************************************************************
* Private functions and variables
*/
var _assert = $.ui.fancytree.assert;
/* 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;
}
/**
* 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) {
/*eslint-disable no-bitwise */
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) {
case 3:
k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16;
// fall through
case 2:
k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8;
// fall through
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;
/*eslint-enable no-bitwise */
}
/*
* Return a unique key for node by calculating the hash of the parents refKey-list.
*/
function calcUniqueKey(node) {
var key,
h1,
path = $.map(node.getParentList(false, true), function(e) {
return e.refKey || e.key;
});
path = path.join("/");
// 32-bit has a high probability of collisions, so we pump up to 64-bit
// https://security.stackexchange.com/q/209882/207588
h1 = hashMurmur3(path, true);
key = "id_" + h1 + hashMurmur3(h1 + path, true);
return key;
}
/**
* [ext-clones] Return a list of clone-nodes (i.e. same refKey) 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] Define a refKey for an existing node.
* @param {string} refKey
* @returns {boolean}
*
* @alias FancytreeNode#setRefKey
* @requires jquery.fancytree.clones.js
* @since 2.16
*/
$.ui.fancytree._FancytreeNodeClass.prototype.setRefKey = function(refKey) {
return this.reRegister(null, refKey);
};
/**
* [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: "2.38.0",
// 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 (node.isStatusNode()) {
return this._super(ctx, add, node);
}
if (add) {
if (keyMap[node.key] != null) {
var other = keyMap[node.key],
msg =
"clones.treeRegisterNode: duplicate key '" +
node.key +
"': /" +
node.getPath(true) +
" => " +
other.getPath(true);
// Sometimes this exception is not visible in the console,
// so we also write it:
tree.error(msg);
$.error(msg);
}
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._super(ctx, add, node);
},
nodeRenderStatus: function(ctx) {
var $span,
res,
node = ctx.node;
res = this._super(ctx);
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, callOpts) {
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;
},
});
// Value returned by `require('jquery.fancytree..')`
return $.ui.fancytree;
}); // End of closure

Datei anzeigen

@ -0,0 +1,216 @@
/*!
* 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-2021, Martin Wendt (https://wwWendt.de)
*
* Released under the MIT license
* https://github.com/mar10/fancytree/wiki/LicenseInfo
*
* @version 2.38.0
* @date 2021-02-09T20:03:49Z
*/
(function(factory) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define(["jquery", "./jquery.fancytree"], factory);
} else if (typeof module === "object" && module.exports) {
// Node/CommonJS
require("./jquery.fancytree");
module.exports = factory(require("jquery"));
} else {
// Browser globals
factory(jQuery);
}
})(function($) {
"use strict";
/*******************************************************************************
* Private functions and variables
*/
var _assert = $.ui.fancytree.assert,
FT = $.ui.fancytree;
/*******************************************************************************
* Private functions and variables
*/
$.ui.fancytree.registerExtension({
name: "columnview",
version: "2.38.0",
// 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.$tdList = $(">td", tree.tr);
tree.columnCount = tree.$tdList.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 = tree.$tdList.eq(0);
_assert(
$.inArray("table", this.options.extensions) < 0,
"columnview extensions must not use ext-table"
);
_assert(
tree.columnCount >= 2,
"columnview target must be a table with at least two columns"
);
$ul.removeClass("fancytree-container").removeAttr("tabindex");
tree.$container = $table;
$table
.addClass("fancytree-container fancytree-ext-columnview")
.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;
$table
// Make sure that only active path is expanded when a node is activated:
.on("fancytreeactivate", function(event, data) {
var node = data.node,
tree = data.tree,
level = node.getLevel();
tree._callHook("nodeCollapseSiblings", node);
// Clear right neighbours
if (!node.expanded) {
tree.$tdList
.eq(level)
.nextAll()
.empty();
}
// Expand nodes on activate, so we populate the right neighbor cell
if (!node.expanded && (node.children || node.lazy)) {
node.setExpanded();
}
})
// Adjust keyboard behaviour:
.on("fancytreekeydown", function(event, data) {
var next = null,
handled = true,
node = data.node || data.tree.getFirstChild();
if (node.getLevel() >= tree.columnCount) {
return;
}
switch (FT.eventToString(event)) {
case "down":
next = node.getNextSibling();
break;
case "left":
if (!node.isTopLevel()) {
next = node.getParent();
}
break;
case "right":
next = node.getFirstChild();
if (!next) {
// default processing: expand or ignore
return;
}
// Prefer an expanded child if any
next.visitSiblings(function(n) {
if (n.expanded) {
next = n;
return false;
}
}, true);
break;
case "up":
next = node.getPrevSibling();
break;
default:
handled = false;
}
if (next) {
next.setActive();
}
return !handled;
});
},
nodeSetExpanded: function(ctx, flag, callOpts) {
var $wait,
node = ctx.node,
tree = ctx.tree,
level = node.getLevel();
if (flag !== false && !node.expanded && node.isUndefined()) {
$wait = $(
"<span class='fancytree-icon fancytree-icon-loading'>"
);
tree.$tdList
.eq(level)
.empty()
.append($wait);
}
return this._superApply(arguments);
},
nodeRemoveChildren: function(ctx) {
// #899: node's children removed: remove child marker...
$(ctx.node.span)
.find("span.fancytree-cv-right")
.remove();
// ...and clear right columns
ctx.tree.$tdList
.eq(ctx.node.getLevel())
.nextAll()
.empty();
return this._superApply(arguments);
},
nodeRender: function(ctx, force, deep, collapsed, _recursive) {
// Render standard nested <ul> - <li> hierarchy
this._super(ctx, force, deep, collapsed, _recursive);
// 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.expanded) {
node.ul.style.display = ""; // might be hidden if RIGHT was pressed
level = node.getLevel();
if (level < tree.columnCount) {
// only if we are not in the last column
$tdChild = tree.$tdList.eq(level);
$ul = $(node.ul).detach();
$tdChild.empty().append($ul);
}
}
},
});
// Value returned by `require('jquery.fancytree..')`
return $.ui.fancytree;
}); // End of closure

Datei anzeigen

@ -0,0 +1,799 @@
/*!
* jquery.fancytree.dnd.js
*
* Drag-and-drop support (jQuery UI draggable/droppable).
* (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/)
*
* Copyright (c) 2008-2021, Martin Wendt (https://wwWendt.de)
*
* Released under the MIT license
* https://github.com/mar10/fancytree/wiki/LicenseInfo
*
* @version 2.38.0
* @date 2021-02-09T20:03:49Z
*/
(function(factory) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define([
"jquery",
"jquery-ui/ui/widgets/draggable",
"jquery-ui/ui/widgets/droppable",
"./jquery.fancytree",
], factory);
} else if (typeof module === "object" && module.exports) {
// Node/CommonJS
require("./jquery.fancytree");
module.exports = factory(require("jquery"));
} else {
// Browser globals
factory(jQuery);
}
})(function($) {
"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) {
// eslint-disable-next-line no-nested-ternary
return n === 0 ? "" : n > 0 ? "+" + n : "" + n;
}
//--- 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
);
targetNode.tree.ext.dnd._onDragEvent(
"over",
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;
}
/******************************************************************************
* 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._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
)
);
}
}
/******************************************************************************
*
*/
$.ui.fancytree.registerExtension({
name: "dnd",
version: "2.38.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
dropMarkerOffsetX: -24, // absolute position offset for .fancytree-drop-marker relatively to ..fancytree-title (icon/img near a node accepting drop)
dropMarkerInsertOffsetX: -16, // additional offset for drop-marker with hitMode = "before"/"after"
// 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)
dragExpand: null, // Callback(targetNode, data), return false to prevent autoExpand
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,
pos,
markerAt = "center",
instData = this._local,
dndOpt = this.options.dnd,
glyphOpt = this.options.glyph,
$source = sourceNode ? $(sourceNode.span) : null,
$target = $(targetNode.span),
$targetTitle = $target.find("span.fancytree-title");
if (!instData.$dropMarker) {
instData.$dropMarker = $(
"<div id='fancytree-drop-marker'></div>"
)
.hide()
.css({ "z-index": 1000 })
.prependTo($(this.$div).parent());
// .prependTo("body");
if (glyphOpt) {
instData.$dropMarker.addClass(
glyphOpt.map._addClass + " " + glyphOpt.map.dropMarker
);
}
}
if (
hitMode === "after" ||
hitMode === "before" ||
hitMode === "over"
) {
markerOffsetX = dndOpt.dropMarkerOffsetX || 0;
switch (hitMode) {
case "before":
markerAt = "top";
markerOffsetX += dndOpt.dropMarkerInsertOffsetX || 0;
break;
case "after":
markerAt = "bottom";
markerOffsetX += dndOpt.dropMarkerInsertOffsetX || 0;
break;
}
pos = {
my: "left" + offsetString(markerOffsetX) + " center",
at: "left " + markerAt,
of: $targetTitle,
};
if (this.options.rtl) {
pos.my = "right" + offsetString(-markerOffsetX) + " center";
pos.at = "right " + markerAt;
}
instData.$dropMarker
.toggleClass(classDropAfter, hitMode === "after")
.toggleClass(classDropOver, hitMode === "over")
.toggleClass(classDropBefore, hitMode === "before")
.toggleClass("fancytree-rtl", !!this.options.rtl)
.show()
.position($.ui.fancytree.fixPositionOptions(pos));
} 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,
parentRect,
rect,
relPos,
relPos2,
enterResponse,
hitMode,
r,
opts = this.options,
dnd = opts.dnd,
ctx = this._makeHookContext(node, event, {
otherNode: otherNode,
ui: ui,
draggable: draggable,
}),
res = null,
self = 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 cancelled, when false is returned)
// TODO: call this._cancelDrag()?
ui.helper.trigger("mouseup").hide();
} else {
if (dnd.smartRevert) {
// #567, #593: fix revert position
// rect = node.li.getBoundingClientRect();
rect = node[
ctx.tree.nodeContainerAttrName
].getBoundingClientRect();
parentRect = $(
draggable.options.appendTo
)[0].getBoundingClientRect();
draggable.originalPosition.left = Math.max(
0,
rect.left - parentRect.left
);
draggable.originalPosition.top = Math.max(
0,
rect.top - parentRect.top
);
}
$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
) {
self.ext.dnd._cancelDrag();
} else if (event.type === "mousedown") {
self.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 !== "before" &&
hitMode !== "after" &&
dnd.autoExpandMS &&
node.hasChildren() !== false &&
!node.expanded &&
(!dnd.dragExpand || dnd.dragExpand(node, ctx) !== false)
) {
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();
}
},
});
// Value returned by `require('jquery.fancytree..')`
return $.ui.fancytree;
}); // End of closure

Datei-Diff unterdrückt, da er zu groß ist Diff laden

Datei anzeigen

@ -0,0 +1,402 @@
/*!
* jquery.fancytree.edit.js
*
* Make node titles editable.
* (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/)
*
* Copyright (c) 2008-2021, Martin Wendt (https://wwWendt.de)
*
* Released under the MIT license
* https://github.com/mar10/fancytree/wiki/LicenseInfo
*
* @version 2.38.0
* @date 2021-02-09T20:03:49Z
*/
(function(factory) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define(["jquery", "./jquery.fancytree"], factory);
} else if (typeof module === "object" && module.exports) {
// Node/CommonJS
require("./jquery.fancytree");
module.exports = factory(require("jquery"));
} else {
// Browser globals
factory(jQuery);
}
})(function($) {
"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();
local.lastDraggableAttrValue = node.span.draggable;
if (local.lastDraggableAttrValue) {
node.span.draggable = false;
}
// #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: tree.options.escapeTitles
? eventData.orgTitle
: 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");
})
.on("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");
if (instOpts.trim) {
$input.val($.trim($input.val()));
}
newVal = $input.val();
eventData.dirty = newVal !== node.title;
eventData.originalEvent = _event;
// 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 everything, 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").off();
// Unbind outer-click handler
$(document).off(".fancytree-edit");
if (eventData.save) {
// # 171: escape user input (not required if global escaping is on)
node.setTitle(
tree.options.escapeTitles ? newVal : escapeHtml(newVal)
);
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();
if (node && local.lastDraggableAttrValue) {
node.span.draggable = true;
}
// Set keyboard focus, even if setFocus() claims 'nothing to do'
tree.$container.get(0).focus({ preventScroll: true });
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);
// #644: Don't filter new nodes.
newNode.match = true;
$(newNode[tree.statusClassPropName])
.removeClass("fancytree-hide")
.addClass("fancytree-match");
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 ? this.ext.edit.currentNode : null;
};
/**
* [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
? this.tree.ext.edit.currentNode === this
: false;
};
/*******************************************************************************
* Extension code
*/
$.ui.fancytree.registerExtension({
name: "edit",
version: "2.38.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", "mac+enter", "shift+click"],
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) {
var tree = ctx.tree;
this._superApply(arguments);
this.$container
.addClass("fancytree-ext-edit")
.on("fancytreebeforeupdateviewport", function(event, data) {
var editNode = tree.isEditing();
// When scrolling, the TR may be re-used by another node, so the
// active cell marker an
if (editNode) {
editNode.info("Cancel edit due to scroll event.");
editNode.editEnd(false, event);
}
});
},
nodeClick: function(ctx) {
var eventStr = $.ui.fancytree.eventToString(ctx.originalEvent),
triggerStart = ctx.options.edit.triggerStart;
if (
eventStr === "shift+click" &&
$.inArray("shift+click", triggerStart) >= 0
) {
if (ctx.originalEvent.shiftKey) {
ctx.node.editStart();
return false;
}
}
if (
eventStr === "click" &&
$.inArray("clickActive", triggerStart) >= 0
) {
// Only when click was inside title text (not aynwhere else in the row)
if (
ctx.node.isActive() &&
!ctx.node.isEditing() &&
$(ctx.originalEvent.target).hasClass("fancytree-title")
) {
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);
},
});
// Value returned by `require('jquery.fancytree..')`
return $.ui.fancytree;
}); // End of closure

Datei anzeigen

@ -0,0 +1,551 @@
/*!
* 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-2021, Martin Wendt (https://wwWendt.de)
*
* Released under the MIT license
* https://github.com/mar10/fancytree/wiki/LicenseInfo
*
* @version 2.38.0
* @date 2021-02-09T20:03:49Z
*/
(function(factory) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define(["jquery", "./jquery.fancytree"], factory);
} else if (typeof module === "object" && module.exports) {
// Node/CommonJS
require("./jquery.fancytree");
module.exports = factory(require("jquery"));
} else {
// Browser globals
factory(jQuery);
}
})(function($) {
"use strict";
/*******************************************************************************
* Private functions and variables
*/
var KeyNoData = "__not_found__",
escapeHtml = $.ui.fancytree.escapeHtml,
exoticStartChar = "\uFFF7",
exoticEndChar = "\uFFF8";
function _escapeRegex(str) {
return (str + "").replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
}
function extractHtmlText(s) {
if (s.indexOf(">") >= 0) {
return $("<div/>")
.html(s)
.text();
}
return s;
}
/**
* @description Marks the matching charecters of `text` either by `mark` or
* by exotic*Chars (if `escapeTitles` is `true`) based on `regexMatchArray`
* which is an array of matching groups.
* @param {string} text
* @param {RegExpMatchArray} regexMatchArray
*/
function _markFuzzyMatchedChars(text, regexMatchArray, escapeTitles) {
// It is extremely infuriating that we can not use `let` or `const` or arrow functions.
// Damn you IE!!!
var matchingIndices = [];
// get the indices of matched characters (Iterate through `RegExpMatchArray`)
for (
var _matchingArrIdx = 1;
_matchingArrIdx < regexMatchArray.length;
_matchingArrIdx++
) {
var _mIdx =
// get matching char index by cumulatively adding
// the matched group length
regexMatchArray[_matchingArrIdx].length +
(_matchingArrIdx === 1 ? 0 : 1) +
(matchingIndices[matchingIndices.length - 1] || 0);
matchingIndices.push(_mIdx);
}
// Map each `text` char to its position and store in `textPoses`.
var textPoses = text.split("");
if (escapeTitles) {
// If escaping the title, then wrap the matchng char within exotic chars
matchingIndices.forEach(function(v) {
textPoses[v] = exoticStartChar + textPoses[v] + exoticEndChar;
});
} else {
// Otherwise, Wrap the matching chars within `mark`.
matchingIndices.forEach(function(v) {
textPoses[v] = "<mark>" + textPoses[v] + "</mark>";
});
}
// Join back the modified `textPoses` to create final highlight markup.
return textPoses.join("");
}
$.ui.fancytree._FancytreeClass.prototype._applyFilterImpl = function(
filter,
branchMode,
_opts
) {
var match,
statusNode,
re,
reHighlight,
reExoticStartChar,
reExoticEndChar,
temp,
prevEnableUpdate,
count = 0,
treeOpts = this.options,
escapeTitles = treeOpts.escapeTitles,
prevAutoCollapse = treeOpts.autoCollapse,
opts = $.extend({}, treeOpts.filter, _opts),
hideMode = opts.mode === "hide",
leavesOnly = !!opts.leavesOnly && !branchMode;
// Default to 'match title substring (not case sensitive)'
if (typeof filter === "string") {
if (filter === "") {
this.warn(
"Fancytree passing an empty string as a filter is handled as clearFilter()."
);
this.clearFilter();
return;
}
if (opts.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("")
// Escaping the `filter` will not work because,
// it gets further split into individual characters. So,
// escape each character after splitting
.map(_escapeRegex)
.reduce(function(a, b) {
// create capture groups for parts that comes before
// the character
return a + "([^" + b + "]*)" + b;
}, "");
} else {
match = _escapeRegex(filter); // make sure a '.' is treated literally
}
re = new RegExp(match, "i");
reHighlight = new RegExp(_escapeRegex(filter), "gi");
if (escapeTitles) {
reExoticStartChar = new RegExp(
_escapeRegex(exoticStartChar),
"g"
);
reExoticEndChar = new RegExp(_escapeRegex(exoticEndChar), "g");
}
filter = function(node) {
if (!node.title) {
return false;
}
var text = escapeTitles
? node.title
: extractHtmlText(node.title),
// `.match` instead of `.test` to get the capture groups
res = text.match(re);
if (res && opts.highlight) {
if (escapeTitles) {
if (opts.fuzzy) {
temp = _markFuzzyMatchedChars(
text,
res,
escapeTitles
);
} else {
// #740: we must not apply the marks to escaped entity names, e.g. `&quot;`
// Use some exotic characters to mark matches:
temp = text.replace(reHighlight, function(s) {
return exoticStartChar + s + exoticEndChar;
});
}
// now we can escape the title...
node.titleWithHighlight = escapeHtml(temp)
// ... and finally insert the desired `<mark>` tags
.replace(reExoticStartChar, "<mark>")
.replace(reExoticEndChar, "</mark>");
} else {
if (opts.fuzzy) {
node.titleWithHighlight = _markFuzzyMatchedChars(
text,
res
);
} else {
node.titleWithHighlight = text.replace(
reHighlight,
function(s) {
return "<mark>" + s + "</mark>";
}
);
}
}
// node.debug("filter", escapeTitles, text, node.titleWithHighlight);
}
return !!res;
};
}
this.enableFilter = true;
this.lastFilterArgs = arguments;
prevEnableUpdate = this.enableUpdate(false);
this.$div.addClass("fancytree-ext-filter");
if (hideMode) {
this.$div.addClass("fancytree-ext-filter-hide");
} else {
this.$div.addClass("fancytree-ext-filter-dimm");
}
this.$div.toggleClass(
"fancytree-ext-filter-hide-expanders",
!!opts.hideExpanders
);
// Reset current filter
this.rootNode.subMatchCount = 0;
this.visit(function(node) {
delete node.match;
delete node.titleWithHighlight;
node.subMatchCount = 0;
});
statusNode = this.getRootNode()._findDirectChild(KeyNoData);
if (statusNode) {
statusNode.remove();
}
// Adjust node.hide, .match, and .subMatchCount properties
treeOpts.autoCollapse = false; // #528
this.visit(function(node) {
if (leavesOnly && node.children != null) {
return;
}
var res = filter(node),
matchedByBranch = false;
if (res === "skip") {
node.visit(function(c) {
c.match = false;
}, true);
return "skip";
}
if (!res && (branchMode || res === "branch") && node.parent.match) {
res = true;
matchedByBranch = true;
}
if (res) {
count++;
node.match = true;
node.visitParents(function(p) {
if (p !== node) {
p.subMatchCount += 1;
}
// Expand match (unless this is no real match, but only a node in a matched branch)
if (opts.autoExpand && !matchedByBranch && !p.expanded) {
p.setExpanded(true, {
noAnimation: true,
noEvents: true,
scrollIntoView: false,
});
p._filterAutoExpanded = true;
}
}, true);
}
});
treeOpts.autoCollapse = prevAutoCollapse;
if (count === 0 && opts.nodata && hideMode) {
statusNode = opts.nodata;
if ($.isFunction(statusNode)) {
statusNode = statusNode();
}
if (statusNode === true) {
statusNode = {};
} else if (typeof statusNode === "string") {
statusNode = { title: statusNode };
}
statusNode = $.extend(
{
statusNodeType: "nodata",
key: KeyNoData,
title: this.options.strings.noData,
},
statusNode
);
this.getRootNode().addNode(statusNode).match = true;
}
// Redraw whole tree
this._callHook("treeStructureChanged", this, "applyFilter");
// this.render();
this.enableUpdate(prevEnableUpdate);
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. Use opts.leavesOnly instead."
);
}
return this._applyFilterImpl(filter, false, opts);
};
/**
* [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] Re-apply current filter.
*
* @returns {integer} count
* @alias Fancytree#updateFilter
* @requires jquery.fancytree.filter.js
* @since 2.38
*/
$.ui.fancytree._FancytreeClass.prototype.updateFilter = function() {
if (
this.enableFilter &&
this.lastFilterArgs &&
this.options.filter.autoApply
) {
this._applyFilterImpl.apply(this, this.lastFilterArgs);
} else {
this.warn("updateFilter(): no filter active.");
}
};
/**
* [ext-filter] Reset the filter.
*
* @alias Fancytree#clearFilter
* @requires jquery.fancytree.filter.js
*/
$.ui.fancytree._FancytreeClass.prototype.clearFilter = function() {
var $title,
statusNode = this.getRootNode()._findDirectChild(KeyNoData),
escapeTitles = this.options.escapeTitles,
enhanceTitle = this.options.enhanceTitle,
prevEnableUpdate = this.enableUpdate(false);
if (statusNode) {
statusNode.remove();
}
// we also counted root node's subMatchCount
delete this.rootNode.match;
delete this.rootNode.subMatchCount;
this.visit(function(node) {
if (node.match && node.span) {
// #491, #601
$title = $(node.span).find(">span.fancytree-title");
if (escapeTitles) {
$title.text(node.title);
} else {
$title.html(node.title);
}
if (enhanceTitle) {
enhanceTitle(
{ type: "enhanceTitle" },
{ node: node, $title: $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._callHook("treeStructureChanged", this, "clearFilter");
// this.render();
this.enableUpdate(prevEnableUpdate);
};
/**
* [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: "2.38.0",
// Default options for this extension.
options: {
autoApply: true, // Re-apply last filter if lazy data is loaded
autoExpand: false, // Expand all branches that contain matches while filtered
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 if parent is expanded
hideExpanders: false, // Hide expanders if all child nodes are hidden by filter
highlight: true, // Highlight matches by wrapping inside <mark> tags
leavesOnly: false, // Match end nodes only
nodata: true, // Display a 'no data' status node if result is empty
mode: "dimm", // Grayout unmatched nodes (pass "hide" to remove unmatched node instead)
},
nodeLoadChildren: function(ctx, source) {
var tree = ctx.tree;
return this._superApply(arguments).done(function() {
if (
tree.enableFilter &&
tree.lastFilterArgs &&
ctx.options.filter.autoApply
) {
tree._applyFilterImpl.apply(tree, tree.lastFilterArgs);
}
});
},
nodeSetExpanded: function(ctx, flag, callOpts) {
var node = ctx.node;
delete node._filterAutoExpanded;
// Make sure counter badge is displayed again, when node is beeing collapsed
if (
!flag &&
ctx.options.filter.hideExpandedCounter &&
node.$subMatchBadge
) {
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,
$title = $(node.span).find("span.fancytree-title"),
$span = $(node[tree.statusClassPropName]),
enhanceTitle = ctx.options.enhanceTitle,
escapeTitles = ctx.options.escapeTitles;
res = this._super(ctx);
// 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, span.fancytree-custom-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)
// #601: also check for $title.length, because we don't need to render
// if node.span is null (i.e. not rendered)
if (node.span && (!node.isEditing || !node.isEditing.call(node))) {
if (node.titleWithHighlight) {
$title.html(node.titleWithHighlight);
} else if (escapeTitles) {
$title.text(node.title);
} else {
$title.html(node.title);
}
if (enhanceTitle) {
enhanceTitle(
{ type: "enhanceTitle" },
{ node: node, $title: $title }
);
}
}
return res;
},
});
// Value returned by `require('jquery.fancytree..')`
return $.ui.fancytree;
}); // End of closure

Datei anzeigen

@ -0,0 +1,689 @@
/*!
* jquery.fancytree.fixed.js
*
* Add fixed colums and headers to ext.table.
* (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/)
*
* Copyright (c) 2008-2021, Martin Wendt (https://wwWendt.de)
*
* Released under the MIT license
* https://github.com/mar10/fancytree/wiki/LicenseInfo
*
* @version 2.38.0
* @date 2021-02-09T20:03:49Z
*/
// Allow to use multiple var statements inside a function
(function(factory) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define([
"jquery",
"./jquery.fancytree",
"./jquery.fancytree.table",
], factory);
} else if (typeof module === "object" && module.exports) {
// Node/CommonJS
require("./jquery.fancytree.table"); // core + table
module.exports = factory(require("jquery"));
} else {
// Browser globals
factory(jQuery);
}
})(function($) {
"use strict";
/******************************************************************************
* Private functions and variables
*/
$.ui.fancytree.registerExtension({
name: "fixed",
version: "0.0.1",
// Default options for this extension.
options: {
fixCol: 1,
fixColWidths: null,
fixRows: true,
scrollSpeed: 50,
resizable: true,
classNames: {
table: "fancytree-ext-fixed",
wrapper: "fancytree-ext-fixed-wrapper",
topLeft: "fancytree-ext-fixed-wrapper-tl",
topRight: "fancytree-ext-fixed-wrapper-tr",
bottomLeft: "fancytree-ext-fixed-wrapper-bl",
bottomRight: "fancytree-ext-fixed-wrapper-br",
hidden: "fancytree-ext-fixed-hidden",
counterpart: "fancytree-ext-fixed-node-counterpart",
scrollBorderBottom: "fancytree-ext-fixed-scroll-border-bottom",
scrollBorderRight: "fancytree-ext-fixed-scroll-border-right",
hover: "fancytree-ext-fixed-hover",
},
},
// 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) {
this._requireExtension("table", true, true);
// 'fixed' requires the table extension to be loaded before itself
var res = this._superApply(arguments),
tree = ctx.tree,
options = this.options.fixed,
fcn = this.options.fixed.classNames,
$table = tree.widget.element,
fixedColCount = options.fixCols,
fixedRowCount = options.fixRows,
$tableWrapper = $table.parent(),
$topLeftWrapper = $("<div>").addClass(fcn.topLeft),
$topRightWrapper = $("<div>").addClass(fcn.topRight),
$bottomLeftWrapper = $("<div>").addClass(fcn.bottomLeft),
$bottomRightWrapper = $("<div>").addClass(fcn.bottomRight),
tableStyle = $table.attr("style"),
tableClass = $table.attr("class"),
$topLeftTable = $("<table>")
.attr("style", tableStyle)
.attr("class", tableClass),
$topRightTable = $("<table>")
.attr("style", tableStyle)
.attr("class", tableClass),
$bottomLeftTable = $table,
$bottomRightTable = $("<table>")
.attr("style", tableStyle)
.attr("class", tableClass),
$head = $table.find("thead"),
$colgroup = $table.find("colgroup"),
headRowCount = $head.find("tr").length;
this.$fixedWrapper = $tableWrapper;
$table.addClass(fcn.table);
$tableWrapper.addClass(fcn.wrapper);
$bottomRightTable.append($("<tbody>"));
if ($colgroup.length) {
$colgroup.remove();
}
if (typeof fixedRowCount === "boolean") {
fixedRowCount = fixedRowCount ? headRowCount : 0;
} else {
fixedRowCount = Math.max(
0,
Math.min(fixedRowCount, headRowCount)
);
}
if (fixedRowCount) {
$topLeftTable.append($head.clone(true));
$topRightTable.append($head.clone(true));
$head.remove();
}
$topLeftTable.find("tr").each(function(idx) {
$(this)
.find("th")
.slice(fixedColCount)
.remove();
});
$topRightTable.find("tr").each(function(idx) {
$(this)
.find("th")
.slice(0, fixedColCount)
.remove();
});
this.$fixedWrapper = $tableWrapper;
$tableWrapper.append(
$topLeftWrapper.append($topLeftTable),
$topRightWrapper.append($topRightTable),
$bottomLeftWrapper.append($bottomLeftTable),
$bottomRightWrapper.append($bottomRightTable)
);
$bottomRightTable.on("keydown", function(evt) {
var node = tree.focusNode,
ctx = tree._makeHookContext(node || tree, evt),
res = tree._callHook("nodeKeydown", ctx);
return res;
});
$bottomRightTable.on("click dblclick", "tr", function(evt) {
var $trLeft = $(this),
$trRight = $trLeft.data(fcn.counterpart),
node = $.ui.fancytree.getNode($trRight),
ctx = tree._makeHookContext(node, evt),
et = $.ui.fancytree.getEventTarget(evt),
prevPhase = tree.phase;
try {
tree.phase = "userEvent";
switch (evt.type) {
case "click":
ctx.targetType = et.type;
if (node.isPagingNode()) {
return (
tree._triggerNodeEvent(
"clickPaging",
ctx,
evt
) === true
);
}
return tree._triggerNodeEvent("click", ctx, evt) ===
false
? false
: tree._callHook("nodeClick", ctx);
case "dblclick":
ctx.targetType = et.type;
return tree._triggerNodeEvent(
"dblclick",
ctx,
evt
) === false
? false
: tree._callHook("nodeDblclick", ctx);
}
} finally {
tree.phase = prevPhase;
}
});
$tableWrapper
.on(
"mouseenter",
"." +
fcn.bottomRight +
" table tr, ." +
fcn.bottomLeft +
" table tr",
function(evt) {
var $tr = $(this),
$trOther = $tr.data(fcn.counterpart);
$tr.addClass(fcn.hover);
$trOther.addClass(fcn.hover);
}
)
.on(
"mouseleave",
"." +
fcn.bottomRight +
" table tr, ." +
fcn.bottomLeft +
" table tr",
function(evt) {
var $tr = $(this),
$trOther = $tr.data(fcn.counterpart);
$tr.removeClass(fcn.hover);
$trOther.removeClass(fcn.hover);
}
);
$bottomLeftWrapper.on("mousewheel DOMMouseScroll", function(event) {
var $this = $(this),
newScroll = $this.scrollTop(),
scrollUp =
event.originalEvent.wheelDelta > 0 ||
event.originalEvent.detail < 0;
newScroll += scrollUp
? -options.scrollSpeed
: options.scrollSpeed;
$this.scrollTop(newScroll);
$bottomRightWrapper.scrollTop(newScroll);
event.preventDefault();
});
$bottomRightWrapper.scroll(function() {
var $this = $(this),
scrollLeft = $this.scrollLeft(),
scrollTop = $this.scrollTop();
$topLeftWrapper
.toggleClass(fcn.scrollBorderBottom, scrollTop > 0)
.toggleClass(fcn.scrollBorderRight, scrollLeft > 0);
$topRightWrapper
.toggleClass(fcn.scrollBorderBottom, scrollTop > 0)
.scrollLeft(scrollLeft);
$bottomLeftWrapper
.toggleClass(fcn.scrollBorderRight, scrollLeft > 0)
.scrollTop(scrollTop);
});
$.ui.fancytree.overrideMethod(
$.ui.fancytree._FancytreeNodeClass.prototype,
"scrollIntoView",
function(effects, options) {
var $prevContainer = tree.$container;
tree.$container = $bottomRightWrapper;
return this._super
.apply(this, arguments)
.always(function() {
tree.$container = $prevContainer;
});
}
);
return res;
},
treeLoad: function(ctx) {
var self = this,
res = this._superApply(arguments);
res.done(function() {
self.ext.fixed._adjustLayout.call(self);
if (self.options.fixed.resizable) {
self.ext.fixed._makeTableResizable();
}
});
return res;
},
_makeTableResizable: function() {
var $wrapper = this.$fixedWrapper,
fcn = this.options.fixed.classNames,
$topLeftWrapper = $wrapper.find("div." + fcn.topLeft),
$topRightWrapper = $wrapper.find("div." + fcn.topRight),
$bottomLeftWrapper = $wrapper.find("div." + fcn.bottomLeft),
$bottomRightWrapper = $wrapper.find("div." + fcn.bottomRight);
function _makeResizable($table) {
$table.resizable({
handles: "e",
resize: function(evt, ui) {
var width = Math.max($table.width(), ui.size.width);
$bottomLeftWrapper.css("width", width);
$topLeftWrapper.css("width", width);
$bottomRightWrapper.css("left", width);
$topRightWrapper.css("left", width);
},
stop: function() {
$table.css("width", "100%");
},
});
}
_makeResizable($topLeftWrapper.find("table"));
_makeResizable($bottomLeftWrapper.find("table"));
},
/* Called by nodeRender to sync node order with tag order.*/
// nodeFixOrder: function(ctx) {
// },
nodeLoadChildren: function(ctx, source) {
return this._superApply(arguments);
},
nodeRemoveChildMarkup: function(ctx) {
var node = ctx.node;
function _removeChild(elem) {
var i,
child,
children = elem.children;
if (children) {
for (i = 0; i < children.length; i++) {
child = children[i];
if (child.trRight) {
$(child.trRight).remove();
}
_removeChild(child);
}
}
}
_removeChild(node);
return this._superApply(arguments);
},
nodeRemoveMarkup: function(ctx) {
var node = ctx.node;
if (node.trRight) {
$(node.trRight).remove();
}
return this._superApply(arguments);
},
nodeSetActive: function(ctx, flag, callOpts) {
var node = ctx.node,
cn = this.options._classNames;
if (node.trRight) {
$(node.trRight)
.toggleClass(cn.active, flag)
.toggleClass(cn.focused, flag);
}
return this._superApply(arguments);
},
nodeKeydown: function(ctx) {
return this._superApply(arguments);
},
nodeSetFocus: function(ctx, flag) {
var node = ctx.node,
cn = this.options._classNames;
if (node.trRight) {
$(node.trRight).toggleClass(cn.focused, flag);
}
return this._superApply(arguments);
},
nodeRender: function(ctx, force, deep, collapsed, _recursive) {
var res = this._superApply(arguments),
node = ctx.node,
isRootNode = !node.parent;
if (!isRootNode) {
var $trLeft = $(node.tr),
fcn = this.options.fixed.classNames,
$trRight = $trLeft.data(fcn.counterpart);
if (!$trRight && $trLeft.length) {
var idx = $trLeft.index(),
fixedColCount = this.options.fixed.fixCols,
$blTableBody = $(
"div." + fcn.bottomLeft + " table tbody"
),
$brTableBody = $(
"div." + fcn.bottomRight + " table tbody"
),
$prevLeftNode = $blTableBody
.find("tr")
.eq(Math.max(idx + 1, 0)),
prevRightNode = $prevLeftNode.data(fcn.counterpart);
$trRight = $trLeft.clone(true);
var trRight = $trRight.get(0);
if (prevRightNode) {
$(prevRightNode).before($trRight);
} else {
$brTableBody.append($trRight);
}
$trRight.show();
trRight.ftnode = node;
node.trRight = trRight;
$trLeft
.find("td")
.slice(fixedColCount)
.remove();
$trRight
.find("td")
.slice(0, fixedColCount)
.remove();
$trLeft.data(fcn.counterpart, $trRight);
$trRight.data(fcn.counterpart, $trLeft);
}
}
return res;
},
nodeRenderTitle: function(ctx, title) {
return this._superApply(arguments);
},
nodeRenderStatus: function(ctx) {
var res = this._superApply(arguments),
node = ctx.node;
if (node.trRight) {
var $trRight = $(node.trRight),
$trLeft = $(node.tr),
fcn = this.options.fixed.classNames,
hovering = $trRight.hasClass(fcn.hover),
trClasses = $trLeft.attr("class");
$trRight.attr("class", trClasses);
if (hovering) {
$trRight.addClass(fcn.hover);
$trLeft.addClass(fcn.hover);
}
}
return res;
},
nodeSetExpanded: function(ctx, flag, callOpts) {
var res,
self = this,
node = ctx.node,
$leftTr = $(node.tr),
fcn = this.options.fixed.classNames,
cn = this.options._classNames,
$rightTr = $leftTr.data(fcn.counterpart);
flag = typeof flag === "undefined" ? true : flag;
if (!$rightTr) {
return this._superApply(arguments);
}
$rightTr.toggleClass(cn.expanded, !!flag);
if (flag && !node.isExpanded()) {
res = this._superApply(arguments);
res.done(function() {
node.visit(function(child) {
var $trLeft = $(child.tr),
$trRight = $trLeft.data(fcn.counterpart);
self.ext.fixed._adjustRowHeight($trLeft, $trRight);
if (!child.expanded) {
return "skip";
}
});
self.ext.fixed._adjustColWidths();
self.ext.fixed._adjustWrapperLayout();
});
} else if (!flag && node.isExpanded()) {
node.visit(function(child) {
var $trLeft = $(child.tr),
$trRight = $trLeft.data(fcn.counterpart);
if ($trRight) {
if (!child.expanded) {
return "skip";
}
}
});
self.ext.fixed._adjustColWidths();
self.ext.fixed._adjustWrapperLayout();
res = this._superApply(arguments);
} else {
res = this._superApply(arguments);
}
return res;
},
nodeSetStatus: function(ctx, status, message, details) {
return this._superApply(arguments);
},
treeClear: function(ctx) {
var tree = ctx.tree,
$table = tree.widget.element,
$wrapper = this.$fixedWrapper,
fcn = this.options.fixed.classNames;
$table
.find("tr, td, th, thead")
.removeClass(fcn.hidden)
.css({
"min-width": "auto",
height: "auto",
});
$wrapper.empty().append($table);
return this._superApply(arguments);
},
treeRegisterNode: function(ctx, add, node) {
return this._superApply(arguments);
},
treeDestroy: function(ctx) {
var tree = ctx.tree,
$table = tree.widget.element,
$wrapper = this.$fixedWrapper,
fcn = this.options.fixed.classNames;
$table
.find("tr, td, th, thead")
.removeClass(fcn.hidden)
.css({
"min-width": "auto",
height: "auto",
});
$wrapper.empty().append($table);
return this._superApply(arguments);
},
_adjustColWidths: function() {
if (this.options.fixed.adjustColWidths) {
this.options.fixed.adjustColWidths.call(this);
return;
}
var $wrapper = this.$fixedWrapper,
fcn = this.options.fixed.classNames,
$tlWrapper = $wrapper.find("div." + fcn.topLeft),
$blWrapper = $wrapper.find("div." + fcn.bottomLeft),
$trWrapper = $wrapper.find("div." + fcn.topRight),
$brWrapper = $wrapper.find("div." + fcn.bottomRight);
function _adjust($topWrapper, $bottomWrapper) {
var $trTop = $topWrapper.find("thead tr").first(),
$trBottom = $bottomWrapper.find("tbody tr").first();
$trTop.find("th").each(function(idx) {
var $thTop = $(this),
$tdBottom = $trBottom.find("td").eq(idx),
thTopWidth = $thTop.width(),
thTopOuterWidth = $thTop.outerWidth(),
tdBottomWidth = $tdBottom.width(),
tdBottomOuterWidth = $tdBottom.outerWidth(),
newWidth = Math.max(
thTopOuterWidth,
tdBottomOuterWidth
);
$thTop.css(
"min-width",
newWidth - (thTopOuterWidth - thTopWidth)
);
$tdBottom.css(
"min-width",
newWidth - (tdBottomOuterWidth - tdBottomWidth)
);
});
}
_adjust($tlWrapper, $blWrapper);
_adjust($trWrapper, $brWrapper);
},
_adjustRowHeight: function($tr1, $tr2) {
var fcn = this.options.fixed.classNames;
if (!$tr2) {
$tr2 = $tr1.data(fcn.counterpart);
}
$tr1.css("height", "auto");
$tr2.css("height", "auto");
var row1Height = $tr1.outerHeight(),
row2Height = $tr2.outerHeight(),
newHeight = Math.max(row1Height, row2Height);
$tr1.css("height", newHeight + 1);
$tr2.css("height", newHeight + 1);
},
_adjustWrapperLayout: function() {
var $wrapper = this.$fixedWrapper,
fcn = this.options.fixed.classNames,
$topLeftWrapper = $wrapper.find("div." + fcn.topLeft),
$topRightWrapper = $wrapper.find("div." + fcn.topRight),
$bottomLeftWrapper = $wrapper.find("div." + fcn.bottomLeft),
$bottomRightWrapper = $wrapper.find("div." + fcn.bottomRight),
$topLeftTable = $topLeftWrapper.find("table"),
$topRightTable = $topRightWrapper.find("table"),
// $bottomLeftTable = $bottomLeftWrapper.find("table"),
wrapperWidth = $wrapper.width(),
wrapperHeight = $wrapper.height(),
fixedWidth = Math.min(wrapperWidth, $topLeftTable.width()),
fixedHeight = Math.min(
wrapperHeight,
Math.max($topLeftTable.height(), $topRightTable.height())
);
// vScrollbar = $bottomRightWrapper.get(0).scrollHeight > (wrapperHeight - fixedHeight),
// hScrollbar = $bottomRightWrapper.get(0).scrollWidth > (wrapperWidth - fixedWidth);
$topLeftWrapper.css({
width: fixedWidth,
height: fixedHeight,
});
$topRightWrapper.css({
// width: wrapperWidth - fixedWidth - (vScrollbar ? 17 : 0),
// width: "calc(100% - " + (fixedWidth + (vScrollbar ? 17 : 0)) + "px)",
width: "calc(100% - " + (fixedWidth + 17) + "px)",
height: fixedHeight,
left: fixedWidth,
});
$bottomLeftWrapper.css({
width: fixedWidth,
// height: vScrollbar ? wrapperHeight - fixedHeight - (hScrollbar ? 17 : 0) : "auto",
// height: vScrollbar ? ("calc(100% - " + (fixedHeight + (hScrollbar ? 17 : 0)) + "px)") : "auto",
// height: vScrollbar ? ("calc(100% - " + (fixedHeight + 17) + "px)") : "auto",
height: "calc(100% - " + (fixedHeight + 17) + "px)",
top: fixedHeight,
});
$bottomRightWrapper.css({
// width: wrapperWidth - fixedWidth,
// height: vScrollbar ? wrapperHeight - fixedHeight : "auto",
width: "calc(100% - " + fixedWidth + "px)",
// height: vScrollbar ? ("calc(100% - " + fixedHeight + "px)") : "auto",
height: "calc(100% - " + fixedHeight + "px)",
top: fixedHeight,
left: fixedWidth,
});
},
_adjustLayout: function() {
var self = this,
$wrapper = this.$fixedWrapper,
fcn = this.options.fixed.classNames,
$topLeftWrapper = $wrapper.find("div." + fcn.topLeft),
$topRightWrapper = $wrapper.find("div." + fcn.topRight),
$bottomLeftWrapper = $wrapper.find("div." + fcn.bottomLeft);
// $bottomRightWrapper = $wrapper.find("div." + fcn.bottomRight)
$topLeftWrapper.find("table tr").each(function(idx) {
var $trRight = $topRightWrapper.find("tr").eq(idx);
self.ext.fixed._adjustRowHeight($(this), $trRight);
});
$bottomLeftWrapper
.find("table tbody")
.find("tr")
.each(function(idx) {
// var $trRight = $bottomRightWrapper.find("tbody").find("tr").eq(idx);
self.ext.fixed._adjustRowHeight($(this));
});
self.ext.fixed._adjustColWidths.call(this);
self.ext.fixed._adjustWrapperLayout.call(this);
},
// treeSetFocus: function(ctx, flag) {
//// alert("treeSetFocus" + ctx.tree.$container);
// ctx.tree.$container.focus();
// $.ui.fancytree.focusTree = ctx.tree;
// }
});
// Value returned by `require('jquery.fancytree..')`
return $.ui.fancytree;
}); // End of closure

Datei anzeigen

@ -0,0 +1,356 @@
/*!
* jquery.fancytree.glyph.js
*
* Use glyph-fonts, ligature-fonts, or SVG icons instead of icon sprites.
* (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/)
*
* Copyright (c) 2008-2021, Martin Wendt (https://wwWendt.de)
*
* Released under the MIT license
* https://github.com/mar10/fancytree/wiki/LicenseInfo
*
* @version 2.38.0
* @date 2021-02-09T20:03:49Z
*/
(function(factory) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define(["jquery", "./jquery.fancytree"], factory);
} else if (typeof module === "object" && module.exports) {
// Node/CommonJS
require("./jquery.fancytree");
module.exports = factory(require("jquery"));
} else {
// Browser globals
factory(jQuery);
}
})(function($) {
"use strict";
/******************************************************************************
* Private functions and variables
*/
var FT = $.ui.fancytree,
PRESETS = {
awesome3: {
// Outdated!
_addClass: "",
checkbox: "icon-check-empty",
checkboxSelected: "icon-check",
checkboxUnknown: "icon-check icon-muted",
dragHelper: "icon-caret-right",
dropMarker: "icon-caret-right",
error: "icon-exclamation-sign",
expanderClosed: "icon-caret-right",
expanderLazy: "icon-angle-right",
expanderOpen: "icon-caret-down",
loading: "icon-refresh icon-spin",
nodata: "icon-meh",
noExpander: "",
radio: "icon-circle-blank",
radioSelected: "icon-circle",
// radioUnknown: "icon-circle icon-muted",
// Default node icons.
// (Use tree.options.icon callback to define custom icons based on node data)
doc: "icon-file-alt",
docOpen: "icon-file-alt",
folder: "icon-folder-close-alt",
folderOpen: "icon-folder-open-alt",
},
awesome4: {
_addClass: "fa",
checkbox: "fa-square-o",
checkboxSelected: "fa-check-square-o",
checkboxUnknown: "fa-square fancytree-helper-indeterminate-cb",
dragHelper: "fa-arrow-right",
dropMarker: "fa-long-arrow-right",
error: "fa-warning",
expanderClosed: "fa-caret-right",
expanderLazy: "fa-angle-right",
expanderOpen: "fa-caret-down",
// We may prevent wobbling rotations on FF by creating a separate sub element:
loading: { html: "<span class='fa fa-spinner fa-pulse' />" },
nodata: "fa-meh-o",
noExpander: "",
radio: "fa-circle-thin", // "fa-circle-o"
radioSelected: "fa-circle",
// radioUnknown: "fa-dot-circle-o",
// Default node icons.
// (Use tree.options.icon callback to define custom icons based on node data)
doc: "fa-file-o",
docOpen: "fa-file-o",
folder: "fa-folder-o",
folderOpen: "fa-folder-open-o",
},
awesome5: {
// fontawesome 5 have several different base classes
// "far, fas, fal and fab" The rendered svg puts that prefix
// in a different location so we have to keep them separate here
_addClass: "",
checkbox: "far fa-square",
checkboxSelected: "far fa-check-square",
// checkboxUnknown: "far fa-window-close",
checkboxUnknown:
"fas fa-square fancytree-helper-indeterminate-cb",
radio: "far fa-circle",
radioSelected: "fas fa-circle",
radioUnknown: "far fa-dot-circle",
dragHelper: "fas fa-arrow-right",
dropMarker: "fas fa-long-arrow-alt-right",
error: "fas fa-exclamation-triangle",
expanderClosed: "fas fa-caret-right",
expanderLazy: "fas fa-angle-right",
expanderOpen: "fas fa-caret-down",
loading: "fas fa-spinner fa-pulse",
nodata: "far fa-meh",
noExpander: "",
// Default node icons.
// (Use tree.options.icon callback to define custom icons based on node data)
doc: "far fa-file",
docOpen: "far fa-file",
folder: "far fa-folder",
folderOpen: "far fa-folder-open",
},
bootstrap3: {
_addClass: "glyphicon",
checkbox: "glyphicon-unchecked",
checkboxSelected: "glyphicon-check",
checkboxUnknown:
"glyphicon-expand fancytree-helper-indeterminate-cb", // "glyphicon-share",
dragHelper: "glyphicon-play",
dropMarker: "glyphicon-arrow-right",
error: "glyphicon-warning-sign",
expanderClosed: "glyphicon-menu-right", // glyphicon-plus-sign
expanderLazy: "glyphicon-menu-right", // glyphicon-plus-sign
expanderOpen: "glyphicon-menu-down", // glyphicon-minus-sign
loading: "glyphicon-refresh fancytree-helper-spin",
nodata: "glyphicon-info-sign",
noExpander: "",
radio: "glyphicon-remove-circle", // "glyphicon-unchecked",
radioSelected: "glyphicon-ok-circle", // "glyphicon-check",
// radioUnknown: "glyphicon-ban-circle",
// Default node icons.
// (Use tree.options.icon callback to define custom icons based on node data)
doc: "glyphicon-file",
docOpen: "glyphicon-file",
folder: "glyphicon-folder-close",
folderOpen: "glyphicon-folder-open",
},
material: {
_addClass: "material-icons",
checkbox: { text: "check_box_outline_blank" },
checkboxSelected: { text: "check_box" },
checkboxUnknown: { text: "indeterminate_check_box" },
dragHelper: { text: "play_arrow" },
dropMarker: { text: "arrow-forward" },
error: { text: "warning" },
expanderClosed: { text: "chevron_right" },
expanderLazy: { text: "last_page" },
expanderOpen: { text: "expand_more" },
loading: {
text: "autorenew",
addClass: "fancytree-helper-spin",
},
nodata: { text: "info" },
noExpander: { text: "" },
radio: { text: "radio_button_unchecked" },
radioSelected: { text: "radio_button_checked" },
// Default node icons.
// (Use tree.options.icon callback to define custom icons based on node data)
doc: { text: "insert_drive_file" },
docOpen: { text: "insert_drive_file" },
folder: { text: "folder" },
folderOpen: { text: "folder_open" },
},
};
function setIcon(node, span, baseClass, opts, type) {
var map = opts.map,
icon = map[type],
$span = $(span),
$counter = $span.find(".fancytree-childcounter"),
setClass = baseClass + " " + (map._addClass || "");
// #871 Allow a callback
if ($.isFunction(icon)) {
icon = icon.call(this, node, span, type);
}
// node.debug( "setIcon(" + baseClass + ", " + type + "): " + "oldIcon" + " -> " + icon );
// #871: propsed this, but I am not sure how robust this is, e.g.
// the prefix (fas, far) class changes are not considered?
// if (span.tagName === "svg" && opts.preset === "awesome5") {
// // fa5 script converts <i> to <svg> so call a specific handler.
// var oldIcon = "fa-" + $span.data("icon");
// // node.debug( "setIcon(" + baseClass + ", " + type + "): " + oldIcon + " -> " + icon );
// if (typeof oldIcon === "string") {
// $span.removeClass(oldIcon);
// }
// if (typeof icon === "string") {
// $span.addClass(icon);
// }
// return;
// }
if (typeof icon === "string") {
// #883: remove inner html that may be added by prev. mode
span.innerHTML = "";
$span.attr("class", setClass + " " + icon).append($counter);
} else if (icon) {
if (icon.text) {
span.textContent = "" + icon.text;
} else if (icon.html) {
span.innerHTML = icon.html;
} else {
span.innerHTML = "";
}
$span
.attr("class", setClass + " " + (icon.addClass || ""))
.append($counter);
}
}
$.ui.fancytree.registerExtension({
name: "glyph",
version: "2.38.0",
// Default options for this extension.
options: {
preset: null, // 'awesome3', 'awesome4', 'bootstrap3', 'material'
map: {},
},
treeInit: function(ctx) {
var tree = ctx.tree,
opts = ctx.options.glyph;
if (opts.preset) {
FT.assert(
!!PRESETS[opts.preset],
"Invalid value for `options.glyph.preset`: " + opts.preset
);
opts.map = $.extend({}, PRESETS[opts.preset], opts.map);
} else {
tree.warn("ext-glyph: missing `preset` option.");
}
this._superApply(arguments);
tree.$container.addClass("fancytree-ext-glyph");
},
nodeRenderStatus: function(ctx) {
var checkbox,
icon,
res,
span,
node = ctx.node,
$span = $(node.span),
opts = ctx.options.glyph;
res = this._super(ctx);
if (node.isRootNode()) {
return res;
}
span = $span.children(".fancytree-expander").get(0);
if (span) {
// if( node.isLoading() ){
// icon = "loading";
if (node.expanded && node.hasChildren()) {
icon = "expanderOpen";
} else if (node.isUndefined()) {
icon = "expanderLazy";
} else if (node.hasChildren()) {
icon = "expanderClosed";
} else {
icon = "noExpander";
}
// span.className = "fancytree-expander " + map[icon];
setIcon(node, span, "fancytree-expander", opts, icon);
}
if (node.tr) {
span = $("td", node.tr)
.find(".fancytree-checkbox")
.get(0);
} else {
span = $span.children(".fancytree-checkbox").get(0);
}
if (span) {
checkbox = FT.evalOption("checkbox", node, node, opts, false);
if (
(node.parent && node.parent.radiogroup) ||
checkbox === "radio"
) {
icon = node.selected ? "radioSelected" : "radio";
setIcon(
node,
span,
"fancytree-checkbox fancytree-radio",
opts,
icon
);
} else {
// eslint-disable-next-line no-nested-ternary
icon = node.selected
? "checkboxSelected"
: node.partsel
? "checkboxUnknown"
: "checkbox";
// span.className = "fancytree-checkbox " + map[icon];
setIcon(node, span, "fancytree-checkbox", opts, icon);
}
}
// Standard icon (note that this does not match .fancytree-custom-icon,
// that might be set by opts.icon callbacks)
span = $span.children(".fancytree-icon").get(0);
if (span) {
if (node.statusNodeType) {
icon = node.statusNodeType; // loading, error
} else if (node.folder) {
icon =
node.expanded && node.hasChildren()
? "folderOpen"
: "folder";
} else {
icon = node.expanded ? "docOpen" : "doc";
}
setIcon(node, span, "fancytree-icon", opts, icon);
}
return res;
},
nodeSetStatus: function(ctx, status, message, details) {
var res,
span,
opts = ctx.options.glyph,
node = ctx.node;
res = this._superApply(arguments);
if (
status === "error" ||
status === "loading" ||
status === "nodata"
) {
if (node.parent) {
span = $(".fancytree-expander", node.span).get(0);
if (span) {
setIcon(node, span, "fancytree-expander", opts, status);
}
} else {
//
span = $(
".fancytree-statusnode-" + status,
node[this.nodeContainerAttrName]
)
.find(".fancytree-icon")
.get(0);
if (span) {
setIcon(node, span, "fancytree-icon", opts, status);
}
}
}
return res;
},
});
// Value returned by `require('jquery.fancytree..')`
return $.ui.fancytree;
}); // End of closure

Datei-Diff unterdrückt, da er zu groß ist Diff laden

Datei anzeigen

@ -0,0 +1,223 @@
/*!
* 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-2021, Martin Wendt (https://wwWendt.de)
*
* Released under the MIT license
* https://github.com/mar10/fancytree/wiki/LicenseInfo
*
* @version 2.38.0
* @date 2021-02-09T20:03:49Z
*/
(function(factory) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define([
"jquery",
"./jquery.fancytree",
"./jquery.fancytree.table",
], factory);
} else if (typeof module === "object" && module.exports) {
// Node/CommonJS
require("./jquery.fancytree.table"); // core + table
module.exports = factory(require("jquery"));
} else {
// Browser globals
factory(jQuery);
}
})(function($) {
"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],
link: [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,a").length) {
break;
}
}
break;
}
return $tdNext;
}
/*******************************************************************************
* Extension code
*/
$.ui.fancytree.registerExtension({
name: "gridnav",
version: "2.38.0",
// 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, callOpts) {
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);
if ($target.is(":input:enabled")) {
inputType = $target.prop("type");
} else if ($target.is("a")) {
inputType = "link";
}
// 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);
if ($td && $td.length) {
// ctx.node.debug("ignore keydown in input", event.which, handleKeys);
$td.find(":input:enabled,a").focus();
// Prevent Fancytree default navigation
return false;
}
}
return true;
}
// ctx.tree.debug("ext-gridnav NOT HANDLED", event, inputType);
return this._superApply(arguments);
},
});
// Value returned by `require('jquery.fancytree..')`
return $.ui.fancytree;
}); // End of closure

Datei-Diff unterdrückt, da er zu groß ist Diff laden

Datei anzeigen

@ -0,0 +1,307 @@
/*!
* jquery.fancytree.logger.js
*
* Miscellaneous debug extensions.
* (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/)
*
* Copyright (c) 2008-2021, Martin Wendt (https://wwWendt.de)
*
* Released under the MIT license
* https://github.com/mar10/fancytree/wiki/LicenseInfo
*
* @version 2.38.0
* @date 2021-02-09T20:03:49Z
*/
(function(factory) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define(["jquery", "./jquery.fancytree"], factory);
} else if (typeof module === "object" && module.exports) {
// Node/CommonJS
require("./jquery.fancytree");
module.exports = factory(require("jquery"));
} else {
// Browser globals
factory(jQuery);
}
})(function($) {
"use strict";
/******************************************************************************
* Private functions and variables
*/
var i,
FT = $.ui.fancytree,
PREFIX = "ft-logger: ",
logLine = window.console.log,
// HOOK_NAMES = "nodeClick nodeCollapseSiblings".split(" "),
TREE_EVENT_NAMES = "beforeRestore beforeUpdateViewport blurTree create init focusTree preInit restore updateViewport".split(
" "
),
NODE_EVENT_NAMES = "activate activateCell beforeActivate beforeExpand beforeSelect blur click collapse createNode dblclick deactivate defaultGridAction expand enhanceTitle focus keydown keypress lazyLoad loadChildren loadError modifyChild postProcess renderNode renderTitle select".split(
" "
),
EVENT_NAMES = TREE_EVENT_NAMES.concat(NODE_EVENT_NAMES),
// 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;
}
function getBrowserInfo() {
var n = navigator.appName,
ua = navigator.userAgent,
tem,
m = ua.match(
/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i
);
if (m && (tem = ua.match(/version\/([.\d]+)/i)) !== null) {
m[2] = tem[1];
}
m = m ? [m[1], m[2]] : [n, navigator.appVersion, "-?"];
return m.join(", ");
}
function logEvent(event, data) {
var res,
self = this,
// logName = PREFIX + "event." + event.type,
opts = data.options.logger,
tree = data.tree,
// widget = data.widget,
obj = data.node || tree,
logName = PREFIX + "event." + event.type + " (" + obj + ")";
if (
!opts.traceEvents ||
(opts.traceEvents !== true && $.inArray(name, opts.traceEvents) < 0)
) {
return self._super.apply(self, arguments);
}
if (
(self._super && opts.timings === true) ||
(opts.timings && $.inArray(name, opts.timings) >= 0)
) {
// if( name === "nodeRender" ) { logName += obj; } // allow timing for recursive calls
// logName += " (" + obj + ")";
window.console.time(logName);
res = self._super.apply(self, arguments);
window.console.timeEnd(logName);
} else {
// obj.info(logName, data);
logLine(logName, event, data);
res = self._super.apply(self, arguments);
}
return res;
}
function logHook(name, this_, args, extra) {
var res,
ctx = args[0],
opts = ctx.options.logger,
obj = ctx.node || ctx.tree,
logName = PREFIX + "hook." + name + " (" + obj + ")";
if (
!opts.traceHooks ||
(opts.traceHooks !== true && $.inArray(name, opts.traceHooks) < 0)
) {
return this_._superApply.call(this_, args);
}
if (
opts.timings === true ||
(opts.timings && $.inArray(name, opts.timings) >= 0)
) {
// if( name === "nodeRender" ) { logName += obj; } // allow timing for recursive calls
// logName += " (" + obj + ")";
window.console.time(logName);
res = this_._superApply.call(this_, args);
window.console.timeEnd(logName);
} else {
if (extra) {
// obj.info(logName, extra, ctx);
logLine(logName, extra, ctx);
} else {
// obj.info(logName, ctx);
logLine(logName, ctx);
}
res = this_._superApply.call(this_, args);
}
return res;
}
/******************************************************************************
* Extension code
*/
$.ui.fancytree.registerExtension({
name: "logger",
version: "2.38.0",
// Default options for this extension.
options: {
logTarget: null, // optional redirect logging to this <div> tag
traceEvents: true, // `true`or list of hook names
traceUnhandledEvents: false,
traceHooks: false, // `true`or list of event names
timings: 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)
treeCreate: function(ctx) {
var tree = ctx.tree,
opts = ctx.options;
if (
this.options.extensions[this.options.extensions.length - 1] !==
"logger"
) {
throw Error(
"Fancytree 'logger' extension must be listed as last entry."
);
}
tree.warn(
"Fancytree logger extension is enabled (this may be slow).",
opts.logger
);
tree.debug(
"Fancytree v" +
$.ui.fancytree.version +
", buildType='" +
$.ui.fancytree.buildType +
"'"
);
tree.debug(
"jQuery UI " +
jQuery.ui.version +
" (uiBackCompat=" +
$.uiBackCompat +
")"
);
tree.debug("jQuery " + jQuery.fn.jquery);
tree.debug("Browser: " + getBrowserInfo());
function _log(event, data) {
logLine(
PREFIX + "event." + event.type + " (unhandled)",
event,
data
);
}
$.each(EVENT_NAMES, function(i, name) {
if (typeof opts[name] === "function") {
// tree.info(PREFIX + "override '" + name + "' event");
$.ui.fancytree.overrideMethod(
opts,
name,
logEvent,
ctx.widget
);
} else if (opts.logger.traceUnhandledEvents) {
opts[name] = _log;
}
});
return logHook("treeCreate", this, arguments);
},
nodeClick: function(ctx) {
return logHook(
"nodeClick",
this,
arguments,
FT.eventToString(ctx.originalEvent)
);
},
nodeCollapseSiblings: function(ctx) {
return logHook("nodeCollapseSiblings", this, arguments);
},
nodeDblclick: function(ctx) {
return logHook("nodeDblclick", this, arguments);
},
nodeKeydown: function(ctx) {
return logHook(
"nodeKeydown",
this,
arguments,
FT.eventToString(ctx.originalEvent)
);
},
nodeLoadChildren: function(ctx, source) {
return logHook("nodeLoadChildren", this, arguments);
},
nodeRemoveChildMarkup: function(ctx) {
return logHook("nodeRemoveChildMarkup", this, arguments);
},
nodeRemoveMarkup: function(ctx) {
return logHook("nodeRemoveMarkup", this, arguments);
},
nodeRender: function(ctx, force, deep, collapsed, _recursive) {
return logHook("nodeRender", this, arguments);
},
nodeRenderStatus: function(ctx) {
return logHook("nodeRenderStatus", this, arguments);
},
nodeRenderTitle: function(ctx, title) {
return logHook("nodeRenderTitle", this, arguments);
},
nodeSetActive: function(ctx, flag, callOpts) {
return logHook("nodeSetActive", this, arguments);
},
nodeSetExpanded: function(ctx, flag, callOpts) {
return logHook("nodeSetExpanded", this, arguments);
},
nodeSetFocus: function(ctx) {
return logHook("nodeSetFocus", this, arguments);
},
nodeSetSelected: function(ctx, flag, callOpts) {
return logHook("nodeSetSelected", this, arguments);
},
nodeSetStatus: function(ctx, status, message, details) {
return logHook("nodeSetStatus", this, arguments);
},
nodeToggleExpanded: function(ctx) {
return logHook("nodeToggleExpanded", this, arguments);
},
nodeToggleSelected: function(ctx) {
return logHook("nodeToggleSelected", this, arguments);
},
treeClear: function(ctx) {
return logHook("treeClear", this, arguments);
},
// treeCreate: function(ctx) {
// return logHook("treeCreate", this, arguments);
// },
treeDestroy: function(ctx) {
return logHook("treeDestroy", this, arguments);
},
treeInit: function(ctx) {
return logHook("treeInit", this, arguments);
},
treeLoad: function(ctx, source) {
return logHook("treeLoad", this, arguments);
},
treeRegisterNode: function(ctx, add, node) {
return logHook("treeRegisterNode", this, arguments);
},
treeSetFocus: function(ctx, flag, callOpts) {
return logHook("treeSetFocus", this, arguments);
},
treeSetOption: function(ctx, key, value) {
return logHook("treeSetOption", this, arguments);
},
treeStructureChanged: function(ctx, type) {
return logHook("treeStructureChanged", this, arguments);
},
});
// Value returned by `require('jquery.fancytree..')`
return $.ui.fancytree;
}); // End of closure

Datei anzeigen

@ -0,0 +1,183 @@
/*!
* 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-2021, Martin Wendt (https://wwWendt.de)
*
* Released under the MIT license
* https://github.com/mar10/fancytree/wiki/LicenseInfo
*
* @version 2.38.0
* @date 2021-02-09T20:03:49Z
*/
(function(factory) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define(["jquery", "./jquery.fancytree"], factory);
} else if (typeof module === "object" && module.exports) {
// Node/CommonJS
require("./jquery.fancytree");
module.exports = factory(require("jquery"));
} else {
// Browser globals
factory(jQuery);
}
})(function($) {
"use strict";
$.ui.fancytree.registerExtension({
name: "menu",
version: "2.38.0",
// 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.on("contextmenu", "span.fancytree-node", 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)
.on("keydown.fancytree", function(event) {
if (event.which === $.ui.keyCode.ESCAPE) {
tree.ext.menu._closeMenu(ctx);
}
})
.on("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).off("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);
// }
});
// Value returned by `require('jquery.fancytree..')`
return $.ui.fancytree;
}); // End of closure

Datei anzeigen

@ -0,0 +1,128 @@
/*!
* jquery.fancytree.multi.js
*
* Allow multiple selection of nodes by mouse or keyboard.
* (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/)
*
* Copyright (c) 2008-2021, Martin Wendt (https://wwWendt.de)
*
* Released under the MIT license
* https://github.com/mar10/fancytree/wiki/LicenseInfo
*
* @version 2.38.0
* @date 2021-02-09T20:03:49Z
*/
(function(factory) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define(["jquery", "./jquery.fancytree"], factory);
} else if (typeof module === "object" && module.exports) {
// Node/CommonJS
require("./jquery.fancytree");
module.exports = factory(require("jquery"));
} else {
// Browser globals
factory(jQuery);
}
})(function($) {
"use strict";
/*******************************************************************************
* Private functions and variables
*/
// var isMac = /Mac/.test(navigator.platform);
/*******************************************************************************
* Extension code
*/
$.ui.fancytree.registerExtension({
name: "multi",
version: "2.38.0",
// Default options for this extension.
options: {
allowNoSelect: false, //
mode: "sameParent", //
// Events:
// beforeSelect: $.noop // Return false to prevent cancel/save (data.input is available)
},
treeInit: function(ctx) {
this._superApply(arguments);
this.$container.addClass("fancytree-ext-multi");
if (ctx.options.selectMode === 1) {
$.error(
"Fancytree ext-multi: selectMode: 1 (single) is not compatible."
);
}
},
nodeClick: function(ctx) {
var //pluginOpts = ctx.options.multi,
tree = ctx.tree,
node = ctx.node,
activeNode = tree.getActiveNode() || tree.getFirstChild(),
isCbClick = ctx.targetType === "checkbox",
isExpanderClick = ctx.targetType === "expander",
eventStr = $.ui.fancytree.eventToString(ctx.originalEvent);
switch (eventStr) {
case "click":
if (isExpanderClick) {
break;
} // Default handler will expand/collapse
if (!isCbClick) {
tree.selectAll(false);
// Select clicked node (radio-button mode)
node.setSelected();
}
// Default handler will toggle checkbox clicks and activate
break;
case "shift+click":
// node.debug("click")
tree.visitRows(
function(n) {
// n.debug("click2", n===node, node)
n.setSelected();
if (n === node) {
return false;
}
},
{
start: activeNode,
reverse: activeNode.isBelowOf(node),
}
);
break;
case "ctrl+click":
case "meta+click": // Mac: [Command]
node.toggleSelected();
return;
}
return this._superApply(arguments);
},
nodeKeydown: function(ctx) {
var tree = ctx.tree,
node = ctx.node,
event = ctx.originalEvent,
eventStr = $.ui.fancytree.eventToString(event);
switch (eventStr) {
case "up":
case "down":
tree.selectAll(false);
node.navigate(event.which, true);
tree.getActiveNode().setSelected();
break;
case "shift+up":
case "shift+down":
node.navigate(event.which, true);
tree.getActiveNode().setSelected();
break;
}
return this._superApply(arguments);
},
});
// Value returned by `require('jquery.fancytree..')`
return $.ui.fancytree;
}); // End of closure

Datei anzeigen

@ -0,0 +1,505 @@
/*!
* 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-2021, Martin Wendt (https://wwWendt.de)
*
* Released under the MIT license
* https://github.com/mar10/fancytree/wiki/LicenseInfo
*
* @version 2.38.0
* @date 2021-02-09T20:03:49Z
*/
(function(factory) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define(["jquery", "./jquery.fancytree"], factory);
} else if (typeof module === "object" && module.exports) {
// Node/CommonJS
require("./jquery.fancytree");
module.exports = factory(require("jquery"));
} else {
// Browser globals
factory(jQuery);
}
})(function($) {
"use strict";
/* global Cookies:false */
/*******************************************************************************
* Private functions and variables
*/
var cookieStore = null,
localStorageStore = null,
sessionStorageStore = null,
_assert = $.ui.fancytree.assert,
ACTIVE = "active",
EXPANDED = "expanded",
FOCUS = "focus",
SELECTED = "selected";
// Accessing window.xxxStorage may raise security exceptions (see #1022)
try {
_assert(window.localStorage && window.localStorage.getItem);
localStorageStore = {
get: function(key) {
return window.localStorage.getItem(key);
},
set: function(key, value) {
window.localStorage.setItem(key, value);
},
remove: function(key) {
window.localStorage.removeItem(key);
},
};
} catch (e) {
$.ui.fancytree.warn("Could not access window.localStorage", e);
}
try {
_assert(window.sessionStorage && window.sessionStorage.getItem);
sessionStorageStore = {
get: function(key) {
return window.sessionStorage.getItem(key);
},
set: function(key, value) {
window.sessionStorage.setItem(key, value);
},
remove: function(key) {
window.sessionStorage.removeItem(key);
},
};
} catch (e) {
$.ui.fancytree.warn("Could not access window.sessionStorage", e);
}
if (typeof Cookies === "function") {
// Assume https://github.com/js-cookie/js-cookie
cookieStore = {
get: Cookies.get,
set: function(key, value) {
Cookies.set(key, value, this.options.persist.cookie);
},
remove: Cookies.remove,
};
} else if ($ && typeof $.cookie === "function") {
// Fall back to https://github.com/carhartl/jquery-cookie
cookieStore = {
get: $.cookie,
set: function(key, value) {
$.cookie.set(key, value, this.options.persist.cookie);
},
remove: $.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,
expandOpts = tree.options.persist.expandOpts,
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(true, expandOpts));
} else {
deferredList.push(node.load());
}
} else {
tree.debug("_loadLazyNodes: " + node + " already loaded.");
node.setExpanded(true, expandOpts);
}
} 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 data of the given type(s).
* Called like
* $.ui.fancytree.getTree("#tree").clearCookies("active expanded focus selected");
*
* @alias Fancytree#clearPersistData
* @requires jquery.fancytree.persist.js
*/
$.ui.fancytree._FancytreeClass.prototype.clearPersistData = 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);
}
};
$.ui.fancytree._FancytreeClass.prototype.clearCookies = function(types) {
this.warn(
"'tree.clearCookies()' is deprecated since v2.27.0: use 'clearPersistData()' instead."
);
return this.clearPersistData(types);
};
/**
* [ext-persist] Return persistence information from cookies
*
* Called like
* $.ui.fancytree.getTree("#tree").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: "2.38.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
expandOpts: undefined, // optional `opts` argument passed to setExpanded()
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 store = this._local.store;
if (value === undefined) {
return store.get.call(this, key);
} else if (value === null) {
store.remove.call(this, key);
} else {
store.set.call(this, key, value);
}
},
/* 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") || cookieStore,
// "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;
local.store = null;
if (instOpts.store === "auto") {
instOpts.store = localStorageStore ? "local" : "cookie";
}
if ($.isPlainObject(instOpts.store)) {
local.store = instOpts.store;
} else if (instOpts.store === "cookie") {
local.store = cookieStore;
} else if (instOpts.store === "local") {
local.store =
instOpts.store === "local"
? localStorageStore
: sessionStorageStore;
} else if (instOpts.store === "session") {
local.store =
instOpts.store === "local"
? localStorageStore
: sessionStorageStore;
}
_assert(local.store, "Need a valid store.");
// Bind init-handler to apply cookie state
tree.$div.on("fancytreeinit", function(event) {
if (
tree._triggerTreeEvent("beforeRestore", null, {}) === false
) {
return;
}
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, callOpts) {
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, callOpts) {
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, callOpts) {
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;
},
});
// Value returned by `require('jquery.fancytree..')`
return $.ui.fancytree;
}); // End of closure

Datei anzeigen

@ -0,0 +1,541 @@
/*!
* jquery.fancytree.table.js
*
* Render tree as table (aka 'tree grid', 'table tree').
* (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/)
*
* Copyright (c) 2008-2021, Martin Wendt (https://wwWendt.de)
*
* Released under the MIT license
* https://github.com/mar10/fancytree/wiki/LicenseInfo
*
* @version 2.38.0
* @date 2021-02-09T20:03:49Z
*/
(function(factory) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define(["jquery", "./jquery.fancytree"], factory);
} else if (typeof module === "object" && module.exports) {
// Node/CommonJS
require("./jquery.fancytree");
module.exports = factory(require("jquery"));
} else {
// Browser globals
factory(jQuery);
}
})(function($) {
"use strict";
/******************************************************************************
* Private functions and variables
*/
var _assert = $.ui.fancytree.assert;
function insertFirstChild(referenceNode, newNode) {
referenceNode.insertBefore(newNode, referenceNode.firstChild);
}
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 && prev.children.length) {
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: "2.38.0",
// Default options for this extension.
options: {
checkboxColumnIdx: null, // render the checkboxes into the this column index (default: nodeColumnIdx)
indentation: 16, // indent every node level by 16px
mergeStatusColumns: true, // display 'nodata', 'loading', 'error' centered in a single, merged TR
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,
n,
$row,
$tbody,
tree = ctx.tree,
opts = ctx.options,
tableOpts = opts.table,
$table = tree.widget.element;
if (tableOpts.customStatus != null) {
if (opts.renderStatusColumns == null) {
tree.warn(
"The 'customStatus' option is deprecated since v2.15.0. Use 'renderStatusColumns' instead."
);
opts.renderStatusColumns = tableOpts.customStatus;
} else {
$.error(
"The 'customStatus' option is deprecated since v2.15.0. Use 'renderStatusColumns' only instead."
);
}
}
if (opts.renderStatusColumns) {
if (opts.renderStatusColumns === true) {
opts.renderStatusColumns = opts.renderColumns;
// } else if( opts.renderStatusColumns === "wide" ) {
// opts.renderStatusColumns = _renderStatusNodeWide;
}
}
$table.addClass("fancytree-container fancytree-ext-table");
$tbody = $table.find(">tbody");
if (!$tbody.length) {
// TODO: not sure if we can rely on browsers to insert missing <tbody> before <tr>s:
if ($table.find(">tr").length) {
$.error(
"Expected table > tbody > tr. If you see this please open an issue."
);
}
$tbody = $("<tbody>").appendTo($table);
}
tree.tbody = $tbody[0];
// Prepare row templates:
// Determine column count from table header if any
tree.columnCount = $("thead >tr", $table)
.last()
.find(">th", $table).length;
// Read TR templates from tbody if any
$row = $tbody.children("tr").first();
if ($row.length) {
n = $row.children("td").length;
if (tree.columnCount && n !== tree.columnCount) {
tree.warn(
"Column count mismatch between thead (" +
tree.columnCount +
") and tbody (" +
n +
"): using tbody."
);
tree.columnCount = n;
}
$row = $row.clone();
} else {
// Only thead is defined: create default row markup
_assert(
tree.columnCount >= 1,
"Need either <thead> or <tbody> with <td> elements to determine column count."
);
$row = $("<tr />");
for (i = 0; i < tree.columnCount; i++) {
$row.append("<td />");
}
}
$row.find(">td")
.eq(tableOpts.nodeColumnIdx)
.html("<span class='fancytree-node' />");
if (opts.aria) {
$row.attr("role", "row");
$row.find("td").attr("role", "gridcell");
}
tree.rowFragment = document.createDocumentFragment();
tree.rowFragment.appendChild($row.get(0));
// // If tbody contains a second row, use this as status node template
// $row = $tbody.children("tr").eq(1);
// if( $row.length === 0 ) {
// tree.statusRowFragment = tree.rowFragment;
// } else {
// $row = $row.clone();
// tree.statusRowFragment = document.createDocumentFragment();
// tree.statusRowFragment.appendChild($row.get(0));
// }
//
$tbody.empty();
// 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;
// Add container to the TAB chain
// #577: Allow to set tabindex to "0", "-1" and ""
this.$container.attr("tabindex", opts.tabindex);
// this.$container.attr("tabindex", opts.tabbable ? "0" : "-1");
if (opts.aria) {
tree.$container
.attr("role", "treegrid")
.attr("aria-readonly", true);
}
},
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 (tree._enableUpdate === false) {
// $.ui.fancytree.debug("*** nodeRender _enableUpdate: false");
return;
}
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 && force) {
this.nodeRemoveMarkup(ctx);
}
if (node.tr) {
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);
}
} else {
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
// if( node.isStatusNode() ) {
// newRow = tree.statusRowFragment.firstChild.cloneNode(true);
// } else {
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) {
insertSiblingAfter(prevNode.tr, newRow);
} else {
_assert(
!prevNode.parent,
"prev. row must have a tr, or be system root"
);
// tree.tbody.appendChild(newRow);
insertFirstChild(tree.tbody, newRow); // #675
}
node.tr = newRow;
if (node.key && opts.generateIds) {
node.tr.id = opts.idPrefix + node.key;
}
node.tr.ftnode = node;
// if(opts.aria){
// $(node.tr).attr("aria-labelledby", "ftal_" + opts.idPrefix + 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);
}
}
}
// 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,
res,
tree = ctx.tree,
node = ctx.node,
opts = ctx.options,
isStatusNode = node.isStatusNode();
res = this._super(ctx, title);
if (node.isRootNode()) {
return res;
}
// Move checkbox to custom column
if (
opts.checkbox &&
!isStatusNode &&
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
this.nodeRenderStatus(ctx);
if (isStatusNode) {
if (opts.renderStatusColumns) {
// Let user code write column content
opts.renderStatusColumns.call(
tree,
{ type: "renderStatusColumns" },
ctx
);
} else if (opts.table.mergeStatusColumns && node.isTopLevel()) {
$(node.tr)
.find(">td")
.eq(0)
.prop("colspan", tree.columnCount)
.text(node.title)
.addClass("fancytree-status-merged")
.nextAll()
.remove();
} // else: default rendering for status node: leave other cells empty
} else if (opts.renderColumns) {
opts.renderColumns.call(tree, { type: "renderColumns" }, ctx);
}
return res;
},
nodeRenderStatus: function(ctx) {
var indent,
node = ctx.node,
opts = ctx.options;
this._super(ctx);
$(node.tr).removeClass("fancytree-node");
// indent
indent = (node.getLevel() - 1) * opts.table.indentation;
if (opts.rtl) {
$(node.span).css({ paddingRight: indent + "px" });
} else {
$(node.span).css({ paddingLeft: indent + "px" });
}
},
/* Expand node, return Deferred.promise. */
nodeSetExpanded: function(ctx, flag, callOpts) {
// flag defaults to true
flag = flag !== false;
if ((ctx.node.expanded && flag) || (!ctx.node.expanded && !flag)) {
// Expanded state isn't changed - just call base implementation
return this._superApply(arguments);
}
var dfd = new $.Deferred(),
subOpts = $.extend({}, callOpts, {
noEvents: true,
noAnimation: true,
});
callOpts = callOpts || {};
function _afterExpand(ok) {
setChildRowVisibility(ctx.node, flag);
if (ok) {
if (
flag &&
ctx.options.autoScroll &&
!callOpts.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 (!callOpts.noEvents) {
ctx.tree._triggerNodeEvent(
flag ? "expand" : "collapse",
ctx
);
}
dfd.resolveWith(ctx.node);
});
} else {
if (!callOpts.noEvents) {
ctx.tree._triggerNodeEvent(
flag ? "expand" : "collapse",
ctx
);
}
dfd.resolveWith(ctx.node);
}
} else {
if (!callOpts.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();
if (this.$source) {
this.$source.removeClass("fancytree-helper-hidden");
}
return this._superApply(arguments);
},
/*,
treeSetFocus: function(ctx, flag) {
// alert("treeSetFocus" + ctx.tree.$container);
ctx.tree.$container.focus();
$.ui.fancytree.focusTree = ctx.tree;
}*/
});
// Value returned by `require('jquery.fancytree..')`
return $.ui.fancytree;
}); // End of closure

Datei anzeigen

@ -0,0 +1,121 @@
/*!
* 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-2021, Martin Wendt (https://wwWendt.de)
*
* Released under the MIT license
* https://github.com/mar10/fancytree/wiki/LicenseInfo
*
* @version 2.38.0
* @date 2021-02-09T20:03:49Z
*/
(function(factory) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define(["jquery", "./jquery.fancytree"], factory);
} else if (typeof module === "object" && module.exports) {
// Node/CommonJS
require("./jquery.fancytree");
module.exports = factory(require("jquery"));
} else {
// Browser globals
factory(jQuery);
}
})(function($) {
"use strict";
/*******************************************************************************
* Extension code
*/
$.ui.fancytree.registerExtension({
name: "themeroller",
version: "2.38.0",
// Default options for this extension.
options: {
activeClass: "ui-state-active", // Class added to active node
// activeClass: "ui-state-highlight",
addClass: "ui-corner-all", // Class added to all nodes
focusClass: "ui-state-focus", // Class added to focused node
hoverClass: "ui-state-hover", // Class added to hovered node
selectedClass: "ui-state-highlight", // Class added to selected nodes
// selectedClass: "ui-state-active"
},
treeInit: function(ctx) {
var $el = ctx.widget.element,
opts = ctx.options.themeroller;
this._superApply(arguments);
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.on("mouseenter mouseleave", ".fancytree-node", function(event) {
var node = $.ui.fancytree.getNode(event.target),
flag = event.type === "mouseenter";
$(node.tr ? node.tr : node.span).toggleClass(
opts.hoverClass + " " + opts.addClass,
flag
);
});
},
treeDestroy: function(ctx) {
this._superApply(arguments);
ctx.widget.element.removeClass(
"ui-widget ui-widget-content ui-corner-all"
);
},
nodeRenderStatus: function(ctx) {
var classes = {},
node = ctx.node,
$el = $(node.tr ? node.tr : node.span),
opts = ctx.options.themeroller;
this._super(ctx);
/*
.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.
*/
// Set ui-state-* class (handle the case that the same class is assigned
// to different states)
classes[opts.activeClass] = false;
classes[opts.focusClass] = false;
classes[opts.selectedClass] = false;
if (node.isActive()) {
classes[opts.activeClass] = true;
}
if (node.hasFocus()) {
classes[opts.focusClass] = true;
}
// activeClass takes precedence before selectedClass:
if (node.isSelected() && !node.isActive()) {
classes[opts.selectedClass] = true;
}
$el.toggleClass(opts.activeClass, classes[opts.activeClass]);
$el.toggleClass(opts.focusClass, classes[opts.focusClass]);
$el.toggleClass(opts.selectedClass, classes[opts.selectedClass]);
// Additional classes (e.g. 'ui-corner-all')
$el.addClass(opts.addClass);
},
});
// Value returned by `require('jquery.fancytree..')`
return $.ui.fancytree;
}); // End of closure

Datei-Diff unterdrückt, da er zu groß ist Diff laden

Datei anzeigen

@ -0,0 +1,257 @@
/*!
* jquery.fancytree.wide.js
* Support for 100% wide selection bars.
* (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/)
*
* Copyright (c) 2008-2021, Martin Wendt (https://wwWendt.de)
*
* Released under the MIT license
* https://github.com/mar10/fancytree/wiki/LicenseInfo
*
* @version 2.38.0
* @date 2021-02-09T20:03:49Z
*/
(function(factory) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define(["jquery", "./jquery.fancytree"], factory);
} else if (typeof module === "object" && module.exports) {
// Node/CommonJS
require("./jquery.fancytree");
module.exports = factory(require("jquery"));
} else {
// Browser globals
factory(jQuery);
}
})(function($) {
"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,
labelOfs,
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, " +
"#" +
containerId +
" li.fancytree-animating span.fancytree-title " + // #716
"{ padding-left: " +
labelOfs +
measureUnit +
"; 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: "2.38.0",
// Default options for this extension.
options: {
iconWidth: null, // Adjust this if @fancy-icon-width != "16px"
iconSpacing: null, // Adjust this if @fancy-icon-spacing != "3px"
labelSpacing: null, // Adjust this if padding between icon and label != "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,
labelSpacingUnit,
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"),
labelSpacing = instOpts.labelSpacing || "3px",
levelOfs = instOpts.levelOfs || $dummyUL.css("padding-left");
$dummyLI.remove();
iconSpacingUnit = iconSpacing.match(reNumUnit)[2];
iconSpacing = parseFloat(iconSpacing, 10);
labelSpacingUnit = labelSpacing.match(reNumUnit)[2];
labelSpacing = parseFloat(labelSpacing, 10);
iconWidthUnit = iconWidth.match(reNumUnit)[2];
iconWidth = parseFloat(iconWidth, 10);
levelOfsUnit = levelOfs.match(reNumUnit)[2];
if (
iconSpacingUnit !== iconWidthUnit ||
levelOfsUnit !== iconWidthUnit ||
labelSpacingUnit !== 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.icon === false ? 0 : 1)) *
(iconWidth + iconSpacing) +
iconSpacing;
this._local.labelOfs = labelSpacing;
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.labelOfs,
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._super(ctx);
// 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.labelSpacing,
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;
},
});
// Value returned by `require('jquery.fancytree..')`
return $.ui.fancytree;
}); // End of closure

Datei anzeigen

@ -0,0 +1,964 @@
/*******************************************************************************
* Common Styles for Fancytree Skins.
*
* This section is automatically generated from the `skin-common.less` template.
*
* Copyright (c) 2008-2021, Martin Wendt (https://wwWendt.de)
* Released under the MIT license
* https://github.com/mar10/fancytree/wiki/LicenseInfo
*
* @version 2.38.0
* @date 2021-02-09T20:03:49Z
******************************************************************************/
// 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;
// webpack uses /dist/skin-common.less as root path
// grunt-less uses /dist/skin-Xxx/ui.fancyree.less as root path
// So we define our theme LESS files for webpack compatibility, i.e.
// define the image path n every main LESS file instead of here.
// Prefix may be set to "", "/", "./", or any other value
// Note: this variable must be defined by the main LESS files:
// @fancy-image-prefix: "";
// 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-prefix}loading.gif");
@fancy-loading-url: data-uri("@{fancy-image-prefix}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: #c0c0c0;
@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-prefix}@{url}");
}
.setBgImageUrl(@url) when (@fancy-use-sprites) and (@fancy-inline-sprites) {
background-image: data-uri("@{fancy-image-prefix}@{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,
.fancytree-helper-hidden {
display: none;
}
.fancytree-helper-indeterminate-cb {
// tri-state checkbox
color: #777;
}
.fancytree-helper-disabled {
color: @fancy-font-color-dimm;
}
/* Helper to allow spinning loader icon with glyph-, ligature-, and SVG-icons. */
.fancytree-helper-spin {
-webkit-animation: spin 1000ms infinite linear;
animation: spin 1000ms infinite linear;
}
@-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
@keyframes spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
/*------------------------------------------------------------------------------
* 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; // ext-dnd5: otherwise this is always the scroll parent
// height: 100%; // DT issue 263, 470
min-height: 0%; // #192
position: relative; // #235
ul {
padding: 0 0 0 @fancy-level-indent;
margin: 0;
}
ul > li:before {
// #538
content: none;
}
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;
}
}
// 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;
}
ul.fancytree-connectors.fancytree-container {
li {
// Use 'data-uri(...)' to embed the image into CSS instead of linking to 'loading.gif':
background-image: data-uri("@{fancy-image-prefix}vline.gif");
background-position: 0 0;
}
}
// Suppress lines for last child node
ul.fancytree-container li.fancytree-lastsib,
// Suppress lines if level is fixed expanded (option minExpandLevel)
ul.fancytree-no-connector > li {
background-image: none;
}
// Fix jQuery UI 'blind' animation for jQuery UI (#717)
li.fancytree-animating {
position: relative;
}
/*------------------------------------------------------------------------------
* 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 icon option: */
span.fancytree-custom-icon {
width: @fancy-icon-width;
height: @fancy-icon-height;
display: inline-block;
margin-left: @fancy-icon-spacing;
.setBgPos(0, 0);
}
/* 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 );
background-image: none;
cursor: default;
}
.fancytree-connectors {
.fancytree-exp-n span.fancytree-expander,
.fancytree-exp-nl span.fancytree-expander {
.setBgImageUrl("icons.gif");
margin-top: 0;
}
.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);
}
/* Fade out expanders, when container is not hovered or active */
.fancytree-fade-expander {
span.fancytree-expander {
transition: opacity 1.5s;
opacity: 0;
}
&:hover span.fancytree-expander,
&.fancytree-treefocus span.fancytree-expander,
.fancytree-treefocus span.fancytree-expander,
[class*="fancytree-statusnode-"] span.fancytree-expander {
transition: opacity 0.6s;
opacity: 1;
}
}
/*------------------------------------------------------------------------------
* Checkbox icon
*----------------------------------------------------------------------------*/
span.fancytree-checkbox {
margin-left: @fancy-icon-spacing;
.useSprite(0, 2);
&:hover {
.useSprite(1, 2);
}
&.fancytree-radio {
.useSprite(0, 3);
}
&.fancytree-radio:hover {
.useSprite(1, 3);
}
}
.fancytree-partsel span.fancytree-checkbox {
.useSprite(4, 2);
&:hover {
.useSprite(5, 2);
}
&.fancytree-radio {
.useSprite(4, 3);
}
&.fancytree-radio:hover {
.useSprite(5, 3);
}
}
// selected after partsel, so it takes precedence:
.fancytree-selected span.fancytree-checkbox {
.useSprite(2, 2);
&:hover {
.useSprite(3, 2);
}
&.fancytree-radio {
.useSprite(2, 3);
}
&.fancytree-radio:hover {
.useSprite(3, 3);
}
}
// 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);
}
span.fancytree-checkbox.fancytree-radio:hover {
.useSprite(0, 3);
}
&.fancytree-partsel span.fancytree-checkbox:hover {
.useSprite(4, 2);
}
&.fancytree-selected span.fancytree-checkbox:hover {
.useSprite(2, 2);
}
&.fancytree-selected span.fancytree-checkbox.fancytree-radio:hover {
.useSprite(2, 3);
}
}
// Auto-hide checkboxes unless selected or hovered
.fancytree-container.fancytree-checkbox-auto-hide {
span.fancytree-checkbox {
visibility: hidden;
}
.fancytree-node:hover span.fancytree-checkbox,
tr:hover td span.fancytree-checkbox,
.fancytree-node.fancytree-selected span.fancytree-checkbox,
tr.fancytree-selected td span.fancytree-checkbox {
visibility: unset;
}
&.fancytree-treefocus {
.fancytree-node.fancytree-active span.fancytree-checkbox,
tr.fancytree-active td span.fancytree-checkbox {
visibility: unset;
}
}
}
/*------------------------------------------------------------------------------
* 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-loading span.fancytree-icon,
.fancytree-statusnode-loading span.fancytree-icon:hover,
span.fancytree-icon.fancytree-icon-loading {
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
*----------------------------------------------------------------------------*/
/* ext-dnd5: */
span.fancytree-childcounter {
color: #fff;
background: #337ab7; // bootstrap blue
border: 1px solid gray;
border-radius: 10px;
padding: 2px;
text-align: center;
}
/* ext-dnd: */
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
}
/*------------------------------------------------------------------------------
* 'rtl' option
*----------------------------------------------------------------------------*/
.fancytree-container.fancytree-rtl {
.fancytree-title {
/*unicode-bidi: bidi-override;*/ /* optional: reverse title letters */
}
span.fancytree-connector,
span.fancytree-expander,
span.fancytree-icon,
span.fancytree-drag-helper-img {
.setBgImageUrl("icons-rtl.gif");
}
.fancytree-exp-n span.fancytree-expander,
.fancytree-exp-nl span.fancytree-expander {
background-image: none;
}
&.fancytree-connectors .fancytree-exp-n span.fancytree-expander,
&.fancytree-connectors .fancytree-exp-nl span.fancytree-expander {
.setBgImageUrl("icons-rtl.gif");
}
}
ul.fancytree-container.fancytree-rtl {
ul {
padding: 0 16px 0 0;
}
&.fancytree-connectors li {
background-position: right 0;
background-image: url("@{fancy-image-prefix}vline-rtl.gif");
}
// Suppress lines for last child node
li.fancytree-lastsib,
// Suppress lines if level is fixed expanded (option minExpandLevel)
&.fancytree-no-connector > li {
background-image: none;
}
}
#fancytree-drop-marker.fancytree-rtl {
.setBgImageUrl("icons-rtl.gif");
}
/*------------------------------------------------------------------------------
* 'table' extension
*----------------------------------------------------------------------------*/
table.fancytree-ext-table {
font-family: @fancy-font-family;
font-size: @fancy-font-size;
border-collapse: collapse;
span.fancytree-node {
display: inline-block; // #117
box-sizing: border-box; // #562
}
td.fancytree-status-merged {
text-align: center;
// font-weight: bold;
font-style: italic;
// line-height: 100px;
color: @fancy-font-color-dimm;
}
tr.fancytree-statusnode-error td.fancytree-status-merged {
color: @fancy-font-error-color;
}
/* ext-ariagrid */
&.fancytree-ext-ariagrid.fancytree-cell-mode {
> tbody > tr.fancytree-active > td {
background-color: #eee;
}
> tbody > tr > td.fancytree-active-cell {
background-color: #cbe8f6;
}
&.fancytree-cell-nav-mode > tbody > tr > td.fancytree-active-cell {
background-color: #3875d7;
}
}
}
/*------------------------------------------------------------------------------
* '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: #e0e0e0;
}
span.fancytree-node.fancytree-active {
background-color: #cbe8f6;
// 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;
}
}
/* Hide expanders if all child nodes are hidden by filter */
.fancytree-ext-filter-hide-expanders {
tr.fancytree-match span.fancytree-expander,
span.fancytree-node.fancytree-match span.fancytree-expander {
visibility: hidden;
}
tr.fancytree-submatch span.fancytree-expander,
span.fancytree-node.fancytree-submatch span.fancytree-expander {
visibility: visible;
}
}
.fancytree-ext-childcounter,
.fancytree-ext-filter {
// span.fancytree-title mark {
// font-style: normal;
// background-color: #ead61c; // yellow
// border-radius: 3px;
// }
span.fancytree-icon,
span.fancytree-custom-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;
min-width: 100%;
margin-left: 0;
margin-right: 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
}
/*------------------------------------------------------------------------------
* 'fixed' extension
*----------------------------------------------------------------------------*/
.fancytree-ext-fixed-wrapper {
.fancytree-ext-fixed-hidden {
display: none;
}
div.fancytree-ext-fixed-scroll-border-bottom {
border-bottom: 3px solid rgba(0, 0, 0, 0.75);
}
div.fancytree-ext-fixed-scroll-border-right {
border-right: 3px solid rgba(0, 0, 0, 0.75);
}
div.fancytree-ext-fixed-wrapper-tl {
position: absolute;
overflow: hidden;
z-index: 3;
top: 0px;
left: 0px;
}
div.fancytree-ext-fixed-wrapper-tr {
position: absolute;
overflow: hidden;
z-index: 2;
top: 0px;
}
div.fancytree-ext-fixed-wrapper-bl {
position: absolute;
overflow: hidden;
z-index: 2;
left: 0px;
}
div.fancytree-ext-fixed-wrapper-br {
position: absolute;
overflow: scroll;
z-index: 1;
}
}

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 5.8 KiB

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 5.8 KiB

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 1.8 KiB

Datei anzeigen

@ -0,0 +1,757 @@
/*!
* 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.
*
* Copyright (c) 2008-2021, Martin Wendt (https://wwWendt.de)
* Released under the MIT license
* https://github.com/mar10/fancytree/wiki/LicenseInfo
*
* @version 2.38.0
* @date 2021-02-09T20:03:49Z
******************************************************************************/
/*------------------------------------------------------------------------------
* Helpers
*----------------------------------------------------------------------------*/
.fancytree-helper-hidden {
display: none;
}
.fancytree-helper-indeterminate-cb {
color: #777;
}
.fancytree-helper-disabled {
color: #c0c0c0;
}
/* Helper to allow spinning loader icon with glyph-, ligature-, and SVG-icons. */
.fancytree-helper-spin {
-webkit-animation: spin 1000ms infinite linear;
animation: spin 1000ms infinite linear;
}
@-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
@keyframes spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
/*------------------------------------------------------------------------------
* 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;
min-height: 0%;
position: relative;
}
ul.fancytree-container ul {
padding: 0 0 0 16px;
margin: 0;
}
ul.fancytree-container ul > li:before {
content: none;
}
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;
}
.ui-fancytree-disabled ul.fancytree-container {
opacity: 0.5;
background-color: silver;
}
ul.fancytree-connectors.fancytree-container li {
background-image: url("../skin-lion/vline.gif");
background-position: 0 0;
}
ul.fancytree-container li.fancytree-lastsib,
ul.fancytree-no-connector > li {
background-image: none;
}
li.fancytree-animating {
position: relative;
}
/*------------------------------------------------------------------------------
* Common icon definitions
*----------------------------------------------------------------------------*/
span.fancytree-empty,
span.fancytree-vline,
span.fancytree-expander,
span.fancytree-icon,
span.fancytree-checkbox,
span.fancytree-drag-helper-img,
#fancytree-drop-marker {
width: 16px;
height: 16px;
display: inline-block;
vertical-align: top;
background-repeat: no-repeat;
background-image: url("../skin-lion/icons.gif");
background-position: 0px 0px;
}
span.fancytree-icon,
span.fancytree-checkbox,
span.fancytree-expander,
span.fancytree-custom-icon {
margin-top: 0px;
}
/* Used by icon option: */
span.fancytree-custom-icon {
width: 16px;
height: 16px;
display: inline-block;
margin-left: 3px;
background-position: 0px 0px;
}
/* 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-connectors .fancytree-exp-n span.fancytree-expander,
.fancytree-connectors .fancytree-exp-nl span.fancytree-expander {
background-image: url("../skin-lion/icons.gif");
margin-top: 0;
}
.fancytree-connectors .fancytree-exp-n span.fancytree-expander,
.fancytree-connectors .fancytree-exp-n span.fancytree-expander:hover {
background-position: 0px -64px;
}
.fancytree-connectors .fancytree-exp-nl span.fancytree-expander,
.fancytree-connectors .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;
}
/* Fade out expanders, when container is not hovered or active */
.fancytree-fade-expander span.fancytree-expander {
transition: opacity 1.5s;
opacity: 0;
}
.fancytree-fade-expander:hover span.fancytree-expander,
.fancytree-fade-expander.fancytree-treefocus span.fancytree-expander,
.fancytree-fade-expander .fancytree-treefocus span.fancytree-expander,
.fancytree-fade-expander [class*="fancytree-statusnode-"] span.fancytree-expander {
transition: opacity 0.6s;
opacity: 1;
}
/*------------------------------------------------------------------------------
* Checkbox icon
*----------------------------------------------------------------------------*/
span.fancytree-checkbox {
margin-left: 3px;
background-position: 0px -32px;
}
span.fancytree-checkbox:hover {
background-position: -16px -32px;
}
span.fancytree-checkbox.fancytree-radio {
background-position: 0px -48px;
}
span.fancytree-checkbox.fancytree-radio:hover {
background-position: -16px -48px;
}
.fancytree-partsel span.fancytree-checkbox {
background-position: -64px -32px;
}
.fancytree-partsel span.fancytree-checkbox:hover {
background-position: -80px -32px;
}
.fancytree-partsel span.fancytree-checkbox.fancytree-radio {
background-position: -64px -48px;
}
.fancytree-partsel span.fancytree-checkbox.fancytree-radio:hover {
background-position: -80px -48px;
}
.fancytree-selected span.fancytree-checkbox {
background-position: -32px -32px;
}
.fancytree-selected span.fancytree-checkbox:hover {
background-position: -48px -32px;
}
.fancytree-selected span.fancytree-checkbox.fancytree-radio {
background-position: -32px -48px;
}
.fancytree-selected span.fancytree-checkbox.fancytree-radio:hover {
background-position: -48px -48px;
}
.fancytree-unselectable span.fancytree-checkbox {
opacity: 0.4;
filter: alpha(opacity=40);
}
.fancytree-unselectable span.fancytree-checkbox:hover {
background-position: 0px -32px;
}
.fancytree-unselectable span.fancytree-checkbox.fancytree-radio:hover {
background-position: 0px -48px;
}
.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-unselectable.fancytree-selected span.fancytree-checkbox.fancytree-radio:hover {
background-position: -32px -48px;
}
.fancytree-container.fancytree-checkbox-auto-hide span.fancytree-checkbox {
visibility: hidden;
}
.fancytree-container.fancytree-checkbox-auto-hide .fancytree-node:hover span.fancytree-checkbox,
.fancytree-container.fancytree-checkbox-auto-hide tr:hover td span.fancytree-checkbox,
.fancytree-container.fancytree-checkbox-auto-hide .fancytree-node.fancytree-selected span.fancytree-checkbox,
.fancytree-container.fancytree-checkbox-auto-hide tr.fancytree-selected td span.fancytree-checkbox {
visibility: unset;
}
.fancytree-container.fancytree-checkbox-auto-hide.fancytree-treefocus .fancytree-node.fancytree-active span.fancytree-checkbox,
.fancytree-container.fancytree-checkbox-auto-hide.fancytree-treefocus tr.fancytree-active td span.fancytree-checkbox {
visibility: unset;
}
/*------------------------------------------------------------------------------
* 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-loading span.fancytree-icon,
.fancytree-statusnode-loading span.fancytree-icon:hover,
span.fancytree-icon.fancytree-icon-loading {
background-image: url("../skin-lion/loading.gif");
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: black;
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: red;
}
/*------------------------------------------------------------------------------
* Drag'n'drop support
*----------------------------------------------------------------------------*/
/* ext-dnd5: */
span.fancytree-childcounter {
color: #fff;
background: #337ab7;
border: 1px solid gray;
border-radius: 10px;
padding: 2px;
text-align: center;
}
/* ext-dnd: */
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 *****************************/
/*------------------------------------------------------------------------------
* 'rtl' option
*----------------------------------------------------------------------------*/
.fancytree-container.fancytree-rtl .fancytree-title {
/*unicode-bidi: bidi-override;*/
/* optional: reverse title letters */
}
.fancytree-container.fancytree-rtl span.fancytree-connector,
.fancytree-container.fancytree-rtl span.fancytree-expander,
.fancytree-container.fancytree-rtl span.fancytree-icon,
.fancytree-container.fancytree-rtl span.fancytree-drag-helper-img {
background-image: url("../skin-lion/icons-rtl.gif");
}
.fancytree-container.fancytree-rtl .fancytree-exp-n span.fancytree-expander,
.fancytree-container.fancytree-rtl .fancytree-exp-nl span.fancytree-expander {
background-image: none;
}
.fancytree-container.fancytree-rtl.fancytree-connectors .fancytree-exp-n span.fancytree-expander,
.fancytree-container.fancytree-rtl.fancytree-connectors .fancytree-exp-nl span.fancytree-expander {
background-image: url("../skin-lion/icons-rtl.gif");
}
ul.fancytree-container.fancytree-rtl ul {
padding: 0 16px 0 0;
}
ul.fancytree-container.fancytree-rtl.fancytree-connectors li {
background-position: right 0;
background-image: url("../skin-lion/vline-rtl.gif");
}
ul.fancytree-container.fancytree-rtl li.fancytree-lastsib,
ul.fancytree-container.fancytree-rtl.fancytree-no-connector > li {
background-image: none;
}
#fancytree-drop-marker.fancytree-rtl {
background-image: url("../skin-lion/icons-rtl.gif");
}
/*------------------------------------------------------------------------------
* 'table' extension
*----------------------------------------------------------------------------*/
table.fancytree-ext-table {
font-family: tahoma, arial, helvetica;
font-size: 10pt;
border-collapse: collapse;
/* ext-ariagrid */
}
table.fancytree-ext-table span.fancytree-node {
display: inline-block;
box-sizing: border-box;
}
table.fancytree-ext-table td.fancytree-status-merged {
text-align: center;
font-style: italic;
color: #c0c0c0;
}
table.fancytree-ext-table tr.fancytree-statusnode-error td.fancytree-status-merged {
color: red;
}
table.fancytree-ext-table.fancytree-ext-ariagrid.fancytree-cell-mode > tbody > tr.fancytree-active > td {
background-color: #eee;
}
table.fancytree-ext-table.fancytree-ext-ariagrid.fancytree-cell-mode > tbody > tr > td.fancytree-active-cell {
background-color: #cbe8f6;
}
table.fancytree-ext-table.fancytree-ext-ariagrid.fancytree-cell-mode.fancytree-cell-nav-mode > tbody > tr > td.fancytree-active-cell {
background-color: #3875d7;
}
/*------------------------------------------------------------------------------
* '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: #e0e0e0;
}
table.fancytree-ext-columnview span.fancytree-node.fancytree-active {
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;
}
/* Hide expanders if all child nodes are hidden by filter */
.fancytree-ext-filter-hide-expanders tr.fancytree-match span.fancytree-expander,
.fancytree-ext-filter-hide-expanders span.fancytree-node.fancytree-match span.fancytree-expander {
visibility: hidden;
}
.fancytree-ext-filter-hide-expanders tr.fancytree-submatch span.fancytree-expander,
.fancytree-ext-filter-hide-expanders span.fancytree-node.fancytree-submatch span.fancytree-expander {
visibility: visible;
}
.fancytree-ext-childcounter span.fancytree-icon,
.fancytree-ext-filter span.fancytree-icon,
.fancytree-ext-childcounter span.fancytree-custom-icon,
.fancytree-ext-filter span.fancytree-custom-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;
min-width: 100%;
margin-left: 0;
margin-right: 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
/*------------------------------------------------------------------------------
* 'fixed' extension
*----------------------------------------------------------------------------*/
.fancytree-ext-fixed-wrapper .fancytree-ext-fixed-hidden {
display: none;
}
.fancytree-ext-fixed-wrapper div.fancytree-ext-fixed-scroll-border-bottom {
border-bottom: 3px solid rgba(0, 0, 0, 0.75);
}
.fancytree-ext-fixed-wrapper div.fancytree-ext-fixed-scroll-border-right {
border-right: 3px solid rgba(0, 0, 0, 0.75);
}
.fancytree-ext-fixed-wrapper div.fancytree-ext-fixed-wrapper-tl {
position: absolute;
overflow: hidden;
z-index: 3;
top: 0px;
left: 0px;
}
.fancytree-ext-fixed-wrapper div.fancytree-ext-fixed-wrapper-tr {
position: absolute;
overflow: hidden;
z-index: 2;
top: 0px;
}
.fancytree-ext-fixed-wrapper div.fancytree-ext-fixed-wrapper-bl {
position: absolute;
overflow: hidden;
z-index: 2;
left: 0px;
}
.fancytree-ext-fixed-wrapper div.fancytree-ext-fixed-wrapper-br {
position: absolute;
overflow: scroll;
z-index: 1;
}
/*******************************************************************************
* 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;
}

Datei anzeigen

@ -0,0 +1,98 @@
/*!
* 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-icon-width: 16px;
@fancy-icon-height: 16px;
@fancy-line-height: 16px;
@fancy-icon-spacing: 3px;
// We need to define this variable here (not in skin-common.less) to make it
// work with grunt and webpack:
@fancy-image-prefix: "./skin-lion/";
// Use 'data-uri(...)' to embed the image into CSS instead of linking to 'loading.gif':
// @fancy-loading-url: data-uri("@{fancy-image-prefix}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;
}

Dateidiff unterdrückt, weil mindestens eine Zeile zu lang ist

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 852 B

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 852 B

Datei anzeigen

@ -0,0 +1,113 @@
<!DOCTYPE html>
<!--
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<html>
<head>
<title>test</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="expires" content="0">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="pragma" content="no-cache">
<script src="scripts/jquery/jquery.js"></script>
<script src="scripts/jquery/jquery-ui.js"></script>
<script src="scripts/general.js" type="text/javascript"></script>
<link href="scripts/fancytree/skin-lion/ui.fancytree.css" rel="stylesheet" type="text/css"/>
<link href="scripts/fancytree/lib/contextmenu-abs/jquery.contextMenu.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="tree">
{item_list}
</div>
<!--
<div>Selected node: <span id="echoActivated">-</span></div>
-->
<script src="scripts/fancytree/jquery.fancytree-all.min.js"></script>
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/jquery-contextmenu@2.9.0/dist/jquery.contextMenu.min.css" />
<script src="//cdn.jsdelivr.net/npm/jquery-contextmenu@2.9.0/dist/jquery.contextMenu.min.js"></script>
<script>
// --- Contextmenu helper --------------------------------------------------
function bindContextMenu(node) {
if (node.extraClasses == "directory") {
$(node.span).contextMenu({menu: "myMenuFolder"}, function (action, el, pos) {
switch (action) {
default:
alert("Todo: appply action '" + action + "' to node " + node.title);
}
});
} else {
$(node.span).contextMenu({menu: "myMenuFile"}, function (action, el, pos) {
switch (action) {
case 'edit':
alert('edit');
break;
default:
alert("Todo: apply action '" + action + "' to node " + node.title);
}
});
}
}
$(function () {
// using default options
$("#tree").fancytree({
imagePath: "images/filetypes/",
activate: function (event, data) {
var node = data.node;
console.log(data);
$("#echoActivated").text(node.title + ", key=" + node.key);
}
});
$.contextMenu({
selector: "#tree span.fancytree-title",
items: {
"edit": {
name: "Edit",
icon: "edit",
disabled: function (event, ui) {
var node = $.ui.fancytree.getNode(this);
console.log(node);
console.log(ui);
// return `true` to disable, `"hide"` to remove entry:
return (node.hasClass('file')) ? false : true;
},
callback: function (itemKey, opt, e) {
var node = $.ui.fancytree.getNode(this);
var file = node.data.filepath;
console.log(node.data);
console.log(`This is ${file} times easier!`);
conMultiLink(
'right_top',
`{multilink1}`,
'right_bottom',
`{multilink2}`
);
}
},
"delete": {name: "Delete", icon: "delete", disabled: function (event, ui) {
var node = $.ui.fancytree.getNode(this);
console.log(node);
console.log(ui);
// return `true` to disable, `"hide"` to remove entry:
return (node.hasClass('notwritable')) ? true : (node.hasClass('file')) ? false : true;
}}
},
callback: function (itemKey, opt) {
var node = $.ui.fancytree.getNode(opt.$trigger);
alert("select " + itemKey + " on " + node);
}
});
});
</script>
</body>
</html>