PageSourceSearch

https://ralk.info/bitrix/js/main/core/core_uploader/file.js?151299898926739

js ralk.info collected 2026-10-02 17:07:16 UTC 26,739 bytes, 914 lines download raw bytes

1;(function(window){
2	if (window.BX["UploaderFile"])
3		return false;
4	var
5		BX = window.BX,
6		statuses = { "new" : 0, ready : 1, preparing : 2, inprogress : 3, done : 4, failed : 5, stopped : 6, changed : 7, uploaded : 8},
7		cnvConstr = function(timelimit)
8		{
9			this.timeLimit = (typeof timelimit == "number" && timelimit > 0 ? timelimit : 50);
10			this.status = statuses.ready;
11			this.queue = new BX.UploaderUtils.Hash();
12		};
13	cnvConstr.prototype = {
14		image : null,
15		getImage : function()
16		{
17			if (!this.image)
18				this.image = new Image();
19			return this.image;
20		},
21		canvas : null,
22		getCanvas : function()
23		{
24			if (!this.canvas)
25				this.canvas = BX.create('CANVAS');
26
27			return this.canvas;
28		},
29		context : null,
30		getContext : function()
31		{
32			if (!this.context && this.getCanvas()["getContext"])
33				this.context = this.getCanvas().getContext('2d');
34			return this.context;
35		},
36		reader : null,
37		getReader : function()
38		{
39			if (!this.reader && window["FileReader"])
40				this.reader = new FileReader();
41			return this.reader;
42		},
43		load : function(file, callback, id, callbackFail)
44		{
45			var image = this.getImage();
46
47			BX.unbindAll(image);
48			this.onload = null;
49			delete this.onload;
50			this.onerror = null;
51			delete this.onerror;
52			image.src = '/bitrix/images/1.gif';
53			this.onload = BX.delegate(function(){
54				if (!!callback)
55				{
56					try{
57						callback(BX.proxy_context, this.getCanvas(), this.getContext());
58					}
59					catch (e)
60					{
61						BX.debug(e);
62					}
63				}
64				if (!!id)
65				{
66					this.queue.removeItem(id);
67					setTimeout(BX.proxy(this.exec, this), this.timeLimit);
68				}
69			}, this);
70			this.onerror = BX.delegate(function(){
71				if (!!callbackFail)
72				{
73					try
74					{
75						callbackFail(BX.proxy_context);
76					}
77					catch (e)
78					{
79						BX.debug(e);
80					}
81				}
82				if (!!id)
83				{
84					this.queue.removeItem(id);
85					setTimeout(BX.proxy(this.exec, this), this.timeLimit);
86				}
87			}, this);
88			image.name = file.name;
89			BX.bind(image, 'load', this.onload);
90			BX.bind(image, 'error', this.onerror);
91
92			var res = Object.prototype.toString.call(file);
93			if (file["tmp_url"])
94			{
95				image.src = file["tmp_url"];
96			}
97			else if (res !== '[object File]' && res !== '[object Blob]')
98			{
99				this.onerror(null);
100			}
101			else if (!!window["URL"])
102			{
103				image.src = window["URL"]["createObjectURL"](file);
104			}
105			else if (this.getReader() !== null)
106			{
107				this.__readerOnLoad = BX.delegate(function(e) {
108					image.src = e.target.result;
109					this.__readerOnLoad = null;
110					delete this.__readerOnLoad;
111				}, this);
112				this.getReader().onload = this.__readerOnLoad;
113				this.getReader().readAsDataURL(file);
114			}
115		},
116		push : function(file, callback, failCallback)
117		{
118			var id = BX.UploaderUtils.getId();
119			this.queue.setItem(id, [id, file, callback, failCallback]);
120			this.exec();
121		},
122		exec : function()
123		{
124			var item = this.queue.getFirst();
125			if (!!item)
126				this.load(item[1], item[2], item[0], item[3]);
127		}
128	};
129	BX.UploaderFileCnvConstr = cnvConstr;
130	var fileLoader = function(timelimit)
131	{
132		this.timeLimit = (typeof timelimit == "number" && timelimit > 0 ? timelimit : 50);
133		this.status = statuses.ready;
134		this.queue = new BX.UploaderUtils.Hash();
135		this._exec = BX.delegate(this.exec, this);
136	};
137	fileLoader.prototype = {
138		xhr : null,
139		goToNext : function(id)
140		{
141			delete this.xhr;
142			this.xhr = null;
143			this.queue.removeItem(id);
144			this.status = statuses.ready;
145			setTimeout(this._exec, this.timeLimit);
146		},
147		load : function(id, path, onsuccess, onfailure)
148		{
149			if (this.status != statuses.ready)
150				return;
151			this.status = statuses.inprogress;
152			var _this = this;
153			this.xhr = BX.ajax({
154				'method': 'GET',
155				'data' : '',
156				'url': path,
157				'onsuccess': function(blob){if (blob === null){onfailure(blob);} else {onsuccess(blob);} _this.goToNext(id);},
158				'onfailure': function(blob){onfailure(blob); _this.goToNext(id);},
159				'start': false,
160				'preparePost':false,
161				'processData':false
162			});
163			this.xhr.withCredentials = true;
164			this.xhr.responseType = 'blob';
165
166
167			this.xhr.send();
168		},
169		push : function(path, onsuccess, onfailure)
170		{
171			var id = BX.UploaderUtils.getId();
172			this.queue.setItem(id, [id, path, onsuccess, onfailure]);
173			this.exec();
174		},
175		exec : function()
176		{
177			var item = this.queue.getFirst();
178			if (!!item)
179				this.load(item[0], item[1], item[2], item[3]);
180		}
181	};
182	BX.UploaderFileFileLoader = fileLoader();
183	var prvw = new cnvConstr(), upld = new cnvConstr(), edtr = new cnvConstr(), canvas = BX.create('CANVAS'), ctx;
184	/**
185	 * @return {BX.UploaderFile}
186	 * @file file
187	 * @params array
188	 * @limits array
189	 * @caller {BX.Uploader}
190	 * You should work with params["fields"] in case you want to change visual part
191	 */
192var mobileNames = {};
193	BX.UploaderFile = function (file, params, limits, caller)
194	{
195		this.dialogName = (this.dialogName ? this.dialogName : "BX.UploaderFile");
196		this.file = file;
197		this.id = (file['id'] || 'file' + BX.UploaderUtils.getId());
198		this.name = file.name;
199		this.isNode = false;
200		if (BX.type.isDomNode(file))
201		{
202			this.isNode = true;
203			this.name = BX.UploaderUtils.getFileNameOnly(file.value);
204			if (/\[(.+?)\]/.test(file.name))
205			{
206				var tmp = /\[(.+?)\]/.exec(file.name);
207				this.id = tmp[1];
208			}
209			this.file.bxuHandler = this;
210		}
211		else if (file["tmp_url"] && !file["name"])
212		{
213			this.name = BX.UploaderUtils.getFileNameOnly(file["tmp_url"]);
214		}
215		this.preview = '<span id="' + this.id + 'Canvas" class="bx-bxu-canvas"></span>';
216		this.nameWithoutExt = (this.name.lastIndexOf('.') > 0 ? this.name.substr(0, this.name.lastIndexOf('.')) : this.name);
217		this.ext = this.name.substr(this.nameWithoutExt.length + 1);
218
219		if (/iPhone|iPad|iPod/i.test(navigator.userAgent) && this.nameWithoutExt == "image")
220		{
221			var nameWithoutExt = 'mobile_' + BX.date.format("Ymd_His");
222			mobileNames[nameWithoutExt] = (mobileNames[nameWithoutExt] || 0);
223			this.nameWithoutExt = nameWithoutExt + (mobileNames[nameWithoutExt] > 0 ? ("_" + mobileNames[nameWithoutExt]) : "");
224			this.name = this.nameWithoutExt + (BX.type.isNotEmptyString(this.ext) ? ("." + this.ext) : "");
225			mobileNames[nameWithoutExt]++;
226		}
227
228		this.size = '';
229		if (file.size)
230			this.size = BX.UploaderUtils.getFormattedSize(file.size, 0);
231		this.type = file.type;
232		this.status = statuses["new"];
233		this.limits = limits;
234		this.caller = caller;
235		this.fields = {
236			thumb : {
237				tagName : 'SPAN',
238				template : '<div class="someclass">#preview#<div>#name#</div>',
239				editorTemplate : '<div class="someeditorclass"><div>#name#</div>',
240				className : "bx-bxu-thumb-thumb",
241				placeHolder : null
242			},
243			preview : {
244				params : { width : 400, height : 400 },
245				template : "#preview#",
246				editorParams : { width : 1024, height : 860 },
247				editorTemplate : '<span>#preview#</span>',
248				className : "bx-bxu-thumb-preview",
249				placeHolder : null,
250				events : {
251					click : BX.delegate(this.clickFile, this)
252				}
253			},
254			name : {
255				template : "#name#",
256				editorTemplate : '<span><input type="text" name="name" value="#name#" /></span>',
257				className : "bx-bxu-thumb-name",
258				placeHolder : null
259			},
260			type : {
261				template : "#type#",
262				editorTemplate : '#type#',
263				className : "bx-bxu-thumb-type",
264				placeHolder : null
265			}
266		};
267
268		if (!!params["fields"])
269		{
270			var ij, key;
271			for (var ii in params["fields"])
272			{
273				if (params["fields"].hasOwnProperty(ii))
274				{
275					if (!!this.fields[ii])
276					{
277						for (ij in params["fields"][ii])
278						{
279							if (params["fields"][ii].hasOwnProperty(ij))
280							{
281								this.fields[ii][ij] = params["fields"][ii][ij];
282							}
283						}
284					}
285					else
286						this.fields[ii] = params["fields"][ii];
287					key = ii + '';
288					if (key.toLowerCase() != "thumb" && key.toLowerCase() != "preview")
289					{
290						this[key.toLowerCase()] = (!!params["fields"][ii]["value"] ? params["fields"][ii]["value"] : "");
291						this.log(key.toLowerCase() + ': ' + this[key.toLowerCase()]);
292					}
293				}
294			}
295		}
296
297		BX.onCustomEvent(this, "onFileIsCreated", [this.id, this, this.caller]);
298		BX.onCustomEvent(this.caller, "onFileIsCreated", [this.id, this, this.caller]);
299
300		this.makePreview();
301		this.preparationStatus = statuses.done;
302		return this;
303	};
304	BX.UploaderFile.prototype = {
305		log : function(text)
306		{
307			BX.UploaderUtils.log('file ' + this.name, text);
308		},
309		makeThumb : function()
310		{
311			var template = this.fields.thumb.template, name, ii, events = {}, node, jj;
312			for (ii in this.fields)
313			{
314				if (this.fields.hasOwnProperty(ii))
315				{
316					if (this.fields[ii].template && this.fields[ii].template.indexOf('#' + ii + '#') >= 0)
317					{
318						name = this.id + ii.toUpperCase().substr(0, 1) + ii.substr(1);
319						node = this.setProps(ii, this[ii], true);
320						template = template.replace('#' + ii + '#', '<span id="' + name + '" class="' + this.fields[ii]["className"] + '">' + (
321							BX.type.isNotEmptyString(node.html) ? node.html.replace("#", "<\x19>") : node.html) + '</span>');
322						for (jj in node.events)
323						{
324							if (node.events.hasOwnProperty(jj))
325							{
326								events[jj] = node.events[jj];
327							}
328						}
329						if (!!this.fields[ii].events)
330							events[name] = this.fields[ii].events;
331					}
332				}
333			}
334			var res, patt = [], repl = [], tmp;
335			while ((res = /#(.+?)#/gi.exec(template)) && !!res)
336			{
337				if (this[res[1]] !== undefined)
338				{
339					template = template.replace(res[0], BX.type.isNotEmptyString(this[res[1]]) ? this[res[1]].replace("#", "<\x19>") : this[res[1]]);
340				}
341				else
342				{
343					tmp = "<\x18" + patt.length + ">";
344					patt.push(tmp);
345					repl.push(res[0]);
346					template = template.replace(res[0], tmp);
347				}
348			}
349			while ((res = patt.shift()) && res)
350			{
351				tmp = repl.shift();
352				template = template.replace(res, tmp);
353			}
354			template = template.replace("<\x19>", "#");
355			if (!!this.fields.thumb.tagName)
356			{
357				res = BX.create(this.fields.thumb.tagName, {
358					attrs : {
359						id : (this.id + 'Thumb'),
360						className : this.fields.thumb.className
361					},
362					events : this.fields.thumb.events,
363					html : template
364					}
365				);
366			}
367			else
368			{
369				res = template;
370			}
371			this.__makeThumbEventsObj = events;
372			this.__makeThumbEvents = BX.delegate(function()
373			{
374				var ii, jj;
375				for (ii in events)
376				{
377					if (events.hasOwnProperty(ii) && BX(ii))
378					{
379						for (jj in events[ii])
380						{
381							if (events[ii].hasOwnProperty(jj))
382							{
383								BX.bind(BX(ii), jj, events[ii][jj]);
384							}
385						}
386					}
387				}
388				this.__makeThumbEvents = null;
389				delete this.__makeThumbEvents;
390			}, this);
391			BX.addCustomEvent(this, "onFileIsAppended", this.__makeThumbEvents);
392
393			if (BX.type.isDomNode(this.file))
394			{
395				if (BX.type.isString(template))
396				{
397					this.__bindFileNode = BX.delegate(function(id)
398					{
399						var node = BX(id + 'Item');
400						if (node.tagName == 'TR')
401							node.cells[0].appendChild(this.file);
402						else if (node.tagName == 'TABLE')
403							node.rows[0].cells[0].appendChild(this.file);
404						else
405							BX(id + 'Item').appendChild(this.file);
406						this.__bindFileNode = null;
407						delete this.__bindFileNode;
408					}, this);
409					BX.addCustomEvent(this, "onFileIsAppended", this.__bindFileNode);
410				}
411				else
412				{
413					res.appendChild(this.file);
414				}
415			}
416			return res;
417		},
418		checkProps : function()
419		{
420			var el2 = BX.UploaderUtils.FormToArray({elements : [BX.proxy_context]}), ii;
421			for (ii in el2.data)
422			{
423				if (el2.data.hasOwnProperty(ii))
424					this[ii] = el2.data[ii];
425			}
426		},
427		setProps : function(name, val, bReturn)
428		{
429			if (typeof name == "string")
430			{
431				if (name == "size")
432					val = BX.UploaderUtils.getFormattedSize(this.file.size, 0);
433				if (typeof this[name] != "undefined" && typeof this.fields[name] != "undefined")
434				{
435					this[name] = val;
436					var template = this.fields[name].template.
437							replace('#' + name + '#', (!!val ? val : '')).
438							replace(/#id#/gi, this.id),
439						fii, fjj, el, result = {html : template, events : {}};
440
441					this.hiddenForm = (!!this.hiddenForm ? this.hiddenForm : BX.create("FORM", { style : { display : "none" } } ));
442					this._checkProps = (!!this._checkProps ? this._checkProps : BX.delegate(this.checkProps, this));
443					this.hiddenForm.innerHTML = template;
444					if (this.hiddenForm.elements.length > 0)
445					{
446						for (fii = 0; fii < this.hiddenForm.elements.length; fii++)
447						{
448							el = this.hiddenForm.elements[fii];
449							if (typeof this[el.name] != "undefined")
450							{
451								if (!el.hasAttribute("id"))
452									el.setAttribute("id", this.id + name + BX.UploaderUtils.getId());
453								result.events[el.id] = {
454									blur : this._checkProps
455								}
456
457							}
458						}
459						result.html = this.hiddenForm.innerHTML;
460					}
461					if (BX(this.hiddenForm))
462						BX.remove(this.hiddenForm);
463					this.hiddenForm = null;
464					delete this.hiddenForm;
465					if (bReturn)
466						return result;
467					var node = this.getPH(name);
468					if (!!node)
469					{
470						node.innerHTML = result.html;
471						for (fii in result.events)
472						{
473							if (result.events.hasOwnProperty(fii))
474							{
475								for (fjj in result.events[fii])
476								{
477									if (result.events[fii].hasOwnProperty(fjj))
478									{
479										BX.bind(BX(fii), fjj, result.events[fii][fjj]);
480									}
481								}
482							}
483						}
484					}
485				}
486			}
487			else if (!!name)
488			{
489				for (var ij in name)
490				{
491					if (name.hasOwnProperty(ij))
492					{
493						if (this.fields.hasOwnProperty(ij) && ij !== "preview")
494							this.setProps(ij, name[ij]);
495					}
496				}
497			}
498			return true;
499		},
500		getProps : function(name)
501		{
502			if (name == "canvas")
503			{
504				return BX(this.id + "ProperCanvas");
505			}
506			else if (typeof name == "string")
507			{
508				return this[name];
509			}
510			var data = {};
511			for (var ii in this.fields)
512			{
513				if (this.fields.hasOwnProperty(ii) && (ii !== "preview" && ii !== "thumb"))
514				{
515					data[ii] = this[ii];
516				}
517			}
518			if (!!this.copies)
519			{
520				var copy;
521				data["canvases"] = {};
522				while ((copy = this.copies.getNext()) && !!copy)
523				{
524					data["canvases"][copy.id] = { width : copy.width, height : copy.height, name : copy.name };
525				}
526			}
527			return data;
528		},
529		getThumbs : function()
530		{
531			return null;
532		},
533		getPH : function(name)
534		{
535			name = (typeof name === "string" ? name : "");
536			name = name.toLowerCase();
537			if (this.fields.hasOwnProperty(name))
538			{
539				var id = name.substr(0, 1).toUpperCase() + name.substr(1);
540				this.fields[name]["placeHolder"] = BX(this.id  + id);
541				return this.fields[name]["placeHolder"];
542			}
543			return null;
544		},
545		clickFile : function ()
546		{
547			return false;
548		},
549		makePreview: function()
550		{
551			this.status = statuses.ready;
552			BX.onCustomEvent(this, "onFileIsInited", [this.id, this, this.caller]);
553			BX.onCustomEvent(this.caller, "onFileIsInited", [this.id, this, this.caller]);
554
555			this.log('is initialized as a file');
556		},
557		preparationStatus : statuses.ready,
558		deleteFile: function()
559		{
560			var ii, events = this.__makeThumbEventsObj;
561			for (ii in this.fields)
562			{
563				if (this.fields.hasOwnProperty(ii))
564				{
565					if (!!this.fields[ii]["placeHolder"])
566					{
567						this.fields[ii]["placeHolder"] = null;
568						BX.unbindAll(this.fields[ii]["placeHolder"]);
569						delete this.fields[ii]["placeHolder"];
570					}
571				}
572			}
573
574			for (ii in events)
575			{
576				if (events.hasOwnProperty(ii) && BX(ii))
577				{
578					BX.unbindAll(BX(ii));
579				}
580			}
581
582			this.file = null;
583			delete this.file;
584
585			BX.remove(this.canvas);
586			this.canvas = null;
587			delete this.canvas;
588
589			BX.onCustomEvent(this.caller, "onFileIsDeleted", [this.id, this, this.caller]);
590			BX.onCustomEvent(this, "onFileIsDeleted", [this, this.caller]);
591		}
592	};
593	BX.UploaderImage = function(file, params, limits, caller)
594	{
595		this.dialogName = "BX.UploaderImage";
596		BX.UploaderImage.superclass.constructor.apply(this, arguments);
597		this.isImage = true;
598		this.copies = new BX.UploaderUtils.Hash();
599		this.caller = caller;
600
601		if (!this.isNode && BX.Uploader.getInstanceName() == "BX.Uploader")
602		{
603			if (!!params["copies"])
604			{
605				var copies = params["copies"], copy;
606				for (var ii in copies)
607				{
608					if (copies.hasOwnProperty(ii) && !!copies[ii])
609					{
610						copy = { width : parseInt(copies[ii]['width']), height : parseInt(copies[ii]["height"]), id : ii };
611						if (copy['width'] > 0 && copy["height"] > 0)
612						{
613							this.copies.setItem(ii, copy);
614						}
615					}
616				}
617			}
618			this.preparationStatus = statuses["new"];
619			BX.addCustomEvent(this, "onFileHasToBePrepared", BX.delegate(function()
620			{
621				this.preparationStatus = statuses.inprogress;
622				if (this.status != statuses["new"])
623				{
624					upld.push(this.file, BX.delegate(this.makeCopies, this));
625				}
626			}, this));
627			BX.addCustomEvent(this, "onUploadDone", BX.delegate(function()
628			{
629				var copy;
630				while ((copy = this.copies.getNext()) && !!copy)
631				{
632					copy.file = null;
633					delete copy.file;
634				}
635				this.preparationStatus = statuses["new"];
636			}, this));
637			this.canvas = BX.create('CANVAS', {attrs : { id : this.id + "ProperCanvas" } } );
638		}
639		else
640		{
641			this.preparationStatus = statuses.done;
642			this.canvas = null;
643		}
644		return this;
645	};
646	BX.extend(BX.UploaderImage, BX.UploaderFile);
647	BX.UploaderImage.prototype.makePreviewImageWork = function(image)
648	{
649		var result = null;
650		if (this.file)
651		{
652			this.file.width = image.width;
653			this.file.height = image.height;
654		}
655
656		if (!!this.canvas)
657		{
658			BX.adjust(prvw.getCanvas(), { props : { width : image.width, height : image.height } } );
659			prvw.getContext().drawImage(image, 0, 0);
660
661			this.applyFile(prvw.getCanvas(), false);
662
663			result = this.canvas;
664		}
665		else if (BX(this.id + 'Canvas'))
666		{
667			var res2 = BX.UploaderUtils.scaleImage(image, this.fields.preview.params),
668				props = {
669					props : { width : res2.destin.width, height : res2.destin.height, src : image.src },
670					attrs : {
671						className : (this.file.width > this.file.height ? "landscape" : "portrait")
672					}
673				};
674			result = BX.create("IMG", props);
675		}
676
677		BX.onCustomEvent(this, "onFileCanvasIsLoaded", [this.id, this, this.caller, image]);
678		BX.onCustomEvent(this.caller, "onFileCanvasIsLoaded", [this.id, this, this.caller, image]);
679
680		if (BX(this.id + 'Canvas'))
681			BX(this.id + 'Canvas').appendChild(result);
682
683		return result;
684	};
685
686	BX.UploaderImage.prototype.makePreviewImageLoadHandler = function(image, canvas, context){
687		this.makePreviewImageWork(image);
688		this.status = statuses.ready;
689
690		BX.onCustomEvent(this, "onFileIsInited", [this.id, this, this.caller]);
691		BX.onCustomEvent(this.caller, "onFileIsInited", [this.id, this, this.caller]);
692		this.log('is initialized as an image with preview');
693		if (this.preparationStatus == statuses.inprogress)
694			this.makeCopies(image, canvas, context);
695		if (this["_makePreviewImageLoadHandler"])
696		{
697			this._makePreviewImageLoadHandler = null;
698			delete this._makePreviewImageLoadHandler;
699		}
700		if (this["_makePreviewImageFailedHandler"])
701		{
702			this._makePreviewImageFailedHandler = null;
703			delete this._makePreviewImageFailedHandler;
704		}
705	};
706
707	BX.UploaderImage.prototype.makePreviewImageFailedHandler = function(){
708		this.status = statuses.ready;
709		this.preparationStatus = statuses.done;
710
711		BX.onCustomEvent(this, "onFileIsInited", [this.id, this, this.caller]);
712		BX.onCustomEvent(this.caller, "onFileIsInited", [this.id, this, this.caller]);
713
714		this.log('is initialized without canvas');
715		if (this["_makePreviewImageLoadHandler"])
716		{
717			this._makePreviewImageLoadHandler = null;
718			delete this._makePreviewImageLoadHandler;
719		}
720		if (this["_makePreviewImageFailedHandler"])
721		{
722			this._makePreviewImageFailedHandler = null;
723			delete this._makePreviewImageFailedHandler;
724		}
725	};
726	BX.UploaderImage.prototype.makePreview = function()
727	{
728		if (!this.isNode)
729		{
730			this._makePreviewImageLoadHandler = BX.delegate(this.makePreviewImageLoadHandler, this);
731			this._makePreviewImageFailedHandler = BX.delegate(this.makePreviewImageFailedHandler, this);
732			prvw.push(this.file, this._makePreviewImageLoadHandler, this._makePreviewImageFailedHandler);
733		}
734		else
735		{
736			this.status = statuses.ready;
737			BX.onCustomEvent(this, "onFileIsInited", [this.id, this, this.caller]);
738			BX.onCustomEvent(this.caller, "onFileIsInited", [this.id, this, this.caller]);
739
740			this.log('is initialized as an image without preview');
741			if (this.caller.queue.placeHolder)
742			{
743				this._onFileHasGotPreview = BX.delegate(function(id, item) {
744
745					BX.removeCustomEvent(this, "onFileHasGotPreview", this._onFileHasGotPreview);
746					BX.removeCustomEvent(this, "onFileHasNotGotPreview", this._onFileHasNotGotPreview);
747
748					this._makePreviewImageLoadHandler = BX.delegate(function(image){
749						image = this.makePreviewImageWork(image);
750						BX.onCustomEvent(this, "onFileHasPreview", [item.id, item, image]);
751						delete this._makePreviewImageLoadHandler;
752						delete this._makePreviewImageFailedHandler;
753					}, this);
754					this._makePreviewImageFailedHandler = BX.delegate(function(image){
755						delete this._makePreviewImageLoadHandler;
756						delete this._makePreviewImageFailedHandler;
757					}, this);
758					prvw.push({tmp_url : item.file.url}, this._makePreviewImageLoadHandler, this._makePreviewImageFailedHandler);
759				}, this);
760				this._onFileHasNotGotPreview = BX.delegate(function(id){
761					if (id == this.id)
762					{
763						BX.removeCustomEvent(this, "onFileHasGotPreview", this._onFileHasGotPreview);
764						BX.removeCustomEvent(this, "onFileHasNotGotPreview", this._onFileHasNotGotPreview);
765					}
766				}, this);
767				BX.addCustomEvent(this, "onFileHasGotPreview", this._onFileHasGotPreview);
768				BX.addCustomEvent(this, "onFileHasNotGotPreview", this._onFileHasNotGotPreview);
769				BX.onCustomEvent(this.caller, "onFileNeedsPreview", [this.id, this, this.caller]);
770			}
771		}
772		return true;
773	};
774	BX.UploaderImage.prototype.checkPreview = function()
775	{
776		// TODO check preview
777	};
778	BX.UploaderImage.prototype.applyFile = function(cnv, params)
779	{
780		this.checkPreview();
781
782		if (!!params && params.data )
783			this.setProps(params.data);
784
785		var realScale = BX.UploaderUtils.scaleImage(cnv, {width : this.limits["uploadFileWidth"], height : this.limits["uploadFileHeight"]}),
786			prvwScale = BX.UploaderUtils.scaleImage(cnv, this.fields.preview.params),
787			prvwProps = {
788				props : { width : prvwScale.destin.width, height : prvwScale.destin.height },
789				attrs : {
790					className : "bx-bxu-proper-canvas"+(prvwScale.destin.width > prvwScale.destin.height ? " landscape" : " portrait")
791				}
792			};
793
794		if (realScale.bNeedCreatePicture || !!params)
795		{
796			BX.adjust(canvas, { props : { width : realScale.destin.width, height : realScale.destin.height } } );
797			ctx = canvas.getContext('2d');
798			ctx.drawImage(cnv,
799				realScale.source.x, realScale.source.y, realScale.source.width, realScale.source.height,
800				realScale.destin.x, realScale.destin.y, realScale.destin.width, realScale.destin.height
801			);
802
803			var dataURI = canvas.toDataURL(this.file.type);
804			this.file = BX.UploaderUtils.dataURLToBlob(dataURI);
805		}
806
807		this.file.name = this.name;
808		this.file.width = realScale.destin.width;
809		this.file.height = realScale.destin.height;
810
811		BX.adjust(this.canvas, prvwProps);
812
813		ctx = this.canvas.getContext('2d');
814		ctx.drawImage(cnv,
815			prvwScale.source.x, prvwScale.source.y, prvwScale.source.width, prvwScale.source.height,
816			prvwScale.destin.x, prvwScale.destin.y, prvwScale.destin.width, prvwScale.destin.height
817		);
818
819		ctx = null;
820		cnv = null;
821
822		this.setProps('size');
823		this.status = statuses.changed;
824	};
825	BX.UploaderImage.prototype.clickFile = function()
826	{
827		if (!this.canvas || !BX["CanvasEditor"] || this.status == statuses["new"])
828			return false;
829		if (!this.__showEditor)
830		{
831			this.__showEditor = BX.delegate(this.showEditor, this);
832			this.eFunc = {
833				"apply" : BX.delegate(this.applyFile, this),
834				"delete" : BX.delegate(this.deleteFile, this),
835				"clear" : BX.delegate(function()
836				{
837					BX.removeCustomEvent(editor, "onApplyCanvas", this.eFunc["apply"]);
838					BX.removeCustomEvent(editor, "onDeleteCanvas", this.eFunc["delete"]);
839					BX.removeCustomEvent(editor, "onClose", this.eFunc["clear"]);
840				}, this)
841			};
842		}
843		var template = this.fields.thumb.editorTemplate, name;
844		for (var ii in this.fields)
845		{
846			if (this.fields.hasOwnProperty(ii))
847			{
848				name = ii.substr(0, 1).toUpperCase() + ii.substr(1);
849				template = template.replace('#' + ii + '#',
850					(ii === "preview" ? "" :
851						('<span id="' + this.id + name + 'Editor" class="' + this.fields[ii]["className"] + '">' +
852						this.fields[ii]["editorTemplate"].replace('#' + ii + '#', (!!this[ii] ? this[ii] : '')) + '</span>')));
853			}
854		}
855
856		BX.adjust(edtr.getCanvas(), { props : { width : this.file.width, height : this.file.height } } );
857		edtr.getContext().drawImage(this.canvas,
858			0, 0, this.canvas.width, this.canvas.height,
859			0, 0, edtr.getCanvas().width, edtr.getCanvas().height);
860		var editor = BX.CanvasEditor.show(edtr.getCanvas(), {title : this.name, template : template});
861
862		BX.addCustomEvent(editor, "onApplyCanvas", this.eFunc["apply"]);
863		BX.addCustomEvent(editor, "onDeleteCanvas", this.eFunc["delete"]);
864		BX.addCustomEvent(editor, "onClose", this.eFunc["clear"]);
865		BX.onCustomEvent(this, "onCanvasEditorIsCreated", [editor, this]);
866
867		edtr.push(this.file, this.__showEditor);
868		this.editor = editor;
869		return false;
870	};
871	BX.UploaderImage.prototype.showEditor = function(image, canvas, context)
872	{
873		BX.adjust(canvas, { props : { width : this.file.width, height : this.file.height } } );
874		context.drawImage(image, 0, 0);
875		this.editor.copyCanvas(canvas);
876	};
877	BX.UploaderImage.prototype.makeCopies = function(image, canvas, context)
878	{
879		var copy, res, dataURI, result;
880
881		while ((copy = this.copies.getNext()) && !!copy)
882		{
883			res = BX.UploaderUtils.scaleImage(image, copy);
884			BX.adjust(canvas, {props : { width : res.destin.width, height : res.destin.height } } );
885			context.drawImage(image,
886				res.source.x, res.source.y, res.source.width, res.source.height,
887				res.destin.x, res.destin.y, res.destin.width, res.destin.height
888			);
889
890			dataURI = canvas.toDataURL(this.file.type);
891			result = BX.UploaderUtils.dataURLToBlob(dataURI);
892			result.width = canvas.width;
893			result.height = canvas.height;
894			result.name = this.name;
895			result.thumb = copy.id;
896			result.canvases = this.copies.length;
897			result.canvas = this.copies.pointer - 1;
898			copy.file = result;
899		}
900		this.preparationStatus = statuses.done;
901	};
902	BX.UploaderImage.prototype.getThumbs = function(name)
903	{
904		if (name == "getCount")
905			return this.copies.length;
906
907		var res = (typeof name == "string" ? this.copies.getItem(name) : this.copies.getNext());
908
909		if (!!res)
910			return res.file;
911		return null;
912	};
913	return true;
914}(window));

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.