PageSourceSearch

https://plastdv.ru/bitrix/js/sale/core_ui_widget.js?169407055911663

js plastdv.ru collected 2026-10-08 17:11:21 UTC 11,663 bytes, 467 lines download raw bytes

1(function(){
2
3	if(typeof BX.ui != 'object')
4		BX.ui = {};
5
6	//////////////////////////////
7	// base widget
8	//////////////////////////////
9
10	BX.ui.widget = function(opts){
11
12		BX.merge(this, {
13			opts: {
14				scope: 						false, // it should be either native dom object, or string that represents node id
15				useSpawn: 					false, // if set to true, you can do .spawn() on this object
16
17				messages: 					{}, // language-dependent messages to display
18				controls: 					{}, // known links to controls
19				bindEvents: 				{}, // event pre-binding (when use this, keep in mind that the resulting instance could not be fully formed yet)
20
21				removeTemplates: 			true, // remove script nodes after search
22
23				initializeByGlobalEvent: 	false, // if equals to a not-empty string, initialization will be performed only by event with that name, being fired on document
24				globalEventScope: 			'document' // initializeByGlobalEvent scope (could be 'document' or 'window')
25			},
26			vars: {}, // significant variables
27			ctrls: {}, // links to controls
28			tmpls: {}, // templates
29			sys: {
30				stack: 				{init:[]},
31				code: 				'widget', // only [a-z0-9_-] allowed
32				initialized: 		false
33			}
34		});
35
36		this.pushFuncStack('init', BX.ui.widget);
37
38		this.isUIWidget = true; // prevent BX.merge() from going deeper on a widget instance
39	}
40	// the following functions can be overrided with inheritance
41	BX.merge(BX.ui.widget.prototype, {
42
43		////////////////////////////
44		/// about initialization
45
46		// only basic things here
47		preInit: function(){
48			var ctx = this,
49				so = this.opts,
50				sc = this.ctrls,
51				code = this.sys.code;
52
53			sc.scope = null;
54
55			if(!('querySelector' in document))
56				throw new Error('Your browser does not support querySelector');
57
58			if(!code.match(/^[a-zA-Z0-9-_]+$/))
59				throw new Error('Only letters, digitis, "-" and "_" allowed in code');
60		},
61
62		// member of stack of initializers, must be defined even if do nothing
63		init: function(){
64
65			var ctx = this,
66				sc = this.ctrls,
67				so = this.opts,
68				code = this.sys.code;
69
70			if(so.scope !== false){ // some widgets may have no scope
71
72				sc.scope = BX.type.isNotEmptyString(so.scope) ? BX(so.scope) : so.scope;
73				if(!BX.type.isElementNode(sc.scope))
74					throw new Error('Invalid node passed');
75
76				if(so.useSpawn && sc.scope)
77					ctx.tmpls['scope'] = sc.scope.outerHTML;
78
79				// templates
80				var templates = sc.scope.querySelectorAll('script[type="text/html"]');
81				for(var k = 0; k < templates.length; k++){
82					var id = BX.data(templates[k], 'template-id');
83
84					if(typeof id == 'string' && id.length > 0 && id.search('bx-ui-'+code) == 0){
85
86						id = id.replace('bx-ui-'+code+'-', '');
87						ctx.tmpls[id] = templates[k].innerHTML;
88
89						if(this.opts.removeTemplates)
90							BX.remove(templates[k]);
91					}
92				}
93			}
94
95			// events
96			if(typeof so.bindEvents == 'object'){
97				for(var k in so.bindEvents)
98				{
99					if(so.bindEvents.hasOwnProperty(k))
100						if(BX.type.isFunction(so.bindEvents[k]))
101							this.bindEvent(k, so.bindEvents[k]);
102				}
103			}
104			so.bindEvents = null;
105		},
106
107		remove: function(){
108			// drop scope
109			if(BX.type.isDomNode(this.ctrls.scope))
110				this.ctrls.scope.innerHTML = '';
111
112			// ubind custom events
113			BX.unbindAll(this);
114
115			// here should be a mechanism of "remove stack", just equal to "init stack", but works in reversed manner
116
117			/*
118			this.opts = null;
119			this.vars = null;
120			this.ctrls = null;
121			this.tmpls = null;
122			this.sys = null;
123			*/
124
125			// later unregister in global dispatcher, if ID is set
126		},
127
128		////////////////////////////
129		/// about system
130
131		getControlClassName: function(id){
132			return 'bx-ui-'+this.sys.code+'-'+id;
133		},
134
135		getControl: function(id, notRequired, scope, getAll){
136
137			if(!BX.type.isNotEmptyString(id))
138				return null;
139
140			if(BX.type.isElementNode(this.opts.controls[id]))
141				return this.opts.controls[id];
142
143			if(!this.ctrls.scope && !searchWholeDoc)
144				return null;
145
146			var sScope = this.ctrls.scope;
147			if(BX.type.isElementNode(scope))
148				sScope = scope;
149
150			var checkFound = function(result){
151				return (!getAll && result !== null) || (getAll && result.length > 0);
152			};
153
154			try{
155
156				// it might be in a special data attribute
157				var node = sScope[getAll ? 'querySelectorAll' : 'querySelector']('[data-bx-ui-id="'+this.sys.code+'-'+id+'"]');
158				if(checkFound(node))
159					return node;
160
161			}catch(e){}
162
163			try{
164
165				// it might be control class
166				var node = sScope[getAll ? 'querySelectorAll' : 'querySelector']('.'+this.getControlClassName(id));
167				if(checkFound(node))
168					return node;
169
170			}catch(e){}
171
172			try{
173
174				// it might be some other class
175				var node = sScope[getAll ? 'querySelectorAll' : 'querySelector']('.'+id);
176				if(checkFound(node))
177					return node;
178
179			}catch(e){}
180
181			try{
182
183				// last chance - it might be a specified selector
184				var node = sScope[getAll ? 'querySelectorAll' : 'querySelector'](id);
185				if(checkFound(node))
186					return node;
187
188			}catch(e){}
189
190			if(node === null && !notRequired)
191				throw new Error('Requested control node can not be found ('+id+')');
192
193			return node;
194		},
195
196		setOption: function(name, value){
197			this.opts[name] = value;
198		},
199
200		getOption: function(name){
201			return this.opts[name];
202		},
203
204		getSysCode: function(){
205			return this.sys.code;
206		},
207
208		////////////////////////////
209		/// about templating
210
211		template: function(id, html)
212		{
213			if(typeof html == 'undefined')
214			{
215				return this.tmpls[id];
216			}
217			else
218			{
219				if(!BX.type.isString(html))
220					throw new TypeError('Bad template html');
221
222				this.tmpls[id] = html;
223			}
224		},
225
226		getHTMLByTemplate: function(templateId, replacements){
227
228			var html = this.tmpls[templateId];
229
230			if(!BX.type.isNotEmptyString(html))
231			{
232				BX.debug("template not found: "+templateId);
233				return '';
234			}
235
236			for(var k in replacements)
237			{
238				if(!replacements.hasOwnProperty(k))
239					continue;
240
241				if(typeof replacements[k] != 'undefined' && replacements.hasOwnProperty(k)){
242
243					var replaceWith = '';
244					if(k.toString().indexOf('=') == 0){ // leading '=' stands for an unsafe replace - no escaping
245						replaceWith = replacements[k].toString();
246						k = k.toString().substr(1);
247					}else
248						replaceWith = BX.util.htmlspecialchars(replacements[k]).toString();
249
250					var placeHolder = '{{'+k.toString().toLowerCase()+'}}';
251
252					if(replaceWith.search(placeHolder) >= 0) // you must be joking
253						replaceWith = '';
254
255					while(html.search(placeHolder) >= 0) // new RegExp('', 'g') on user-controlled data seems not so harmless
256						html = html.replace(placeHolder, replaceWith);
257				}
258			}
259
260			return html;
261		},
262
263		createNodesByTemplate: function(templateId, replacements, onlyTags){
264
265			var html = this.getHTMLByTemplate(templateId, replacements);
266
267			var template = this.tmpls[templateId];
268			if(!BX.type.isNotEmptyString(template))
269			{
270				return null;
271			}
272
273			template = template.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); // trim
274
275			// table makeup behaves not so well when being parsed by a browser, so a little hack is on route:
276
277			var isTableRow = false;
278			var isTableCell = false;
279
280			if(template.search(/^<\s*(tr|th)[^<]*>/) >= 0)
281				isTableRow = true;
282			else if(template.search(/^<\s*td[^<]*>/) >= 0)
283				isTableCell = true;
284
285			var keeper = document.createElement('div');
286
287			if(isTableRow || isTableCell){
288
289				if(isTableRow){
290					keeper.innerHTML = '<table><tbody>'+html+'</tbody></table>';
291					keeper = keeper.childNodes[0].childNodes[0];
292				}else{
293					keeper.innerHTML = '<table><tbody><tr>'+html+'</tr></tbody></table>';
294					keeper = keeper.childNodes[0].childNodes[0].childNodes[0];
295				}
296			}else
297				keeper.innerHTML = html;
298
299			if(onlyTags){
300
301				var children = keeper.childNodes;
302				var result = [];
303
304				// we need only non-text nodes
305				for(var k = 0; k < children.length; k++)
306					if(BX.type.isElementNode(children[k]))
307						result.push(children[k]);
308
309				return result;
310			}else
311				return Array.prototype.slice.call(keeper.childNodes);
312		},
313
314		replaceTemplate: function(templateId, html){
315			this.tmpls[templateId] = html;
316		},
317
318		////////////////////////////
319		/// about inheritance
320
321		parentConstruct: function(owner, opts){
322			var c = owner.superclass;
323			if(typeof c == 'object')
324				c.constructor.apply(this, [opts, true]);
325		},
326
327		handleInitStack: function(nf, owner, opts){
328
329			this.pushFuncStack('init', owner);
330
331			if(!nf){
332				BX.merge(this.opts, opts);
333
334				BX.ui.widget.prototype.preInit.call(this);
335
336				var init = function(){
337
338					if(this.sys.initialized) // already initialized once
339						return;
340
341					this.resolveFuncStack('init'); // resove init stacks
342
343					for(var i in this.sys.stack)
344					{
345						if(this.sys.stack.hasOwnProperty(i))
346							if(i != 'init')
347								this.resolveFuncStack(i, true); // resolve all other stacks
348					}
349
350					this.sys.initialized = true;
351					this.fireEvent('init', [this]);
352				};
353
354				if(BX.type.isString(this.opts.initializeByGlobalEvent) && this.opts.initializeByGlobalEvent.length > 0){
355					var scope = this.opts.globalEventScope == 'window' ? window : document;
356					BX.addCustomEvent(scope, this.opts.initializeByGlobalEvent, BX.proxy(init, this));
357				}else
358					init.call(this);
359			}
360		},
361
362		// when you add fName to the stack, function with the corresponding name must exist, at least equal to BX.DoNothing()
363		pushFuncStack: function(fName, owner){
364			if(BX.type.isFunction(owner.prototype[fName])){
365
366				if(typeof this.sys.stack[fName] == 'undefined')
367					this.sys.stack[fName] = [];
368
369				this.sys.stack[fName].push({owner: owner, f: owner.prototype[fName]});
370			}
371		},
372
373		disableInFuncStack: function(fName, owner){
374
375			var stack = this.sys.stack[fName];
376
377			if(typeof stack == 'undefined')
378				return;
379
380			for(var k = 0; k < stack.length; k++){
381				if(stack[k].owner == owner)
382					stack[k].f = BX.DoNothing;
383			}
384		},
385
386		resolveFuncStack: function(fName, fire){
387
388			var stack = this.sys.stack[fName];
389
390			if(typeof stack == 'undefined')
391				return;
392
393			for(var k = 0; k < stack.length; k++){
394				stack[k].f.call(this);
395			}
396
397			if(fire)
398				this.fireEvent(fName, [this], document);
399
400			this.sys.stack[fName] = null;
401		},
402
403		////////////////////////////
404		/// about events
405
406		fireEvent: function(eventName, args, scope){
407			scope = scope || this;
408			args = args || [];
409			BX.onCustomEvent(scope, 'bx-ui-'+this.sys.code+'-'+eventName, args);
410		},
411
412		bindEvent: function(eventName, callback){
413			BX.addCustomEvent(this, 'bx-ui-'+this.sys.code+'-'+eventName, callback);
414		},
415
416		////////////////////////////
417		/// about css states
418
419		setCSSState: function(statName, scope)
420		{
421			this.changeCSSState(statName, scope, true);
422		},
423
424		dropCSSState: function(statName, scope)
425		{
426			this.changeCSSState(statName, scope, false);
427		},
428
429		changeCSSState: function(statName, scope, way)
430		{
431			scope = scope || this.ctrls.scope;
432			if(typeof statName != 'string' || statName.length == 0)
433				return;
434
435			BX[way ? 'addClass' : 'removeClass'](scope, 'bx-ui-state-'+statName);
436		},
437
438		////////////////////////////
439		/// about miscellaneous
440
441		spawn: function(node, onSpawn){
442
443			// if spawning was enabled, you can spawn widget on auto-duplicated scope
444			// otherwise, you should prepare scope by yourself
445
446			if(this.opts.useSpawn)
447				BX.html(node, this.tmpls.scope);
448
449			var opts = BX.clone(this.opts);
450			opts.scope = node;
451
452			if(BX.type.isFunction(onSpawn))
453				onSpawn.apply(this, [opts, node]);
454
455			return new this.constructor(opts);
456		},
457
458		getRandom: function(){
459			// only letters, digits, - and _ allowed to return
460			return 	'bx'+this.sys.code+
461					Math.floor((Math.random() * 1000) + 1)+
462					Math.floor((Math.random() * 1000) + 1);
463		}
464
465	});
466
467})();

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.