1/*!
2 * jquery.fancytree.glyph.js
3 *
4 * Use glyph-fonts, ligature-fonts, or SVG icons instead of icon sprites.
5 * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/)
6 *
7 * Copyright (c) 2008-2023, Martin Wendt (https://wwWendt.de)
8 *
9 * Released under the MIT license
10 * https://github.com/mar10/fancytree/wiki/LicenseInfo
11 *
12 * @version 2.38.3
13 * @date 2023-02-01T20:52:50Z
14 */
15
16(function (factory) {
17	if (typeof define === "function" && define.amd) {
18		// AMD. Register as an anonymous module.
19		define(["jquery", "./jquery.fancytree"], factory);
20	} else if (typeof module === "object" && module.exports) {
21		// Node/CommonJS
22		require("./jquery.fancytree");
23		module.exports = factory(require("jquery"));
24	} else {
25		// Browser globals
26		factory(jQuery);
27	}
28})(function ($) {
29	"use strict";
30
31	/******************************************************************************
32	 * Private functions and variables
33	 */
34
35	var FT = $.ui.fancytree,
36		PRESETS = {
37			awesome3: {
38				// Outdated!
39				_addClass: "",
40				checkbox: "icon-check-empty",
41				checkboxSelected: "icon-check",
42				checkboxUnknown: "icon-check icon-muted",
43				dragHelper: "icon-caret-right",
44				dropMarker: "icon-caret-right",
45				error: "icon-exclamation-sign",
46				expanderClosed: "icon-caret-right",
47				expanderLazy: "icon-angle-right",
48				expanderOpen: "icon-caret-down",
49				loading: "icon-refresh icon-spin",
50				nodata: "icon-meh",
51				noExpander: "",
52				radio: "icon-circle-blank",
53				radioSelected: "icon-circle",
54				// radioUnknown: "icon-circle icon-muted",
55				// Default node icons.
56				// (Use tree.options.icon callback to define custom icons based on node data)
57				doc: "icon-file-alt",
58				docOpen: "icon-file-alt",
59				folder: "icon-folder-close-alt",
60				folderOpen: "icon-folder-open-alt",
61			},
62			awesome4: {
63				_addClass: "fa",
64				checkbox: "fa-square-o",
65				checkboxSelected: "fa-check-square-o",
66				checkboxUnknown: "fa-square fancytree-helper-indeterminate-cb",
67				dragHelper: "fa-arrow-right",
68				dropMarker: "fa-long-arrow-right",
69				error: "fa-warning",
70				expanderClosed: "fa-caret-right",
71				expanderLazy: "fa-angle-right",
72				expanderOpen: "fa-caret-down",
73				// We may prevent wobbling rotations on FF by creating a separate sub element:
74				loading: { html: "<span class='fa fa-spinner fa-pulse' />" },
75				nodata: "fa-meh-o",
76				noExpander: "",
77				radio: "fa-circle-thin", // "fa-circle-o"
78				radioSelected: "fa-circle",
79				// radioUnknown: "fa-dot-circle-o",
80				// Default node icons.
81				// (Use tree.options.icon callback to define custom icons based on node data)
82				doc: "fa-file-o",
83				docOpen: "fa-file-o",
84				folder: "fa-folder-o",
85				folderOpen: "fa-folder-open-o",
86			},
87			awesome5: {
88				// fontawesome 5 have several different base classes
89				// "far, fas, fal and fab" The rendered svg puts that prefix
90				// in a different location so we have to keep them separate here
91				_addClass: "",
92				checkbox: "far fa-square",
93				checkboxSelected: "far fa-check-square",
94				// checkboxUnknown: "far fa-window-close",
95				checkboxUnknown:
96					"fas fa-square fancytree-helper-indeterminate-cb",
97				radio: "far fa-circle",
98				radioSelected: "fas fa-circle",
99				radioUnknown: "far fa-dot-circle",
100				dragHelper: "fas fa-arrow-right",
101				dropMarker: "fas fa-long-arrow-alt-right",
102				error: "fas fa-exclamation-triangle",
103				expanderClosed: "fas fa-caret-right",
104				expanderLazy: "fas fa-angle-right",
105				expanderOpen: "fas fa-caret-down",
106				loading: "fas fa-spinner fa-pulse",
107				nodata: "far fa-meh",
108				noExpander: "",
109				// Default node icons.
110				// (Use tree.options.icon callback to define custom icons based on node data)
111				doc: "far fa-file",
112				docOpen: "far fa-file",
113				folder: "far fa-folder",
114				folderOpen: "far fa-folder-open",
115			},
116			bootstrap3: {
117				_addClass: "glyphicon",
118				checkbox: "glyphicon-unchecked",
119				checkboxSelected: "glyphicon-check",
120				checkboxUnknown:
121					"glyphicon-expand fancytree-helper-indeterminate-cb", // "glyphicon-share",
122				dragHelper: "glyphicon-play",
123				dropMarker: "glyphicon-arrow-right",
124				error: "glyphicon-warning-sign",
125				expanderClosed: "glyphicon-menu-right", // glyphicon-plus-sign
126				expanderLazy: "glyphicon-menu-right", // glyphicon-plus-sign
127				expanderOpen: "glyphicon-menu-down", // glyphicon-minus-sign
128				loading: "glyphicon-refresh fancytree-helper-spin",
129				nodata: "glyphicon-info-sign",
130				noExpander: "",
131				radio: "glyphicon-remove-circle", // "glyphicon-unchecked",
132				radioSelected: "glyphicon-ok-circle", // "glyphicon-check",
133				// radioUnknown: "glyphicon-ban-circle",
134				// Default node icons.
135				// (Use tree.options.icon callback to define custom icons based on node data)
136				doc: "glyphicon-file",
137				docOpen: "glyphicon-file",
138				folder: "glyphicon-folder-close",
139				folderOpen: "glyphicon-folder-open",
140			},
141			material: {
142				_addClass: "material-icons",
143				checkbox: { text: "check_box_outline_blank" },
144				checkboxSelected: { text: "check_box" },
145				checkboxUnknown: { text: "indeterminate_check_box" },
146				dragHelper: { text: "play_arrow" },
147				dropMarker: { text: "arrow-forward" },
148				error: { text: "warning" },
149				expanderClosed: { text: "chevron_right" },
150				expanderLazy: { text: "last_page" },
151				expanderOpen: { text: "expand_more" },
152				loading: {
153					text: "autorenew",
154					addClass: "fancytree-helper-spin",
155				},
156				nodata: { text: "info" },
157				noExpander: { text: "" },
158				radio: { text: "radio_button_unchecked" },
159				radioSelected: { text: "radio_button_checked" },
160				// Default node icons.
161				// (Use tree.options.icon callback to define custom icons based on node data)
162				doc: { text: "insert_drive_file" },
163				docOpen: { text: "insert_drive_file" },
164				folder: { text: "folder" },
165				folderOpen: { text: "folder_open" },
166			},
167		};
168
169	function setIcon(node, span, baseClass, opts, type) {
170		var map = opts.map,
171			icon = map[type],
172			$span = $(span),
173			$counter = $span.find(".fancytree-childcounter"),
174			setClass = baseClass + " " + (map._addClass || "");
175
176		// #871 Allow a callback
177		if (typeof icon === "function") {
178			icon = icon.call(this, node, span, type);
179		}
180		// node.debug( "setIcon(" + baseClass + ", " + type + "): " + "oldIcon" + " -> " + icon );
181		// #871: propsed this, but I am not sure how robust this is, e.g.
182		// the prefix (fas, far) class changes are not considered?
183		// if (span.tagName === "svg" && opts.preset === "awesome5") {
184		// 	// fa5 script converts <i> to <svg> so call a specific handler.
185		// 	var oldIcon = "fa-" + $span.data("icon");
186		// 	// node.debug( "setIcon(" + baseClass + ", " + type + "): " + oldIcon + " -> " + icon );
187		// 	if (typeof oldIcon === "string") {
188		// 		$span.removeClass(oldIcon);
189		// 	}
190		// 	if (typeof icon === "string") {
191		// 		$span.addClass(icon);
192		// 	}
193		// 	return;
194		// }
195		if (typeof icon === "string") {
196			// #883: remove inner html that may be added by prev. mode
197			span.innerHTML = "";
198			$span.attr("class", setClass + " " + icon).append($counter);
199		} else if (icon) {
200			if (icon.text) {
201				span.textContent = "" + icon.text;
202			} else if (icon.html) {
203				span.innerHTML = icon.html;
204			} else {
205				span.innerHTML = "";
206			}
207			$span
208				.attr("class", setClass + " " + (icon.addClass || ""))
209				.append($counter);
210		}
211	}
212
213	$.ui.fancytree.registerExtension({
214		name: "glyph",
215		version: "2.38.3",
216		// Default options for this extension.
217		options: {
218			preset: null, // 'awesome3', 'awesome4', 'bootstrap3', 'material'
219			map: {},
220		},
221
222		treeInit: function (ctx) {
223			var tree = ctx.tree,
224				opts = ctx.options.glyph;
225
226			if (opts.preset) {
227				FT.assert(
228					!!PRESETS[opts.preset],
229					"Invalid value for `options.glyph.preset`: " + opts.preset
230				);
231				opts.map = $.extend({}, PRESETS[opts.preset], opts.map);
232			} else {
233				tree.warn("ext-glyph: missing `preset` option.");
234			}
235			this._superApply(arguments);
236			tree.$container.addClass("fancytree-ext-glyph");
237		},
238		nodeRenderStatus: function (ctx) {
239			var checkbox,
240				icon,
241				res,
242				span,
243				node = ctx.node,
244				$span = $(node.span),
245				opts = ctx.options.glyph;
246
247			res = this._super(ctx);
248
249			if (node.isRootNode()) {
250				return res;
251			}
252			span = $span.children(".fancytree-expander").get(0);
253			if (span) {
254				// if( node.isLoading() ){
255				// icon = "loading";
256				if (node.expanded && node.hasChildren()) {
257					icon = "expanderOpen";
258				} else if (node.isUndefined()) {
259					icon = "expanderLazy";
260				} else if (node.hasChildren()) {
261					icon = "expanderClosed";
262				} else {
263					icon = "noExpander";
264				}
265				// span.className = "fancytree-expander " + map[icon];
266				setIcon(node, span, "fancytree-expander", opts, icon);
267			}
268
269			if (node.tr) {
270				span = $("td", node.tr).find(".fancytree-checkbox").get(0);
271			} else {
272				span = $span.children(".fancytree-checkbox").get(0);
273			}
274			if (span) {
275				checkbox = FT.evalOption("checkbox", node, node, opts, false);
276				if (
277					(node.parent && node.parent.radiogroup) ||
278					checkbox === "radio"
279				) {
280					icon = node.selected ? "radioSelected" : "radio";
281					setIcon(
282						node,
283						span,
284						"fancytree-checkbox fancytree-radio",
285						opts,
286						icon
287					);
288				} else {
289					// eslint-disable-next-line no-nested-ternary
290					icon = node.selected
291						? "checkboxSelected"
292						: node.partsel
293						? "checkboxUnknown"
294						: "checkbox";
295					// span.className = "fancytree-checkbox " + map[icon];
296					setIcon(node, span, "fancytree-checkbox", opts, icon);
297				}
298			}
299
300			// Standard icon (note that this does not match .fancytree-custom-icon,
301			// that might be set by opts.icon callbacks)
302			span = $span.children(".fancytree-icon").get(0);
303			if (span) {
304				if (node.statusNodeType) {
305					icon = node.statusNodeType; // loading, error
306				} else if (node.folder) {
307					icon =
308						node.expanded && node.hasChildren()
309							? "folderOpen"
310							: "folder";
311				} else {
312					icon = node.expanded ? "docOpen" : "doc";
313				}
314				setIcon(node, span, "fancytree-icon", opts, icon);
315			}
316			return res;
317		},
318		nodeSetStatus: function (ctx, status, message, details) {
319			var res,
320				span,
321				opts = ctx.options.glyph,
322				node = ctx.node;
323
324			res = this._superApply(arguments);
325
326			if (
327				status === "error" ||
328				status === "loading" ||
329				status === "nodata"
330			) {
331				if (node.parent) {
332					span = $(".fancytree-expander", node.span).get(0);
333					if (span) {
334						setIcon(node, span, "fancytree-expander", opts, status);
335					}
336				} else {
337					//
338					span = $(
339						".fancytree-statusnode-" + status,
340						node[this.nodeContainerAttrName]
341					)
342						.find(".fancytree-icon")
343						.get(0);
344					if (span) {
345						setIcon(node, span, "fancytree-icon", opts, status);
346					}
347				}
348			}
349			return res;
350		},
351	});
352	// Value returned by `require('jquery.fancytree..')`
353	return $.ui.fancytree;
354}); // End of closure
355