diff --git a/application/frontend/skin/developer/components/media/uploader/uploader.tpl b/application/frontend/skin/developer/components/media/uploader/uploader.tpl index 0b78dcd1..34774ceb 100644 --- a/application/frontend/skin/developer/components/media/uploader/uploader.tpl +++ b/application/frontend/skin/developer/components/media/uploader/uploader.tpl @@ -2,45 +2,8 @@ {block 'uploader_aside' append} {* Основные настройки *} - + {include './uploader-block.insert.tpl'} {* Опции фотосета *} - + {include './uploader-block.photoset.tpl'} {/block} \ No newline at end of file diff --git a/application/frontend/skin/developer/components/uploader/css/uploader.css b/application/frontend/skin/developer/components/uploader/css/uploader.css index 9373bca6..cca1bb1d 100644 --- a/application/frontend/skin/developer/components/uploader/css/uploader.css +++ b/application/frontend/skin/developer/components/uploader/css/uploader.css @@ -7,15 +7,32 @@ } .uploader-file-list { overflow: auto; - width: 68%; - margin-right: 2%; + margin-right: 320px; min-height: 30px; max-height: 354px; - float: left; } .uploader-aside { - width: 30%; - float: left; + width: 300px; + float: right; +} + +/* TODO: Responsive */ +@media (max-width: 999px) { + .uploader-file-list { + margin: 15px 0 0; + } + .uploader-aside { + width: auto; + float: none; + } +} + + +/* Empty alert */ +.uploader .alert--empty { + text-align: center; + padding-top: 30px; + padding-bottom: 30px; } @@ -61,7 +78,10 @@ /* Selected */ .uploader-file.is-selected { - border-color: #D5CE3D; + border-color: #B9C4FF; +} +.uploader-file.is-selected .uploader-file-image { + opacity: .5; } /* Active */ @@ -97,29 +117,42 @@ /** - * Info + * Block */ -.uploader-info-block { +.block.uploader-block { border: 1px solid #eee; - padding: 20px; border-radius: 5px; - margin-bottom: 15px; + margin-top: 15px; + margin-bottom: 0; +} +.block.uploader-block:first-child { + margin-top: 0; } -/* Empty alert */ -.uploader-info .alert--empty { - text-align: center; - padding-top: 30px; - padding-bottom: 30px; + +/** + * Info + */ +.block.uploader-block.uploader-info .block-content { + padding: 0; +} +.uploader-info-actions { + padding: 10px 20px; + border-bottom: 1px solid #eee; +} +.uploader-info-properties { + padding: 20px; + background: #fafafa; } .uploader-info-base { - padding-left: 115px; + padding: 20px 20px 20px 135px; position: relative; min-height: 100px; + border-bottom: 1px solid #eee; } .uploader-info-base-image { position: absolute; - top: 0; - left: 0; + top: 20px; + left: 20px; } \ No newline at end of file diff --git a/application/frontend/skin/developer/components/uploader/js/uploader-file-list.js b/application/frontend/skin/developer/components/uploader/js/uploader-file-list.js index 2a3a480c..cd45a513 100644 --- a/application/frontend/skin/developer/components/uploader/js/uploader-file-list.js +++ b/application/frontend/skin/developer/components/uploader/js/uploader-file-list.js @@ -29,14 +29,14 @@ // Селекторы selectors: { - file: '.js-media-upload-gallery-item' + file: '.js-uploader-file' }, // HTML // TODO: Move to template html: { file: - '
  • ' + '
    ' + '
    ' + '0%' + @@ -90,7 +90,9 @@ * Добавляет файл в список */ addFile: function( data ) { - data.context = $( this.option( 'html.file' ) ).lsUploaderFile({ uploader: this.option( 'uploader' ) }); + data.context = $( this.option( 'html.file' ) ) + .lsUploaderFile({ uploader: this.option( 'uploader' ) }) + .lsUploaderFile( 'uploading' ); this.option( 'uploader' ).lsUploader( 'markAsNotEmpty' ); this.element.prepend( data.context ); @@ -108,7 +110,7 @@ */ getSelectedFiles: function() { return this.getFiles().filter(function () { - return $( this ).lsUploaderFile( 'isSelected' ); + return $( this ).lsUploaderFile( 'getState', 'selected' ); }); }, diff --git a/application/frontend/skin/developer/components/uploader/js/uploader-file.js b/application/frontend/skin/developer/components/uploader/js/uploader-file.js index 3314d0b2..4edb0eba 100644 --- a/application/frontend/skin/developer/components/uploader/js/uploader-file.js +++ b/application/frontend/skin/developer/components/uploader/js/uploader-file.js @@ -16,10 +16,12 @@ * Дефолтные опции */ options: { + // Основной блок загрузчика uploader: $(), // Ссылки urls: { + // Удаление remove: aRouter['ajax'] + 'media/remove-file/' }, @@ -33,7 +35,13 @@ // Классы classes : { + // Файл активен active: 'active', + // Произошла ошибка при загрузке + error: 'is-error', + // Файл загружается + uploading: 'is-uploading', + // Файл выделен selected: 'is-selected' } }, @@ -45,23 +53,25 @@ * @private */ _create: function () { - this.elements = {}; - // Информация о файле this.info = this.getInfo(); - // Файл активен - this.active = false; - // Файл выделен - this.selected = false; + + // Состояния файла + this.states = { + active: false, + selected: false, + uploading: false, + error: false + }; this._on({ click: this.toggle.bind( this ) }); }, /** - * Method + * Изменение состояния файла активен/не активен */ toggle: function() { - this[ this.isActive() ? 'unselect' : 'activate' ](); + this[ this.getState( 'active' ) ? 'unselect' : 'activate' ](); }, /** @@ -111,6 +121,7 @@ onRemove: function( response ) { this.destroy(); this.element.remove(); + this.element = null; if ( ! this._getComponent( 'list' ).lsUploaderFileList( 'getFiles' ).length ) { this.option( 'uploader' ).lsUploader( 'markAsEmpty' ); @@ -119,10 +130,11 @@ /** * Помечает файл как активный - * - * TODO: Activate ERROR file */ activate: function() { + // Не активируем незагруженный файл + if ( this.getState( 'error' ) || this.getState( 'uploading' ) ) return; + if ( ! this._getComponent( 'list' ).lsUploaderFileList( 'option', 'multiselect' ) ) { this._getComponent( 'list' ).lsUploaderFileList( 'clearSelected' ); } @@ -131,9 +143,10 @@ this._getComponent( 'list' ).lsUploaderFileList( 'getActiveFile' ).lsUploaderFile( 'deactivate' ); - this.active = true; + this.setState( 'active', true ); this.element.addClass( this.option( 'classes.active' ) ); + this.option( 'uploader' ).lsUploader( 'showBlocks' ); this._getComponent( 'info' ).lsUploaderInfo( 'setFile', this.element ); }, @@ -141,9 +154,10 @@ * Помечает файл как неактивный */ deactivate: function() { - this.active = false; + this.setState( 'active', false ); this.element.removeClass( this.option( 'classes.active' ) ); + this.option( 'uploader' ).lsUploader( 'hideBlocks' ); this._getComponent( 'info' ).lsUploaderInfo( 'empty' ); }, @@ -151,7 +165,7 @@ * Выделяет файл */ select: function() { - this.selected = true; + this.setState( 'selected', true ); this.element.addClass( this.option( 'classes.selected' ) ); }, @@ -159,27 +173,62 @@ * Убирает выделение с файла */ unselect: function() { - this.selected = false; + this.setState( 'selected', false ); this.element.removeClass( this.option( 'classes.selected' ) ); - if ( this.isActive() ) { + if ( this.getState( 'active' ) ) { this.deactivate(); this._getComponent( 'list' ).lsUploaderFileList( 'activateNextFile' ); } }, /** - * Проверяет активен файл или нет + * Помечает файл как незагруженный */ - isActive: function() { - return this.active; + error: function() { + this.setState( 'error', true ); + this.element.addClass( this.option( 'classes.error' ) ); + + this.element.find( this.option( 'selectors.progress.value' ) ).height( 0 ); + this.element.find( this.option( 'selectors.progress.label' ) ).text( 'ERROR' ); }, /** - * Проверяет выделен файл или нет + * Помечает файл как незагруженный */ - isSelected: function() { - return this.selected; + uploading: function() { + this.setState( 'uploading', true ); + this.element.addClass( this.option( 'classes.uploading' ) ); + }, + + /** + * Помечает файл как загруженный + */ + uploaded: function() { + this.setState( 'uploading', false ); + this.element.removeClass( this.option( 'classes.uploading' ) ); + }, + + /** + * Устанавливает процент загрузки + */ + setProgress: function( percent ) { + this.element.find( this.option( 'selectors.progress.value' ) ).height( percent + '%' ); + this.element.find( this.option( 'selectors.progress.label' ) ).text( percent + '%' ); + }, + + /** + * Получает состяние + */ + getState: function( state ) { + return this.states[ state ]; + }, + + /** + * Устанавливает состяние + */ + setState: function( state, value ) { + this.states[ state ] = value; }, /** diff --git a/application/frontend/skin/developer/components/uploader/js/uploader-info.js b/application/frontend/skin/developer/components/uploader/js/uploader-info.js index d9be7b56..fad74a6d 100644 --- a/application/frontend/skin/developer/components/uploader/js/uploader-info.js +++ b/application/frontend/skin/developer/components/uploader/js/uploader-info.js @@ -16,8 +16,8 @@ * Дефолтные опции */ options: { + // Основной блок загрузчика uploader: $(), - list: $(), // Ссылки urls: { @@ -25,14 +25,12 @@ // Селекторы selectors: { - // Блок с информацией о файле - info: '.js-media-properties', // Группа с информацией уникальной для каждого типа - group: '.js-media-info-group', + group: '.js-uploader-info-group', // Свойство - property: '.js-media-info-property', - // Сообщение об отсутствии выделенного файла - empty: '.js-media-info-empty' + property: '.js-uploader-info-property', + // Кнопка удаления + remove: '.js-uploader-info-remove', } }, @@ -45,8 +43,7 @@ _create: function () { this.elements = { groups: this.element.find( this.option( 'selectors.group' ) ), - empty: this.element.find( this.option( 'selectors.empty' ) ), - info: this.element.find( this.option( 'selectors.info' ) ), + info: this.element.find( this.option( 'selectors.info' ) ), properties: { image: this.element.find( this.option( 'selectors.property' ) + '[data-name=image]' ), name: this.element.find( this.option( 'selectors.property' ) + '[data-name=name]' ), @@ -59,7 +56,7 @@ this.file = $(); // Удаление файла - this.element.on( 'click', '.js-media-item-info-remove', function () { + this.element.on( 'click', this.option( 'selectors.remove' ), function () { this.file.lsUploaderFile( 'remove' ); }.bind( this )); }, @@ -73,10 +70,6 @@ this.file = file; - // Показываем блок с информацией - this.elements.empty.hide(); - this.elements.info.show(); - // Устанавливаем общие для всех типов свойства this._setProperty( this.elements.properties.image, data['preview'] ); this._setProperty( this.elements.properties.name, data['file-name'] ); @@ -96,14 +89,9 @@ /** * Помечает блок как пустой - * - * TODO: Перенести в lsUploader */ empty: function() { this.file = $(); - - this.elements.info.hide(); - this.elements.empty.show(); }, /** @@ -117,7 +105,6 @@ * @private */ _activateGroup: function( group ) { - this.elements.empty.hide(); this.elements.groups.hide(); group.show(); }, diff --git a/application/frontend/skin/developer/components/uploader/js/uploader.js b/application/frontend/skin/developer/components/uploader/js/uploader.js index 35e6d608..200c04c2 100644 --- a/application/frontend/skin/developer/components/uploader/js/uploader.js +++ b/application/frontend/skin/developer/components/uploader/js/uploader.js @@ -18,16 +18,36 @@ options: { // Ссылки urls: { + // Загрузка файла upload: aRouter['ajax'] + 'media/upload/', + // Генерация временного хэша generate_target_tmp: aRouter['ajax'] + 'media/generate-target-tmp/', }, // Селекторы selectors: { - list: '.js-media-upload-gallery-list', - info: '.js-media-info', - upload_zone: '.js-media-upload-area', - upload_input: '.js-media-upload-file', + // Список файлов + list: '.js-uploader-list', + // Информация о файле + info: '.js-uploader-info', + + // Контейнер с элементами blocks и empty + aside: '.js-uploader-aside', + // Контейнер который отображается когда есть активный файл + // и скрывается когда активного файла нет + blocks: '.js-uploader-blocks', + // Сообщение об отсутствии активного файла + empty: '.js-uploader-aside-empty', + + // Drag & drop зона + upload_zone: '.js-uploader-area', + // Инпут + upload_input: '.js-uploader-file', + }, + + // Классы + classes: { + empty: 'is-empty' }, // Настройки загрузчика @@ -38,11 +58,12 @@ limitConcurrentUploads: 3 }, + // Параметры target_type: null, target_id: null, target_tmp: null, - // Подгрузка списк сразу после иниц-ии + // Подгрузка файлов сразу после иниц-ии autoload: true, }, @@ -53,17 +74,18 @@ * @private */ _create: function () { - this.elements = { - list: this.element.find( this.option( 'selectors.list' ) ), - info: this.element.find( this.option( 'selectors.info' ) ), - upload_zone: this.element.find( this.option( 'selectors.upload_zone' ) ), - upload_input: this.element.find( this.option( 'selectors.upload_input' ) ), - }; + // Получение элементов + this.elements = {}; - this.option( 'params', this.element.data( 'params' ) ); + $.each( this.option( 'selectors' ), function ( key, value ) { + this.elements[ key ] = this.element.find( value ); + }.bind( this )); + + // Получение параметров + this.option( 'params', this.element.data( 'params' ) ); this.option( 'target_type', this.element.data( 'type' ) ); - this.option( 'target_id', this.element.data( 'id' ) ); - this.option( 'target_tmp', this.element.data( 'tmp' ) || $.cookie( 'media_target_tmp_' + this.option( 'target_type' ) ) ); + this.option( 'target_id', this.element.data( 'id' ) ); + this.option( 'target_tmp', this.element.data( 'tmp' ) || $.cookie( 'media_target_tmp_' + this.option( 'target_type' ) ) ); // Генерация временного хэша для привязки if ( ! this.option( 'target_id' ) && ! this.option( 'target_tmp' ) ) { @@ -83,7 +105,7 @@ }, /** - * Method + * Иниц-ия загрузчика */ initUploader: function() { // Настройки загрузчика @@ -117,8 +139,7 @@ * */ onUploadProgress: function( file, percent ) { - file.find( file.lsUploaderFile( 'option', 'selectors.progress.value' ) ).height( percent + '%' ); - file.find( file.lsUploaderFile( 'option', 'selectors.progress.label' ) ).text( percent + '%' ); + file.lsUploaderFile( 'setProgress', percent ); }, /** @@ -132,11 +153,14 @@ * */ onUploadDone: function( file, response ) { + file.lsUploaderFile( 'destroy' ); file.replaceWith( $( $.trim( response.sTemplateFile ) ) .lsUploaderFile({ uploader: this.element }) + .lsUploaderFile( 'uploaded' ) .lsUploaderFile( 'activate' ) ); + file = null; }, /** @@ -145,8 +169,7 @@ onUploadError: function( file, response ) { ls.msg.error( response.sMsgTitle, response.sMsg ); - file.find( file.lsUploaderFile( 'option', 'selectors.progress.value' ) ).height( 0 ); - file.find( file.lsUploaderFile( 'option', 'selectors.progress.label' ) ).text( 'ERROR' ); + file.lsUploaderFile( 'error' ); }, /** @@ -160,22 +183,38 @@ }.bind(this)); }, + /** + * Скрывает контейнер с блоками + */ + hideBlocks: function() { + this.getElement( 'blocks' ).hide(); + this.getElement( 'empty' ).show(); + }, + + /** + * Показывает контейнер с блоками + */ + showBlocks: function() { + this.getElement( 'empty' ).hide(); + this.getElement( 'blocks' ).show(); + }, + /** * Помечает загрузчик как пустой */ markAsEmpty: function() { - this.element.addClass('is-empty'); + this.element.addClass( this.option( 'classes.empty' ) ); }, /** * Помечает загрузчик как не пустой */ markAsNotEmpty: function() { - this.element.removeClass('is-empty'); + this.element.removeClass( this.option( 'classes.empty' ) ); }, /** - * + * Получает элемент */ getElement: function( name ) { return this.elements[ name ]; diff --git a/application/frontend/skin/developer/components/uploader/uploader-block.info.tpl b/application/frontend/skin/developer/components/uploader/uploader-block.info.tpl new file mode 100644 index 00000000..149077c8 --- /dev/null +++ b/application/frontend/skin/developer/components/uploader/uploader-block.info.tpl @@ -0,0 +1,52 @@ +{** + * Информация об активном файле + *} + +{extends './uploader-block.tpl'} + +{block 'block_options' append} + {$classes = "{$classes} uploader-info js-uploader-info"} +{/block} + +{block 'block_content'} + {$component_info = 'uploader-info'} + + {* Информация о файле *} +
    + + {* Основная информация о файле *} +
    + {* Превью *} + + + {* Информация *} +
      +
    • +
    • +
    • +
    +
    + + {* Информация о файле *} +
    + {* Действия *} + + + {* Уникальные св-ва для каждого типа *} +
    +
    + Разрешение: +
    + + {* Описание *} + {include 'components/field/field.text.tpl' + sName = 'title' + sInputClasses = 'js-{$component_info}-property' + sInputAttributes = 'data-name="title"' + sLabel = $aLang.uploadimg_title} +
    +
    +
    +{/block} \ No newline at end of file diff --git a/application/frontend/skin/developer/components/uploader/uploader-block.tpl b/application/frontend/skin/developer/components/uploader/uploader-block.tpl new file mode 100644 index 00000000..e7daea40 --- /dev/null +++ b/application/frontend/skin/developer/components/uploader/uploader-block.tpl @@ -0,0 +1,5 @@ +{extends 'components/block/block.tpl'} + +{block 'block_options' append} + {$classes = "{$classes} uploader-block"} +{/block} \ No newline at end of file diff --git a/application/frontend/skin/developer/components/uploader/uploader-file.tpl b/application/frontend/skin/developer/components/uploader/uploader-file.tpl index 583b1223..15d919c4 100644 --- a/application/frontend/skin/developer/components/uploader/uploader-file.tpl +++ b/application/frontend/skin/developer/components/uploader/uploader-file.tpl @@ -6,7 +6,7 @@ {$file = $oMediaItem} -