Refactor media manager from image block to a behavior [MAILPOET-1403]
This will make the media manager reusable in other blocks like e.g. container.
This commit is contained in:
@ -0,0 +1,304 @@
|
||||
/* eslint-disable func-names */
|
||||
/**
|
||||
* Media manager behaviour
|
||||
*
|
||||
* Adds a media manager integration with the view
|
||||
*/
|
||||
define([
|
||||
'backbone.marionette',
|
||||
'underscore',
|
||||
'newsletter_editor/behaviors/BehaviorsLookup',
|
||||
'jquery'
|
||||
], function (Marionette, _, BehaviorsLookup, jQuery) {
|
||||
var BL = BehaviorsLookup;
|
||||
|
||||
BL.MediaManagerBehavior = Marionette.Behavior.extend({
|
||||
ui: {
|
||||
'select-image': '.mailpoet_field_image_select_image',
|
||||
'address-input': '.mailpoet_field_image_address'
|
||||
},
|
||||
events: {
|
||||
'click @ui.select-image': 'showMediaManager',
|
||||
'input @ui.address-input': 'changeAddress'
|
||||
},
|
||||
initialize: function () {
|
||||
if (this.view.options.showImageManager) {
|
||||
this.showMediaManager();
|
||||
}
|
||||
},
|
||||
changeAddress: function (event) {
|
||||
var src = jQuery(event.target).val();
|
||||
var image = new Image();
|
||||
|
||||
image.onload = function () {
|
||||
if (this.options.onSelect) {
|
||||
this.view[this.options.onSelect]({
|
||||
src: src,
|
||||
width: image.naturalWidth + 'px',
|
||||
height: image.naturalHeight + 'px'
|
||||
});
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
image.src = src;
|
||||
},
|
||||
showMediaManager: function () {
|
||||
var that = this;
|
||||
var MediaManager;
|
||||
var theFrame;
|
||||
if (this._mediaManager) {
|
||||
this._mediaManager.resetSelections();
|
||||
this._mediaManager.open();
|
||||
return;
|
||||
}
|
||||
|
||||
MediaManager = window.wp.media.view.MediaFrame.Select.extend({
|
||||
|
||||
initialize: function () {
|
||||
window.wp.media.view.MediaFrame.prototype.initialize.apply(this, arguments);
|
||||
|
||||
_.defaults(this.options, {
|
||||
multiple: true,
|
||||
editing: false,
|
||||
state: 'insert'
|
||||
});
|
||||
|
||||
this.createSelection();
|
||||
this.createStates();
|
||||
this.bindHandlers();
|
||||
this.createIframeStates();
|
||||
|
||||
// Hide title
|
||||
this.$el.addClass('hide-title');
|
||||
},
|
||||
|
||||
resetSelections: function () {
|
||||
this.state().get('selection').reset();
|
||||
},
|
||||
|
||||
createQuery: function (options) {
|
||||
var query = window.wp.media.query(options);
|
||||
return query;
|
||||
},
|
||||
|
||||
createStates: function () {
|
||||
var options = this.options;
|
||||
|
||||
// Add the default states.
|
||||
this.states.add([
|
||||
// Main states.
|
||||
new window.wp.media.controller.Library({
|
||||
id: 'insert',
|
||||
title: 'Add images',
|
||||
priority: 20,
|
||||
toolbar: 'main-insert',
|
||||
filterable: 'image',
|
||||
library: this.createQuery(options.library),
|
||||
multiple: options.multiple ? 'reset' : false,
|
||||
editable: false,
|
||||
|
||||
// If the user isn't allowed to edit fields,
|
||||
// can they still edit it locally?
|
||||
allowLocalEdits: false,
|
||||
|
||||
// Show the attachment display settings.
|
||||
displaySettings: false,
|
||||
// Update user settings when users adjust the
|
||||
// attachment display settings.
|
||||
displayUserSettings: false
|
||||
})
|
||||
]);
|
||||
|
||||
if (window.wp.media.view.settings.post.featuredImageId) {
|
||||
this.states.add(new window.wp.media.controller.FeaturedImage());
|
||||
}
|
||||
},
|
||||
|
||||
bindHandlers: function () {
|
||||
var handlers;
|
||||
// from Select
|
||||
this.on('router:create:browse', this.createRouter, this);
|
||||
this.on('router:render:browse', this.browseRouter, this);
|
||||
this.on('content:create:browse', this.browseContent, this);
|
||||
this.on('content:render:upload', this.uploadContent, this);
|
||||
this.on('toolbar:create:select', this.createSelectToolbar, this);
|
||||
|
||||
this.on('menu:create:gallery', this.createMenu, this);
|
||||
this.on('toolbar:create:main-insert', this.createToolbar, this);
|
||||
this.on('toolbar:create:main-gallery', this.createToolbar, this);
|
||||
this.on('toolbar:create:main-embed', this.mainEmbedToolbar, this);
|
||||
|
||||
this.on('updateExcluded', this.browseContent, this);
|
||||
|
||||
handlers = {
|
||||
content: {
|
||||
embed: 'embedContent',
|
||||
'edit-selection': 'editSelectionContent'
|
||||
},
|
||||
toolbar: {
|
||||
'main-insert': 'mainInsertToolbar'
|
||||
}
|
||||
};
|
||||
|
||||
_.each(handlers, function (regionHandlers, region) {
|
||||
_.each(regionHandlers, function (callback, handler) {
|
||||
this.on(region + ':render:' + handler, this[callback], this);
|
||||
}, this);
|
||||
}, this);
|
||||
},
|
||||
|
||||
uploadContent: function () {
|
||||
window.wp.media.view.MediaFrame.Select.prototype.uploadContent.apply(this, arguments);
|
||||
this.$el.addClass('hide-toolbar');
|
||||
},
|
||||
|
||||
// Content
|
||||
embedContent: function () {
|
||||
var view = new window.wp.media.view.Embed({
|
||||
controller: this,
|
||||
model: this.state()
|
||||
}).render();
|
||||
|
||||
this.content.set(view);
|
||||
view.url.focus();
|
||||
},
|
||||
|
||||
editSelectionContent: function () {
|
||||
var state = this.state();
|
||||
var selection = state.get('selection');
|
||||
var view;
|
||||
|
||||
view = new window.wp.media.view.AttachmentsBrowser({
|
||||
controller: this,
|
||||
collection: selection,
|
||||
selection: selection,
|
||||
model: state,
|
||||
sortable: true,
|
||||
search: false,
|
||||
dragInfo: true,
|
||||
|
||||
AttachmentView: window.wp.media.view.Attachment.EditSelection
|
||||
}).render();
|
||||
|
||||
view.toolbar.set('backToLibrary', {
|
||||
text: 'Return to library',
|
||||
priority: -100,
|
||||
|
||||
click: function () {
|
||||
this.controller.content.mode('browse');
|
||||
}
|
||||
});
|
||||
|
||||
// Browse our library of attachments.
|
||||
this.content.set(view);
|
||||
},
|
||||
|
||||
// Toolbars
|
||||
selectionStatusToolbar: function (view) {
|
||||
var editable = this.state().get('editable');
|
||||
|
||||
view.set('selection', new window.wp.media.view.Selection({
|
||||
controller: this,
|
||||
collection: this.state().get('selection'),
|
||||
priority: -40,
|
||||
|
||||
// If the selection is editable, pass the callback to
|
||||
// switch the content mode.
|
||||
editable: editable && function () {
|
||||
this.controller.content.mode('edit-selection');
|
||||
}
|
||||
}).render());
|
||||
},
|
||||
|
||||
mainInsertToolbar: function (view) {
|
||||
var controller = this;
|
||||
|
||||
this.selectionStatusToolbar(view);
|
||||
|
||||
view.set('insert', {
|
||||
style: 'primary',
|
||||
priority: 80,
|
||||
text: 'Select Image',
|
||||
requires: { selection: true },
|
||||
|
||||
click: function () {
|
||||
var state = controller.state();
|
||||
var selection = state.get('selection');
|
||||
|
||||
controller.close();
|
||||
state.trigger('insert', selection).reset();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
mainEmbedToolbar: function (toolbar) {
|
||||
var tbar = toolbar;
|
||||
tbar.view = new window.wp.media.view.Toolbar.Embed({
|
||||
controller: this,
|
||||
text: 'Add images'
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
theFrame = new MediaManager({
|
||||
id: 'mailpoet-media-manager',
|
||||
frame: 'select',
|
||||
title: 'Select image',
|
||||
editing: false,
|
||||
multiple: false,
|
||||
library: {
|
||||
type: 'image'
|
||||
},
|
||||
displaySettings: false,
|
||||
button: {
|
||||
text: 'Select'
|
||||
}
|
||||
});
|
||||
this._mediaManager = theFrame;
|
||||
|
||||
this._mediaManager.on('insert', function () {
|
||||
// Append media manager image selections to Images tab
|
||||
var selection = theFrame.state().get('selection');
|
||||
selection.each(function (attachment) {
|
||||
var sizes = attachment.get('sizes');
|
||||
// Following advice from Becs, the target width should
|
||||
// be a double of one column width to render well on
|
||||
// retina screen devices
|
||||
var targetImageWidth = 1320;
|
||||
|
||||
// Pick the width that is closest to target width
|
||||
var increasingByWidthDifference = _.sortBy(
|
||||
_.keys(sizes),
|
||||
function (size) {
|
||||
return Math.abs(targetImageWidth - sizes[size].width);
|
||||
}
|
||||
);
|
||||
var bestWidth = sizes[_.first(increasingByWidthDifference)].width;
|
||||
var imagesOfBestWidth = _.filter(
|
||||
_.values(sizes),
|
||||
function (size) { return size.width === bestWidth; }
|
||||
);
|
||||
|
||||
// Maximize the height if there are multiple images with same width
|
||||
var mainSize = _.max(imagesOfBestWidth, function (size) { return size.height; });
|
||||
|
||||
if (that.options.onSelect) {
|
||||
that.view[that.options.onSelect]({
|
||||
height: mainSize.height + 'px',
|
||||
width: mainSize.width + 'px',
|
||||
src: mainSize.url,
|
||||
alt: (attachment.get('alt') !== '' && attachment.get('alt') !== undefined) ? attachment.get('alt') : attachment.get('title')
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
this._mediaManager.open();
|
||||
},
|
||||
onBeforeDestroy: function () {
|
||||
if (typeof this._mediaManager === 'object') {
|
||||
this._mediaManager.remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
@ -75,6 +75,11 @@ define([
|
||||
});
|
||||
|
||||
Module.ImageBlockSettingsView = base.BlockSettingsView.extend({
|
||||
behaviors: _.extend({}, base.BlockSettingsView.prototype.behaviors, {
|
||||
MediaManagerBehavior: {
|
||||
onSelect: 'onImageSelect'
|
||||
}
|
||||
}),
|
||||
onRender: function () {
|
||||
MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-full-width'), {
|
||||
tooltipId: 'tooltip-editor-full-width',
|
||||
@ -89,11 +94,9 @@ define([
|
||||
events: function () {
|
||||
return {
|
||||
'input .mailpoet_field_image_link': _.partial(this.changeField, 'link'),
|
||||
'input .mailpoet_field_image_address': 'changeAddress',
|
||||
'input .mailpoet_field_image_alt_text': _.partial(this.changeField, 'alt'),
|
||||
'change .mailpoet_field_image_full_width': _.partial(this.changeBoolCheckboxField, 'fullWidth'),
|
||||
'change .mailpoet_field_image_alignment': _.partial(this.changeField, 'styles.block.textAlign'),
|
||||
'click .mailpoet_field_image_select_another_image': 'showMediaManager',
|
||||
'click .mailpoet_done_editing': 'close',
|
||||
'input .mailpoet_field_image_width': _.partial(this.updateValueAndCall, '.mailpoet_field_image_width_input', _.partial(this.changePixelField, 'width').bind(this)),
|
||||
'change .mailpoet_field_image_width': _.partial(this.updateValueAndCall, '.mailpoet_field_image_width_input', _.partial(this.changePixelField, 'width').bind(this)),
|
||||
@ -120,284 +123,10 @@ define([
|
||||
this.$('.mailpoet_field_image_width').val(width);
|
||||
this.$('.mailpoet_field_image_width_input').val(width);
|
||||
},
|
||||
initialize: function (options) {
|
||||
base.BlockSettingsView.prototype.initialize.apply(this, arguments);
|
||||
|
||||
if (options.showImageManager) {
|
||||
this.showMediaManager();
|
||||
}
|
||||
},
|
||||
showMediaManager: function () {
|
||||
var that = this;
|
||||
var MediaManager;
|
||||
var theFrame;
|
||||
if (this._mediaManager) {
|
||||
this._mediaManager.resetSelections();
|
||||
this._mediaManager.open();
|
||||
return;
|
||||
}
|
||||
|
||||
MediaManager = window.wp.media.view.MediaFrame.Select.extend({
|
||||
|
||||
initialize: function () {
|
||||
window.wp.media.view.MediaFrame.prototype.initialize.apply(this, arguments);
|
||||
|
||||
_.defaults(this.options, {
|
||||
multiple: true,
|
||||
editing: false,
|
||||
state: 'insert'
|
||||
});
|
||||
|
||||
this.createSelection();
|
||||
this.createStates();
|
||||
this.bindHandlers();
|
||||
this.createIframeStates();
|
||||
|
||||
// Hide title
|
||||
this.$el.addClass('hide-title');
|
||||
},
|
||||
|
||||
resetSelections: function () {
|
||||
this.state().get('selection').reset();
|
||||
},
|
||||
|
||||
createQuery: function (options) {
|
||||
var query = window.wp.media.query(options);
|
||||
return query;
|
||||
},
|
||||
|
||||
createStates: function () {
|
||||
var options = this.options;
|
||||
|
||||
// Add the default states.
|
||||
this.states.add([
|
||||
// Main states.
|
||||
new window.wp.media.controller.Library({
|
||||
id: 'insert',
|
||||
title: 'Add images',
|
||||
priority: 20,
|
||||
toolbar: 'main-insert',
|
||||
filterable: 'image',
|
||||
library: this.createQuery(options.library),
|
||||
multiple: options.multiple ? 'reset' : false,
|
||||
editable: false,
|
||||
|
||||
// If the user isn't allowed to edit fields,
|
||||
// can they still edit it locally?
|
||||
allowLocalEdits: false,
|
||||
|
||||
// Show the attachment display settings.
|
||||
displaySettings: false,
|
||||
// Update user settings when users adjust the
|
||||
// attachment display settings.
|
||||
displayUserSettings: false
|
||||
})
|
||||
]);
|
||||
|
||||
if (window.wp.media.view.settings.post.featuredImageId) {
|
||||
this.states.add(new window.wp.media.controller.FeaturedImage());
|
||||
}
|
||||
},
|
||||
|
||||
bindHandlers: function () {
|
||||
var handlers;
|
||||
// from Select
|
||||
this.on('router:create:browse', this.createRouter, this);
|
||||
this.on('router:render:browse', this.browseRouter, this);
|
||||
this.on('content:create:browse', this.browseContent, this);
|
||||
this.on('content:render:upload', this.uploadContent, this);
|
||||
this.on('toolbar:create:select', this.createSelectToolbar, this);
|
||||
|
||||
this.on('menu:create:gallery', this.createMenu, this);
|
||||
this.on('toolbar:create:main-insert', this.createToolbar, this);
|
||||
this.on('toolbar:create:main-gallery', this.createToolbar, this);
|
||||
this.on('toolbar:create:main-embed', this.mainEmbedToolbar, this);
|
||||
|
||||
this.on('updateExcluded', this.browseContent, this);
|
||||
|
||||
handlers = {
|
||||
content: {
|
||||
embed: 'embedContent',
|
||||
'edit-selection': 'editSelectionContent'
|
||||
},
|
||||
toolbar: {
|
||||
'main-insert': 'mainInsertToolbar'
|
||||
}
|
||||
};
|
||||
|
||||
_.each(handlers, function (regionHandlers, region) {
|
||||
_.each(regionHandlers, function (callback, handler) {
|
||||
this.on(region + ':render:' + handler, this[callback], this);
|
||||
}, this);
|
||||
}, this);
|
||||
},
|
||||
|
||||
uploadContent: function () {
|
||||
window.wp.media.view.MediaFrame.Select.prototype.uploadContent.apply(this, arguments);
|
||||
this.$el.addClass('hide-toolbar');
|
||||
},
|
||||
|
||||
// Content
|
||||
embedContent: function () {
|
||||
var view = new window.wp.media.view.Embed({
|
||||
controller: this,
|
||||
model: this.state()
|
||||
}).render();
|
||||
|
||||
this.content.set(view);
|
||||
view.url.focus();
|
||||
},
|
||||
|
||||
editSelectionContent: function () {
|
||||
var state = this.state();
|
||||
var selection = state.get('selection');
|
||||
var view;
|
||||
|
||||
view = new window.wp.media.view.AttachmentsBrowser({
|
||||
controller: this,
|
||||
collection: selection,
|
||||
selection: selection,
|
||||
model: state,
|
||||
sortable: true,
|
||||
search: false,
|
||||
dragInfo: true,
|
||||
|
||||
AttachmentView: window.wp.media.view.Attachment.EditSelection
|
||||
}).render();
|
||||
|
||||
view.toolbar.set('backToLibrary', {
|
||||
text: 'Return to library',
|
||||
priority: -100,
|
||||
|
||||
click: function () {
|
||||
this.controller.content.mode('browse');
|
||||
}
|
||||
});
|
||||
|
||||
// Browse our library of attachments.
|
||||
this.content.set(view);
|
||||
},
|
||||
|
||||
// Toolbars
|
||||
selectionStatusToolbar: function (view) {
|
||||
var editable = this.state().get('editable');
|
||||
|
||||
view.set('selection', new window.wp.media.view.Selection({
|
||||
controller: this,
|
||||
collection: this.state().get('selection'),
|
||||
priority: -40,
|
||||
|
||||
// If the selection is editable, pass the callback to
|
||||
// switch the content mode.
|
||||
editable: editable && function () {
|
||||
this.controller.content.mode('edit-selection');
|
||||
}
|
||||
}).render());
|
||||
},
|
||||
|
||||
mainInsertToolbar: function (view) {
|
||||
var controller = this;
|
||||
|
||||
this.selectionStatusToolbar(view);
|
||||
|
||||
view.set('insert', {
|
||||
style: 'primary',
|
||||
priority: 80,
|
||||
text: 'Select Image',
|
||||
requires: { selection: true },
|
||||
|
||||
click: function () {
|
||||
var state = controller.state();
|
||||
var selection = state.get('selection');
|
||||
|
||||
controller.close();
|
||||
state.trigger('insert', selection).reset();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
mainEmbedToolbar: function (toolbar) {
|
||||
var tbar = toolbar;
|
||||
tbar.view = new window.wp.media.view.Toolbar.Embed({
|
||||
controller: this,
|
||||
text: 'Add images'
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
theFrame = new MediaManager({
|
||||
id: 'mailpoet-media-manager',
|
||||
frame: 'select',
|
||||
title: 'Select image',
|
||||
editing: false,
|
||||
multiple: false,
|
||||
library: {
|
||||
type: 'image'
|
||||
},
|
||||
displaySettings: false,
|
||||
button: {
|
||||
text: 'Select'
|
||||
}
|
||||
});
|
||||
this._mediaManager = theFrame;
|
||||
|
||||
this._mediaManager.on('insert', function () {
|
||||
// Append media manager image selections to Images tab
|
||||
var selection = theFrame.state().get('selection');
|
||||
selection.each(function (attachment) {
|
||||
var sizes = attachment.get('sizes');
|
||||
// Following advice from Becs, the target width should
|
||||
// be a double of one column width to render well on
|
||||
// retina screen devices
|
||||
var targetImageWidth = 1320;
|
||||
|
||||
// Pick the width that is closest to target width
|
||||
var increasingByWidthDifference = _.sortBy(
|
||||
_.keys(sizes),
|
||||
function (size) { return Math.abs(targetImageWidth - sizes[size].width); }
|
||||
);
|
||||
var bestWidth = sizes[_.first(increasingByWidthDifference)].width;
|
||||
var imagesOfBestWidth = _.filter(
|
||||
_.values(sizes),
|
||||
function (size) { return size.width === bestWidth; }
|
||||
);
|
||||
|
||||
// Maximize the height if there are multiple images with same width
|
||||
var mainSize = _.max(imagesOfBestWidth, function (size) { return size.height; });
|
||||
|
||||
that.model.set({
|
||||
height: mainSize.height + 'px',
|
||||
width: mainSize.width + 'px',
|
||||
src: mainSize.url,
|
||||
alt: (attachment.get('alt') !== '' && attachment.get('alt') !== undefined) ? attachment.get('alt') : attachment.get('title')
|
||||
});
|
||||
onImageSelect: function (image) {
|
||||
this.model.set(image);
|
||||
// Rerender settings view due to changes from outside of settings view
|
||||
that.render();
|
||||
});
|
||||
});
|
||||
|
||||
this._mediaManager.open();
|
||||
},
|
||||
changeAddress: function (event) {
|
||||
var src = jQuery(event.target).val();
|
||||
var image = new Image();
|
||||
|
||||
image.onload = function () {
|
||||
this.model.set({
|
||||
src: src,
|
||||
width: image.naturalWidth + 'px',
|
||||
height: image.naturalHeight + 'px'
|
||||
});
|
||||
}.bind(this);
|
||||
|
||||
image.src = src;
|
||||
},
|
||||
onBeforeDestroy: function () {
|
||||
base.BlockSettingsView.prototype.onBeforeDestroy.apply(this, arguments);
|
||||
if (typeof this._mediaManager === 'object') {
|
||||
this._mediaManager.remove();
|
||||
}
|
||||
this.render();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -80,7 +80,7 @@
|
||||
</div>
|
||||
<hr />
|
||||
<div class="mailpoet_form_field">
|
||||
<input type="button" name="select-another-image" class="button button-secondary mailpoet_button_full mailpoet_field_image_select_another_image" value="<%= __('Select another image') | escape('html_attr') %>" />
|
||||
<input type="button" name="select-image" class="button button-secondary mailpoet_button_full mailpoet_field_image_select_image" value="<%= __('Select another image') | escape('html_attr') %>" />
|
||||
</div>
|
||||
|
||||
<div class="mailpoet_form_field">
|
||||
|
@ -310,6 +310,7 @@ var adminConfig = {
|
||||
'newsletter_editor/behaviors/DraggableBehavior.js',
|
||||
'newsletter_editor/behaviors/HighlightContainerBehavior.js',
|
||||
'newsletter_editor/behaviors/HighlightEditingBehavior.js',
|
||||
'newsletter_editor/behaviors/MediaManagerBehavior.js',
|
||||
'newsletter_editor/behaviors/ResizableBehavior.js',
|
||||
'newsletter_editor/behaviors/SortableBehavior.js',
|
||||
'newsletter_editor/behaviors/ShowSettingsBehavior.js',
|
||||
@ -414,6 +415,7 @@ var testConfig = {
|
||||
'newsletter_editor/behaviors/DraggableBehavior.js',
|
||||
'newsletter_editor/behaviors/HighlightContainerBehavior.js',
|
||||
'newsletter_editor/behaviors/HighlightEditingBehavior.js',
|
||||
'newsletter_editor/behaviors/MediaManagerBehavior.js',
|
||||
'newsletter_editor/behaviors/ResizableBehavior.js',
|
||||
'newsletter_editor/behaviors/SortableBehavior.js',
|
||||
'newsletter_editor/behaviors/ShowSettingsBehavior.js',
|
||||
|
Reference in New Issue
Block a user