PageSourceSearch

https://artium.eus/templates/favourite/roksprocket/layouts/mosaic/themes/default/mosaic.js

js artium.eus collected 2026-10-02 07:16:57 UTC 24,061 bytes, 735 lines download raw bytes

1/*!
2 * @version   $Id: mosaic.js 10889 2013-05-30 07:48:35Z btowles $
3 * @author    RocketTheme http://www.rockettheme.com
4 * @copyright Copyright (C) 2007 - 2015 RocketTheme, LLC
5 * @license   http://www.gnu.org/licenses/gpl-2.0.html GNU/GPLv2 only
6 */
7((function(){
8	if (typeof this.RokSprocket == 'undefined') this.RokSprocket = {};
9	else Object.merge(this.RokSprocket, {Mosaic: null, MosaicBuilder: null});
10
11	var supportsOrientationChange = "onorientationchange" in window;
12
13	var Mosaic = new Class({
14
15		Implements: [Options, Events],
16
17		options: {
18			settings: {}
19		},
20
21		initialize: function(options){
22			this.setOptions(options);
23
24			this.mosaics = document.getElements('[data-mosaic]');
25			this.mosaic = {};
26			this.settings = {};
27			this.curve = Browser.opera ? {equation: 'ease-in-out'} : {curve: 'cubic-bezier(0.37,0.61,0.59,0.87)'};
28
29			try {
30				RokMediaQueries.on('every', this.mediaQuery.bind(this));
31			}
32			catch(error) { if (typeof console != 'undefined') console.error('Error while trying to add a RokMediaQuery "match" event', error); }
33		},
34
35		attach: function(mosaic, settings){
36			mosaic = typeOf(mosaic) == 'number' ?
37					document.getElements('[data-mosaic=' + this.getID(mosaic) + ']')
38					:
39					mosaic;
40			settings = typeOf(settings) == 'string' ? JSON.decode(settings) : settings;
41
42			var containers = (mosaic ? new Elements([mosaic]).flatten() : this.mosaics);
43
44			containers.each(function(container){
45				container.store('roksprocket:mosaic:attached', true);
46
47				this.setSettings(container, settings, 'restore');
48
49				var relay = {
50					loadmore: container.retrieve('roksprocket:mosaic:loadmore', function(event, page){
51						if (event) event.preventDefault();
52						this.loadMore.call(this, event, container, page);
53					}.bind(this)),
54
55					ordering: container.retrieve('roksprocket:mosaic:ordering', function(event, element){
56						this.orderBy.call(this, event, container, element);
57					}.bind(this)),
58
59					filtering: container.retrieve('roksprocket:mosaic:filtering', function(event, element){
60						this.filterBy.call(this, event, container, element);
61					}.bind(this)),
62
63					document: document.retrieve('roksprocket:mosaic:document', function(event, element){
64						this.toggleShift.call(this, event, container, element);
65					}.bind(this))
66				};
67
68				container.addEvent('click:relay([data-mosaic-loadmore])', relay['loadmore']);
69				container.addEvent('click:relay([data-mosaic-orderby])', relay['ordering']);
70				container.addEvent('click:relay([data-mosaic-filterby])', relay['filtering']);
71
72				container.retrieve('roksprocket:mosaic:ajax', new RokSprocket.Request({
73					model: 'mosaic',
74					model_action: 'getPage',
75					onRequest: this.onRequest.bind(this, container),
76					onSuccess: function(response){
77						this.onSuccess(response, container, container.retrieve('roksprocket:mosaic:ajax'));
78					}.bind(this)
79				}));
80
81				document.addEvents({
82					'keydown:keys(shift)': relay['document'],
83					'keyup:keys(shift)': relay['document']
84				});
85
86				this.initializeMosaic(container, function(){
87					this.mediaQuery.delay(5, this, RokMediaQueries.getQuery());
88				}.bind(this));
89			}, this);
90		},
91
92		detach: function(mosaic){
93			mosaic = typeOf(mosaic) == 'number' ?
94					document.getElements('[data-mosaic=' + this.getID(mosaic) + ']')
95					:
96					mosaic;
97
98			var containers = (mosaic ? new Elements([mosaic]).flatten() : this.mosaics);
99
100			containers.each(function(container){
101				container.store('roksprocket:mosaic:attached', false);
102				var relay = {
103					loadmore: container.retrieve('roksprocket:mosaic:loadmore'),
104					ordering: container.retrieve('roksprocket:mosaic:ordering'),
105					filtering: container.retrieve('roksprocket:mosaic:filtering'),
106					document: document.retrieve('roksprocket:mosaic:document')
107				};
108
109				container.removeEvent('click:relay([data-mosaic-loadmore])', relay['loadmore']);
110				container.removeEvent('click:relay([data-mosaic-orderby])', relay['ordering']);
111				container.removeEvent('click:relay([data-mosaic-filterby])', relay['filtering']);
112				document.removeEvents({
113					'keydown:keys(shift)': relay['document'],
114					'keyup:keys(shift)': relay['document']
115				});
116
117			}, this);
118		},
119
120		mediaQuery: function(query){
121			var mosaic;
122
123			for (var id in this.mosaic){
124				mosaic = this.mosaic[id];
125				mosaic.resize('fast');
126			}
127		},
128
129		setSettings: function(container, settings, restore){
130			var id = this.getID(container),
131				options = Object.clone(this.getSettings(container) || this.options.settings);
132
133			if (!restore || !this.settings['id-' + id]){
134				this.settings['id-' + id] = Object.merge(options, settings || options);
135			}
136		},
137
138		getSettings: function(container){
139			var id = this.getID(container);
140
141			return this.settings['id-' + id];
142		},
143
144		getContainer: function(container){
145			if (!container) container = document.getElements('[data-mosaic]');
146			if (typeOf(container) == 'number') container = document.getElement('[data-mosaic='+container+']');
147			if (typeOf(container) == 'string') container = document.getElement(container);
148
149			return container;
150		},
151
152		getID: function(id){
153			if (typeOf(id) == 'number') id = document.getElement('[data-mosaic='+id+']');
154			if (typeOf(id) == 'string') id = document.getElement(id);
155			return !id ? id : id.get('data-mosaic');
156		},
157
158		loadMore: function(event, container, page){
159			container = this.getContainer(container);
160			page = (typeOf(page) == 'number') ? page : this.getSettings(container).page || 1;
161			if (!container.retrieve('roksprocket:mosaic:attached')) return;
162			
163			if (Browser.name == 'ie' && Browser.version < 11)
164				languageval = container.getAttribute('data-language');
165			else 
166				languageval = container.dataset.language;
167			var ajax = container.retrieve('roksprocket:mosaic:ajax'),
168				filterby = container.getElement('[data-mosaic-filterby].active'),
169				params = {
170					language: languageval,
171					moduleid: container.get('data-mosaic'),
172					behavior: !page ? 'reset' : 'append',
173					displayed: !page ? [] : this.getSettings(container).displayed || [],
174					filter: filterby ? filterby.get('data-mosaic-filterby') || 'all' : 'all',
175					page: ++page
176				};
177
178			if (event && event.shift) params.all = true;
179
180			if (!ajax.isRunning()){
181				ajax.cancel().setParams(params).send();
182			}
183		},
184
185		filterBy: function(event, container, element){
186			container.getElements('[data-mosaic-filterby]').removeClass('active');
187			
188			container.getElements('#idfiltrofecha').removeClass('active');
189			if (jQuery('#button_fechas').size()>0)
190				if (!element.hasClass("filtrofecha")) {
191					jQuery('#button_fechas').text(jQuery('#button_fechas').data().texto);
192				}
193
194			element.addClass('active');
195
196			container.addClass('refreshing');
197			this.loadMore(event, container, 0);
198
199		},
200
201		nextAll: function(containers, element){
202			containers = this.getContainer(containers);
203			if (typeOf(containers) == 'element') return this.next(containers, element);
204
205			containers.each(function(container){
206				this.next(container, element);
207			}, this);
208		},
209
210		toggleShift: function(event, container, element){
211			var type = event.type || 'keyup',
212				loadmore = document.getElements('[data-mosaic-loadmore]');
213
214			if (!loadmore.length) return true;
215
216			if (type == 'keydown') loadmore.addClass('load-all');
217			else loadmore.removeClass('load-all');
218		},
219
220		onRequest: function(container){
221			var loadmore = container.getElements('[data-mosaic-loadmore]');
222			if (loadmore) loadmore.addClass('loader');
223
224			this.detach(container);
225		},
226
227		onSuccess: function(response, container){
228			var id = 'id-' + this.getID(container),
229				ajax = container.retrieve('roksprocket:mosaic:ajax'),
230				items = container.getElement('[data-mosaic-items]'),
231				html = response.getPath('payload.html'),
232				page = response.getPath('payload.page'),
233				more = response.getPath('payload.more'),
234				behavior = response.getPath('payload.behavior'),
235				displayed = response.getPath('payload.displayed'),
236				settings = this.getSettings(container),
237				animations = settings.animations,
238				imgList;
239
240			this.setSettings(container, {page: (behavior == 'reset' ? 1 : page), displayed: displayed});
241			container.removeClass('refreshing');
242
243			var dummy = new Element('div', {html: html}),
244				elements = dummy.getChildren(),
245				styles = {},
246				options = {};
247
248			styles = this.getAnimation(container, '_set').style;
249
250			if (elements.length > 0) { // if de carlos
251				moofx(elements).style(styles);
252			} // carlos
253
254			items.adopt(elements);
255			imgList = new Elements(elements.getElements('img').flatten());
256
257			this._loadImages(imgList.get('src'), function(){
258				if (behavior == 'reset'){
259					this.mosaic[id].bricks.each(function(element, i){
260						(function(){
261							styles = this.getAnimation(container, '_out');
262							moofx(element).style(styles.style);
263							options = Object.merge({}, this.curve, {duration: '250ms', callback: function(){ element.dispose(); }});
264							moofx(element).animate(styles.animate, options);
265						}).delay(i * 50, this);
266					}, this);
267				}
268				this.mosaic[id][behavior](elements, function(){
269					loadmore = container.getElements('[data-mosaic-loadmore]');
270					if (loadmore) loadmore.removeClass('loader');
271
272					elements = this.mosaic[id].bricks.filter(function(element){ return elements.contains(element); });
273					elements.each(function(element, i){
274						(function(){
275							styles = this.getAnimation(container, '_in');
276							options = Object.merge({}, this.curve, {curve: 'cubic-bezier(0.37,0.61,0.59,0.87)', duration: '300ms'});
277							moofx(element).animate(styles.animate, options);
278						}).delay(i * 100, this);
279					}, this);
280
281					this.attach(container);
282					container.getElements('[data-mosaic-loadmore]').removeClass('load-all')[!more ? 'addClass' : 'removeClass']('hide');
283
284				}.bind(this));
285			}.bind(this));
286
287		},
288
289		getAnimation: function(container, what){
290			var settings = this.getSettings(container),
291				type = settings.animations || null,
292				styles = {},
293				animation = {
294					_set: {style: {opacity: 0}, animate: {}},
295					_out: {style: {opacity: 1}, animate: {opacity: 0}},
296					_in: {style: {}, animate: {opacity: 1}}
297				};
298
299			type = type ? type.erase('fade') : null;
300			if (type && type.contains('flip')) type = type.erase('scale').erase('rotate');
301
302			// types: _set / _out / _in
303			switch(type ? type.join(',') : null){
304				case 'scale':
305					animation['_set']['style'] = Object.merge(animation['_set']['style'], {
306						transform: 'scale(0.5)'
307					});
308					animation['_out']['style'] = Object.merge(animation['_out']['style'], {
309						'transform-origin': '50% 50%'
310					});
311					animation['_out']['animate'] = Object.merge(animation['_out']['animate'], {
312						transform: Browser.ie9 ? 'scale(0.001)' : 'scale(0)'
313					});
314					animation['_in']['animate'] = Object.merge(animation['_in']['animate'], {
315						transform: Browser.ie9 || Browser.opera ? 'matrix(1, 0, 0, 1, 0, 0)' : 'scale(1)'
316					});
317					break;
318
319				case 'rotate':
320					animation['_set']['style'] = Object.merge(animation['_set']['style'], {
321						'transform-origin': '0 0',
322						transform: 'rotate(-10deg)'
323					});
324					animation['_out']['style'] = Object.merge(animation['_out']['style'], {
325						'transform-origin': '0 0'
326					});
327					animation['_out']['animate'] = Object.merge(animation['_out']['animate'], {
328						transform: 'rotate(10deg)'
329					});
330					animation['_in']['animate'] = Object.merge(animation['_in']['animate'], {
331						transform: 'rotate(0)'
332					});
333					break;
334
335				case 'rotate,scale': case 'scale,rotate':
336					animation['_set']['style'] = Object.merge(animation['_set']['style'], {
337						'transform-origin': '0 0',
338						transform: 'scale(0.5) rotate(-10deg)'
339					});
340					animation['_out']['style'] = Object.merge(animation['_out']['style'], {
341						'transform-origin': '50% 50%'
342					});
343					animation['_out']['animate'] = Object.merge(animation['_out']['animate'], {
344						transform: Browser.ie9 ? 'scale(0.001) rotate(10deg)' : 'scale(0) rotate(10deg)'
345					});
346					animation['_in']['animate'] = Object.merge(animation['_in']['animate'], {
347						transform: Browser.ie9 || Browser.opera ? 'matrix(1, 0, 0, 1, 0, 0)' : 'scale(1) rotate(0)'
348					});
349					break;
350
351				case 'flip':
352					animation['_set']['style'] = Object.merge(animation['_set']['style'], {
353						'transform-origin': '50% 50%',
354						transform: 'scale(0.5) rotateY(360deg)'
355					});
356					animation['_out']['style'] = Object.merge(animation['_out']['style'], {
357						'transform-origin': '50% 50%'
358					});
359					animation['_out']['animate'] = Object.merge(animation['_out']['animate'], {
360						transform: Browser.ie9 ? 'scale(0.0001) rotateY(360deg)' : 'scale(0.5) rotateY(360deg)'
361					});
362					animation['_in']['animate'] = Object.merge(animation['_in']['animate'], {
363						transform: 'scale(1) rotateY(0)'
364					});
365					break;
366				default:
367			}
368
369			return animation[what];
370
371		},
372
373		orderBy: function(event, container, element){
374			var id = 'id-' + this.getID(container);
375
376			if (!this.mosaic || !this.mosaic[id]) throw new Error('RokSprocket Mosaic: Mosaic class not available');
377
378			var orderBy = element.get('data-mosaic-orderby');
379			this.mosaic[id].order(orderBy/*, null, function(callback){}*/);
380
381			container.getElements('[data-mosaic-orderby]').removeClass('active');
382			if (orderBy != 'random') element.addClass('active');
383		},
384
385		initializeMosaic: function(container, callback){
386			var id = 'id-' + this.getID(container), loadmore;
387
388			if (this.mosaic && this.mosaic[id]){
389				if (typeof callback == 'function') callback.call(this.mosaic[id].bricks);
390
391				loadmore = container.getElements('[data-mosaic-loadmore]');
392				if (loadmore) loadmore.removeClass('loader');
393
394				return this.mosaic[id];
395			}
396
397			var imgList = container.getElements('img'),
398				elements = container.getElement('[data-mosaic-items]'),
399				activeOrder = container.getElement('.active[data-mosaic-orderby]'),
400				options = {
401					container: container,
402					animated: true,
403					gutter: 0,
404					order: activeOrder ? activeOrder.get('data-mosaic-orderby') : (container.getElements('[data-mosaic-orderby]').length ? 'random' : 'default')
405				},
406				items = elements.getElements('[data-mosaic-item]');
407
408			if (!items.length) return this.mosaic[id];
409
410			if (callback && typeof callback == 'function') options.callback = callback;
411
412			moofx(elements).style({'transform-style': 'preserve-3d', 'backface-visibility': 'hidden', opacity: 1});
413			moofx(items).style(this.getAnimation(container, '_in').animate);
414			if (!imgList.length){
415				loadmore = container.getElements('[data-mosaic-loadmore]');
416				if (loadmore) loadmore.removeClass('loader');
417
418				this.mosaic[id] = new RokSprocket.MosaicBuilder(elements, options);
419			} else {
420				this._loadImages(imgList.get('src'), function(){
421					loadmore = container.getElements('[data-mosaic-loadmore]');
422					if (loadmore) loadmore.removeClass('loader');
423
424					this.mosaic[id] = new RokSprocket.MosaicBuilder(elements, options);
425				}.bind(this));
426			}
427
428			return this.mosaic[id];
429		},
430
431		_loadImages: function(images, callback){
432			return images.length ? new Asset.images(images, {onComplete: callback.bind(this)}) : callback.bind(this)();
433		}
434
435	});
436
437
438	var MosaicBuilder = new Class({
439
440		Implements: [Options, Events],
441
442		options: {
443			/*columnWidth: function(){},*/
444			container: null,
445			resizeable: false,
446			animated: false,
447			gutter: 0,
448			fitwidth: false,
449			order: 'default',
450			containerStyle: {
451				position: 'relative'
452			}
453		},
454
455		initialize: function(element, options){
456			this.setOptions(options);
457
458			this.element = document.id(element) || document.getElement(element) || null;
459
460			if (!this.element) throw new Error('Mosaic Builder Error: Element "'+element+'" not found in the DOM.');
461
462			this.styleQueue = [];
463			this.curve = Browser.opera ? {equation: 'ease-in-out'} : {curve: 'cubic-bezier(0.37,0.61,0.59,0.87)'};
464			this.originalState = this.getBricks();
465
466			this.build();
467			this.init(options.callback || null);
468		},
469
470		build: function(){
471			var styles = this.element.style;
472
473			this.originalStyle = {
474				height: styles.height || ''
475			};
476
477			Object.each(this.options.containerStyle, function(value, prop){
478				this.originalStyle[prop] = styles[prop] || '';
479			}, this);
480
481			moofx(this.element).style(this.originalStyle);
482
483			this.offset = {
484				x: this.element.getStyle('padding-left').toInt(),
485				y: this.element.getStyle('padding-top').toInt()
486			};
487
488			this.isFluid = this.options.columnWidth && typeof this.options.columnWidth === 'function';
489
490			this.reloadItems(this.options.order || null);
491
492		},
493
494		init: function(callback){
495			this.getColumns();
496			this.reLayout(callback);
497		},
498
499		getBricks: function(items){
500			return (items ? items : this.element.getElements('[data-mosaic-item]')).setStyle('position', 'absolute');
501		},
502
503		reloadItems: function(order, items){
504			this.bricks = this.getBricks(items);
505			if (order == 'random' || order == 'default'){
506				if (order == 'random') this.bricks = this.bricks.shuffle();
507				if (order == 'default') this.bricks = this.originalState.clone();
508
509				return this.bricks;
510			}
511
512			this.bricks = order ? this.orderBy(order) : this.bricks;
513
514			return this.bricks;
515		},
516
517		orderBy: function(order){
518			var errorCheck = false;
519
520			return this.bricks.sort(function(a, b){
521				var aSort = a.getElement('[data-mosaic-order-' + order + ']'),
522					bSort = b.getElement('[data-mosaic-order-' + order + ']');
523
524				if (!aSort || !bSort){
525					if (console && console.error && !errorCheck) console.error('RokSprocket MosaicBuilder: Trying to sort by "'+order+'" but no sorting rule has been found.');
526					errorCheck = true;
527					return 0;
528				}
529
530				aSort = aSort.get('data-mosaic-order-' + order);
531				bSort = bSort.get('data-mosaic-order-' + order);
532
533				return aSort == bSort ? 0 : (aSort < bSort ? -1 : 1);
534			}.bind(this));
535		},
536
537		reload: function(callback){
538			this.reloadItems();
539			this.init(callback);
540		},
541
542		layout: function(bricks, callback, fast){
543			for (var i = 0, len = bricks.length; i < len; i++){
544				this.placeBrick(bricks[i]);
545			}
546
547			var containerSize = {}, options = {};
548			containerSize.height = Math.max.apply(Math, this.colYs);
549
550			if (this.options.fitwidth){
551				var unused = 0;
552				i = this.cols;
553
554				while (--i){
555					if (this.colYs[i] !== 0) break;
556					unused++;
557				}
558
559				containerSize.width = (this.cols - unused) * this.columnWidth - this.options.gutter;
560			}
561
562			this.styleQueue.push({element: this.element, style: containerSize});
563			var styleFn = !this.isLaidOut ? 'style' : (this.options.animated && !fast ? 'animate' : 'style'), obj;
564
565			this.styleQueue.each(function(style, i){
566				options = Object.merge({}, this.curve, {duration: '400ms'});
567
568				if (i == this.styleQueue.length - 1) if (callback) options.callback = callback.bind(callback, bricks);
569				moofx(style.element)[styleFn](style.style, options);
570			}, this);
571
572			this.styleQueue.empty();
573
574			if (callback && styleFn == 'style') callback.call(bricks);
575
576			this.isLaidOut = true;
577		},
578
579		getColumns: function(){
580			var container = this.options.fitwidth ? this.element.getParent() : this.element,
581				containerWidth = container.offsetWidth;
582
583			this.columnWidth =	this.isFluid ? this.options.columnWidth(containerWidth) : this.options.columnWidth ||
584								(this.bricks.length && this.bricks[0].offsetWidth) ||
585								containerWidth;
586
587			this.columnWidth += this.options.gutter;
588			this.cols = Math.round((containerWidth + this.options.gutter) / this.columnWidth);
589			this.cols = Math.max(this.cols, 1);
590		},
591
592		placeBrick: function(brick){
593			brick = document.id(brick);
594			var colSpan, groupCount, groupY, groupColY;
595
596			colSpan = Math.round(brick.offsetWidth / (this.columnWidth + this.options.gutter));
597			colSpan = Math.min(colSpan, this.cols);
598
599			if (colSpan == 1) groupY = this.colYs;
600			else {
601				groupCount = this.cols + 1 - colSpan;
602				groupY = [];
603
604				(groupCount).times(function(i){
605					groupColY = this.colYs.slice(i, i + colSpan);
606					groupY[i] = Math.max.apply(Math, groupColY);
607				}, this);
608			}
609
610			var minimumY = Math.min.apply(Math, groupY), shortCol = 0;
611
612			for (var i = 0, len = groupY.length; i < len; i++){
613				if (groupY[i] === minimumY){
614					shortCol = i;
615					break;
616				}
617			}
618
619			var position = {
620				top: minimumY + this.offset.y
621			};
622
623			//position.left = this.columnWidth * shortCol + this.offset.x;
624			position.left = shortCol * (100 / this.cols) + '%';
625			this.styleQueue.push({element: brick, style: position});
626
627			var setHeight = minimumY + brick.offsetHeight + ((this.options.gutter || 0)),
628				setSpan = this.cols + 1 - groupY.length;
629
630			(setSpan).times(function(i){
631				this.colYs[shortCol + i] = setHeight;
632			}, this);
633		},
634
635		resize: function(fast){
636			var prevColCount = this.cols;
637			this.getColumns();
638
639			if ((this.isFluid || fast) && this.cols !== prevColCount || fast) this.reLayout(null, fast);
640		},
641
642		reLayout: function(callback, fast){
643			var i = this.cols;
644			this.colYs = [];
645			while (i--) this.colYs.push(0);
646
647			this.layout(this.bricks, callback, fast);
648		},
649
650		reset: function(content, callback){
651			content = content.filter(function(element){
652				return element.get('data-mosaic-item') !== null || element.getElement('data-mosaic-item');
653			});
654
655			this.bricks = this.originalState = new Elements();
656			if (content.length==0) {
657				jQuery('.sprocket-mosaic-container #sinregistros').remove();
658				jQuery('.sprocket-mosaic-container').append('<li id="sinregistros">No hay registros</li>');
659			} else {
660				jQuery('.sprocket-mosaic-container #sinregistros').remove();
661			}
662
663			content.setStyles({'top': 0, left: 0, position: 'absolute'});
664			this.appendedBricks.delay(1, this, [content, content, callback]);
665		},
666
667		append: function(content, callback){
668			content = content.filter(function(element){
669				return element.get('data-mosaic-item') !== null || element.getElement('data-mosaic-item');
670			});
671
672			if (!content) return;
673
674			content.setStyles({'top': this.element.getSize().y, left: 0, position: 'absolute'});
675			this.appendedBricks.delay(1, this, [content, null, callback]);
676		},
677
678		appendedBricks: function(content, items, callback){
679			var order = this.options.container.getElement('[data-mosaic-orderby].active') || this.options.container.getElement('[data-mosaic-orderby=random]'),
680				by = order ? order.get('data-mosaic-orderby') : (this.options.container.getElements('[data-mosaic-orderby]').length ? 'random' : 'default');
681
682			this.originalState.append(content);
683			this.order(by, items, callback);
684			//this.reloadItems(by, callback);
685			//this.reload(callback);
686			//this.layout(content, callback);
687		},
688
689		order: function(type, items, callback){
690			this.reloadItems(type, items || null);
691			this.init(callback);
692		}
693
694	});
695
696	this.RokSprocket.Mosaic = Mosaic;
697	this.RokSprocket.MosaicBuilder = MosaicBuilder;
698
699	if (supportsOrientationChange){
700		window.addEventListener('orientationchange', function(){
701			if (typeof RokSprocket == 'undefined' || typeof RokSprocket.instances == 'undefined' || typeof RokSprocket.instances.mosaic == 'undefined') return;
702			var mosaic;
703
704			for (var id in RokSprocket.instances.mosaic.mosaic){
705				mosaic = RokSprocket.instances.mosaic.mosaic[id];
706				mosaic.resize('fast');
707			}
708		});
709	}
710
711	Element.implement({
712		mosaic : function(options) {
713			var mosaic = this.retrieve('roksprocket:mosaic:builder');
714			if (!mosaic) mosaic = this.store('roksprocket:mosaic:builder', new RokSprocket.MosaicBuilder(this, options));
715
716			return mosaic;
717		}
718	});
719
720	/* Ugly workaround for data-sets issue for IE < 9 on Moo < 1.4.4 */
721	if (MooTools.version < "1.4.4" && (Browser.name == 'ie' && Browser.version < 9)){
722		((function(){
723			var dataList = [
724				'rel', 'data-next',
725				'data-mosaic', 'data-mosaic-items', 'data-mosaic-item', 'data-mosaic-content', 'data-mosaic-page', 'data-mosaic-next',
726				'data-mosaic-order', 'data-mosaic-orderby', 'data-mosaic-order-title', 'data-mosaic-order-date',
727				'data-mosaic-filterby', 'data-mosaic-loadmore'
728			];
729
730			dataList.each(function(data){
731				Element.Properties[data] = {get: function(){ return this.getAttribute(data); }};
732			});
733		})());
734	}
735})());

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.