1(function($){ 2 /** 3 * Komponenta pro editaci vetsiho mnozstvi souboru 4 * 5 * Jako hodnota se zadava id adresare z VFS. 6 * 7 * Komponenta je obdoba filemanageru z ExtJS. Jen s modernejsim navrhem 8 * 9 * Events: 10 * * fea.fileEdit - vola se pred editaci souboru, pokud se vrati false, nevyvola se vychozi okno a vse ma v rukach 11 * zpracovatel udalosti. Vysledne metainformace zavola pres callback funkci, ktera je jako druhy parametr. 12 * do return je mozne vratit formular v podobe html, musi obshaovat formular tj '<form>...</form>'. 13 */ 14 $.fea.registerType('multiFile',{ 15 extends: 'bssimpleTemplate', 16 fileMetadataValue: null, 17 maxSize: null, 18 minSize: null, 19 denyButtons: [], 20 async: null, 21 _getCtConfig: function(){ 22 var ctCfg = this._callParent('bssimple','_getCtConfig',arguments); 23 $.extend(ctCfg,{ 24 editor: { 25 selector: '.fea-field-files input[type=hidden]' 26 }, 27 fileList: { 28 selector: '.fea-field-files .file-list' 29 }, 30 toolbar:{ 31 selector: '.fea-field-files .toolbar' 32 }, 33 button_add:{ 34 selector: '.fea-field-files .toolbar .add' 35 }, 36 button_replace:{ 37 selector: '.fea-field-files .toolbar .replace' 38 } 39 }); 40 41 return ctCfg; 42 }, 43 init: function(){ 44 var me = this; 45 me._callParent('bssimple','init',arguments); 46 47 me.maxSize = me._getProp('max-size'); 48 me.minSize = me._getProp('min-size'); 49 me.async = this.fea.helpers.toBool(me._getProp('async', true)); 50 me.baseUrl = me._getProp('base-url'); 51 me.rootDir = me._getProp('root-dir'); 52 me.imageSize = me._getProp('image-size', ''); 53 54 me.sort = me._getProp('sort'); 55 me.sortDirection = me._getProp('sort-direction'); 56 57 var dropZone = me._getCt('fileList'); 58 59 me.buttons = $.extend({},{ 60 remove: {'enabled': false, 'titleT': 'label_fea_file_remove', 'autoDeselect': true, 'selectable': '*', 'icon': 'fa fa-minus', handler: me._removeFile}, 61 edit: {'enabled': false, 'titleT': 'label_fea_file_edit', 'selectable': '1', 'icon': 'fa fa-edit', handler: me._editFile}, 62 download: {'enabled': false, 'titleT': 'label_fea_file_download', 'selectable': '*', 'icon': 'fa fa-download', handler: me._downloadFile}, 63 refresh: {'enabled': true, 'titleT': 'label_fea_file_refresh', 'icon': 'fa fa-refresh', handler: me._refreshFiles} 64 }, me._getButtons(), me.extendButtons || {}); 65 66 me._renderButtons(me.buttons); 67 68 dropZone.bind('dragover', function (e){ 69 dropZone.addClass('in'); 70 e.stopPropagation(); 71 }); 72 dropZone.bind('dragleave drop', function (e){ 73 dropZone.removeClass('in'); 74 e.stopPropagation(); 75 }); 76 77 var addOptions = { 78 replaceFileInput: false, 79 dropZone: dropZone, 80 autoUpload: false 81 }; 82 83 if ( me.maxSize ) { 84 addOptions.maxFileSize = me.maxSize; 85 } 86 87 if ( me.minSize ) { 88 addOptions.minFileSize = me.minSize; 89 } 90 91 if ( me.async && me.baseUrl) { 92 addOptions.url = me.baseUrl + 'create' ; 93 addOptions.autoUpload = true; 94 addOptions.paramName = 'Filedata', 95 addOptions.dataType = 'json', 96 addOptions.formData = { 97 root: me.rootDir, // root name VFS 98 dir: me.getValue() // dir_id VFS 99 }; 100 } 101 102 me.selectHandler = me._getCt('fileList').on('click', '.editor-file', function(e){ 103 var el = $(this) 104 ; 105 if ( e.target.tagName !== 'INPUT' ) { 106 e.stopPropagation(); 107 el.find("input[type='checkbox'].file-select").trigger('click'); 108 } 109 }); 110 111 me.selectChangeHandler = me._getCt('fileList').on('change', "input[type='checkbox'].file-select", function(e){ 112 var select = me._selectedFiles(); 113 me._updateToolbar(select.length); 114 115 var input = $(this), 116 parent = input.closest('.editor-file'); 117 118 if ( parent && parent.length > 0 ) { 119 if ( input.prop('checked') ) { 120 parent.addClass('file-selected'); 121 } else { 122 parent.removeClass('file-selected'); 123 } 124 } 125 }); 126 127 me.buttonClickHandler = me._getCt('toolbar').on('click', '.btn:not(.disabled):not(.nohandler)', function(e){ 128 var button = $(this), 129 name = button.data('name'); 130 131 if ( me.buttons.hasOwnProperty(name) ) { 132 var defButton = me.buttons[name]; 133 if ( typeof defButton.handler === 'function' ) { 134 var files = me._selectedFiles(); 135 defButton.handler.call(defButton.scope || me, files, me); 136 } 137 } 138 139 if ( button.data('autoDeselect') ) { 140 me._unselectAll(); 141 } 142 }); 143 144 var fileAdd = me._getCt('button_add').fileupload(addOptions); 145 146 fileAdd.on('fileuploaddone', $.proxy(me._uploadDone, me)); 147 fileAdd.on('fileuploadstart', $.proxy(me._showLoadMask, me)); 148 fileAdd.on('fileuploadstop', $.proxy(me._hideLoadMask, me)); 149 150 var replaceOptions = { 151 replaceFileInput: true, 152 dropZone: null, //TODO lze navazat na konkretni soubor pres selector by to nemel byt problem 153 autoUpload: false 154 }; 155 156 //replace 157 if ( me.async && me.baseUrl) { 158 replaceOptions.url = me.baseUrl + 'replace' ; 159 replaceOptions.autoUpload = true; 160 replaceOptions.paramName = 'file', 161 replaceOptions.dataType = 'json', 162 163 replaceOptions.formData = { 164 root: me.rootDir, // root name VFS 165 dir: me.getValue() // dir_id VFS 166 }; 167 } 168 var fileReplace = me._getCt('button_replace').fileupload(replaceOptions); 169 170 fileReplace.on('fileuploaddone', $.proxy(me._uploadDone, me)); 171 fileReplace.on('fileuploadstart', $.proxy(me._showLoadMask, me)); 172 173 fileReplace.on('fileuploadsubmit', function(e, data){ 174 var files = me._selectedFiles(); 175 if ( files.length > 0 ) { 176 var file = files[0], 177 fileInfo = me._getFileInfo(file), 178 i, len 179 ; 180 181 data.formData = { 182 root: me.rootDir, // root name VFS 183 dir: me.getValue(), // dir_id VFS 184 id: fileInfo.id 185 }; 186 var checkbox = me._getCt('button_replace').siblings('ul.dropdown-menu').find("input[type='checkbox'].file-select:checked"); //TODO hezci selector 187 188 for ( i = 0, len = checkbox.length; i < len; ++i) { 189 var elm = $(checkbox[i]); 190 var param = elm.data('param'); 191 if ( param ) { 192 data.formData[param] = 1; 193 } 194 } 195 } 196 else { 197 return false;
198 } 199 }); 200 fileReplace.on('fileuploadstop', $.proxy(me._hideLoadMask, me)); 201 202 me._getCt('button_add').fileupload('disable'); 203 me._getCt('button_replace').fileupload('disable'); 204 }, 205 _activate: function() { 206 var me = this; 207 me._callParent('bssimple','_activate',arguments); 208 //me._refreshEditorFiles(me.getValue()); 209 me._getCt('button_add').fileupload('enable'); 210 me._getCt('button_replace').fileupload('enable'); 211 }, 212 _deactivate: function() { 213 var me = this; 214 me._callParent('bssimple','_deactivate',arguments); 215 me._getCt('button_add').fileupload('disable'); 216 me._getCt('button_replace').fileupload('disable'); 217 }, 218 _getButtons: function(){ 219 return {}; 220 }, 221 _showLoadMask: function() { 222 // TODO zabranit vicenasobnemu zobrazeni 223 this.fea.helpers.componentLoading(this, true); 224 }, 225 _hideLoadMask: function() { 226 this.fea.helpers.componentLoading(this, false); 227 }, 228 _uploadDone: function(e, data) { 229 230 if ( data.result && !data.result.success ) { 231 this.addErrors(data.result.message); 232 } else { 233 this.clearErrors(); 234 } 235 236 this._refreshFiles(); 237 }, 238 _refreshFiles: function() { 239 this._refreshEditorFiles(this.getValue()); 240 this._unselectAll(); 241 }, 242 reset: function() { 243 this._callParent('bssimple','reset',arguments); 244 245 ///this._clearContainers(); 246 }, 247 _unselectAll: function(){ 248 this._getCt('fileList').find("input[type='checkbox'].file-select:checked").prop('checked', false).trigger("change"); 249 this._updateToolbar(0); 250 }, 251 _renderButtons: function(buttons) 252 { 253 var me = this, 254 toolbar = me._getCt('toolbar'), 255 buttonName, 256 key, 257 filter = ['class', 'icon', 'title', 'titleT', 'tooltip', 'enabled', 'handler', 'scope'] 258 ; 259 260 for ( buttonName in buttons){ 261 262 if ( -1 !== $.inArray(buttonName, me.denyButtons) ) { 263 continue; 264 } 265 266 var button = buttons[buttonName], 267 attrs = {'data-name': buttonName, 'data-toggle': 'tooltip' } 268 ; 269 270 var btnElm = $('<span></span>').addClass('btn btn-default'); 271 272 if ( button.class) { 273 btnElm.addClass(button.class); 274 } 275 276 if ( button.icon ) { 277 btnElm.append($('<i class="'+button.icon+'"></i>')); 278 } 279 280 if ( button.titleT ) { 281 button.title = T(button.titleT) ; 282 } 283 284 if ( button.title ) { 285 btnElm.append($('<span class="label">'+button.title+'</span>')); 286 } 287 288 if ( typeof button.enabled !== 'undefiened' && !button.enabled ) { 289 btnElm.addClass('disabled'); 290 } 291 292 attrs['title'] = button.tooltip || button.title; 293 294 for ( key in button ) 295 { 296 if ( button.hasOwnProperty(key) && $.inArray(key, filter) === -1 ) { 297 attrs['data-'+key] = button[key]; 298 } 299 } 300 301 btnElm.attr(attrs); 302 303 toolbar.append(btnElm); 304 } 305 306 }, 307 _selectedFiles: function(){ 308 var me = this, 309 inputs = me._getCt('fileList').find('.editor-file'), 310 len = inputs.length, 311 selected = [], 312 i, input 313 ; 314 315 if ( len === 1 ) { 316 selected.push($(inputs[0])); 317 } else { 318 for ( i = 0; i < len; ++i ) { 319 input = $(inputs[i]); 320 if ( input.find("input[type='checkbox'].file-select:checked" ).length ) { 321 selected.push(input); 322 } 323 } 324 } 325 326 return selected; 327 }, 328 _updateToolbar: function(count){ 329 var me = this, 330 items = me._getCt('toolbar').find('[data-selectable]'), 331 len = items.length, 332 i, item, selectable 333 ; 334 for ( i = 0 ; i < len; ++i) { 335 item = $(items[i]); 336 selectable = item.data('selectable'); 337 if ( (selectable === '*' && count > 0) || (selectable === count ) ) { 338 item.removeClass('disabled'); 339 } 340 else { 341 item.addClass('disabled'); 342 } 343 } 344 }, 345 _removeFile: function(select){ 346 var me = this, 347 i, len = select.length 348 ; 349 350 if ( true === confirm( T('text_fea_files_remove_question') ) ) { 351 352 for (i = 0; i < len; ++i ) { 353 (function(){ //obalka kvuli kontextu 354 var file = select[i]; 355 356 file.toggleClass('fea-file-remove'); 357 358 if ( me.async ) { 359 me._showLoadMask(); 360 $.ajax(me.baseUrl+'delete', { 361 method: 'POST', 362 data: { 363 root: me.rootDir, // root name VFS 364 dir: me.getValue(), // dir_id VFS 365 data: JSON.stringify(me._getFileInfo(file)) 366 } 367 }).done(function( data ) { 368 if ( data && data.success ) { 369 file.remove(); 370 } else { 371 if (data.message) { 372 me.addErrors(data.message); 373 } 374 } 375 }).fail(function(){ 376 me.addErrors(T('error_fea_files_remove')); 377 }).always(function(){ 378 me._hideLoadMask(); 379 }); 380 } else { 381 //TODO: sync rezim - asi vygenerovat ID do hidden elementu ve formatu JSON pole 382 } 383 })(); 384 } 385 386 } 387 }, 388 _download: function(url) { 389 $('<iframe src="'+url+'" style="display: none"></iframe>') 390 .load(function() { 391 var that = this; 392 setTimeout(function() { 393 $(that).remove(); 394 }, 100); 395 }) 396 .appendTo($('body')); 397 }, 398 _downloadFile: function(selections){ 399 var me = this, 400 i, len = selections.length 401 ; 402 403 for (i = 0; i < len; ++i ) { 404 var fileInfo = me._getFileInfo(selections[i]) 405 ; 406 if ( fileInfo && fileInfo.url ) { 407 me._download(fileInfo.url); 408 } 409 } 410 }, 411 _openDialog: function(options) { 412 options = options || {}; 413 414 var me = this, 415 winHtml = '<div class="modal fade" tabindex="-1" role="dialog">' + 416 '<div class="modal-dialog">' + 417 '<div class="modal-content">' + 418 '<div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>' + 419 '<h4 class="modal-title">'+(options.title || '') +'</h4>' + 420 '</div>' + 421 '<div class="modal-body">'+ (options.html || '') + '</div>' + 422 '<div class="modal-footer">' + 423 '<button type="button" class="btn btn-default" data-dismiss="modal">'+T('label_fea_files_win_close')+'</button>' + 424 '<button type="button" class="btn btn-primary">'+T('label_fea_files_win_submit')+'</button>' + 425 '</div>' + 426 '</div>'; 427 428 var win = $(winHtml).appendTo($('body')).on('click', 'div.modal-footer > button.btn-primary', function(){
429 var content = win.find('.modal-body').children(); 430 var state = false; 431 432 if ( typeof options.callback === 'function') { 433 state = options.callback.call(options.scope || me, content, win); 434 } 435 if ( options.autoClose || state ) { 436 437 win.on('hidden.bs.modal', function(){ 438 win.remove(); 439 }); 440 441 win.modal('hide'); 442 } 443 }); 444 445 win.modal(); 446 447 }, 448 _editFile: function(select) { 449 var me = this; 450 if ( select.length > 0 ) { 451 var fileInfo = me._getFileInfo(select[0]), 452 storeFunction = function(newMetadata, callbackSucces, scope) { //TODO predelat na promise 453 me._storeMetadata(select[0], newMetadata, {callback: callbackSucces, scope: scope}); 454 } 455 ; 456 457 var res = me.$elem.triggerHandler('fea.fileEdit', [fileInfo, storeFunction]); 458 if ( res !== false ) { 459 me._openDialog({ 460 title: fileInfo.name, 461 html: ( typeof res === 'string' ? res : me._baseForm(fileInfo)), 462 callback: function(content, callbackSucces, scope){ 463 var newMetadata = me.fea.helpers.unlinearizeData(content.serializeArray()) 464 ; 465 storeFunction(newMetadata); 466 }, 467 autoClose: true 468 }); 469 } 470 } 471 }, 472 _baseForm: function(fileInfo) { 473 var formHtml = '<form class="form-horizontal">' + 474 '<div class="form-group"><label class="col-sm-4 control-label">'+T('label_fea_file_name')+':</label><div class="col-sm-8"><input class="form-control" name="name" value="'+(fileInfo.name || '')+'"></div></div>'+ 475 '<div class="form-group"><label class="col-sm-4 control-label">'+T('label_fea_file_title')+':</label><div class="col-sm-8"><input class="form-control" name="title" value="'+(fileInfo.title || '')+'"></div></div>'+ 476 '</form>'; 477 478 return formHtml; 479 }, 480 _storeMetadata: function(fileElm, newMetadata, options) { 481 options = options || {}; 482 483 var me = this, 484 fileInfo = me._getFileInfo(fileElm), 485 metadata = $.extend({}, fileInfo, newMetadata); 486 ; 487 if ( me.async ) { 488 me._showLoadMask(); 489 $.ajax(me.baseUrl+'update', { 490 method: 'POST', 491 dataType: 'json', 492 data: { 493 root: me.rootDir, // root name VFS 494 dir: me.getValue(), // dir_id VFS 495 data: JSON.stringify(metadata) 496 } 497 }).done(function( data ) { 498 if ( data && data.success ) { 499 me._setFileInfo(fileElm, data.data); 500 501 if ( typeof options.callback === 'function' ) { 502 options.callback.call(options.scope || me, data.data); 503 } 504 } 505 else if ( data.message ) { 506 me.addErrors(data.message); 507 } else { 508 me.addErrors(T('error_fea_files_edit')); 509 } 510 }).fail(function(){ 511 me.addErrors(T('error_fea_files_edit')); 512 }).always(function(){ 513 me._hideLoadMask(); 514 }); 515 } else { 516 //TODO: sync rezim - asi vygenerova hidden elementy ve formatu JSON pole 517 } 518 519 }, 520 _setFileInfo: function(select, data) { 521 var me = this; 522 523 select.data('file-info', data); 524 //.attr('data-file-info', JSON.stringify(data)); 525 526 //select.children('.file-preview').html(me._renderFile(data, me.editType)); 527 me._localRefresh(); 528 529 return null; 530 }, 531 _getFileInfo: function(select) { 532 return select.data('file-info'); 533 }, 534 loadData: function(id, callback){ 535 var me = this, 536 baseUrl = me.baseUrl 537 ; 538 539 if ( id && baseUrl ) { 540 541 var params = { 542 root: me._getProp('root-dir'), 543 dir: id 544 }; 545 546 if ( me.sort ) { 547 params.sort = [{'property': me.sort , 'direction': me.sortDirection || "ASC"}]; 548 } 549 550 $.ajax(baseUrl+'read', { 551 data: params 552 }).success(function(result){ 553 if ( result && result.success ) { 554 var imageInfo = result.data; 555 556 if ( $.isArray(imageInfo) && typeof callback === 'function' ) { 557 callback.call(me, imageInfo); 558 } 559 } 560 }); 561 } 562 }, 563 _normalizeData: function(data) { 564 var me = this, 565 imageSize = me.imageSize, 566 i, len, 567 fileInfo, 568 varReplace 569 ; 570 571 if ( imageSize.length > 0 ) { 572 imageSize = '/'+imageSize; 573 } 574 575 for ( i = 0, len = data.length; i < len; ++i) { 576 fileInfo = data[i]; 577 varReplace = $.extend({'imageSize': imageSize}, fileInfo); 578 579 var imageUrl; 580 581 if ( 'image' === fileInfo.type ) { 582 imageUrl = me.fea.helpers.varsReplace(fileInfo.path_template, varReplace); 583 584 if ( fileInfo.hasOwnProperty('checksum') && !!fileInfo.checksum ) { 585 imageUrl += '?v=' + fileInfo.checksum; 586 } 587 } 588 else { 589 imageUrl = me._getProp('default-thumb'); 590 } 591 592 fileInfo.imageUrl = imageUrl; 593 fileInfo.adminAttr = me.fea.helpers.attrsToString({'class': "editor-file", 'data-file-info': JSON.stringify(fileInfo)}); 594 } 595 596 return data; 597 }, 598 _localRefresh: function(){ 599 var me = this, 600 fileList = me._getCt('fileList'), 601 files = fileList.find('.editor-file'), 602 len, i, 603 filesInfo = [], 604 foo; 605 606 for ( i = 0, len = files.length; i < len; i++ ) { 607 foo = me._getFileInfo($(files[i])); 608 if ( foo ) { 609 filesInfo.push(foo); 610 } 611 } 612 613 if (filesInfo.length > 0 ) { 614 filesInfo = me._normalizeData(filesInfo); 615 616 me._renderEditorFiles(filesInfo); 617 618 me._unselectAll(); 619 } 620 }, 621 _refreshEditorFiles: function(value) { 622 var me = this; 623 624 me.loadData(value, function(imagesInfo){ 625 me._renderEditorFiles(me._normalizeData(imagesInfo)); 626 }); 627 }, 628 _renderEditorFiles: function(imagesInfo){ 629 var me = this, 630 fileList = me._getCt('fileList'), 631 data = { 632 'files': imagesInfo, 633 'isAdmin': true 634 }; 635 636 fileList.empty();
637 fileList.append(me._renderTpl('adminTpl', data)); 638 }, 639 displayTrafo: function(value) { 640 var me = this; 641 642 me.loadData(value, function(imagesInfo){ 643 var data = { 644 'files': me._normalizeData(imagesInfo), 645 'isAdmin': false 646 }; 647 648 me._getCt('presentation').html(me._renderTpl('tpl', data)); 649 }); 650 651 return ''; 652 } 653 }); 654})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.