PageSourceSearch

https://igormitin.com/_jsapps/_libs/cargo_plugins/elementResizer.js

js igormitin.com collected 2026-10-04 13:25:56 UTC 12,140 bytes, 402 lines download raw bytes

1// initialize and store reference in Cargo.Plugins
2var Cargo = Cargo || {};
3
4Cargo.Plugins = Cargo.Plugins || {};
5
6// use a closure so we have private and public methods.
7Cargo.Plugins.elementResizer = (function($) {
8		
9		var self = {
10			
11			vars: {
12				ticking: false,
13				initialized: false
14			},
15
16			options: {
17				cargo_refreshEvents: ['show_index_complete', 'pagination_complete', 'project_load_complete', 'inspector_preview', 'project_collection_reset', 'direct_link_loaded'],
18				generic_refreshEvents: [],
19				updateEvents: ['resize', 'orientationchange'],
20				selectors: ['img', 'object', 'iframe', 'video', '.elementresizer', '[data-elementresizer-child]', '.slideshow', '.audio_component'],
21				targets: {},
22				minimumHeight: 100,
23				minimumWidth: 100,
24				centerElements: true,
25				adjustElementsToWindowHeight: true,
26				forceMargin: false,
27				forceVerticalMargin: 40,
28				forceHorizontalMargin: 0,
29				allowInit: true
30			},
31
32			init: function() {
33
34				if(Cargo.hasOwnProperty('Event')){
35					Cargo.Event.trigger("element_resizer_init", publicVars);
36				}
37				
38				// stupid IE8 fallback
39				function bindEvent(el, eventName, eventHandler) {
40					if (el.addEventListener){
41						el.addEventListener(eventName, eventHandler, false); 
42					} else if (el.attachEvent){
43						el.attachEvent('on'+eventName, eventHandler);
44					}
45				}
46				
47				if(!self.options.allowInit){
48					return false;
49				}
50
51				var resizeTimeout;
52
53				$.each(self.options.updateEvents, function(key, event) {
54					bindEvent(window, event, function() {
55						self.requestTick();
56
57						if(event === "resize"){
58							clearTimeout(resizeTimeout);
59							resizeTimeout = setTimeout(function(){
60								self.requestTick();
61							}, 100);
62						}
63
64					});
65				});
66
67				// bind some event listeners to automagically refresh
68				$.each(self.options.generic_refreshEvents, function(key, event) {
69					bindEvent(window, event, function() {
70						self.refresh();
71						self.update();
72					});
73				});
74
75				$.each(self.options.cargo_refreshEvents, function(key, val) {
76					// these are Cargo specific events. Only do this when we are on Cargo.
77					if(Cargo.hasOwnProperty('Event')){
78						Cargo.Event.on(val, function() {
79							self.refresh();
80							self.update();
81						});
82					}
83				});
84
85				if(Cargo.hasOwnProperty('Event')){
86					Cargo.Event.on("inspector_open", function() {
87						CargoInspector.eventManager.subscribe('style_changed', function(source){
88							self.update();
89						});
90					});
91				}
92
93				self.vars.initialized = true;
94
95				self.refresh();
96				self.update();
97
98			},
99
100			refresh: function() {
101
102				if(!self.vars.initialized){
103					return false;
104				}
105
106				var containers = $('[data-elementresizer]');
107
108				self.options.targets = {};
109
110				containers.each(function(index, container) {
111					var children = $(container).find(self.options.selectors.join(',')),
112						resize_parent = $(container).closest('[data-resize-parent]');
113
114					if (resize_parent.length == 0) {
115						resize_parent = $('body');
116					}
117
118					var childrenArray = [],
119						queueArray = [];
120
121					// minimize DOM api calls
122					children.each(function(key, child) {
123
124						var columnizerParent = $(child).closest('[data-columnize]'),
125							nodeName = child.nodeName,
126							child = $(child);
127
128						if ((columnizerParent.length == 0 || columnizerParent.is('[data-allow-elementresizer]') !== false) && !(child.closest('[data-no-elementresizer]').length > 0 || child[0].hasAttribute('data-no-elementresizer'))) {
129
130							var childWidth = child.width(),
131								childHeight = child.height(),
132						
133								actualWidth  = parseInt(child.attr('width')),
134								actualHeight = parseInt(child.attr('height')),
135						
136								originalWidth  = (isNaN(actualWidth) ? childWidth : actualWidth),
137								originalHeight = (isNaN(actualHeight) ? childHeight : actualHeight),
138						
139								minimumHeight = self.constrain(self.options.minimumHeight, 0, originalHeight),
140								minimumWidth  = self.constrain(self.options.minimumWidth, 0, originalWidth),
141						
142								isSlideshow = (child.hasClass('slideshow') ? Cargo.Core.Slideshow.SlideshowObjects[child.attr('data-id')] : false),
143								isVideoPlayer = child.closest('.video_component').length > 0 && child.is('video'),
144
145								noResize = isVideoPlayer ?
146									child.closest('.video_component').parent('[data-elementresizer-no-resize]').length > 0 || child.closest('.video_component')[0].hasAttribute('data-elementresizer-no-resize') :
147									child.parent('[data-elementresizer-no-resize]').length > 0 || child[0].hasAttribute('data-elementresizer-no-resize'),
148
149								noVerticalResize = isVideoPlayer ?
150									child.closest('.video_component').parent('[data-elementresizer-no-vertical-resize]').length > 0 || child.closest('.video_component')[0].hasAttribute('data-elementresizer-no-vertical-resize') :
151									child.parent('[data-elementresizer-no-vertical-resize]').length > 0 || child[0].hasAttribute('data-elementresizer-no-vertical-resize'),									
152
153								noCentering = isVideoPlayer ?
154									child.closest('.video_component').parent('[data-elementresizer-no-centering]').length > 0 || child.closest('.video_component')[0].hasAttribute('data-elementresizer-no-centering') :
155									child.parent('[data-elementresizer-no-centering]').length > 0 || child[0].hasAttribute('data-elementresizer-no-centering'),
156
157								childObj = {
158									element: child,
159									originalWidth    : originalWidth,
160									originalHeight   : originalHeight,
161									actualWidth      : actualWidth,
162									actualHeight     : actualHeight,
163									minimumHeight    : (minimumHeight > originalHeight ? originalHeight : minimumHeight),
164									minimumWidth     : (minimumWidth > originalWidth ? originalWidth : minimumWidth),
165									ratio            : (originalHeight / originalWidth),
166									nodeName         : child[0].nodeName.toLowerCase(),
167									isVideoPlayer	 : isVideoPlayer,
168									isSlideshow      : isSlideshow,
169									isAudioPlayer	 : child.hasClass('audio_component'),
170									noResize         : noResize,
171									noCentering      : noCentering,
172									noVerticalResize : noVerticalResize,
173									prevLeftMargin   : 0,
174									isSoundCloudFrame: (child.attr('src') + '').indexOf('soundcloud') !== -1 && child[0].nodeName === "IFRAME"
175								};
176
177							if(isSlideshow){
178								queueArray.push(childObj);
179							} else {
180								childrenArray.push(childObj);
181							}
182
183						}
184					});
185
186					childrenArray = childrenArray.concat(queueArray);
187
188					var padding = parseInt($(resize_parent).css('paddingLeft')) + parseInt($(resize_parent).css('paddingRight'));
189					
190					
191					if (isNaN(padding)) {
192						padding = 0;
193					}
194
195					self.options.targets[index] = {
196						container: $(container),
197						resize_parent: resize_parent,
198						children: childrenArray,
199						padding: padding
200					}
201
202				});
203
204				self.update();
205
206			},
207
208			requestTick: function() {
209
210				if (!self.vars.ticking) {
211					
212					requestAnimationFrame(function(){
213						self.update();
214					});
215
216					self.vars.ticking = true;
217				}
218
219			},
220
221			constrain: function(val, min, max){
222				return val > max ? max : val < min ? min : val;
223			},
224
225			update: function() {  
226
227				// for in vars
228				var targetKey,
229					childKey, 
230					childObj,
231					target;
232
233				for(targetKey in self.options.targets){
234
235					target = self.options.targets[targetKey];
236
237					var parentWidth = target.container.width(),
238						padding = target.padding,
239						maxWidth = target.resize_parent.width() - self.options.forceHorizontalMargin,
240						globalMaxHeight = (self.options.adjustElementsToWindowHeight ? document.documentElement.clientHeight - self.options.forceVerticalMargin : 9e9),
241						maxHeight = globalMaxHeight,
242						scalingRatio = 1; // set it to one. Just in case.
243
244					// handle rotation
245					if(self.options.adjustElementsToWindowHeight && window.orientation !== undefined){
246						if(window.orientation != 0){
247							maxHeight = document.documentElement.clientWidth - (self.options.forceMargin === false ? 40 : self.options.forceMargin);
248						}
249					}
250
251					for(childKey in target.children){
252
253						childObj = target.children[childKey];
254
255						if(!childObj.noResize){
256							if(childObj.noVerticalResize){
257								maxHeight  = 9e9;
258							} else {
259								maxHeight = globalMaxHeight;
260							}
261
262							var childWidth = childObj.actualWidth,
263								childHeight = childObj.actualHeight;
264
265							// check if we need to scale the horizontal or vertical side
266							horizontalDelta = self.constrain(maxWidth - childWidth, 1, 9e9),
267							verticalDelta = self.constrain(maxHeight - childHeight, 1, 9e9);
268
269							// get the ratio based on the side that's being scaled
270							scalingRatio = [maxWidth / childObj.actualWidth, maxHeight / childObj.actualHeight];
271							scalingRatio = Math.min(scalingRatio[0], scalingRatio[1]);
272
273							// calculate new size
274							childHeight = self.constrain(childHeight * scalingRatio, -9e9, childObj.originalHeight);
275							childWidth = self.constrain(childWidth * scalingRatio, -9e9, childObj.originalWidth);
276
277							// rescale if one of the dimensions is smaller than the minimum value
278							if(childHeight <= childObj.minimumHeight || childWidth <= childObj.minimumWidth){
279								scalingRatio = [childObj.minimumWidth / childWidth, childObj.minimumHeight / childHeight];
280								scalingRatio = Math.max(scalingRatio[0], scalingRatio[1]);
281
282								childHeight = childHeight * scalingRatio;
283								childWidth = childWidth * scalingRatio;
284							}
285
286							if(childObj.isAudioPlayer){
287								if(Cargo.hasOwnProperty('Core')){
288									Cargo.Core.Audio.InitPlayerSize();
289								}
290							}
291
292							// check if anything changed. Otherwise no need to redraw.
293							if(childObj.actualWidth != childWidth || childObj.actualHeight != childHeight){
294
295								if(!isNaN(childWidth) && !isNaN(childHeight)){
296
297									childObj.actualWidth  = childWidth;
298									childObj.actualHeight = childHeight;
299
300									childObj.element.add(childObj.nodeName === "object" ? childObj.element.find('embed') : '').css({
301										'width': childObj.actualWidth + 'px',
302										'height': childObj.actualHeight + 'px'
303									});
304
305									if ( childObj.isVideoPlayer){
306										var mediaPlayer = childObj.element.closest('.mediaplayer')
307										mediaPlayer.css({
308											'width': childObj.actualWidth + 'px',
309											'height': childObj.actualHeight + 'px'
310										});
311									}						
312
313								} 
314
315							}
316
317						}
318
319						if(self.options.centerElements && !childObj.noCentering){
320							self.setLeftMargin(childObj, parentWidth);
321						}
322
323						if(childObj.isSlideshow){
324							if(childObj.isSlideshow !== undefined){
325								childObj.actualWidth = childObj.isSlideshow.resizeContainer();
326							}
327						}
328
329					};
330
331				};
332
333				self.vars.ticking = false;
334
335				if(Cargo.hasOwnProperty('Event')){
336					Cargo.Event.trigger("elementresizer_update_complete", publicVars);
337				}
338
339			},
340
341			setLeftMargin: function(childObj, parentWidth, force){
342
343				var marginLeft;
344
345				if(childObj.isSoundCloudFrame){
346					marginLeft = (parentWidth - childObj.element.width()) / 2;
347				} else {
348					marginLeft = (parentWidth - childObj.actualWidth) / 2;
349				}
350
351				
352				if(!isNaN(marginLeft)){
353
354					if (childObj.prevLeftMargin !== marginLeft) {
355
356						if ( childObj.isVideoPlayer ){
357							childObj.element.closest('.mediaplayer').css('marginLeft', marginLeft);
358						} else {
359							childObj.element.css('marginLeft', marginLeft);						
360						}
361
362					}
363
364					childObj.prevLeftMargin = marginLeft;
365
366				}
367
368			}
369
370		};
371
372		 var publicVars = {
373			options: self.options,
374			init: self.init,
375			refresh: self.refresh,
376			update: self.update,
377			setOptions: function(newOptions) {
378
379				$.extend(self.options, newOptions);
380
381				if(self.options.forceMargin !== false){
382					self.options.forceHorizontalMargin = self.options.forceMargin;
383					self.options.forceVerticalMargin = self.options.forceMargin;
384				}
385
386				if(self.options.allowInit && self.vars.initialized){
387					self.update();
388				}
389
390			},
391			targets: function() {
392				return self.options.targets;
393			}
394		};
395
396		$(function(){  
397			self.init();
398		});
399
400		return publicVars
401
402 })(jQuery);

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.