1/*!
2 * jquery.fancytree.wide.js
3 * Support for 100% wide selection bars.
4 * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/)
5 *
6 * Copyright (c) 2008-2023, Martin Wendt (https://wwWendt.de)
7 *
8 * Released under the MIT license
9 * https://github.com/mar10/fancytree/wiki/LicenseInfo
10 *
11 * @version 2.38.3
12 * @date 2023-02-01T20:52:50Z
13 */
14
15(function (factory) {
16	if (typeof define === "function" && define.amd) {
17		// AMD. Register as an anonymous module.
18		define(["jquery", "./jquery.fancytree"], factory);
19	} else if (typeof module === "object" && module.exports) {
20		// Node/CommonJS
21		require("./jquery.fancytree");
22		module.exports = factory(require("jquery"));
23	} else {
24		// Browser globals
25		factory(jQuery);
26	}
27})(function ($) {
28	"use strict";
29
30	var reNumUnit = /^([+-]?(?:\d+|\d*\.\d+))([a-z]*|%)$/; // split "1.5em" to ["1.5", "em"]
31
32	/*******************************************************************************
33	 * Private functions and variables
34	 */
35	// var _assert = $.ui.fancytree.assert;
36
37	/* Calculate inner width without scrollbar */
38	// function realInnerWidth($el) {
39	// 	// http://blog.jquery.com/2012/08/16/jquery-1-8-box-sizing-width-csswidth-and-outerwidth/
40	// //	inst.contWidth = parseFloat(this.$container.css("width"), 10);
41	// 	// 'Client width without scrollbar' - 'padding'
42	// 	return $el[0].clientWidth - ($el.innerWidth() -  parseFloat($el.css("width"), 10));
43	// }
44
45	/* Create a global embedded CSS style for the tree. */
46	function defineHeadStyleElement(id, cssText) {
47		id = "fancytree-style-" + id;
48		var $headStyle = $("#" + id);
49
50		if (!cssText) {
51			$headStyle.remove();
52			return null;
53		}
54		if (!$headStyle.length) {
55			$headStyle = $("<style />")
56				.attr("id", id)
57				.addClass("fancytree-style")
58				.prop("type", "text/css")
59				.appendTo("head");
60		}
61		try {
62			$headStyle.html(cssText);
63		} catch (e) {
64			// fix for IE 6-8
65			$headStyle[0].styleSheet.cssText = cssText;
66		}
67		return $headStyle;
68	}
69
70	/* Calculate the CSS rules that indent title spans. */
71	function renderLevelCss(
72		containerId,
73		depth,
74		levelOfs,
75		lineOfs,
76		labelOfs,
77		measureUnit
78	) {
79		var i,
80			prefix = "#" + containerId + " span.fancytree-level-",
81			rules = [];
82
83		for (i = 0; i < depth; i++) {
84			rules.push(
85				prefix +
86					(i + 1) +
87					" span.fancytree-title { padding-left: " +
88					(i * levelOfs + lineOfs) +
89					measureUnit +
90					"; }"
91			);
92		}
93		// Some UI animations wrap the UL inside a DIV and set position:relative on both.
94		// This breaks the left:0 and padding-left:nn settings of the title
95		rules.push(
96			"#" +
97				containerId +
98				" div.ui-effects-wrapper ul li span.fancytree-title, " +
99				"#" +
100				containerId +
101				" li.fancytree-animating span.fancytree-title " + // #716
102				"{ padding-left: " +
103				labelOfs +
104				measureUnit +
105				"; position: static; width: auto; }"
106		);
107		return rules.join("\n");
108	}
109
110	// /**
111	//  * [ext-wide] Recalculate the width of the selection bar after the tree container
112	//  * was resized.<br>
113	//  * May be called explicitly on container resize, since there is no resize event
114	//  * for DIV tags.
115	//  *
116	//  * @alias Fancytree#wideUpdate
117	//  * @requires jquery.fancytree.wide.js
118	//  */
119	// $.ui.fancytree._FancytreeClass.prototype.wideUpdate = function(){
120	// 	var inst = this.ext.wide,
121	// 		prevCw = inst.contWidth,
122	// 		prevLo = inst.lineOfs;
123
124	// 	inst.contWidth = realInnerWidth(this.$container);
125	// 	// Each title is precceeded by 2 or 3 icons (16px + 3 margin)
126	// 	//     + 1px title border and 3px title padding
127	// 	// TODO: use code from treeInit() below
128	// 	inst.lineOfs = (this.options.checkbox ? 3 : 2) * 19;
129	// 	if( prevCw !== inst.contWidth || prevLo !== inst.lineOfs ) {
130	// 		this.debug("wideUpdate: " + inst.contWidth);
131	// 		this.visit(function(node){
132	// 			node.tree._callHook("nodeRenderTitle", node);
133	// 		});
134	// 	}
135	// };
136
137	/*******************************************************************************
138	 * Extension code
139	 */
140	$.ui.fancytree.registerExtension({
141		name: "wide",
142		version: "2.38.3",
143		// Default options for this extension.
144		options: {
145			iconWidth: null, // Adjust this if @fancy-icon-width != "16px"
146			iconSpacing: null, // Adjust this if @fancy-icon-spacing != "3px"
147			labelSpacing: null, // Adjust this if padding between icon and label != "3px"
148			levelOfs: null, // Adjust this if ul padding != "16px"
149		},
150
151		treeCreate: function (ctx) {
152			this._superApply(arguments);
153			this.$container.addClass("fancytree-ext-wide");
154
155			var containerId,
156				cssText,
157				iconSpacingUnit,
158				labelSpacingUnit,
159				iconWidthUnit,
160				levelOfsUnit,
161				instOpts = ctx.options.wide,
162				// css sniffing
163				$dummyLI = $(
164					"<li id='fancytreeTemp'><span class='fancytree-node'><span class='fancytree-icon' /><span class='fancytree-title' /></span><ul />"
165				).appendTo(ctx.tree.$container),
166				$dummyIcon = $dummyLI.find(".fancytree-icon"),
167				$dummyUL = $dummyLI.find("ul"),
168				// $dummyTitle = $dummyLI.find(".fancytree-title"),
169				iconSpacing =
170					instOpts.iconSpacing || $dummyIcon.css("margin-left"),
171				iconWidth = instOpts.iconWidth || $dummyIcon.css("width"),
172				labelSpacing = instOpts.labelSpacing || "3px",
173				levelOfs = instOpts.levelOfs || $dummyUL.css("padding-left");
174
175			$dummyLI.remove();
176
177			iconSpacingUnit = iconSpacing.match(reNumUnit)[2];
178			iconSpacing = parseFloat(iconSpacing, 10);
179			labelSpacingUnit = labelSpacing.match(reNumUnit)[2];
180			labelSpacing = parseFloat(labelSpacing, 10);
181			iconWidthUnit = iconWidth.match(reNumUnit)[2];
182			iconWidth = parseFloat(iconWidth, 10);
183			levelOfsUnit = levelOfs.match(reNumUnit)[2];
184			if (
185				iconSpacingUnit !== iconWidthUnit ||
186				levelOfsUnit !== iconWidthUnit ||
187				labelSpacingUnit !== iconWidthUnit
188			) {
189				$.error(
190					"iconWidth, iconSpacing, and levelOfs must have the same css measure unit"
191				);
192			}
193			this._local.measureUnit = iconWidthUnit;
194			this._local.levelOfs = parseFloat(levelOfs);
195			this._local.lineOfs =
196				(1 +
197					(ctx.options.checkbox ? 1 : 0) +
198					(ctx.options.icon === false ? 0 : 1)) *
199					(iconWidth + iconSpacing) +
200				iconSpacing;
201			this._local.labelOfs = labelSpacing;
202			this._local.maxDepth = 10;
203
204			// Get/Set a unique Id on the container (if not already exists)
205			containerId = this.$container.uniqueId().attr("id");
206			// Generated css rules for some levels (extended on demand)
207			cssText = renderLevelCss(
208				containerId,
209				this._local.maxDepth,
210				this._local.levelOfs,
211				this._local.lineOfs,
212				this._local.labelOfs,
213				this._local.measureUnit
214			);
215			defineHeadStyleElement(containerId, cssText);
216		},
217		treeDestroy: function (ctx) {
218			// Remove generated css rules
219			defineHeadStyleElement(this.$container.attr("id"), null);
220			return this._superApply(arguments);
221		},
222		nodeRenderStatus: function (ctx) {
223			var containerId,
224				cssText,
225				res,
226				node = ctx.node,
227				level = node.getLevel();
228
229			res = this._super(ctx);
230			// Generate some more level-n rules if required
231			if (level > this._local.maxDepth) {
232				containerId = this.$container.attr("id");
233				this._local.maxDepth *= 2;
234				node.debug(
235					"Define global ext-wide css up to level " +
236						this._local.maxDepth
237				);
238				cssText = renderLevelCss(
239					containerId,
240					this._local.maxDepth,
241					this._local.levelOfs,
242					this._local.lineOfs,
243					this._local.labelSpacing,
244					this._local.measureUnit
245				);
246				defineHeadStyleElement(containerId, cssText);
247			}
248			// Add level-n class to apply indentation padding.
249			// (Setting element style would not work, since it cannot easily be
250			// overriden while animations run)
251			$(node.span).addClass("fancytree-level-" + level);
252			return res;
253		},
254	});
255	// Value returned by `require('jquery.fancytree..')`
256	return $.ui.fancytree;
257}); // End of closure
258