diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php index bfb142322..b92692f17 100644 --- a/application/cmdbabstract.class.inc.php +++ b/application/cmdbabstract.class.inc.php @@ -2099,16 +2099,13 @@ EOF $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/edit_image.js'); $oDocument = $value; // Value is an ormDocument objectm $sDefaultUrl = $oAttDef->Get('default_image'); - if (is_object($oDocument) && !$oDocument->IsEmpty()) - { + if (is_object($oDocument) && !$oDocument->IsEmpty()) { $sUrl = 'data:'.$oDocument->GetMimeType().';base64,'.base64_encode($oDocument->GetData()); - } - else - { + } else { $sUrl = null; } - $sHTMLValue = "
\n"; + $sHTMLValue = "
\n"; $sHTMLValue .= "{$sValidationSpan}{$sReloadSpan}\n"; $aEditImage = array( diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php index 904cbbbb3..18a251542 100644 --- a/core/attributedef.class.inc.php +++ b/core/attributedef.class.inc.php @@ -8112,10 +8112,10 @@ class AttributeImage extends AttributeBlob $sRet = $this->GetHtmlForImageUrl($sCustomImageUrl, $iMaxWidthPx, $iMaxHeightPx); } - $sCssClasses = 'view-image attribute-image'; + $sCssClasses = 'ibo-input-image--image-view attribute-image'; $sCssClasses .= ' '.(($bIsCustomImage) ? 'attribute-image-custom' : 'attribute-image-default'); - return '
'.$sRet.'
'; + return '
'.$sRet.'
'; } /** diff --git a/core/pdfbulkexport.class.inc.php b/core/pdfbulkexport.class.inc.php index 2812fb9ca..5f8df7c6d 100644 --- a/core/pdfbulkexport.class.inc.php +++ b/core/pdfbulkexport.class.inc.php @@ -229,7 +229,7 @@ EOF $sUrl = 'data:'.$value->GetMimeType().';base64,'.base64_encode($value->GetData()); } $sRet = ($sUrl !== null) ? '' : ''; - $sRet = '
'.$sRet.'
'; + $sRet = '
'.$sRet.'
'; } else { diff --git a/css/backoffice/components/input/_all.scss b/css/backoffice/components/input/_all.scss index 615c9ecdf..088f7cd3e 100644 --- a/css/backoffice/components/input/_all.scss +++ b/css/backoffice/components/input/_all.scss @@ -4,11 +4,12 @@ */ @import "input"; -@import "input-select"; @import "input-checkbox"; @import "input-date"; @import "input-datetime"; @import "input-duration"; +@import "input-image"; +@import "input-select"; @import "input-select-icon"; @import "input-string"; @import "input-tagset"; diff --git a/css/backoffice/components/input/_input-image.scss b/css/backoffice/components/input/_input-image.scss new file mode 100644 index 000000000..ef55d510f --- /dev/null +++ b/css/backoffice/components/input/_input-image.scss @@ -0,0 +1,45 @@ +/*! + * @copyright Copyright (C) 2010-2021 Combodo SARL + * @license http://opensource.org/licenses/AGPL-3.0 + */ + +.ibo-input-image { + display: flex; + justify-content: flex-start; + align-items: flex-start; +} + +.ibo-input-image--image-view { + position: relative; + overflow: hidden; + background-color: $ibo-color-grey-200; + border-radius: $ibo-border-radius-500; + @extend %ibo-fully-centered-content; + + img[src=""], + img[src="null"] { + // Hiding "broken" image when src is not set + visibility: hidden; + } + + input[type="file"] { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + opacity: 0; + } +} + +.ibo-input-image--edit-buttons { + display: flex; + flex-direction: column; + margin-left: 0.5rem; + + // Overload original siblings rule as buttons are displayed vertically + .ibo-button + .ibo-button { + margin-top: 0.5rem; + margin-left: 0; + } +} \ No newline at end of file diff --git a/css/light-grey.scss b/css/light-grey.scss index f4de46447..5d4bb1eb4 100644 --- a/css/light-grey.scss +++ b/css/light-grey.scss @@ -154,60 +154,6 @@ // color: $text-color; //} - .edit-image { - .view-image { - display: inline-block; - - img[src=""], - img[src="null"] { - // Hiding "broken" image when src is not set - visibility: hidden; - } - - &.dirty { - // The image will be modified when saving the changes - - &.compat { - // Browser not supporting FileReader - background-image: url($approot-relative + "css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png?v=" + $version); - - img { - opacity: 0.3; - } - } - } - } - - .edit-buttons { - display: inline-block; - vertical-align: top; - margin-top: 4px; - margin-left: 3px; - - .button { - cursor: pointer; - margin-bottom: 3px; - padding: 2px; - background-color: $highlight-color; - - &.disabled { - cursor: default; - background-color: $grey-color; - opacity: 0.3; - } - - .ui-icon { - background-image: url($approot-relative + "css/ui-lightness/images/ui-icons_ffffff_256x240.png?v=" + $version); - } - } - } - - .file-input { - display: block; - position: relative; - } - } - /* Center the image both horizontally and vertically, withing a box which size is fixed (depends on the attribute definition) */ .details .view-image { text-align: center; diff --git a/js/edit_image.js b/js/edit_image.js index 3d094423c..f0e977174 100644 --- a/js/edit_image.js +++ b/js/edit_image.js @@ -27,108 +27,10 @@ $(function() // the constructor _create: function () { - var me = this; - me.bLoadedEmpty = (me.options.current_image_url == '' || me.options.current_image_url == null); + this.element.addClass('ibo-input-image'); - var sMarkup = ''; - sMarkup += ''; - - var sCssClasses = "view-image attribute-image"; - console.debug("edit_image", me.options.current_image_url); - var sCssClassToAdd, sImageUrl; - if (me.options.current_image_url === null) - { - sCssClassToAdd = "attribute-image-default"; - sImageUrl = me.options.default_image_url; - } - else - { - sCssClassToAdd = "attribute-image-custom"; - sImageUrl = me.options.current_image_url; - } - sCssClasses += ' '+sCssClassToAdd; - sMarkup += '
'; - - sMarkup += ''; - sMarkup += ''; - sMarkup += '
'; - sMarkup += '
'; - sMarkup += '
'; - - var sDisabled = me.bLoadedEmpty ? 'disabled' : ''; - var sLoadedDisabled = me.bLoadedEmpty ? 'yes' : 'no'; - sMarkup += '
'; - sMarkup += '
'; - - sMarkup += ''; - sMarkup += ''; - - this.element - .addClass('edit-image') - .append(sMarkup); - - $('#file_' + me.options.input_name).change(function () { - - $('#do_remove_' + me.options.input_name).val('0'); - - me.previewImage(this, '#preview_' + me.options.input_name + ' img'); - - var oImage = $('#preview_' + me.options.input_name + ' img'); - oImage.closest('.view-image').addClass('dirty'); - - $('#reset_' + me.options.input_name).removeClass('disabled'); - $('#remove_' + me.options.input_name).removeClass('disabled'); - }); - $('#reset_' + me.options.input_name).click(function () { - - if ($(this).hasClass('disabled')) return; - - $('#do_remove_' + me.options.input_name).val('0'); - - // Restore the image - var oImage = $('#preview_' + me.options.input_name + ' img'); - oImage.attr('src', oImage.attr('data-original-src')); - oImage.closest('.view-image').removeClass('dirty').removeClass('compat'); - - // Reset the file input without losing events bound to it - var oInput = $('#file_' + me.options.input_name); - oInput.replaceWith(oInput.val('').clone(true)); - - $('#reset_' + me.options.input_name).addClass('disabled'); - var oRemoveBtn = $('#remove_' + me.options.input_name); - if (oRemoveBtn.attr('data-loaded-disabled') == 'yes') { - oRemoveBtn.addClass('disabled'); - } - else { - oRemoveBtn.removeClass('disabled'); - } - }); - $('#remove_' + me.options.input_name).click(function () { - - if ($(this).hasClass('disabled')) return; - - $('#do_remove_' + me.options.input_name).val('1'); - - // Restore the default image - var oImage = $('#preview_' + me.options.input_name + ' img'); - oImage.attr('src', oImage.attr('data-default-src')); - oImage.closest('.view-image') - .removeClass('compat') - .addClass('dirty'); - - // Reset the file input without losing events bound to it - var oInput = $('#file_' + me.options.input_name); - oInput.replaceWith(oInput.val('').clone(true)); - - var oRemoveBtn = $('#remove_' + me.options.input_name); - if (oRemoveBtn.attr('data-loaded-disabled') == 'yes') { - $('#reset_' + me.options.input_name).addClass('disabled'); - } - else { - $('#reset_' + me.options.input_name).removeClass('disabled'); - } - oRemoveBtn.addClass('disabled'); - }); + this._buildMarkup(); + this._bindEvents(); }, // called when created, and later when changing options _refresh: function () { @@ -136,7 +38,7 @@ $(function() // events bound via _bind are removed automatically // revert other modifications here _destroy: function () { - this.element.removeClass('edit-image'); + this.element.removeClass('ibo-input-image'); }, // _setOptions is called with a hash of all options that are changing _setOptions: function () { @@ -146,6 +48,114 @@ $(function() _setOption: function (key, value) { this._superApply(arguments); }, + + _buildMarkup: function () { + CombodoJSConsole.Debug('edit_image: '+this.options.current_image_url); + + this.bLoadedEmpty = (this.options.current_image_url == '' || this.options.current_image_url == null); + + const sDisabled = this.bLoadedEmpty ? 'disabled' : ''; + const sLoadedDisabled = this.bLoadedEmpty ? 'yes' : 'no'; + const sUploadButtonTooltipAttribute = this.options.labels.upload_button !== '' ? 'data-tooltip-content="'+this.options.labels.upload_button+'"' : ''; + let sCssClasses = "ibo-input-image--image-view attribute-image"; + let sCssClassToAdd, sImageUrl; + + if (this.options.current_image_url === null) { + sCssClassToAdd = "attribute-image-default"; + sImageUrl = this.options.default_image_url; + } else { + sCssClassToAdd = "attribute-image-custom"; + sImageUrl = this.options.current_image_url; + } + sCssClasses += ' '+sCssClassToAdd; + + let sMarkup = ` + +
+ + +
+
+ + +
+ + `; + + this.element.append(sMarkup); + + CombodoGlobalToolbox.InitAllNonInstantiatedTooltips(this.element); + }, + _bindEvents: function () { + const me = this; + + $('#file_'+me.options.input_name).change(function () { + $('#do_remove_'+me.options.input_name).val('0'); + + me.previewImage(this, '#preview_'+me.options.input_name+' img'); + + let oImage = $('#preview_'+me.options.input_name+' img'); + oImage.closest('.ibo-input-image--image-view').addClass('dirty'); + + $('#reset_'+me.options.input_name).prop('disabled', false); + $('#remove_'+me.options.input_name).prop('disabled', false); + }); + + $('#reset_'+me.options.input_name).click(function () { + if ($(this).prop('disabled')) { + return; + } + + $('#do_remove_'+me.options.input_name).val('0'); + + // Restore the image + let oImage = $('#preview_'+me.options.input_name+' img'); + oImage.attr('src', oImage.attr('data-original-src')); + oImage.closest('.ibo-input-image--image-view').removeClass('dirty'); + + // Reset the file input without losing events bound to it + let oInput = $('#file_'+me.options.input_name); + oInput.replaceWith(oInput.val('').clone(true)); + + $('#reset_'+me.options.input_name).prop('disabled', true); + let oRemoveBtn = $('#remove_'+me.options.input_name); + if (oRemoveBtn.attr('data-loaded-disabled') == 'yes') { + oRemoveBtn.prop('disabled', true); + } else { + oRemoveBtn.prop('disabled', false); + } + }); + + $('#remove_'+me.options.input_name).click(function () { + if ($(this).prop('disabled')) { + return; + } + + $('#do_remove_'+me.options.input_name).val('1'); + + // Restore the default image + let oImage = $('#preview_'+me.options.input_name+' img'); + oImage.attr('src', oImage.attr('data-default-src')); + oImage.closest('.ibo-input-image--image-view') + .addClass('dirty'); + + // Reset the file input without losing events bound to it + let oInput = $('#file_'+me.options.input_name); + oInput.replaceWith(oInput.val('').clone(true)); + + let oRemoveBtn = $('#remove_'+me.options.input_name); + if (oRemoveBtn.attr('data-loaded-disabled') == 'yes') { + $('#reset_'+me.options.input_name).prop('disabled', true); + } else { + $('#reset_'+me.options.input_name).prop('disabled', false); + } + oRemoveBtn.prop('disabled', true); + }); + }, previewImage: function (input, sImageSelector) { if (input.files && input.files[0]) { if (window.FileReader) { @@ -157,12 +167,6 @@ $(function() reader.readAsDataURL(input.files[0]); } - else { - $(sImageSelector).closest('.view-image').addClass('compat'); - } - } - else { - $(sImageSelector).closest('.view-image').addClass('compat'); } } }); diff --git a/sources/application/WebPage/iTopWebPage.php b/sources/application/WebPage/iTopWebPage.php index bacb141a1..6d64a970d 100644 --- a/sources/application/WebPage/iTopWebPage.php +++ b/sources/application/WebPage/iTopWebPage.php @@ -343,7 +343,7 @@ JS // Make image attributes zoomable $this->add_ready_script( <<