PageSourceSearch

https://www.bitrix24.pl/bitrix/content_vendors/popup.manager/popup.manager.js

js bitrix24.pl collected 2026-10-04 12:01:46 UTC 21,230 bytes, 939 lines download raw bytes

1;(function() {
2	'use strict';
3
4	BX.namespace('BX.SB.Popup');
5
6	if (BX.SB.Popup.Manager)
7	{
8		return;
9	}
10
11	/**
12	 * @class
13	 * @property {Object} entities
14	 * @property {Object} currentEntities
15	 * @property {Object} events
16	 * @property {Object} classes
17	 * @property {Object} defaults
18	 * @property {Object} attributes
19	 * @property {Object} documentEvents
20	 */
21	BX.SB.Popup.Manager = {
22		entities: {},
23		currentEntities: {},
24		events: {
25			onBeforeInitialized: 'BX.SB.Popup.Manager:beforeInitialized',
26			onInitialized: 'BX.SB.Popup.Manager:afterInitialized',
27		},
28		classes: {
29			section: 'popup-window',
30			ready: 'popup-window_ready',
31			active: 'popup-window_active',
32			popup: 'popup-window__popup',
33			popupFixedPos: 'popup-window__popup_fixed',
34			inner: 'popup-window__inner',
35			overlay: 'popup-window__overlay',
36			overlayFixedPos: 'popup-window__overlay_fixed',
37			close: 'popup-window__close',
38			preloader: 'popup-window__preloader',
39			defaultTemplate: 'popup-window_default',
40		},
41		defaults: {
42			template: null,
43			parent: null,
44			content: null,
45			classPrefix: 'bx-sb',
46			disableDefaultTemplate: false,
47			disableOverflow: true,
48			disableOverlay: true,
49			disableOn: 0,
50			calcContentPos: false,
51			calcBgPos: false,
52			stickToNode: null,
53			stickToNodePosition: null,
54			fixedContentPos: true,
55			fixedBgPos: true,
56			closeOnExternalClick: true,
57			closeOnBgClick: true,
58			closeOnContentClick: false,
59			closeOnEscapeKey: true,
60			showPreloader: true,
61			showCloseBtn: true,
62			events: {},
63			classes: {},
64			attributes: {},
65			ajax: {
66				url: null,
67				data: {},
68				method: 'POST',
69				dataType: 'html',
70				timeout: 30,
71				async: true,
72				processData: true,
73				scriptsRunFirst: false,
74				emulateOnload: true,
75				start: true,
76				cache: true,
77				onsuccess: null,
78				onfailure: null,
79			},
80		},
81		attributes: {
82			section: 'data-sb-popup-window',
83			overlay: 'data-sb-popup-overlay',
84			popup: 'data-sb-popup-popup',
85			inner: 'data-sb-popup-inner',
86			close: 'data-sb-popup-window-close',
87			preloader: 'data-sb-popup-window-preloader',
88			ready: 'data-sb-popup-window-ready',
89		},
90		documentEvents: {
91			initialClick: 'sbPopupManagerInitialClick'
92		},
93	};
94
95	/**
96	 * @param {Object} [params.parent]
97	 * @param {Object} [params.content]
98	 * @param {String} [params.classPrefix]
99	 * @param {Number} [params.disableDefaultTemplate]
100	 * @param {Number} [params.disableOn]
101	 * @param {Boolean} [params.disableOverflow]
102	 * @param {Boolean} [params.disableOverlay]
103	 * @param {Boolean} [params.calcContentPos]
104	 * @param {Boolean} [params.calcBgPos]
105	 * @param {Object} [params.stickToNode]
106	 * @param {String} [params.stickToNodePosition]
107	 * @param {Boolean} [params.fixedContentPos]
108	 * @param {Boolean} [params.fixedBgPos]
109	 * @param {Boolean} [params.closeOnExternalClick]
110	 * @param {Boolean} [params.closeOnBgClick]
111	 * @param {Boolean} [params.closeOnContentClick]
112	 * @param {Boolean} [params.closeOnEscapeKey]
113	 * @param {Boolean} [params.showPreloader]
114	 * @param {Boolean} [params.showCloseBtn]
115	 * @param {Object} [params.events]
116	 * @param {Object} [params.classes]
117	 * @param {Object} [params.attributes]
118	 * @param {Object} [params.ajax]
119	 * @constructor
120	 */
121	BX.SB.Popup.Window = function(params) {
122		if (!(this instanceof BX.SB.Popup.Window))
123		{
124			return new BX.SB.Popup.Window(params);
125		}
126
127		/** @var {String} **/
128		this._id = null;
129		/** @var {Object} **/
130		this._window = window;
131		/** @var {Object} **/
132		this._document = document;
133		/** @var {Object} **/
134		this._body = this._document.body;
135		/** @var {BX.SB.Popup.Manager} **/
136		this._manager = null;
137		/** @var {Boolean} **/
138		this._isOpened = false;
139		/** @var {Object} **/
140		this._events = {
141			onBeforeInitialized: 'BX.SB.Popup.Window:beforeInitialized',
142			onInitialized: 'BX.SB.Popup.Window:afterInitialized',
143
144			onBeforeDestroyed: 'BX.SB.Popup.Window:beforeDestroyed',
145			onDestroyed: 'BX.SB.Popup.Window:afterDestroyed',
146
147			onBeforeCreated: 'BX.SB.Popup.Window:beforeCreated',
148			onCreated: 'BX.SB.Popup.Window:afterCreated',
149
150			onBeforeContentUpdated: 'BX.SB.Popup.Window:beforeContentUpdated',
151			onContentUpdated: 'BX.SB.Popup.Window:afterContentUpdated',
152
153			onBeforeContentUpdatedAjax: 'BX.SB.Popup.Window:beforeContentUpdatedAjax',
154			onContentUpdatedAjax: 'BX.SB.Popup.Window:afterContentUpdatedAjax',
155
156			onContentUpdatedAjaxSuccess: 'BX.SB.Popup.Window:afterContentUpdatedAjaxSuccess',
157			onContentUpdatedAjaxFailure: 'BX.SB.Popup.Window:afterContentUpdatedAjaxFailure',
158
159			onBeforeClosed: 'BX.SB.Popup.Window:beforeClosed',
160			onClosed: 'BX.SB.Popup.Window:afterClosed',
161
162			onBeforeOpened: 'BX.SB.Popup.Window:beforeOpened',
163			onOpened: 'BX.SB.Popup.Window:afterOpened',
164		};
165		/** @var {Object} **/
166		this._params = params || {};
167		/** @var {Object} **/
168		this._nodes = {
169			section: null,
170			overlay: null,
171			popup: null,
172			inner: null,
173			close: null,
174			preloader: null,
175		};
176
177		if (!BX.type.isNotEmptyObject(BX.SB.Popup.Manager))
178		{
179			return;
180		}
181
182		this._manager = BX.SB.Popup.Manager;
183
184		BX.onCustomEvent(this, this._events.onBeforeInitialized);
185
186		this._init();
187
188		BX.onCustomEvent(this, this._events.onInitialized);
189	};
190
191	BX.SB.Popup.Window.prototype = {
192		constructor: BX.SB.Popup.Window,
193
194		/**
195		 * @api private
196		 */
197		_init: function() {
198			this._params = BX.mergeEx({}, this._manager.defaults, this._params);
199			this._params.ajax = BX.mergeEx({}, this._manager.defaults.ajax, this._params.ajax || {});
200			this._params.classes = BX.mergeEx({}, this._manager.classes, this._params.classes);
201			this._params.attributes = BX.mergeEx({}, this._manager.attributes, this._params.attributes);
202
203			this._setEntityId(this._getRandomString());
204			this._saveEntity();
205		},
206
207		/**
208		 * @param {Number} [windowHeight=null]
209		 * @return {Number}
210		 * @api private
211		 */
212		_hasScrollBar: function(windowHeight) {
213			windowHeight = windowHeight || null;
214			return this._document.body.scrollHeight > (windowHeight || this._window.innerHeight);
215		},
216
217		/**
218		 * @return {Number}
219		 * @api private
220		 */
221		_getScrollbarSize: function() {
222			let scroll = this._document.createElement('DIV');
223			scroll.style.cssText = 'position: absolute; width: 99px; height: 99px; top: -9999px; overflow: scroll;';
224
225			this._document.body.appendChild(scroll);
226			let size = scroll.offsetWidth - scroll.clientWidth;
227			this._document.body.removeChild(scroll);
228
229			return size;
230		},
231
232		/**
233		 * @api private
234		 */
235		_checkOpening: function() {
236			return this._isOpened === true && this._manager.currentEntities.hasOwnProperty(this._getEntityId());
237		},
238
239		/**
240		 * @api private
241		 */
242		_checkInitialClickEvent: function(event) {
243			event = event || this._window.event;
244			let isInitialClick = false;
245
246			if (typeof event !== 'undefined' && event.hasOwnProperty(this._manager.documentEvents.initialClick))
247			{
248				isInitialClick = event.type === 'click' && event[this._manager.documentEvents.initialClick] === this._getEntityId();
249			}
250
251			return isInitialClick;
252		},
253
254		_setInitialClickEvent: function(event) {
255			event = event || this._window.event;
256
257			if (typeof event !== 'undefined' && event.type === 'click' && !this._checkOpening())
258			{
259				this._window.event[this._manager.documentEvents.initialClick] = this._getEntityId();
260			}
261		},
262
263		/**
264		 * @api private
265		 */
266		_removeCurrentEntity: function() {
267			delete this._manager.currentEntities[this._getEntityId()];
268		},
269
270		/**
271		 * @api private
272		 */
273		_setCurrentEntity: function() {
274			this._manager.currentEntities[this._getEntityId()] = this._manager.entities[this._getEntityId()];
275		},
276
277		/**
278		 * @api private
279		 */
280		_saveEntity: function() {
281			this._manager.entities[this._getEntityId()] = this;
282		},
283
284		/**
285		 * @param {String} id
286		 * @api private
287		 */
288		_setEntityId: function(id) {
289			this._id = id;
290		},
291
292		/**
293		 * @return {String}
294		 * @api private
295		 */
296		_getEntityId: function() {
297			return this._id;
298		},
299
300		/**
301		 * @param {Number} [length=5]
302		 * @return {String}
303		 * @api private
304		 */
305		_getRandomString: function(length) {
306			length = length ? length : 5;
307			return BX.util.getRandomString(length);
308		},
309
310		/**
311		 * @param {Object} element
312		 * @param {String} attribute
313		 * @param {String=} value
314		 * @api private
315		 */
316		_setDataAttribute: function(element, attribute, value) {
317			value = value ? value : '';
318			if (BX.type.isElementNode(element) && attribute.toString().length > 0)
319			{
320				element.setAttribute(attribute.toString(), value);
321			}
322		},
323
324		/**
325		 * @return {Object}
326		 * @api private
327		 */
328		_getNodes: function() {
329			return this._nodes;
330		},
331
332		/**
333		 * @return {Object}
334		 * @api private
335		 */
336		_getParams: function() {
337			return this._params;
338		},
339
340		/**
341		 * @param {Object} params
342		 * @api private
343		 */
344		_updateParams: function(params) {
345			params = params || {};
346			this._params = BX.mergeEx({}, this._params, params);
347		},
348
349		/**
350		 * @param {String=} html
351		 * @return {Object}
352		 * @api private
353		 */
354		_createElementNodeFromHtml: function(html) {
355			return BX.type.isElementNode(html) ? html : (new DOMParser().parseFromString(html, 'text/html').body.firstChild);
356		},
357
358		/**
359		 * @api private
360		 */
361		_disablePageScrollbar: function() {
362			this._document.body.style.paddingRight = this._getScrollbarSize() + 'px';
363			this._document.body.style.overflow = 'hidden';
364		},
365
366		/**
367		 * @api private
368		 */
369		_enablePageScrollbar: function() {
370			this._document.body.style.removeProperty('padding-right');
371			this._document.body.style.removeProperty('overflow');
372		},
373
374		/**
375		 * @api private
376		 */
377		_unbindParamsEvents: function() {
378			for (let event in this._params.events)
379			{
380				if (this._params.events.hasOwnProperty(event))
381				{
382					if (this._events.hasOwnProperty(event))
383					{
384						BX.removeCustomEvent(this, event, this._params.events[event]);
385					}
386				}
387			}
388		},
389
390		/**
391		 * @api private
392		 */
393		_bindParamsEvents: function() {
394			for (let event in this._params.events)
395			{
396				if (this._params.events.hasOwnProperty(event))
397				{
398					if (this._events.hasOwnProperty(event))
399					{
400						BX.addCustomEvent(this, this._events[event], this._params.events[event]);
401					}
402				}
403			}
404		},
405
406		/**
407		 * @api private
408		 */
409		_unbindEvents: function() {
410			BX.unbind(window, 'resize', BX.proxy(this._updateWindow, this));
411
412			BX.unbind(this._nodes.close, 'click', BX.proxy(this.close, this));
413			BX.unbind(this._document.body, 'click', BX.proxy(this._closeClickHandler, this));
414			BX.unbind(this._document.body, 'keyup', BX.proxy(this._closeKeyUpHandler, this));
415
416			this._unbindParamsEvents();
417		},
418
419		/**
420		 * @api private
421		 */
422		_bindEvents: function() {
423			BX.bind(window, 'resize', BX.proxy(this._updateWindow, this));
424
425			BX.bind(this._nodes.close, 'click', BX.proxy(this.close, this));
426			BX.bind(this._document.body, 'click', BX.proxy(this._closeClickHandler, this));
427			BX.bind(this._document.body, 'keyup', BX.proxy(this._closeKeyUpHandler, this));
428
429			this._bindParamsEvents();
430		},
431
432		/**
433		 * @param {Object|String} content
434		 * @api private
435		 */
436		_updateContent: function(content) {
437			BX.onCustomEvent(this, this._events.onBeforeContentUpdated);
438
439			this._params.content = content;
440
441			if (this._nodes.inner !== null)
442			{
443				if (BX.type.isElementNode(content))
444				{
445					BX.cleanNode(this._nodes.inner);
446					this._nodes.inner.appendChild(content);
447				}
448				else if (BX.type.isString(content))
449				{
450					this._nodes.inner.innerHTML = content;
451				}
452			}
453
454			BX.onCustomEvent(this, this._events.onContentUpdated);
455		},
456
457		/**
458		 * @param {Object} params
459		 * @api private
460		 */
461		_updateContentAjax: function(params) {
462			let _this = this;
463			params = params || this._params.ajax;
464
465			BX.onCustomEvent(this, this._events.onBeforeContentUpdatedAjax);
466
467			if (BX.type.isNotEmptyObject(params))
468			{
469				if (BX.type.isFunction(params.onsuccess))
470				{
471					let callOnSuccess = params.onsuccess;
472					params.onsuccess = function(data) {
473						callOnSuccess(data, this, _this);
474
475						BX.onCustomEvent(this, _this._events.onContentUpdatedAjaxSuccess);
476					};
477				}
478
479				if (BX.type.isFunction(params.onfailure))
480				{
481					let callOnFailure = params.onfailure;
482					params.onfailure = function(data) {
483						callOnFailure(data, this, _this);
484
485						BX.onCustomEvent(this, _this._events.onContentUpdatedAjaxFailure);
486					}
487				}
488
489				BX.ajax(params);
490			}
491
492			BX.onCustomEvent(this, this._events.onContentUpdatedAjax);
493		},
494
495		/**
496		 * @api private
497		 */
498		_updateWindow: function() {
499			if (BX.type.isElementNode(this._nodes.overlay))
500			{
501				BX.adjust(this._nodes.overlay, {
502					style: {
503						height: this._params.calcBgPos ? false : this._document.body.clientHeight + 'px',
504					},
505				});
506			}
507		},
508
509		/**
510		 * @api private
511		 */
512		_destroy: function() {
513			BX.onCustomEvent(this, this._events.onBeforeDestroyed);
514
515			BX.remove(this._nodes.section);
516
517			BX.onCustomEvent(this, this._events.onDestroyed);
518		},
519
520		/**
521		 * @api private
522		 */
523		_updatePosition: function() {
524			if (this._params.calcContentPos && BX.type.isElementNode(this._nodes.popup))
525			{
526				BX.adjust(this._nodes.popup, {
527					style: {
528						top: this._window.scrollY + (this._window.innerHeight / 2) + 'px',
529					},
530				});
531			}
532
533			if (this._params.calcBgPos && !this._params.disableOverlay)
534			{
535				BX.adjust(this._nodes.popup, {
536					style: {
537						height: this._document.body.clientHeight + 'px',
538					},
539				});
540			}
541		},
542
543		/**
544		 * @api private
545		 */
546		_create: function() {
547			BX.onCustomEvent(this, this._events.onBeforeCreated);
548
549			if (this._params.template)
550			{
551				if (!BX.type.isElementNode(this._params.template))
552				{
553					this._params.template = this._createElementNodeFromHtml(this._params.template);
554				}
555
556				let template = this._document.createElement('DIV');
557				template.appendChild(this._params.template);
558
559				for (let key in this._nodes)
560				{
561					if (this._nodes.hasOwnProperty(key) && this._params.attributes.hasOwnProperty(key))
562					{
563						let element = template.querySelector('[' + this._params.attributes[key] + ']');
564						if (BX.type.isElementNode(element))
565						{
566							this._nodes[key] = element;
567						}
568					}
569				}
570			}
571			else
572			{
573				if (this._params.showCloseBtn)
574				{
575					this._nodes.close = BX.create('DIV', {
576						attrs: {
577							className: this.getPrefixedClassName(this._params.classes.close, this._params.classPrefix),
578						},
579					});
580					this._setDataAttribute(this._nodes.close, this._params.attributes.close);
581				}
582
583				if (this._params.showPreloader)
584				{
585					this._nodes.preloader = BX.create('DIV', {
586						attrs: {
587							className: this.getPrefixedClassName(this._params.classes.preloader, this._params.classPrefix),
588						},
589					});
590					this._setDataAttribute(this._nodes.preloader, this._params.attributes.preloader);
591				}
592
593				this._nodes.inner = BX.create('DIV', {
594					attrs: {
595						className: this.getPrefixedClassName(this._params.classes.inner, this._params.classPrefix),
596					},
597				});
598
599				this._nodes.popup = BX.create('DIV', {
600					attrs: {
601						className: this.getPrefixedClassName(this._params.classes.popup, this._params.classPrefix) +
602							(this._params.fixedContentPos ? ' ' + this.getPrefixedClassName(this._params.classes.popupFixedPos, this._params.classPrefix) : ''),
603					},
604					children: [this._nodes.close, this._nodes.inner, this._nodes.preloader],
605				});
606
607				if (this._params.disableOverlay === false)
608				{
609					this._nodes.overlay = BX.create('DIV', {
610						attrs: {
611							className: this.getPrefixedClassName(this._params.classes.overlay, this._params.classPrefix) +
612								(this._params.fixedBgPos ? ' ' + this.getPrefixedClassName(this._params.classes.overlayFixedPos, this._params.classPrefix) : ''),
613						},
614					});
615				}
616
617				this._nodes.section = BX.create('DIV', {
618					attrs: {
619						className: this.getPrefixedClassName(this._params.classes.section, this._params.classPrefix) +
620							(this._params.disableDefaultTemplate ? '' : ' ' + this.getPrefixedClassName(this._params.classes.defaultTemplate, this._params.classPrefix)),
621					},
622					children: [this._nodes.popup, this._nodes.overlay],
623				});
624			}
625
626			BX.addClass(this._nodes.section, this._params.classes.ready);
627
628			this._updatePosition();
629
630			let parent = BX.type.isElementNode(this._params.parent) ? this._params.parent : this._body;
631			parent.appendChild(this._nodes.section);
632
633			if (BX.type.isNotEmptyObject(this._params.ajax))
634			{
635				this._updateContentAjax(this._params.ajax);
636			}
637			if (this._params.content !== null)
638			{
639				this._updateContent(this._params.content);
640			}
641
642			BX.onCustomEvent(this, this._events.onCreated);
643		},
644
645		/**
646		 * @param {Object} event
647		 * @api private
648		 */
649		_closeClickHandler: function(event) {
650			event = event || this._window.event;
651
652			if (this._checkInitialClickEvent())
653			{
654				return;
655			}
656
657			if (this._params.closeOnExternalClick && !this._nodes.section.contains(event.target))
658			{
659				this.close();
660			}
661
662			if (this._params.closeOnBgClick && this._nodes.section.contains(event.target) && !this._nodes.popup.contains(event.target))
663			{
664				this.close();
665			}
666
667			if (this._params.closeOnContentClick && this._nodes.section.contains(event.target) && this._nodes.inner.contains(event.target))
668			{
669				this.close();
670			}
671		},
672
673		/**
674		 * @param {Object} event
675		 * @api private
676		 */
677		_closeKeyUpHandler: function(event) {
678			event = event || this._window.event;
679
680			if (this._params.closeOnEscapeKey && event.keyCode === 27)
681			{
682				this.close();
683			}
684		},
685
686		/**
687		 * @api private
688		 */
689		_close: function() {
690			if (!this._checkOpening())
691			{
692				return;
693			}
694
695			BX.onCustomEvent(this, this._events.onBeforeClosed);
696
697			BX.removeClass(this._nodes.section, this._params.classes.active);
698
699			this._removeCurrentEntity();
700			this._isOpened = false;
701
702			this._unbindEvents();
703
704			this._destroy();
705
706			this._enablePageScrollbar();
707
708			BX.onCustomEvent(this, this._events.onClosed);
709		},
710
711		/**
712		 * @api private
713		 */
714		_open: function() {
715			if (this._checkOpening())
716			{
717				return;
718			}
719
720			if (this._window.innerWidth < this._params.disableOn)
721			{
722				return;
723			}
724
725			BX.onCustomEvent(this, this._events.onBeforeOpened);
726
727			if (!this._checkInitialClickEvent())
728			{
729				if (typeof this._window.event !== 'undefined')
730				{
731					if (this._window.event.stopPropagation)
732					{
733						this._window.event.stopPropagation();
734					}
735					else
736					{
737						this._window.event.cancelBubble = true;
738					}
739				}
740			}
741
742			if (!this._params.disableOverflow)
743			{
744				this._disablePageScrollbar();
745			}
746
747			this._create();
748
749			this._bindEvents();
750
751			BX.addClass(this._nodes.section, this._params.classes.active);
752
753			this._isOpened = true;
754			this._setCurrentEntity();
755
756			BX.onCustomEvent(this, this._events.onOpened);
757		},
758
759		/**
760		 * @param {String} name
761		 * @param {String} prefix
762		 * @return {String}
763		 * @api private
764		 */
765		_getPrefixedClassName: function(name, prefix) {
766			prefix = this._params.classPrefix.toString().length > 0 ? this._params.classPrefix : '';
767			return prefix.toString().length > 0 ? prefix + '-' + name : name;
768		},
769
770		/**
771		 * @param {String} name
772		 * @param {String} prefix
773		 * @return {String}
774		 * @api public
775		 */
776		getPrefixedClassName: function(name, prefix) {
777			return this._getPrefixedClassName(name, prefix);
778		},
779
780		/**
781		 * @return {Object}
782		 * @api public
783		 */
784		getNodes: function() {
785			return this._getNodes();
786		},
787
788		/**
789		 * @return {Object}
790		 * @api public
791		 */
792		getParams: function() {
793			return this._getParams();
794		},
795
796		/**
797		 * @param {Object} params
798		 * @api public
799		 */
800		updateParams: function(params) {
801			this._updateParams(params);
802		},
803
804		/**
805		 * @param {Object|String} content
806		 * @api public
807		 */
808		updateContent: function(content) {
809			this._updateContent(content);
810		},
811
812		/**
813		 * @param {Object} params
814		 * @api public
815		 */
816		updateContentAjax: function(params) {
817			this._updateContentAjax(params);
818		},
819
820		/**
821		 * @api public
822		 */
823		close: function() {
824			this._close();
825		},
826
827		/**
828		 * @api public
829		 */
830		open: function() {
831			this._open();
832		},
833
834		/**
835		 * @api public
836		 */
837		setInitialClickEvent: function() {
838			this._setInitialClickEvent();
839		},
840
841		/**
842		 * @api public
843		 */
844		onBeforeInitialized: function() {
845		},
846
847		/**
848		 * @api public
849		 */
850		onInitialized: function() {
851		},
852
853		/**
854		 * @api public
855		 */
856		onBeforeDestroyed: function() {
857		},
858
859		/**
860		 * @api public
861		 */
862		onDestroyed: function() {
863		},
864
865		/**
866		 * @api public
867		 */
868		onBeforeCreated: function() {
869		},
870
871		/**
872		 * @api public
873		 */
874		onCreated: function() {
875		},
876
877		/**
878		 * @api public
879		 */
880		onBeforeContentUpdated: function() {
881		},
882
883		/**
884		 * @api public
885		 */
886		onContentUpdated: function() {
887		},
888
889		/**
890		 * @api public
891		 */
892		onBeforeContentUpdatedAjax: function() {
893		},
894
895		/**
896		 * @api public
897		 */
898		onContentUpdatedAjax: function() {
899		},
900
901		/**
902		 * @api public
903		 */
904		onContentUpdatedAjaxSuccess: function() {
905		},
906
907		/**
908		 * @api public
909		 */
910		onContentUpdatedAjaxFailure: function() {
911		},
912
913		/**
914		 * @api public
915		 */
916		onBeforeClosed: function() {
917		},
918
919		/**
920		 * @api public
921		 */
922		onClosed: function() {
923		},
924
925		/**
926		 * @api public
927		 */
928		onBeforeOpened: function() {
929		},
930
931		/**
932		 * @api public
933		 */
934		onOpened: function() {
935		},
936	};
937
938
939})();

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.