PageSourceSearch

https://empop.online/bundles/empopclient/js/vendor/vxJS/widget.js

js empop.online collected 2026-09-25 20:47:59 UTC 8,479 bytes, 391 lines download raw bytes

1/**
2 * Provides custom elements and functionality used with widgets
3 * 
4 * @version 0.6.12 2012-07-28
5 * @author Gregor Kofler
6 * 
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code
9 */
10
11/**
12 * vxJS.widget.shared.overlay()
13 * vxJS.widget.shared.hiLite(text, node, className)
14 * vxJS.widget.shared.shadeTableRows(parameterObject)
15 * vxJS.widget.shared.list(parameterObject)
16 * 
17 * @todo list: Safari doesn't follow keystrokes
18 */
19
20"use strict";
21
22vxJS.widget.shared = {
23
24	overlay: function() {
25		var that;
26
27		return function(config) {
28			var size, resizeListenerId, shown, elem, body = vxJS.dom.getBody();
29
30			if(that) {
31				return that;
32			}
33
34			var resize = function() {
35				var sizeTo = vxJS.dom.getViewportSize();
36				
37				if(sizeTo.x <= size.x && sizeTo.y <= size.y) {
38					return;
39				}
40
41				size = sizeTo;
42				vxJS.dom.setElementSize(elem, size);
43			};
44
45			var show = function() {
46				if(shown || !body) {
47					return;
48				}
49				
50				shown = true;
51
52				if(!elem) {
53					elem = "div".setProp("class", "vxJS_overlay").create();
54					vxJS.dom.setElementPosition(elem, new Coord());
55
56					body.appendChild(elem);									// IE requires attached element to check properties
57					elem.style.position = vxJS.dom.allowsFixedPosition() ? "fixed" : "absolute";
58				}
59				
60				else {
61					body.appendChild(elem);
62				}
63				size = vxJS.dom.getViewportSize();
64				vxJS.dom.setElementSize(elem, size);
65
66				resizeListenerId = vxJS.event.addListener(window, "resize", resize);
67			};
68
69			var hide = function() {
70				if(!shown || !elem) {
71					return;
72				}
73
74				shown = false;
75				vxJS.event.removeListener(resizeListenerId);
76				elem = body.removeChild(elem);
77			};
78
79			that = {
80				show: show,
81				hide: hide
82			};
83
84			return that;
85		};
86	}(),
87
88	/**
89	 * hilight text beneath a given node
90	 */
91	hiLite: function(text, node, cN) {
92
93		var	rex = new RegExp(text, "gi"), fixRex = new RegExp("^" + text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), "i"),
94			chunks, hits, frag = document.createDocumentFragment(), i;
95
96		if(!cN)		{ cN = "hiLite"; }
97		if(!node)	{ node = document; }
98
99		vxJS.dom.walk(node, function(n) {
100			if(n.nodeType !== 3) {
101				return;
102			}
103
104			hits = n.nodeValue.match(rex);
105
106			if(hits && hits.length) {
107
108				chunks = n.nodeValue.split(rex);
109
110				if(chunks.length < 2) {
111					if(fixRex.test(n.nodeValue)) {
112						frag.appendChild("span".setProp("class", cN).create(hits[0]));
113						frag.appendChild(document.createTextNode(chunks[0]));
114					}
115					else {
116						frag.appendChild(document.createTextNode(chunks[0]));
117						frag.appendChild("span".setProp("class", cN).create(hits[0]));
118					}
119				}
120				else {
121					for(i = 0; i < chunks.length-1; ++i) {
122						frag.appendChild(document.createTextNode(chunks[i]));
123						frag.appendChild("span".setProp("class", cN).create(hits.shift()));
124					}
125					frag.appendChild(document.createTextNode(chunks[i]));
126				}
127				n.parentNode.replaceChild(frag, n);
128			}
129		});
130	},
131
132	/**
133	 * shade table rows by assigning alternating class names
134	 */
135	shadeTableRows: function(param) {
136		var t, r, c, i, j, l;
137		if(!param || !(t = param.element)) {
138			return;
139		}
140
141		if (t.nodeName.toUpperCase() !== "TBODY") {
142			if (!t.tBodies || !(t = t.tBodies[0])) {
143				return;
144			}
145		}
146		if(!(r = t.rows)) {
147			return;
148		}
149		c = param.classNames && param.classNames.length && param.classNames.length > 1 ? param.classNames : ["row0", "row1"];
150
151		for(i = 0, j = 0, l = r.length; l--; ++j) {
152			if(r[j].style.display !== "none") {
153				r[j].className = [r[j].className.replace(new RegExp("(^| )(" + c.join("|") +")( |$)"), ""), c[i++ % c.length]].join(" ");
154			}
155		}
156	},
157
158	/**
159	 * a list widget, used with vxJS.widget.autoSuggest(), vxJS.widget.queryPopup(), etc.
160	 *
161	 * served events: "choose", "toggle", "cancel"
162	 */
163	list: function(param) {
164		param = param || {};
165
166		var	ul = "ul".setProp("class", param.className || "vxJS_list").create(),
167			entries, multiple = param.multiple || false, selected = [], current, that = {},
168			kc, kdFlag;
169		
170		ul.style.position = "relative";
171		
172		var setCurrent = function(n) {
173			if(current === n) {
174				return;
175			}
176			if(current) {
177				vxJS.dom.removeClassName(current, "current");
178			}
179			vxJS.dom.addClassName(n, "current");
180			current = n;
181
182			if(!multiple) {
183				selected[0] = n;
184			}
185		};
186		
187		var focus = function() {
188			ul.tabIndex = -1;
189			ul.focus();
190		};
191		
192		var toggleSelected = function(n) {
193			var i;
194			if(!multiple) {
195				return;
196			}
197			for(i = selected.length; i--;) {
198				if(selected[i] === n) {
199					selected.splice(i, 1);
200					n.className = n.className.replace(/([ ]?selected)/, "");
201					vxJS.serve(that, "toggle");
202					return;
203				}
204			}
205			n.className += n.className ? " selected" : "selected";
206			selected.push(n);
207			vxJS.serve(that, "toggle");
208		};
209
210		var scrollIn = function() {
211			var	d = vxJS.dom.getElementOffset(current, ul).y,
212				liH = d + vxJS.dom.getElementSize(current).y,
213				ulH = vxJS.dom.getElementSize(ul).y;
214
215			if(d < ul.scrollTop) {
216				ul.scrollTop = d;
217			}
218			
219			else if(liH > ulH + ul.scrollTop) {
220				ul.scrollTop = liH - ulH;
221			}
222		};
223
224		var hiLite = function(n) {
225			if(n !== ul) {
226				setCurrent(n.nodeName.toUpperCase() !== "LI" ? vxJS.dom.getParentElement(n, "li") : n);
227			}
228		};
229
230		var findEntry = function(n) {
231			var i;
232			for(i = entries.length; i--;) {
233				if(entries[i].elem === n) {
234					return entries[i];
235				}
236			}
237		};
238
239		var fill = function(newEntries) {
240			var i;
241			entries = newEntries || [];
242			
243			if(!entries.length) {
244				ul.style.display = "none";
245				return;
246			}
247
248			vxJS.dom.deleteChildNodes(ul);
249			for(i = 0; i < entries.length; ++i) {
250				entries[i].elem = "li".create(entries[i].elements ? vxJS.dom.parse(entries[i].elements) : entries[i].text);
251				entries[i].elem.style.position = "relative";
252				ul.appendChild(entries[i].elem);
253			}
254
255			ul.style.display = "";
256			setCurrent(ul.firstChild);
257			scrollIn();
258		};
259
260		var keypress = function(e) {
261			if(!kdFlag) {
262				switch (kc) {
263					case 38:
264						that.up();
265						break;
266					case 40:
267						that.down();
268						break;
269				}
270			}
271			kdFlag = false;
272			vxJS.event.preventDefault(e);
273		};
274
275		var mousedown = function() {
276			if(!param.hoverSelect) {
277				hiLite(this);
278			}
279			if(this !== ul) {
280				vxJS.event.serve(that, "choose");
281			}
282		};
283
284		var click = function() {
285			if(this !== ul) {
286				toggleSelected(this.nodeName.toUpperCase() !== "LI" ? vxJS.dom.getParentElement(this, "li") : this);
287			}
288		};
289
290		var keydown = function(e) {
291
292			kdFlag = true;
293			kc = e.keyCode;
294
295			switch (kc) {
296				case 13:
297					vxJS.event.serve(that, "choose"); break;
298				case 27:
299					vxJS.event.serve(that, "cancel"); break;
300				case 38:
301					that.up(); break;
302				case 40:
303					that.down(); break;
304				case 36:
305					that.first(); break;
306				case 35:
307					that.last(); break;
308				case 32:
309					toggleSelected(current); break;
310			}
311			vxJS.event.preventDefault(e);
312		};
313
314		vxJS.event.addListener(ul, "mousedown", mousedown);
315		vxJS.event.addListener(ul, "click", click);
316		vxJS.event.addListener(ul, "keydown", keydown);
317		vxJS.event.addListener(ul, "keypress", keypress);
318		
319		vxJS.event.addMousewheelListener(ul, function(e) { that[vxJS.event.getMousewheelDirection(e)](); });
320
321		if(param.hoverSelect) {
322			vxJS.event.addListener(ul, "mouseover", function() {
323					hiLite(this);
324				}
325			);
326		}
327		fill(param.entries);
328
329		/**
330		 * public properties and functions
331		 */
332		that.getSelected = function() {
333			var s = [], i;
334			if(selected.length) {
335				for(i = 0; i < selected.length; ++i) {
336					s.push(findEntry(selected[i]));
337				}
338				return s;
339			}
340		};
341
342		that.up = function() {
343			if(current === ul.firstChild) {
344				return;
345			}
346			if(!current && ul.lastChild) {
347				setCurrent(ul.lastChild);
348			}
349			else {
350				setCurrent(current.previousSibling);
351			}
352			scrollIn();
353		};
354
355		that.down = function() {
356			if(current === ul.lastChild) {
357				return;
358			}
359			if(!current && ul.firstChild) {
360				setCurrent(ul.firstChild);
361			}
362			else {
363				setCurrent(current.nextSibling);
364			}
365			scrollIn();
366		};
367		
368		that.first = function() {
369			if(current === ul.firstChild) {
370				return;
371			}
372			setCurrent(ul.firstChild);
373			scrollIn();
374		};
375
376		that.last = function() {
377			if(current === ul.lastChild) {
378				return;
379			}
380			setCurrent(ul.lastChild);
381			scrollIn();
382		};
383
384		that.getRows	= function() { return entries ? entries.length : 0; };
385		that.focus		= focus;
386		that.fill		= fill;
387		that.element	= ul;
388
389		return that;
390	}
391};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.