PageSourceSearch

https://dpi.lv/assets/js/utopia.js

js dpi.lv collected 2026-10-03 22:08:15 UTC 10,558 bytes, 440 lines download raw bytes

1/**
2 * Utopia: A JavaScript util library that assumes modern standards support and doesn't fix any browser bugs
3 * @author Lea Verou (http://lea.verou.me)
4 * MIT license (http://www.opensource.org/licenses/mit-license.php)
5 * Last update: 2012-4-29
6 */
7 
8function $(expr, con) {
9	return typeof expr === 'string'? (con || document).querySelector(expr) : expr;
10}
11
12function $$(expr, con) {
13	return Array.prototype.slice.call((con || document).querySelectorAll(expr));
14}
15
16// Make each ID a global variable
17// Many browsers do this anyway (it’s in the HTML5 spec), so it ensures consistency
18$$('[id]').forEach(function(element) { window[element.id] = element; });
19
20// Array#splice but for strings
21String.prototype.splice = function(i, remove, add) {
22	remove = +remove || 0;
23	add = add || '';
24	
25	return this.slice(0,i) + add + this.slice(i + remove);
26};
27
28(function(){
29
30var _ = window.Utopia = {
31	/**
32	 * Returns the [[Class]] of an object in lowercase (eg. array, date, regexp, string etc)
33	 * Caution: Results for DOM elements and collections aren't reliable.
34	 * @param {Object} obj
35	 *
36	 * @return {String}
37	 */
38	type: function(obj) {
39		if(obj === null) { return 'null'; }
40
41		if(obj === undefined) { return 'undefined'; }
42
43		var ret = Object.prototype.toString.call(obj).match(/^\[object\s+(.*?)\]$/)[1];
44
45		ret = ret? ret.toLowerCase() : '';
46
47		if(ret == 'number' && isNaN(obj)) {
48			return 'NaN';
49		}
50
51		return ret;
52	},
53
54	/**
55	 * Iterate over the properties of an object. Checks whether the properties actually belong to it.
56	 * Can be stopped if the function explicitly returns a value that isn't null, undefined or NaN.
57	 * 
58	 * @param obj {Object} The object to iterate over
59	 * @param func {Function} The function used in the iteration. Can accept 2 parameters: one of the
60	 * 							value of the object and one for its name.
61	 * @param context {Object} Context for the above function. Default is the object being iterated.
62	 *
63	 * @return {Object} Null or the return value of func, if it broke the loop at some point.
64	 */
65	each: function(obj, func, context) {
66		if(!_.type(func) == 'function') {
67			throw Error('The second argument in Utopia.each() must be a function');
68		};
69
70		context = context || obj;
71
72		for (var i in obj) {
73			if(obj.hasOwnProperty && obj.hasOwnProperty(i)) {
74				var ret = func.call(context, obj[i], i);
75
76				if(!!ret || ret === 0 || ret === '') {
77					return ret;
78				}
79			}
80		}
81
82		return null;
83	},
84
85	/**
86	 * Copies the properties of one object onto another.
87	 * When there is a collision, the later one wins
88	 *
89	 * @return {Object} destination object
90	 */
91	merge: function(objects) {
92		var ret = {};
93		
94		for(var i=0; i<arguments.length; i++) {
95			var o = arguments[i];
96			
97			for(var j in o) {
98				ret[j] = o[j];
99			}
100		}
101		
102		return ret;
103	},
104	
105	/**
106	 * Copies the properties of one or more objects onto the first one
107	 * When there is a collision, the first object wins
108	 */
109	attach: function(object, objects) {
110		for(var i=0; i<arguments.length; i++) {
111			var o = arguments[i];
112			
113			for(var j in o) {
114				if(!(j in object)) {
115					object[j] = o[j];
116				}
117			}
118		}
119		
120		return object;
121	},
122	
123	element: {
124		/**
125		 * Creates a new DOM element
126		 * @param options {Object} A set of key/value pairs for attributes, properties, contents, placement in the DOM etc
127		 * @return The new DOM element
128		 */
129		create: function() {
130			var options;
131
132			if(_.type(arguments[0]) === 'string') {
133				if(_.type(arguments[1]) === 'object') {
134					// Utopia.element.create('div', { ... });
135					options = arguments[1];
136					options.tag = arguments[0];
137				}
138				else {
139					// Utopia.element.create('div', ...);
140					options = {
141						tag: arguments[0]
142					};
143					
144					// Utopia.element.create('div', [contents]);
145					if(_.type(arguments[1]) === 'array') {
146						options.contents = arguments[1];
147					}
148					// Utopia.element.create('div', 'Text contents');
149					else if(_.type(arguments[1]) === 'string' || _.type(arguments[1]) === 'number') {
150						options.contents = ['' + arguments[1]];
151					}
152				}
153			}
154			else {
155				options = arguments[0];
156			}
157			
158			var namespace = options.namespace || '', element;
159			
160			if(namespace) {
161				element = document.createElementNS(namespace, options.tag);
162			}
163			else {
164				element = document.createElement(options.tag);
165			}
166			
167			if(options.className) {
168				options.properties = options.properties || {};
169				options.properties.className = options.className;
170			}
171			
172			// Set properties, attributes and contents
173			_.element.set(element, options);
174			
175			// Place the element in the DOM (inside, before or after an existing element)
176			// This could be a selector
177			if(options.inside) {
178				$(options.inside).appendChild(element);
179			}
180			else if(options.before) {
181				var before = $(options.before);
182				
183				before.parentNode.insertBefore(element, before)
184			}
185			else if(options.after) {
186				var after = $(options.after);
187				
188				after.parentNode.insertBefore(element, after.nextSibling)
189			}
190			
191			return element;
192		},
193		
194		set: function(element, options) {
195			_.element.prop(element, options.properties || options.prop);
196					
197			_.element.attr(element, options.attributes || options.attr);
198			
199			_.element.contents(element, options.contents);
200	
201			return element;
202		},
203		
204		prop: function (element, properties) {
205			if (properties) {
206				for (var prop in properties) {
207					try { // Bloody IE <= 9
208						element[prop] = properties[prop];
209					}
210					catch(e) {}
211				}
212			}
213			
214			return element;
215		},
216		
217		attr: function (element, attributes) {
218			if (attributes) {
219				for (attr in attributes) {
220					element.setAttribute(attr, attributes[attr]);
221				}
222			}
223			
224			return element;
225		},
226		
227		/**
228		 * Sets an element’s contents
229		 * Contents could be: One or multiple (as an array) of the following:
230		 *			- An object literal that will be passed through Utopia.element.create
231		 *			- A string or number, which will become a text node
232		 *			- An existing DOM element
233		 */
234		contents: function (element, contents, where) {
235			if(contents || contents === 0) {
236				if (_.type(contents) !== 'array') {
237					contents = [contents];
238				}
239				
240				var firstChild = element.firstChild;
241				
242				for (var i=0; i<contents.length; i++) {
243					var content = contents[i], child;
244					
245					switch(_.type(content)) {
246						case 'string':
247							if(content === '') {
248								continue;
249							}
250							// fall through
251						case 'number':
252							child = document.createTextNode(content);
253							break;
254						case 'object':
255							child = _.element.create(content);
256							break;
257						default:
258							child = content;
259
260					}
261					
262					if(child) {
263						if (!where || where === 'end') {
264							element.appendChild(child);
265						}
266						else if (where === 'start') {
267							element.insertBefore(child, firstChild);
268						}
269					}
270				}	
271			}
272			
273			return element;
274		}
275	},
276	
277	elements: {
278		// set, attr, prop, contents functions from Utopia.element, but for multiple elements
279	},
280	
281	event: {
282		/**
283		 * Binds one or more events to one or more elements
284		 */
285		bind: function(target, event, callback, traditional) {
286			if(_.type(target) === 'string' || _.type(target) === 'array') {
287				var elements = _.type(target) === 'string'? $$(target) : target;
288				
289				elements.forEach(function(element) {
290					_.event.bind(element, event, callback, traditional);
291				});
292			}
293			else if(_.type(event) === 'string') {
294				if(traditional) {
295					target['on' + event] = callback;
296				}
297				else {
298					target.addEventListener(event, callback, false);
299				}
300			}
301			else if(_.type(event) === 'array') {
302				for (var i=0; i<event.length; i++) {
303					_.event.bind(target, event[i], callback, arguments[2]);
304				}
305			}
306			else {
307				for (var name in event) {
308					_.event.bind(target, name, event[name], arguments[2]);
309				}
310			}
311		},
312		
313		/**
314		 * Fire a custom event
315		 */
316		fire: function(target, type, properties) {
317			if(_.type(target) === 'string' || _.type(target) === 'array') {
318				var elements = _.type(target) === 'string'? $$(target) : target;
319				
320				elements.forEach(function(element) {
321					_.event.fire(element, type, properties);
322				});
323			}
324			else {
325				var evt = document.createEvent("HTMLEvents");
326		
327				evt.initEvent(type, true, true );
328				evt.custom = true;
329		
330				if(properties) {
331					_.attach(evt, properties);
332				}
333
334				target.dispatchEvent(evt);
335			}
336		}
337	},
338	
339	/**
340	 * Helper for XHR requests
341	 */
342	xhr: function(o) {
343		document.body.setAttribute('data-loading', '');
344		
345		var xhr = new XMLHttpRequest(),
346			method = o.method || 'GET',
347			data = o.data || '';
348		
349		o.headers = o.headers || {};
350		
351		xhr.open(method, o.url + (method === 'GET' && data? '?' + data : ''), !o.sync);
352		
353		if (method !== 'GET' && !o.headers['Content-type'] && !o.headers['Content-Type']) {
354			xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
355		}
356		
357		for (var header in o.headers) {
358			xhr.setRequestHeader(header, o.headers[header]);
359		}
360		
361		var callback = function() {
362			document.body.removeAttribute('data-loading');
363			
364			o.callback(xhr);
365		};
366		
367		xhr.onreadystatechange = function(){
368			if (xhr.readyState === 4) {
369				callback();
370			}
371		};
372		
373		xhr.send(method === 'GET'? null : data);
374		
375		return xhr;
376	},
377	
378	/**
379	 * Lazy loads an external script
380	 */
381	script: function(url, callback, doc) {
382		doc = doc || document;
383		
384		return _.element.create('script', {
385			properties: {
386				src: url,
387				async: true,
388				onload: callback
389			},
390			inside: doc.documentElement
391		});
392	},
393	
394	/**
395	 * Returns the absolute X, Y offsets for an element
396	 */
397	offset: function(element) {
398	    var left = 0, top = 0, el = element;
399	    
400	    if (el.parentNode) {
401			do {
402				left += el.offsetLeft;
403				top += el.offsetTop;
404			} while ((el = el.offsetParent) && el.nodeType < 9);
405			
406			el = element;
407			
408			do {
409				left -= el.scrollLeft;
410				top -= el.scrollTop;
411			} while ((el = el.parentNode) && !/body/i.test(el.nodeName));
412		}
413	
414	    return {
415			top: top,
416	    	right: innerWidth - left - element.offsetWidth,
417	    	bottom: innerHeight - top - element.offsetHeight,
418	    	left: left,
419	    };
420	}
421};
422
423['set', 'prop', 'attr', 'contents'].forEach(function(method) {
424	_.elements[method] = function(elements) {
425		elements = _.type(elements) === 'string'? $$(elements) : Array.prototype.slice.call(elements);
426		
427		var args = Array.prototype.slice.call(arguments);
428		args.shift(); // Remove the elements argument
429		
430		elements = elements.map(function(element) {
431			return _.element[method](element, args);
432		});
433		
434		return elements;
435	}
436});
437
438})();
439
440window.$u = window.$u || Utopia;

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.