1;(function(window){ 2 window.BX = window['BX'] || {}; 3 if (window.BX["UploaderFile"]) 4 return false; 5 var getOrientation = (function(){ 6 var exif = { 7 tags : { 8 // 0x0100 : "ImageWidth", 9 // 0x0101 : "ImageHeight", 10 // 0x8769 : "ExifIFDPointer", 11 // 0x8825 : "GPSInfoIFDPointer", 12 // 0xA005 : "InteroperabilityIFDPointer", 13 // 0x0102 : "BitsPerSample", 14 // 0x0103 : "Compression", 15 // 0x0106 : "PhotometricInterpretation", 16 0x0112 : "Orientation", 17 // 0x0115 : "SamplesPerPixel", 18 // 0x011C : "PlanarConfiguration", 19 // 0x0212 : "YCbCrSubSampling", 20 // 0x0213 : "YCbCrPositioning", 21 // 0x011A : "XResolution", 22 // 0x011B : "YResolution", 23 // 0x0128 : "ResolutionUnit", 24 // 0x0111 : "StripOffsets", 25 // 0x0116 : "RowsPerStrip", 26 // 0x0117 : "StripByteCounts", 27 // 0x0201 : "JPEGInterchangeFormat", 28 // 0x0202 : "JPEGInterchangeFormatLength", 29 // 0x012D : "TransferFunction", 30 // 0x013E : "WhitePoint", 31 // 0x013F : "PrimaryChromaticities", 32 // 0x0211 : "YCbCrCoefficients", 33 // 0x0214 : "ReferenceBlackWhite", 34 // 0x0132 : "DateTime", 35 // 0x010E : "ImageDescription", 36 // 0x010F : "Make", 37 // 0x0110 : "Model", 38 // 0x0131 : "Software", 39 // 0x013B : "Artist", 40 // 0x8298 : "Copyright" 41 }, 42 getStringFromDB : function (buffer, start, length) { 43 var outstr = "", n; 44 for (n = start; n < start+length; n++) { 45 outstr += String.fromCharCode(buffer.getUint8(n)); 46 } 47 return outstr; 48 }, 49 readTags : function(file, tiffStart, dirStart, strings, bigEnd) { 50 var entries = file.getUint16(dirStart, !bigEnd), 51 tags = {}, 52 entryOffset, tag, 53 i, 54 l = 0; 55 for (i in strings) 56 { 57 if (strings.hasOwnProperty(i)) 58 l++; 59 } 60 61 for (i = 0; i < entries; i++) 62 { 63 entryOffset = dirStart + i*12 + 2; 64 tag = strings[file.getUint16(entryOffset, !bigEnd)]; 65 tags[tag] = exif.readTagValue(file, entryOffset, tiffStart, dirStart, bigEnd); 66 l--; 67 if (l <= 0) 68 break; 69 } 70 return tags; 71 }, 72 readTagValue : function(file, entryOffset, tiffStart, dirStart, bigEnd) { 73 var type = file.getUint16(entryOffset+2, !bigEnd), 74 numValues = file.getUint32(entryOffset+4, !bigEnd), 75 valueOffset = file.getUint32(entryOffset+8, !bigEnd) + tiffStart, 76 offset, 77 vals, val, n, 78 numerator, denominator; 79 80 switch (type) 81 { 82 case 1: // byte, 8-bit unsigned int 83 case 7: // undefined, 8-bit byte, value depending on field 84 if (numValues == 1) { 85 return file.getUint8(entryOffset + 8, !bigEnd); 86 } else { 87 offset = numValues > 4 ? valueOffset : (entryOffset + 8); 88 vals = []; 89 for (n=0;n<numValues;n++) { 90 vals[n] = file.getUint8(offset + n); 91 } 92 return vals; 93 } 94 case 2: // ascii, 8-bit byte 95 offset = numValues > 4 ? valueOffset : (entryOffset + 8); 96 return exif.getStringFromDB(file, offset, numValues-1); 97 case 3: // short, 16 bit int 98 if (numValues == 1) { 99 return file.getUint16(entryOffset + 8, !bigEnd); 100 } else { 101 offset = numValues > 2 ? valueOffset : (entryOffset + 8); 102 vals = []; 103 for (n=0;n<numValues;n++) { 104 vals[n] = file.getUint16(offset + 2*n, !bigEnd); 105 } 106 return vals; 107 } 108 case 4: // long, 32 bit int 109 if (numValues == 1) { 110 return file.getUint32(entryOffset + 8, !bigEnd); 111 } else { 112 vals = []; 113 for (n=0;n<numValues;n++) { 114 vals[n] = file.getUint32(valueOffset + 4*n, !bigEnd); 115 } 116 return vals; 117 } 118 case 5: // rational = two long values, first is numerator, second is denominator 119 if (numValues == 1) { 120 numerator = file.getUint32(valueOffset, !bigEnd); 121 denominator = file.getUint32(valueOffset+4, !bigEnd); 122 val = new Number(numerator / denominator); 123 val.numerator = numerator; 124 val.denominator = denominator; 125 return val; 126 } else { 127 vals = []; 128 for (n=0;n<numValues;n++) { 129 numerator = file.getUint32(valueOffset + 8*n, !bigEnd); 130 denominator = file.getUint32(valueOffset+4 + 8*n, !bigEnd); 131 vals[n] = new Number(numerator / denominator); 132 vals[n].numerator = numerator; 133 vals[n].denominator = denominator; 134 } 135 return vals; 136 } 137 case 9: // slong, 32 bit signed int 138 if (numValues == 1) { 139 return file.getInt32(entryOffset + 8, !bigEnd); 140 } else { 141 vals = []; 142 for (n=0;n<numValues;n++) { 143 vals[n] = file.getInt32(valueOffset + 4*n, !bigEnd); 144 } 145 return vals; 146 } 147 case 10: // signed rational, two slongs, first is numerator, second is denominator 148 if (numValues == 1) { 149 return file.getInt32(valueOffset, !bigEnd) / file.getInt32(valueOffset+4, !bigEnd); 150 } else { 151 vals = []; 152 for (n=0;n<numValues;n++) { 153 vals[n] = file.getInt32(valueOffset + 8*n, !bigEnd) / file.getInt32(valueOffset+4 + 8*n, !bigEnd); 154 } 155 return vals; 156 } 157 } 158 }, 159 readData : function (file, start) { 160 if (exif.getStringFromDB(file, start, 4) != "Exif") 161 { 162 return false;
163 } 164 165 var bigEnd, 166 tiffOffset = start + 6; 167 168 // test for TIFF validity and endianness 169 if (file.getUint16(tiffOffset) == 0x4949) 170 { 171 bigEnd = false; 172 } 173 else if (file.getUint16(tiffOffset) == 0x4D4D) 174 { 175 bigEnd = true; 176 } 177 else 178 { 179 return false; 180 } 181 182 if (file.getUint16(tiffOffset+2, !bigEnd) != 0x002A) 183 { 184 return false; 185 } 186 187 var firstIFDOffset = file.getUint32(tiffOffset + 4, !bigEnd); 188 189 if (firstIFDOffset < 0x00000008) 190 { 191 return false; 192 } 193 194 return exif.readTags(file, tiffOffset, tiffOffset + firstIFDOffset, exif.tags, bigEnd); 195 }, 196 readBase64 : function (base64) 197 { 198 base64 = base64.replace(/^data\:([^\;]+)\;base64,/gmi, ''); 199 var binary_string = window.atob(base64), //decode base64 200 len = binary_string.length, 201 bytes = new Uint8Array(len); 202 for (var i = 0; i < len; i++) { 203 bytes[i] = binary_string.charCodeAt(i); 204 } 205 var dataView = new DataView(bytes.buffer); 206 if ((dataView.getUint8(0) != 0xFF) || (dataView.getUint8(1) != 0xD8)) 207 { 208 return false; // not a valid jpeg 209 } 210 211 var offset = 2, 212 length = bytes.buffer.byteLength, 213 marker, 214 result = false;
215 while (offset < length) 216 { 217 if (dataView.getUint8(offset) != 0xFF) { 218 break; // not a valid marker, something is wrong 219 } 220 221 marker = dataView.getUint8(offset + 1); 222 223 // we could implement handling for other markers here, 224 // but we're only looking for 0xFFE1 for EXIF data 225 226 if (marker == 225) 227 { 228 result = exif.readData(dataView, offset + 4, dataView.getUint16(offset + 2) - 2); 229 break; 230 } 231 else 232 { 233 offset += 2 + dataView.getUint16(offset+2); 234 } 235 } 236 return result; 237 } 238 }; 239 return function(base64){ 240 if (BX.type.isString(base64)) 241 { 242 try { 243 var tags = exif.readBase64(base64); 244 if(tags && tags["Orientation"]) 245 return tags["Orientation"]; 246 } 247 catch (e) 248 { 249 } 250 } 251 return false; 252 }; 253 })(), 254 setOrientation = function(image, cnv, ctx, exifOrientation) { 255 var width = image.width, 256 height = image.height; 257 if ([5,6,7,8].indexOf(exifOrientation) >= 0) 258 { 259 width = image.height; 260 height = image.width; 261 } 262 263 BX.adjust(cnv, {props: {width: width, height: height}}); 264 265 ctx.save(); 266 switch(exifOrientation) { 267 case 2: 268 // $img.addClass('flip'); 269 ctx.scale(-1, 1); 270 ctx.translate(-cnv.width, 0); 271 break; 272 case 3: 273 // $img.addClass('rotate-180'); 274 ctx.translate(cnv.width, cnv.height); 275 ctx.rotate(Math.PI); 276 break; 277 case 4: 278 // $img.addClass('flip-and-rotate-180'); 279 ctx.scale(-1, 1); 280 ctx.translate(0, cnv.height); 281 ctx.rotate(Math.PI); 282 break; 283 case 5: 284 // $img.addClass('flip-and-rotate-90'); 285 ctx.scale(-1, 1); 286 ctx.translate(0, 0); 287 ctx.rotate(Math.PI / 2); 288 break; 289 case 6: 290 // $img.addClass('rotate-90'); 291 ctx.translate(cnv.width, 0); 292 ctx.rotate(Math.PI / 2); 293 break; 294 case 7: 295 // $img.addClass('flip-and-rotate-90'); 296 ctx.scale(-1, 1); 297 ctx.translate(-cnv.width, cnv.height); 298 ctx.rotate(Math.PI * 3 / 2); 299 break; 300 case 8: 301 // $img.addClass('rotate-270'); 302 ctx.translate(0, cnv.height); 303 ctx.rotate(Math.PI * 3 / 2); 304 break; 305 } 306 ctx.drawImage(image, 0, 0); 307 ctx.restore(); 308 }; 309 var BX = window.BX, 310 statuses = { "new" : 0, ready : 1, preparing : 2, inprogress : 3, done : 4, failed : 5, stopped : 6, changed : 7, uploaded : 8}, 311 cnvConstr = (function(){ 312 var cnvConstructor = function(timelimit) { 313 this.timeLimit = (typeof timelimit === "number" && timelimit > 0 ? timelimit : 50); 314 this.status = statuses.ready; 315 this.queue = new BX.UploaderUtils.Hash(); 316 this.id = (new Date()).getTime(); 317 }; 318 cnvConstructor.prototype = { 319 counter : 0, 320 active : null, 321 image : null, 322 getImage : function() { 323 if (!this.image) 324 this.image = new Image(); 325 return this.image; 326 }, 327 canvas : null, 328 getCanvas : function() { 329 if (!this.canvas) 330 { 331 this.canvas = BX.create('CANVAS', {style : {display: "none"}}); 332 document.body.appendChild(this.canvas); 333 } 334 335 return this.canvas; 336 }, 337 context : null, 338 getContext : function() { 339 if (!this.context && this.getCanvas()["getContext"]) 340 this.context = this.getCanvas().getContext('2d'); 341 return this.context; 342 }, 343 reader : null, 344 getReader : function() { 345 if (!this.reader && window["FileReader"]) 346 this.reader = new FileReader(); 347 return this.reader; 348 }, 349 load : function(file, callback, id, callbackFail) { 350 if (this.active !== null || (this.getReader() && this.getReader().readyState == 1)) 351 return; 352 353 this.counter++; 354 this.active = file; 355 var image = this.getImage(); 356 BX.unbindAll(image); 357 image.onload = function(){}; 358 image.onerror = function(){}; 359 360 /* Almost all browsers cache images from local resource except of FF on 06.03.2017. It appears that 361 FF collect src and does not abort image uploading when src is changed. And we had a bug when in 362 onload event we got e.target.src of one element but source of image was from '/bitrix/images/1.gif'. */ 363 // TODO check if chrome and other browsers cache local files for now. If it does not then delete next 2 strings 364 if (!BX.browser.IsFirefox()) 365 image.src = '/bitrix/images/1.gif'; 366 367 /** For Garbage collector */ 368 this.onload = null; 369 delete this.onload; 370 this.onerror = null; 371 delete this.onerror; 372 373 this.onload = BX.delegate(function(e){ 374 if (e && e.target && e.target.src && e.target.src.substr(-20) == "/bitrix/images/1.gif") 375 return; 376 if (!!callback) 377 { 378 try { 379 callback(BX.proxy_context, this.getCanvas(), this.getContext(), getOrientation((((e && e.target && e.target.src) ? e.target.src : (BX.proxy_context || null))))); 380 } 381 catch (e) 382 { 383 BX.debug(e); 384 } 385 } 386 if (!!id) 387 { 388 this.queue.removeItem(id); 389 setTimeout(BX.proxy(function() { 390 this.active = null; 391 this.exec(); 392 }, this), this.timeLimit); 393 } 394 else 395 this.active = null; 396 }, this); 397 this.onerror = BX.delegate(function(){ 398 if (!!callbackFail) 399 { 400 try 401 { 402 callbackFail(BX.proxy_context); 403 } 404 catch (e) 405 { 406 BX.debug(e); 407 } 408 } 409 if (!!id) 410 { 411 this.queue.removeItem(id); 412 setTimeout(BX.proxy(function() { 413 this.active = null; 414 this.exec(); 415 }, this), this.timeLimit); 416 } 417 else 418 this.active = null; 419 }, this); 420 421 image.name = file.name; 422 423 image.onload = this.onload; 424 image.onerror = this.onerror; 425 426 var res = Object.prototype.toString.call(file); 427 if (file["tmp_url"]) 428 { 429 image.src = file["tmp_url"] + (file["tmp_url"].indexOf("?") > 0 ? '&' : '?') + 'imageUploader' + this.id + this.counter; 430 } 431 else if (res !== '[object File]' && res !== '[object Blob]') 432 {
433 this.onerror(null); 434 } 435 else if (window["URL"]) 436 { 437 image.src = window["URL"]["createObjectURL"](file); 438 } 439 else if (this.getReader() !== null) 440 { 441 this.__readerOnLoad = null; 442 delete this.__readerOnLoad; 443 this.__readerOnLoad = BX.delegate(function(e) { 444 this.__readerOnLoad = null; 445 delete this.__readerOnLoad; 446 image.src = e.target.result; 447 }, this); 448 this.getReader().onloadend = this.__readerOnLoad; 449 this.getReader().onerror = BX.proxy(function(e) { this.onerror(null); }, this); 450 this.getReader().readAsDataURL(file); 451 } 452 }, 453 push : function(file, callback, failCallback) { 454 var id = BX.UploaderUtils.getId(); 455 this.queue.setItem(id, [id, file, callback, failCallback]); 456 this.exec(); 457 }, 458 exec : function() { 459 var item = this.queue.getFirst(); 460 if (!!item) 461 this.load(item[1], item[2], item[0], item[3]); 462 }, 463 pack : function(fileType) { 464 return BX.UploaderUtils.dataURLToBlob(this.getCanvas().toDataURL(fileType)); 465 } 466 }; 467 return cnvConstructor; 468 })(); 469 BX.UploaderFileCnvConstr = cnvConstr; 470 BX.UploaderFileFileLoader = (function(){ 471 var d = function(timelimit) { 472 this.timeLimit = (typeof timelimit === "number" && timelimit > 0 ? timelimit : 50); 473 this.status = statuses.ready; 474 this.queue = new BX.UploaderUtils.Hash(); 475 this._exec = BX.delegate(this.exec, this); 476 }; 477 d.prototype = { 478 xhr : null, 479 goToNext : function(id) 480 { 481 delete this.xhr; 482 this.xhr = null; 483 this.queue.removeItem(id); 484 this.status = statuses.ready; 485 setTimeout(this._exec, this.timeLimit); 486 }, 487 load : function(id, path, onsuccess, onfailure) 488 { 489 if (this.status != statuses.ready) 490 return; 491 this.status = statuses.inprogress; 492 var _this = this; 493 this.xhr = BX.ajax({ 494 'method': 'GET', 495 'data' : '', 496 'url': path, 497 'onsuccess': function(blob){if (blob === null){onfailure(blob);} else {onsuccess(blob);} _this.goToNext(id);}, 498 'onfailure': function(blob){onfailure(blob); _this.goToNext(id);}, 499 'start': false, 500 'preparePost':false, 501 'processData':false 502 }); 503 this.xhr.withCredentials = true; 504 this.xhr.responseType = 'blob'; 505 506 this.xhr.send(); 507 }, 508 push : function(path, onsuccess, onfailure) 509 { 510 var id = BX.UploaderUtils.getId(); 511 this.queue.setItem(id, [id, path, onsuccess, onfailure]); 512 this.exec(); 513 }, 514 exec : function() 515 { 516 var item = this.queue.getFirst(); 517 if (!!item) 518 this.load(item[0], item[1], item[2], item[3]); 519 } 520 }; 521 return d; 522 })(); 523 var prvw = new cnvConstr(), upld = new cnvConstr(), edtr = new cnvConstr(), canvas = BX.create('CANVAS'), ctx; 524 /** 525 * @return {BX.UploaderFile} 526 * @file file 527 * @params array 528 * @limits array 529 * @caller {BX.Uploader} 530 * You should work with params["fields"] in case you want to change visual part 531 */ 532 var mobileNames = {}; 533 BX.UploaderFile = function (file, params, limits, caller) 534 { 535 this.dialogName = (this.dialogName ? this.dialogName : "BX.UploaderFile"); 536 this.file = file; 537 this.id = (file['id'] || 'file' + BX.UploaderUtils.getId()); 538 this.name = file.name; 539 this.isNode = false; 540 if (BX.type.isDomNode(file)) 541 { 542 this.isNode = true; 543 this.name = BX.UploaderUtils.getFileNameOnly(file.value); 544 if (/\[(.+?)\]/.test(file.name)) 545 { 546 var tmp = /\[(.+?)\]/.exec(file.name); 547 this.id = tmp[1]; 548 } 549 this.file.bxuHandler = this; 550 } 551 else if (file["tmp_url"] && !file["name"]) 552 { 553 this.name = BX.UploaderUtils.getFileNameOnly(file["tmp_url"]); 554 } 555 this.preview = '<span id="' + this.id + 'Canvas" class="bx-bxu-canvas"></span>'; 556 this.nameWithoutExt = (this.name.lastIndexOf('.') > 0 ? this.name.substr(0, this.name.lastIndexOf('.')) : this.name); 557 this.ext = this.name.substr(this.nameWithoutExt.length + 1); 558 559 if (/iPhone|iPad|iPod/i.test(navigator.userAgent) && this.nameWithoutExt == "image") 560 { 561 var nameWithoutExt = 'mobile_' + BX.date.format("Ymd_His"); 562 mobileNames[nameWithoutExt] = (mobileNames[nameWithoutExt] || 0); 563 this.nameWithoutExt = nameWithoutExt + (mobileNames[nameWithoutExt] > 0 ? ("_" + mobileNames[nameWithoutExt]) : ""); 564 this.name = this.nameWithoutExt + (BX.type.isNotEmptyString(this.ext) ? ("." + this.ext) : ""); 565 mobileNames[nameWithoutExt]++; 566 } 567 568 this.size = ''; 569 if (file.size) 570 this.size = BX.UploaderUtils.getFormattedSize(file.size, 0); 571 this.type = file.type; 572 this.status = statuses["new"]; 573 this.limits = limits; 574 this.caller = caller; 575 this.fields = { 576 thumb : { 577 tagName : 'SPAN', 578 template : '<div class="someclass">#preview#<div>#name#</div>', 579 editorTemplate : '<div class="someeditorclass"><div>#name#</div>', 580 className : "bx-bxu-thumb-thumb", 581 placeHolder : null 582 }, 583 preview : { 584 params : { width : 400, height : 400 },
585 template : "#preview#", 586 editorParams : { width : 1024, height : 860 }, 587 editorTemplate : '<span>#preview#</span>', 588 className : "bx-bxu-thumb-preview", 589 placeHolder : null, 590 events : { 591 click : BX.delegate(this.clickFile, this) 592 }, 593 type : "html" 594 }, 595 name : { 596 template : "#name#", 597 editorTemplate : '<span><input type="text" name="name" value="#name#" /></span>', 598 className : "bx-bxu-thumb-name", 599 placeHolder : null 600 }, 601 type : { 602 template : "#type#", 603 editorTemplate : '#type#', 604 className : "bx-bxu-thumb-type", 605 placeHolder : null 606 } 607 }; 608 609 if (!!params["fields"]) 610 { 611 var ij, key; 612 for (var ii in params["fields"]) 613 { 614 if (params["fields"].hasOwnProperty(ii)) 615 { 616 if (!!this.fields[ii]) 617 { 618 for (ij in params["fields"][ii]) 619 { 620 if (params["fields"][ii].hasOwnProperty(ij)) 621 { 622 this.fields[ii][ij] = params["fields"][ii][ij]; 623 } 624 } 625 } 626 else 627 this.fields[ii] = params["fields"][ii]; 628 key = ii + ''; 629 if (key.toLowerCase() != "thumb" && key.toLowerCase() != "preview") 630 { 631 this[key.toLowerCase()] = (!!params["fields"][ii]["value"] ? params["fields"][ii]["value"] : ""); 632 this.log(key.toLowerCase() + ': ' + this[key.toLowerCase()]); 633 } 634 } 635 } 636 } 637 638 BX.onCustomEvent(this, "onFileIsCreated", [this.id, this, this.caller]); 639 BX.onCustomEvent(this.caller, "onFileIsCreated", [this.id, this, this.caller]); 640 641 this.makePreview(); 642 this.preparationStatus = statuses.done; 643 return this; 644 }; 645 BX.UploaderFile.prototype = { 646 getId: function() 647 { 648 return this.id; 649 }, 650 651 log : function(text) 652 { 653 BX.UploaderUtils.log('file ' + this.name, text); 654 }, 655 makeThumb : function() 656 { 657 var template = this.fields.thumb.template, name, ii, events = {}, node, jj; 658 for (ii in this.fields) 659 { 660 if (this.fields.hasOwnProperty(ii)) 661 { 662 if (this.fields[ii].template && this.fields[ii].template.indexOf('#' + ii + '#') >= 0) 663 { 664 name = this.id + ii.toUpperCase().substr(0, 1) + ii.substr(1); 665 node = this.setProps(ii, this[ii], true); 666 template = template.replace('#' + ii + '#', '<span id="' + name + '" class="' + this.fields[ii]["className"] + '">' + ( 667 BX.type.isNotEmptyString(node.html) ? node.html.replace("#", "<\x19>") : node.html) + '</span>'); 668 for (jj in node.events) 669 { 670 if (node.events.hasOwnProperty(jj)) 671 { 672 events[jj] = node.events[jj]; 673 } 674 } 675 if (!!this.fields[ii].events) 676 events[name] = this.fields[ii].events; 677 } 678 } 679 } 680 var res, patt = [], repl = [], tmp; 681 while ((res = /#([^\\<\\>\\"\\']+?)#/gi.exec(template)) && !!res) 682 { 683 if (this[res[1]] !== undefined) 684 { 685 template = template.replace(res[0], BX.type.isNotEmptyString(this[res[1]]) ? this[res[1]].replace("#", "<\x19>") : this[res[1]]); 686 } 687 else 688 { 689 tmp = "<\x18" + patt.length + ">"; 690 patt.push(tmp); 691 repl.push(res[0]); 692 template = template.replace(res[0], tmp); 693 } 694 } 695 while ((res = patt.shift()) && res) 696 { 697 tmp = repl.shift(); 698 template = template.replace(res, tmp); 699 } 700 template = template.replace("<\x19>", "#"); 701 if (!!this.fields.thumb.tagName) 702 { 703 res = BX.create(this.fields.thumb.tagName, { 704 attrs : { 705 id : (this.id + 'Thumb'), 706 className : this.fields.thumb.className 707 }, 708 events : this.fields.thumb.events, 709 html : template 710 } 711 ); 712 } 713 else 714 { 715 res = template; 716 } 717 this.__makeThumbEventsObj = events; 718 this.__makeThumbEvents = BX.delegate(function() 719 { 720 var ii, jj; 721 for (ii in events) 722 { 723 if (events.hasOwnProperty(ii) && BX(ii)) 724 { 725 for (jj in events[ii]) 726 { 727 if (events[ii].hasOwnProperty(jj)) 728 { 729 BX.bind(BX(ii), jj, events[ii][jj]); 730 } 731 } 732 } 733 } 734 this.__makeThumbEvents = null; 735 delete this.__makeThumbEvents; 736 }, this); 737 BX.addCustomEvent(this, "onFileIsAppended", this.__makeThumbEvents); 738 739 if (BX.type.isDomNode(this.file)) 740 { 741 if (BX.type.isString(template)) 742 { 743 this.__bindFileNode = BX.delegate(function(id) 744 { 745 var node = BX(id + 'Item'); 746 if (node.tagName == 'TR') 747 node.cells[0].appendChild(this.file); 748 else if (node.tagName == 'TABLE') 749 node.rows[0].cells[0].appendChild(this.file); 750 else 751 BX(id + 'Item').appendChild(this.file); 752 this.__bindFileNode = null; 753 delete this.__bindFileNode; 754 }, this); 755 BX.addCustomEvent(this, "onFileIsAppended", this.__bindFileNode); 756 } 757 else 758 { 759 res.appendChild(this.file); 760 } 761 } 762 return res; 763 }, 764 checkProps : function() 765 { 766 var el2 = BX.UploaderUtils.FormToArray({elements : [BX.proxy_context]}), ii; 767 for (ii in el2.data) 768 { 769 if (el2.data.hasOwnProperty(ii)) 770 this[ii] = el2.data[ii]; 771 } 772 }, 773 setProps : function(name, val, bReturn) 774 { 775 if (typeof name == "string") 776 { 777 if (name == "size") 778 val = BX.UploaderUtils.getFormattedSize(this.file.size, 0); 779 if (typeof this[name] != "undefined" && typeof this.fields[name] != "undefined") 780 { 781 this[name] = val; 782 var template = this.fields[name].template.
783 replace('#' + name + '#', this.fields[name]["type"] === "html" ? (val || '') : BX.util.htmlspecialchars(val || '')). 784 replace(/#id#/gi, this.id), 785 fii, fjj, el, result = {html : template, events : {}}; 786 787 this.hiddenForm = (!!this.hiddenForm ? this.hiddenForm : BX.create("FORM", { style : { display : "none" } } )); 788 this._checkProps = (!!this._checkProps ? this._checkProps : BX.delegate(this.checkProps, this)); 789 this.hiddenForm.innerHTML = template; 790 if (this.hiddenForm.elements.length > 0) 791 { 792 for (fii = 0; fii < this.hiddenForm.elements.length; fii++) 793 { 794 el = this.hiddenForm.elements[fii]; 795 if (typeof this[el.name] != "undefined") 796 { 797 if (!el.hasAttribute("id")) 798 el.setAttribute("id", this.id + name + BX.UploaderUtils.getId()); 799 result.events[el.id] = { 800 blur : this._checkProps 801 } 802 803 } 804 } 805 result.html = this.hiddenForm.innerHTML; 806 } 807 if (BX(this.hiddenForm)) 808 BX.remove(this.hiddenForm); 809 this.hiddenForm = null; 810 delete this.hiddenForm; 811 if (bReturn) 812 return result; 813 var node = this.getPH(name); 814 if (!!node) 815 { 816 node.innerHTML = result.html; 817 for (fii in result.events) 818 { 819 if (result.events.hasOwnProperty(fii)) 820 { 821 for (fjj in result.events[fii]) 822 { 823 if (result.events[fii].hasOwnProperty(fjj)) 824 { 825 BX.bind(BX(fii), fjj, result.events[fii][fjj]); 826 } 827 } 828 } 829 } 830 } 831 } 832 } 833 else if (!!name) 834 { 835 for (var ij in name) 836 { 837 if (name.hasOwnProperty(ij)) 838 { 839 if (this.fields.hasOwnProperty(ij) && ij !== "preview") 840 this.setProps(ij, name[ij]); 841 } 842 } 843 } 844 return true; 845 }, 846 getProps : function(name) 847 { 848 if (name == "canvas") 849 { 850 return BX(this.id + "ProperCanvas"); 851 } 852 else if (typeof name == "string") 853 { 854 return this[name]; 855 } 856 var data = {}; 857 for (var ii in this.fields) 858 { 859 if (this.fields.hasOwnProperty(ii) && (ii !== "preview" && ii !== "thumb")) 860 { 861 data[ii] = this[ii]; 862 } 863 } 864 data["size"] = this.file["size"]; 865 data["type"] = this["type"]; 866 if (!!this.copies) 867 { 868 var copy; 869 data["canvases"] = {}; 870 while ((copy = this.copies.getNext()) && !!copy) 871 { 872 data["canvases"][copy.id] = { width : copy.width, height : copy.height, name : copy.id }; 873 } 874 } 875 return data; 876 }, 877 getThumbs : function() 878 { 879 return null; 880 }, 881 getPH : function(name) 882 { 883 name = (typeof name === "string" ? name : ""); 884 name = name.toLowerCase(); 885 if (this.fields.hasOwnProperty(name)) 886 { 887 var id = name.substr(0, 1).toUpperCase() + name.substr(1); 888 this.fields[name]["placeHolder"] = BX(this.id + id); 889 return this.fields[name]["placeHolder"]; 890 } 891 return null; 892 }, 893 clickFile : function () 894 { 895 return false; 896 }, 897 makePreview: function() 898 { 899 this.status = statuses.ready; 900 BX.onCustomEvent(this, "onFileIsInited", [this.id, this, this.caller]); 901 BX.onCustomEvent(this.caller, "onFileIsInited", [this.id, this, this.caller]); 902 903 this.log('is initialized as a file'); 904 }, 905 preparationStatus : statuses.ready, 906 deleteFile: function() 907 { 908 var ii, events = this.__makeThumbEventsObj; 909 for (ii in this.fields) 910 { 911 if (this.fields.hasOwnProperty(ii)) 912 { 913 if (!!this.fields[ii]["placeHolder"]) 914 { 915 this.fields[ii]["placeHolder"] = null; 916 BX.unbindAll(this.fields[ii]["placeHolder"]); 917 delete this.fields[ii]["placeHolder"]; 918 } 919 } 920 } 921 922 for (ii in events) 923 { 924 if (events.hasOwnProperty(ii) && BX(ii)) 925 { 926 BX.unbindAll(BX(ii)); 927 } 928 } 929 930 var removedFile = this.file; 931 this.file = null; 932 delete this.file; 933 934 BX.remove(this.canvas); 935 this.canvas = null; 936 delete this.canvas; 937 938 BX.onCustomEvent(this.caller, "onFileIsDeleted", [this.id, this, this.caller, removedFile]); 939 BX.onCustomEvent(this, "onFileIsDeleted", [this, this.caller]); 940 } 941 }; 942 BX.UploaderImage = function(file, params, limits, caller) 943 { 944 this.dialogName = "BX.UploaderImage"; 945 BX.UploaderImage.superclass.constructor.apply(this, arguments); 946 this.isImage = true; 947 this.copies = new BX.UploaderUtils.Hash(); 948 this.caller = caller; 949 950 if (!this.isNode && BX.Uploader.getInstanceName() == "BX.Uploader") 951 { 952 if (!!params["copies"]) 953 { 954 var copies = params["copies"], copy; 955 for (var ii in copies) 956 { 957 if (copies.hasOwnProperty(ii) && !!copies[ii]) 958 { 959 copy = { width : parseInt(copies[ii]['width']), height : parseInt(copies[ii]["height"]), id : ii }; 960 if (copy['width'] > 0 && copy["height"] > 0) 961 { 962 this.copies.setItem(ii, copy); 963 } 964 } 965 } 966 } 967 this.preparationStatus = statuses["new"]; 968 BX.addCustomEvent(this, "onFileHasToBePrepared", BX.delegate(function() 969 { 970 this.preparationStatus = statuses.inprogress; 971 if (this.status !== statuses["new"]) 972 { 973 upld.push(this.file, BX.delegate(this.makeCopies, this)); 974 } 975 }, this)); 976 BX.addCustomEvent(this, "onUploadDone", BX.delegate(function() 977 { 978 var copy; 979 while ((copy = this.copies.getNext()) && !!copy) 980 { 981 copy.file = null; 982 delete copy.file; 983 } 984 this.preparationStatus = statuses["new"]; 985 }, this)); 986 this.canvas = BX.create('CANVAS', {attrs : { id : this.id + "ProperCanvas" } } ); 987 } 988 else 989 { 990 this.preparationStatus = statuses.done; 991 this.canvas = null; 992 } 993 return this; 994 }; 995 BX.extend(BX.UploaderImage, BX.UploaderFile); 996 BX.UploaderImage.prototype.makePreviewImageWork = function(image, cnv, ctx, exifOrientation) 997 { 998 exifOrientation = parseInt(exifOrientation); 999 1000 var result = null, 1001 width = cnv.width, 1002 height = cnv.height; 1003 1004 if (this.file) 1005 { 1006 this.file.width = cnv.width; 1007 this.file.height = cnv.height; 1008 } 1009 1010 if (!!this.canvas) 1011 { 1012 setOrientation(image, cnv, ctx, exifOrientation); 1013 if (this.file) 1014 { 1015 this.file.width = cnv.width; 1016 this.file.height = cnv.height; 1017 if (exifOrientation) 1018 { 1019 this.file.exif = { 1020 Orientation : exifOrientation 1021 } 1022 } 1023 } 1024 this.applyFile(cnv, false); 1025 result = this.canvas; 1026 } 1027 else if (BX(this.id + 'Canvas')) 1028 { 1029 var res2 = BX.UploaderUtils.scaleImage({width : width, height : height}, this.fields.preview.params), 1030 props = { 1031 props : { width : res2.destin.width, height : res2.destin.height, src : image.src }, 1032 attrs : { 1033 className : (this.file.width > this.file.height ? "landscape" : "portrait") 1034 } 1035 }; 1036 switch (exifOrientation) 1037 { 1038 case 2: 1039 props.attrs.className += ' flip'; break; 1040 case 3: 1041 props.attrs.className += ' rotate-180'; break; 1042 case 4: 1043 props.attrs.className += ' flip-and-rotate-180'; break; 1044 case 5: 1045 props.attrs.className += ' flip-and-rotate-270'; break; 1046 case 6: 1047 props.attrs.className += ' rotate-90'; break; 1048 case 7: 1049 props.attrs.className += ' flip-and-rotate-90'; break; 1050 case 8: 1051 props.attrs.className += ' rotate-270'; break; 1052 } 1053 result = BX.create("IMG", props); 1054 } 1055 1056 BX.onCustomEvent(this, "onFileCanvasIsLoaded", [this.id, this, this.caller, image]); 1057 BX.onCustomEvent(this.caller, "onFileCanvasIsLoaded", [this.id, this, this.caller, image]); 1058 1059 if (BX(this.id + 'Canvas')) 1060 BX(this.id + 'Canvas').appendChild(result); 1061 1062 return result; 1063 }; 1064 1065 BX.UploaderImage.prototype.makePreviewImageLoadHandler = function(image, canvas, context, exifOrientation){ 1066 this.makePreviewImageWork(image, canvas, context, exifOrientation); 1067 this.status = statuses.ready; 1068 1069 BX.onCustomEvent(this, "onFileIsInited", [this.id, this, this.caller]); 1070 BX.onCustomEvent(this.caller, "onFileIsInited", [this.id, this, this.caller]); 1071 this.log('is initialized as an image with preview'); 1072 if (this.preparationStatus == statuses.inprogress) 1073 this.makeCopies(image, canvas, context, exifOrientation); 1074 if (this["_makePreviewImageLoadHandler"]) 1075 { 1076 this._makePreviewImageLoadHandler = null; 1077 delete this._makePreviewImageLoadHandler; 1078 } 1079 if (this["_makePreviewImageFailedHandler"]) 1080 { 1081 this._makePreviewImageFailedHandler = null; 1082 delete this._makePreviewImageFailedHandler; 1083 } 1084 }; 1085 1086 BX.UploaderImage.prototype.makePreviewImageFailedHandler = function(){ 1087 this.status = statuses.ready; 1088 this.preparationStatus = statuses.done; 1089 1090 BX.onCustomEvent(this, "onFileIsInited", [this.id, this, this.caller]); 1091 BX.onCustomEvent(this.caller, "onFileIsInited", [this.id, this, this.caller]); 1092 1093 this.log('is initialized without canvas'); 1094 if (this["_makePreviewImageLoadHandler"]) 1095 { 1096 this._makePreviewImageLoadHandler = null; 1097 delete this._makePreviewImageLoadHandler; 1098 } 1099 if (this["_makePreviewImageFailedHandler"]) 1100 { 1101 this._makePreviewImageFailedHandler = null; 1102 delete this._makePreviewImageFailedHandler; 1103 } 1104 }; 1105 BX.UploaderImage.prototype.makePreview = function() 1106 { 1107 if (!this.isNode) 1108 { 1109 this._makePreviewImageLoadHandler = BX.delegate(this.makePreviewImageLoadHandler, this); 1110 this._makePreviewImageFailedHandler = BX.delegate(this.makePreviewImageFailedHandler, this); 1111 prvw.push(this.file, this._makePreviewImageLoadHandler, this._makePreviewImageFailedHandler); 1112 } 1113 else 1114 { 1115 this.status = statuses.ready; 1116 BX.onCustomEvent(this, "onFileIsInited", [this.id, this, this.caller]); 1117 BX.onCustomEvent(this.caller, "onFileIsInited", [this.id, this, this.caller]); 1118 1119 this.log('is initialized as an image without preview'); 1120 if (this.caller.queue.placeHolder) 1121 { 1122 this._onFileHasGotPreview = BX.delegate(function(id, item) { 1123 1124 BX.removeCustomEvent(this, "onFileHasGotPreview", this._onFileHasGotPreview); 1125 BX.removeCustomEvent(this, "onFileHasNotGotPreview", this._onFileHasNotGotPreview); 1126 1127 this._makePreviewImageLoadHandler = BX.delegate(function(image){ 1128 image = this.makePreviewImageWork(image); 1129 BX.onCustomEvent(this, "onFileHasPreview", [item.id, item, image]); 1130 delete this._makePreviewImageLoadHandler; 1131 delete this._makePreviewImageFailedHandler; 1132 }, this); 1133 this._makePreviewImageFailedHandler = BX.delegate(function(image){ 1134 delete this._makePreviewImageLoadHandler; 1135 delete this._makePreviewImageFailedHandler; 1136 }, this); 1137 prvw.push({tmp_url : item.file.url}, this._makePreviewImageLoadHandler, this._makePreviewImageFailedHandler); 1138 }, this); 1139 this._onFileHasNotGotPreview = BX.delegate(function(id){ 1140 if (id == this.id) 1141 { 1142 BX.removeCustomEvent(this, "onFileHasGotPreview", this._onFileHasGotPreview); 1143 BX.removeCustomEvent(this, "onFileHasNotGotPreview", this._onFileHasNotGotPreview); 1144 } 1145 }, this); 1146 BX.addCustomEvent(this, "onFileHasGotPreview", this._onFileHasGotPreview); 1147 BX.addCustomEvent(this, "onFileHasNotGotPreview", this._onFileHasNotGotPreview); 1148 BX.onCustomEvent(this.caller, "onFileNeedsPreview", [this.id, this, this.caller]); 1149 } 1150 } 1151 return true; 1152 }; 1153 BX.UploaderImage.prototype.checkPreview = function() 1154 { 1155 // TODO check preview 1156 }; 1157 BX.UploaderImage.prototype.applyFile = function(cnv, params) 1158 { 1159 this.checkPreview(); 1160 1161 if (!!params && params.data ) 1162 this.setProps(params.data); 1163 1164 var realScale = BX.UploaderUtils.scaleImage(cnv, {width : this.limits["uploadFileWidth"], height : this.limits["uploadFileHeight"]}), 1165 prvwScale = BX.UploaderUtils.scaleImage(cnv, this.fields.preview.params), 1166 prvwProps = {
1167 props : { width : prvwScale.destin.width, height : prvwScale.destin.height }, 1168 attrs : { 1169 className : "bx-bxu-proper-canvas"+(prvwScale.destin.width > prvwScale.destin.height ? " landscape" : " portrait") 1170 } 1171 }; 1172 1173 if (realScale.bNeedCreatePicture || !!params) 1174 { 1175 BX.adjust(canvas, { props : { width : realScale.destin.width, height : realScale.destin.height } } ); 1176 ctx = canvas.getContext('2d'); 1177 ctx.drawImage(cnv, 1178 realScale.source.x, realScale.source.y, realScale.source.width, realScale.source.height, 1179 realScale.destin.x, realScale.destin.y, realScale.destin.width, realScale.destin.height 1180 ); 1181 1182 var dataURI = canvas.toDataURL(this.file.type); 1183 this.file = BX.UploaderUtils.dataURLToBlob(dataURI); 1184 } 1185 1186 this.file.name = this.name; 1187 this.file.width = realScale.destin.width; 1188 this.file.height = realScale.destin.height; 1189 1190 BX.adjust(this.canvas, prvwProps); 1191 1192 ctx = this.canvas.getContext('2d'); 1193 ctx.drawImage(cnv, 1194 prvwScale.source.x, prvwScale.source.y, prvwScale.source.width, prvwScale.source.height, 1195 prvwScale.destin.x, prvwScale.destin.y, prvwScale.destin.width, prvwScale.destin.height 1196 ); 1197 1198 ctx = null; 1199 cnv = null; 1200 1201 this.setProps('size'); 1202 this.status = statuses.changed; 1203 }; 1204 BX.UploaderImage.prototype.clickFile = function() 1205 { 1206 if (!this.canvas || !BX["CanvasEditor"] || this.status == statuses["new"]) 1207 return false; 1208 if (!this.__showEditor) 1209 { 1210 this.__showEditor = BX.delegate(this.showEditor, this); 1211 this.eFunc = { 1212 "apply" : BX.delegate(this.applyFile, this), 1213 "delete" : BX.delegate(this.deleteFile, this), 1214 "clear" : BX.delegate(function() 1215 { 1216 BX.removeCustomEvent(editor, "onApplyCanvas", this.eFunc["apply"]); 1217 BX.removeCustomEvent(editor, "onDeleteCanvas", this.eFunc["delete"]); 1218 BX.removeCustomEvent(editor, "onClose", this.eFunc["clear"]); 1219 }, this) 1220 }; 1221 } 1222 var template = this.fields.thumb.editorTemplate, name; 1223 for (var ii in this.fields) 1224 { 1225 if (this.fields.hasOwnProperty(ii)) 1226 { 1227 name = ii.substr(0, 1).toUpperCase() + ii.substr(1); 1228 template = template.replace('#' + ii + '#', 1229 (ii === "preview" ? "" : 1230 ('<span id="' + this.id + name + 'Editor" class="' + this.fields[ii]["className"] + '">' + 1231 this.fields[ii]["editorTemplate"].replace('#' + ii + '#', (!!this[ii] ? BX.util.htmlspecialchars(this[ii]) : '')) + '</span>'))); 1232 } 1233 } 1234 1235 BX.adjust(edtr.getCanvas(), { props : { width : this.file.width, height : this.file.height } } ); 1236 edtr.getContext().drawImage(this.canvas, 1237 0, 0, this.canvas.width, this.canvas.height, 1238 0, 0, edtr.getCanvas().width, edtr.getCanvas().height); 1239 var editor = BX.CanvasEditor.show(edtr.getCanvas(), {title : this.name, template : template}); 1240 1241 BX.addCustomEvent(editor, "onApplyCanvas", this.eFunc["apply"]); 1242 BX.addCustomEvent(editor, "onDeleteCanvas", this.eFunc["delete"]); 1243 BX.addCustomEvent(editor, "onClose", this.eFunc["clear"]); 1244 BX.onCustomEvent(this, "onCanvasEditorIsCreated", [editor, this]); 1245 1246 edtr.push(this.file, this.__showEditor); 1247 this.editor = editor; 1248 return false; 1249 }; 1250 BX.UploaderImage.prototype.showEditor = function(image, canvas, context, exifOrientation) 1251 { 1252 BX.adjust(canvas, { props : { width : this.file.width, height : this.file.height } } ); 1253 setOrientation(image, canvas, context, exifOrientation); 1254 this.editor.copyCanvas(canvas); 1255 }; 1256 BX.UploaderImage.prototype.makeCopies = function(image, cnv, ctx, exifOrientation) 1257 { 1258 var copy, res, dataURI, result, 1259 context = canvas.getContext('2d'); 1260 setOrientation(image, canvas, context, exifOrientation); 1261 while ((copy = this.copies.getNext()) && !!copy) 1262 { 1263 res = BX.UploaderUtils.scaleImage(canvas, copy); 1264 BX.adjust(cnv, {props : { width : res.destin.width, height : res.destin.height } } ); 1265 ctx.drawImage(canvas, 1266 res.source.x, res.source.y, res.source.width, res.source.height, 1267 res.destin.x, res.destin.y, res.destin.width, res.destin.height 1268 ); 1269 1270 dataURI = cnv.toDataURL(this.file.type); 1271 result = BX.UploaderUtils.dataURLToBlob(dataURI); 1272 result.width = cnv.width; 1273 result.height = cnv.height; 1274 result.name = this.name; 1275 result.thumb = copy.id; 1276 result.canvases = this.copies.length; 1277 result.canvas = this.copies.pointer - 1; 1278 copy.file = result; 1279 } 1280 this.preparationStatus = statuses.done; 1281 BX.onCustomEvent(this, 'onFileIsPrepared'); 1282 }; 1283 BX.UploaderImage.prototype.getThumbs = function(name) 1284 { 1285 if (name == "getCount") 1286 return this.copies.length; 1287 1288 var res = (typeof name == "string" ? this.copies.getItem(name) : this.copies.getNext()); 1289 1290 if (!!res) 1291 return res.file; 1292 return null; 1293 }; 1294 return true; 1295}(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.