/*jslint nomen: true*/ /*global define*/ /** * Create an image uploader. * * The `.presentationUiUploadImage()` renders an image uploader, i.e. a `div` containing a title, an image, an upload button, a delete button and, * if needed, a checkbox with a label, which determines whether a newly uploaded image will be scaled on the server. * * ### Examples * Render a basic image uploader with no image previously set. * * JavaScript: * * <div id='uploadImage-widget'></div> * <script> * de_epages('#uploadImage-widget') * .presentationUiUploadImage(); * </script> * * Render an image uploader with a previously set image,a checkbox with a label. Also, pass along data objects needed for the upload and delete requests. * * JavaScript: * * <div id='uploadImage-widget'></div> * <script> * de_epages('#uploadImage-widget') * .presentationUiUploadImage({ * imagePath : '/WebRoot/Store/Shops/DemoShop/image.jpg', * scaleText : 'Do you want the server to change the image's size during the upload process?', * uploadData : { * ViewAction : 'JSONViewResponse', * ObjectID : 2436278, * ChangeAction : 'UploadSmallProductImage', * Image : 'ImageSmall', * Width : 100, * Height : 100, * UseMediaGallery : 0 * }, * deleteData : { * ViewAction : 'JSONViewResponse', * ObjectID : 2436278, * ChangeAction : 'DeleteSmallProductImage', * ACCEPT : 1, * File : 'ImageSmall' * } * }); * </script> * * * @class jQuery.ui.presentationUiUploadImage * @extends jQuery.widget * * @uses jQuery.tmpl * @uses jQuery.dict * @uses jQuery.uid * @uses ep.alert * @uses ep.ajax * @uses ep.i18n * @uses ep.ui.tooltip * @uses ep.ui.input * @uses ep.ui.lightbox * @uses de_epages.presentation.ui.uploader * @since 6.15.0 */ define('de_epages/presentation/ui/uploadimage', [ 'jquery', 'ep', 'de_epages', '$dict!../dictionary', '$tmpl!./uploadimage', '$tmpl!./uploadimage-tooltip', '$tmpl!./uploadimage-deletedialog', 'jquery/uid', 'ep/ui/tooltip', 'ep/ui/input', 'ep/ui/lightbox', 'ep/alert', 'ep/ajax', 'ep/i18n', 'de_epages/presentation/ui/uploader' ], function ($, ep, de_epages, presentationDict, tmplUploadImage, tmplUploadImageTooltip, tmplUploadImageDeleteDialog) { 'use strict'; $.widget('ui.presentationUiUploadImage', { /** * Options to be passed to the widgt on initialzation * * @cfg {Object} options * @cfg {String} [options.addClass=null] Optional class which is added to the widget element. * @cfg {Boolean} [options.showPreview=true] A boolean value determining whether the preview should be shown. * @cfg {Boolean} [options.multiple=false] A boolean value determining whether it should be possible to upload more than one file at once. * @cfg {Boolean} [options.big=false] A boolean value determining whether the upload button should be styled BIG. * @cfg {String} [options.imagePath=''] A string containing the link to an image which is to be displayed by the image uploader. * @cfg {String} [options.defaultImage=''] Path to a default image to be displayed after an image has been deleted. Note that only images passed to imagePath will be displayed. This will only show up on screen after an image which was previously set by imagePath was deleted. * @cfg {Boolean} [options.scales=false] A boolean value determining whether a newly uploaded image will be scaled on the server. If true, the image will be scaled according to the Width and Height properties passed in the uploadData option. * @cfg {Number} [options.confirm=1] A bit determining whether to ask the user for confirmation after clicking the delete button. * @cfg {String} [options.accept='image/*'] A string of MIME types and/or MIME type groups to be accepted by the uploader. * @cfg {String} [options.title=''] A title string. * @cfg {String} [options.subtitle=''] A subtitle string. * @cfg {String} [options.confirmation=''] A string which fades in and out after completion of image upload. * @cfg {String} [options.imageInfo={Size: null, Filename: null, Width: null, Height: null}] An object containing information about the displayed image which is to be shown in the image's tooltip. * @cfg {Object} [options.uploadData=null] An object containing the parameters needed for the upload action (server-side). If uploadData.Width or uploadData.Height are set, scales is set to true during _create-method * @cfg {String} [options.uploadButtonText='{UploadImage}'] A string which is set as text for uploader widgets button. * @cfg {Object} [options.deleteData=null] An object containing the parameters needed for the delete action (server-side). * @cfg {Object} [options.saveData=null] An object containing the parameters needed for the save action (server-side). Some upload actions do not actually save the uploaded image on the server themselves. * @cfg {String} [options.scaleText=''] A string to show in the first line of the image uploader's checkbox. The second line will be rendered according to the properties passed in the Width and Height properties of the uploadData option. Note that, if this is not set at creation of the widget, the respective checkbox and label will not be added to the DOM. * @cfg {String} [options.deleteText={DeleteFile}] A string for delete link. * @cfg {Function} [options.onUpload=null] A function to be called after an image was uploaded (and saved) to the server. The callback function receives the imagePath and imageInfo of the uploaded image as arguments. * @cfg {Function} [options.onDelete=null] A function to be called after an image was deleted from the server. The callback function receives no arguments. * @cfg {Function} [options.onComplete=null] A function to be called after ALL images have been uploaded. * */ options: { addClass: null, showPreview: true, multiple: false, big: false, imagePath: '', defaultImage: '', scales: false, confirm: 1, accept: 'image/*', title: '', subtitle: '', confirmation: '', imageInfo: { Size: null, FileName: null, Width: null, Height: null }, uploadData: null, uploadButtonText: presentationDict.translate('{UploadImage}'), deleteData: null, saveData: null, scaleText: '', deleteText: '{DeleteFile}', onUpload: null, onDelete: null, onComplete: null }, _create: function () { var self = this, o = self.options, // Set up the DOM using jQuery template. renderedView = tmplUploadImage({ title: o.title, subtitle: o.subtitle, showPreview: o.showPreview, showDeleteFile: o.deleteData || false, toggleScales_uid: $.uid('toggleScales'), toggleScales_name: o.scales.name || "toggleScales", scaleHeight: o.uploadData && o.uploadData.Height, scaleWidth: o.uploadData && o.uploadData.Width, scaleText: o.scaleText, deleteText: o.deleteText }); // Add DOM elements to self. $.extend(self, renderedView.tmplItem('elements')); // Hide *confirmation*. self.confirmationContainer.hide(); renderedView.dictParse(presentationDict, true).appendTo(self.element); if (o.addClass) { self.element.addClass(o.addClass); } // Create *tooltip* (disabled!). self.tooltip = ep(self.tooltip).uiTooltip({ orientation: 'cursor', context: self.image, disabled: true, oldhandling: true }); // Set up *checkbox* widget, // if *toggleScales* is present in the DOM, // otherwise set *toggleScales* to []. (See uploadImage.tmpl.html.) self.toggleScales = ep(self.toggleScales).uiInput(); // The checkbox is checked by default, // so let us keep *scales* in check. // if a scales data object is commited it's not essential to set o.scales to true if (o.scaleText && o.scales === false) { o.scales = true; } // Create *uploader* widget. self.uploader = de_epages(self.uploader).presentationUiUploader({ style: o.style ? o.style : 'normal', buttonText: o.uploadButtonText, multiple: o.multiple, big: o.big, callback: o.onComplete || $.proxy(self._onUpload, self) }); // Event handling. (The *uploader* handles itself.) self.deleteFile.children().on('click', function () { self._onDeleteFile(); }); if (self.toggleScales) { if (o.scales.checked !== undefined) { o.scales = o.scales.checked; } self.toggleScales.on('click', function () { self._setOption('scales', !o.scales); }).prop('checked', o.scales).on('change', function () { $(this).prop('defaultChecked', $(this).prop('checked')); }); } // Open `uiLightbox` when image is clicked. if (o.showPreview) { this._on(this.imageContainer, { 'click img': function (e) { var $currentTarget = $(e.currentTarget); if (!$currentTarget.is(':data(ui-ui-lightbox)')) { $currentTarget.uiLightbox({ images: e.currentTarget }).trigger('click'); } } }); } // The remaining setup is taking care of by *_setOptions*. self._setOptions(o); }, _setOption: function (key, value) { var self = this, o = self.options; this._superApply(arguments); // Now we have 'o[key] = value'. switch (key) { case 'title': if (self.title) { self.title.html(value); } break; case 'subtitle': if (value) { self.subtitle.html(value).removeClass('HideElement'); } else { self.subtitle.addClass('HideElement'); } break; case 'confirmation': self.confirmation.html(value); break; case 'scaleText': if (self.scaleText) { // Otherwise *toggleScales* has no label, no checkbox and all that jazz. self.scaleText.html(value).dictParse(presentationDict, true); } break; case 'scales': // Otherwise we would call *_setUploaderData* twice during *_create*. self._setUploaderData(); break; case 'uploadData': self.uploader.attr('disabled', !value); self._setUploaderData(); break; case 'deleteData': self.deleteFile.toggleClass('HideElement', !value); break; case 'accept': self.uploader.presentationUiUploader('option', 'accept', value); break; case 'imageInfo': if (value) { self.tooltip.uiTooltip('option', 'disabled', false); if (value.Size) { value.formattedSize = ep.i18n.formatBytes(value.Size, 0); } // Setup tooltip text. self.tooltip.html(tmplUploadImageTooltip(value)); } else { self.tooltip.uiTooltip('option', 'disabled', true); } break; case 'imagePath': if (value) { // Show/Switch the image. self.image.fadeOut(function () { self.image.attr({ 'src': value, 'alt': o.imageInfo ? (o.imageInfo.FileName || '') : value }); // This is why imageInfo should be set before imagePath. if (self.imageContainer.find('img').length === 0) { self.image.appendTo(self.imageContainer).fadeIn(); } else { self.image.fadeIn(); } if (o.defaultImage === value) { // Hide *deleteFile*, when *defaultImage* is displayed. self.deleteFile.hide(); } else { // Otherwise show *deleteFile*. self.deleteFile.show(); } }); } else { // Hide the image. if (o.defaultImage) { // Display *defaultImage* self._setOptions({ 'imagePath': o.defaultImage, 'imageInfo': null }); } else if (self.image) { // Remove *image* from DOM if exists self.image.fadeOut(function () { self._setOption('imageInfo', null); self.image.remove(); // Simply removing the 'src' attribute does not suffice. self.deleteFile.hide(); }); } } break; } }, // Show *confirmation*. _showConfirmation: function () { if (this.options.confirmation) { this.confirmationContainer.fadeIn('slow').delay(2000).fadeOut('slow'); } }, // *uploader* (widget) callback. _onUpload: function (data, statusText) { var self = this, o = self.options, image, imageInfo, _uploadData; if (data[0] && data[0].success) { image = data[0].success.uploadedFile; imageInfo = data[0].success.imageInfo; if (o.saveData) { // If present, we ajax the *saveData* over to the server. _uploadData = self.uploader.presentationUiUploader('option', 'data'); // The following depends on the server action used. o.saveData[_uploadData.Image || 'Filename'] = _uploadData.UseMediaGallery ? 'MediaGallery/' + imageInfo.FileName : imageInfo.FileName; ep.ajax({ data: o.saveData, type: 'POST', dataType: 'json' }).done(function (newData) { if (newData.uploadedFile) { image = newData.uploadedFile; } else if (newData.FileName) { image = newData.FileName; } // Set and show the uploaded *image*. self._setOption('imagePath', image); if (o.onUpload) { // Call callback, if present. o.onUpload(o.imagePath, imageInfo); } }); } else { // Set and show the uploaded *image*. self._setOption('imagePath', image); if (o.onUpload) { // Call callback, if present. o.onUpload(o.imagePath, imageInfo); } } // Set the *tooltip*'s text. self._setOption('imageInfo', imageInfo); // Show *confirmation* text. self._showConfirmation(); } }, // *deleteFile* (node) callback. _onDeleteFile: function () { var self = this, o = self.options, deleteDialog; if (o.confirm) { // Ask for confirmation. deleteDialog = ep.alert({ title: presentationDict.translate('DeleteFile'), closeOnEscape: true, content: tmplUploadImageDeleteDialog(o.imageInfo).dictParse(presentationDict, true), type: 'confirmation', okTitle: presentationDict.translate('Delete'), cancel: function () {}, ok: $.proxy(self._deleteFileOnServer, self) }); } else { self._deleteFileOnServer(); } }, // After confirmation delete the image from the server. _deleteFileOnServer: function () { var self = this, o = self.options, changeAction = o.uploadData.ChangeAction || null, setDefault = function () { self._setOptions({ 'imagePath': o.defaultImage || null, 'imageInfo': null }); if (o.onDelete) { o.onDelete(); } }; if (o.saveData || changeAction) { ep.ajax({ data: o.deleteData, type: 'POST', dataType: 'json' }).done(function () { setDefault(); }); } else { // If the file isn't stored at the server. setDefault(); } }, // Set *uploader*'s data object depending on *scales* and *uploaderData* _setUploaderData: function () { var self = this, o = self.options, _uploadData = $.extend({}, o.uploadData); if (!o.scales) { delete _uploadData.Width; delete _uploadData.Height; } self.uploader.presentationUiUploader('option', 'data', _uploadData); }, destroy: function () { this.mainContainer.remove(); this._superApply(arguments); } }); return de_epages; });