UNPKG

apostrophe

Version:

The Apostrophe Content Management System.

314 lines (281 loc) • 11 kB
apos.define('apostrophe-attachments', { afterConstruct: function(self) { self.addFieldType(); self.addHandlers(); }, construct: function(self, options) { self.name = options.name; self.action = options.action; // Invoke with an attachment, options (such as minSize), and a callback. // Callback receives (err, crop). If no err, crop has coordinates and // can be stored as the crop property of the attachment (when there is // one and only one crop ever for this attachment), or stored as part // of a relationship to the doc containing the attachment; that part // is up to you. self.crop = function(attachment, options, callback) { var args = { action: self.action, attachment: attachment, cropped: function(crop) { return callback(null, crop); } }; // If there is an existing crop of the attachment itself (not just a relationship), // omit that from the attachment object for purposes of cropping again, and move it to the options if (args.attachment.crop) { if (!args.crop) { args.crop = args.attachment.crop; } delete args.attachment.crop; } _.assign(args, options); apos.create('apostrophe-attachments-crop-editor', args); }; // Invoke with an attachment, options (such as minSize), and a callback. // Callback receives (err, focalPoint). If no err, focalPoint has x and y // properties and can be stored as the focalPoint property of the attachment // (when there is one and only one focal point ever for this attachment), or // stored as part of a relationship to the doc containing the attachment; that part // is up to you. self.focalPoint = function(attachment, options, callback) { var args = { action: self.action, attachment: attachment, setFocalPoint: function(focalPoint) { return callback(null, focalPoint); } }; // If there is an existing focal point for the attachment itself (not just a relationship), // omit that from the attachment object for purposes of editing again, and move it to the options if (args.attachment.focalPoint) { if (!args.focalPoint) { args.focalPoint = args.attachment.focalPoint; } delete args.attachment.focalPoint; } _.assign(args, options); apos.create('apostrophe-attachments-focal-point-editor', args); }; self.addFieldType = function() { apos.schemas.addFieldType({ name: self.name, populate: self.populate, convert: self.convert }); }; self.populate = function(object, name, $field, $el, field, callback) { var $fieldset = apos.schemas.findFieldset($el, name); self.updateExisting($fieldset, object[name], field); var $trashButton = $fieldset.find('[data-apos-trash]'); // A bulk upload button is provided separately at the array level // if multipleUpload: true is set on an array schema field. -Tom var $uploaderButton = $fieldset.find('[data-apos-uploader-target]'); var $input = $fieldset.find('input[type="file"]'); // configure button to fire input click $uploaderButton.on('click', function() { // input element gets replaced after each use, so we have to // find it each time we want to click it programmatically. -Tom $fieldset.find('input[type="file"]').click(); }); $trashButton.on('click', function() { self.updateExisting($fieldset, null, field); return false; }); $input.fileupload({ dataType: 'json', dropZone: $fieldset, maxNumberOfFiles: 1, url: self.action + '/upload', start: function (e) { busy(true); apos.emit('attachmentUploadStarted', { $fieldset: $fieldset, field: field }); }, // Even on an error we should note we're not spinning anymore always: function (e, data) { busy(false); }, done: function (e, data) { var extensions; if (data.result.status !== 'ok') { apos.notify(data.result.status, { type: 'error' }); apos.emit('attachmentUploadError', { $fieldset: $fieldset, field: field, status: data.result.status }); return; } var file = data.result.file; var groups = field.fileGroups || (field.fileGroup && [ field.fileGroup ]); if (groups) { if (!_.contains(groups, file.group)) { extensions = []; _.each(groups, function(group) { var groupInfo = _.find(self.options.fileGroups, { name: group }); if (!groupInfo) { return; } extensions = extensions.concat(groupInfo.extensions); }); apos.notify("The file must be of one of the following types: %s", extensions.join(', '), { type: 'error' }); return; } } extensions = field.extensions || (field.extension && [ field.extension ]); if (extensions) { if (!_.contains(extensions, file.extension)) { apos.notify("The file must be of one of the following types: %s", extensions.join(', '), { type: 'error' }); return; } } apos.emit('attachmentUploadSuccess', { $fieldset: $fieldset, field: field }); self.updateExisting($fieldset, file, field); }, add: function(e, data) { return data.submit(); } }); return setImmediate(callback); function busy(state) { $uploaderButton.attr('data-busy', state ? '1' : '0'); apos.ui.busy($fieldset, !!state); } }; self.convert = function(data, name, $field, $el, field, callback) { var $fieldset = apos.schemas.findFieldset($el, name); var $uploaderButton = $fieldset.find('[data-apos-uploader-target]'); if ($uploaderButton.attr('data-busy') === '1') { // If upload is in progress stay busy until this upload // completes. Other file attachment fields may be doing // the same dance. setTimeout(function() { self.convert(data, name, $field, $el, field, callback); }, 100); return; } data[name] = $fieldset.find('[data-existing]').data('existing'); if (data[name] && (!data[name].crop) && field.aspectRatio) { return self.autocrop(field, data[name], function(err) { if (err) { return callback(err); } return finish(); }); } else { return finish(); } function finish() { if (field.required && (!data[name])) { return setImmediate(_.partial(callback, 'required')); } return setImmediate(callback); } }; self.autocrop = function(field, attachment, callback) { var aspectRatio = field.aspectRatio; if (!aspectRatio) { return callback(null); } aspectRatio = aspectRatio[0] / aspectRatio[1]; var width = attachment.width; var height = attachment.width / aspectRatio; var left = 0; var top = (attachment.height - height) / 2; if (height > attachment.height) { width = attachment.height * aspectRatio; height = attachment.height; left = (attachment.width - width) / 2; top = 0; } return apos.attachments.api( 'crop', { _id: attachment._id, crop: { top: top, left: left, width: width, height: height } }, function(data) { if (data.status !== 'ok') { apos.notify('An error occurred while cropping.', { type: 'error', dismiss: true }); return callback('fail'); } attachment.crop = { top: top, left: left, width: width, height: height }; return callback(null); } ); }; self.addHandlers = function() { apos.ui.link('apos-crop', 'attachment', function($el, _id) { var $existing = $el.closest('[data-existing]'); var attachment = $existing.data('existing'); var field = $existing.data('field'); var $fieldset = $el.closest('[data-name]'); var options = {}; options.focalPoint = field.focalPoint || (field.hints && field.hints.focalPoint); options.minSize = field.minSize || (field.hints && field.hints.minSize); options.aspectRatio = field.aspectRatio || (field.hints && field.hints.aspectRatio); self.crop(attachment, options, function(err, crop) { if (!err) { attachment.crop = crop; self.updateExisting($fieldset, attachment, field); } }); }); apos.ui.link('apos-focal-point', 'attachment', function($el, _id) { var $existing = $el.closest('[data-existing]'); var attachment = $existing.data('existing'); var field = $existing.data('field'); var $fieldset = $el.closest('[data-name]'); var options = {}; options.focalPoint = field.focalPoint || (field.hints && field.hints.focalPoint); self.focalPoint(attachment, options, function(err, focalPoint) { if (!err) { attachment.focalPoint = focalPoint; self.updateExisting($fieldset, attachment, field); } }); }); }; self.updateExisting = function($fieldset, info, field) { var $existing = $fieldset.find('[data-existing]'); if (!info) { $existing.data('existing', null); $existing.hide(); return; } $existing.data('existing', info); $existing.data('field', field); $existing.attr('data-existing', info._id); $existing.find('[data-name]').text(info.name); $existing.find('[data-link]').attr('href', self.url(info)); $existing.alterClass('apos-extension-*', 'apos-extension-' + info.extension); var $preview = $existing.find('[data-preview]'); if (info.group === 'images') { $preview.attr('src', self.url(info, { size: 'one-half', crop: info.crop })); $fieldset.find('[data-apos-crop-attachment]').show(); $fieldset.find('[data-apos-focal-point-attachment]').show(); } else { $preview.hide(); $fieldset.find('[data-apos-crop-attachment]').hide(); $fieldset.find('[data-apos-focal-point-attachment]').hide(); } $existing.show(); apos.emit('attachmentUpdated', { $fieldset: $fieldset, attachment: info, field: field }); }; apos.attachments = self; } });