diff --git a/assets/js/src/newsletter_editor/App.js b/assets/js/src/newsletter_editor/App.js index 725e5442e7..d1116eae9e 100644 --- a/assets/js/src/newsletter_editor/App.js +++ b/assets/js/src/newsletter_editor/App.js @@ -1,21 +1,14 @@ define([ 'backbone', 'backbone.marionette', + 'backbone.radio', 'jquery', 'underscore', 'handlebars', 'handlebars_helpers' - ], function(Backbone, Marionette, jQuery, _, Handlebars) { + ], function(Backbone, Marionette, Radio, jQuery, _, Handlebars) { - var app = new Marionette.Application(), AppView; - - // Decoupled communication between application components - app.getChannel = function(channel) { - if (channel === undefined) return app.channel; - return Radio.channel(channel); - }; - - AppView = Marionette.LayoutView.extend({ + var AppView = Marionette.View.extend({ el: '#mailpoet_editor', regions: { stylesRegion: '#mailpoet_editor_styles', @@ -26,10 +19,23 @@ define([ }, }); - app.on('start', function(options) { - app._appView = new AppView(); + var EditorApplication = Marionette.Application.extend({ + region: '#mailpoet_editor', + + onStart: function() { + this._appView = new AppView(); + this.showView(this._appView); + }, + + getChannel: function(channel) { + if (channel === undefined) channel = 'global'; + return Radio.channel(channel); + } }); + var app = new EditorApplication(); window.EditorApplication = app; + return app; + }); diff --git a/assets/js/src/newsletter_editor/behaviors/ContainerDropZoneBehavior.js b/assets/js/src/newsletter_editor/behaviors/ContainerDropZoneBehavior.js index fd5bb27711..285230c4c4 100644 --- a/assets/js/src/newsletter_editor/behaviors/ContainerDropZoneBehavior.js +++ b/assets/js/src/newsletter_editor/behaviors/ContainerDropZoneBehavior.js @@ -71,6 +71,7 @@ define([ markerWidth = '', markerHeight = '', containerOffset = element.offset(), + viewCollection = that.getCollection(), marker, targetModel, targetView, targetElement, topOffset, leftOffset, isLastBlockInsertion, $targetBlock, margin; @@ -80,19 +81,19 @@ define([ element.find('.mailpoet_drop_marker').remove(); // Allow empty collections to handle their own drop marking - if (view.model.get('blocks').isEmpty()) return; + if (viewCollection.isEmpty()) return; - if (view.collection.length === 0) { + if (viewCollection.length === 0) { targetElement = element.find(view.childViewContainer); topOffset = targetElement.offset().top - element.offset().top; leftOffset = targetElement.offset().left - element.offset().left; markerWidth = targetElement.width(); markerHeight = targetElement.height(); } else { - isLastBlockInsertion = view.collection.length === dropPosition.index; - targetModel = isLastBlockInsertion ? view.collection.at(dropPosition.index - 1) : view.collection.at(dropPosition.index); + isLastBlockInsertion = that.getCollection().length === dropPosition.index; + targetModel = isLastBlockInsertion ? viewCollection.at(dropPosition.index - 1) : viewCollection.at(dropPosition.index); - targetView = view.children.findByModel(targetModel); + targetView = that.getChildren().findByModel(targetModel); targetElement = targetView.$el; topOffset = targetElement.offset().top - containerOffset.top; @@ -135,10 +136,10 @@ define([ if (dropPosition.index === 0) { marker.addClass('mailpoet_drop_marker_first'); } - if (view.collection.length - 1 === dropPosition.index) { + if (viewCollection.length - 1 === dropPosition.index) { marker.addClass('mailpoet_drop_marker_last'); } - if (dropPosition.index > 0 && view.collection.length - 1 > dropPosition.index) { + if (dropPosition.index > 0 && viewCollection.length - 1 > dropPosition.index) { marker.addClass('mailpoet_drop_marker_middle'); } marker.addClass('mailpoet_drop_marker_' + dropPosition.position); @@ -147,9 +148,9 @@ define([ // compensated for to position marker right in the middle of two // blocks if (dropPosition.position === 'before') { - $targetBlock = view.children.findByModel(view.collection.at(dropPosition.index-1)).$el; + $targetBlock = that.getChildren().findByModel(viewCollection.at(dropPosition.index-1)).$el; } else { - $targetBlock = view.children.findByModel(view.collection.at(dropPosition.index)).$el; + $targetBlock = that.getChildren().findByModel(viewCollection.at(dropPosition.index)).$el; } margin = $targetBlock.outerHeight(true) - $targetBlock.outerHeight(); @@ -182,6 +183,7 @@ define([ view.model.get('blocks').length ), droppableModel = event.draggable.getDropModel(), + viewCollection = that.getCollection(), droppedView, droppedModel, index, tempCollection, tempCollection2; if (dropPosition === undefined) return; @@ -196,22 +198,22 @@ define([ orientation: 'vertical', }); tempCollection.get('blocks').add(droppableModel); - view.collection.add(tempCollection, {at: index}); + viewCollection.add(tempCollection, {at: index}); } else { - view.collection.add(droppableModel, {at: index}); + viewCollection.add(droppableModel, {at: index}); } - droppedView = view.children.findByModel(droppableModel); + droppedView = that.getChildren().findByModel(droppableModel); } else { // Special insertion by replacing target block with collection // and inserting dropModel into that - var tempModel = view.collection.at(dropPosition.index); + var tempModel = viewCollection.at(dropPosition.index); tempCollection = new (EditorApplication.getBlockTypeModel('container'))({ orientation: (view.model.get('orientation') === 'vertical') ? 'horizontal' : 'vertical', }); - view.collection.remove(tempModel); + viewCollection.remove(tempModel); if (tempCollection.get('orientation') === 'horizontal') { if (dropPosition.position === 'before') { @@ -242,10 +244,10 @@ define([ tempCollection.get('blocks').add(droppableModel); } } - view.collection.add(tempCollection, {at: dropPosition.index}); + viewCollection.add(tempCollection, {at: dropPosition.index}); // Call post add actions - droppedView = view.children.findByModel(tempCollection).children.findByModel(droppableModel); + droppedView = that.getChildren().findByModel(tempCollection).children.findByModel(droppableModel); } // Call post add actions @@ -290,7 +292,7 @@ define([ unsafe = !!unsafe; - if (this.view.collection.length === 0) { + if (this.getCollection().length === 0) { return { insertionType: 'normal', index: 0, @@ -327,7 +329,7 @@ define([ index = indexAndPosition.index; } - if (!unsafe && orientation === 'vertical' && insertionType === 'special' && this.view.collection.at(index).get('orientation') === 'horizontal') { + if (!unsafe && orientation === 'vertical' && insertionType === 'special' && this.getCollection().at(index).get('orientation') === 'horizontal') { // Prevent placing horizontal container in another horizontal container, // which would allow breaking the column limit. // Switch that to normal insertion @@ -356,7 +358,7 @@ define([ var index = this._computeCellIndex(eventX, eventY), // TODO: Handle case when there are no children, container is empty - targetView = this.view.children.findByModel(this.view.collection.at(index)), + targetView = this.getChildren().findByModel(this.getCollection().at(index)), orientation = this.view.model.get('orientation'), element = targetView.$el, eventOffset, closeOffset, elementDimension; @@ -391,7 +393,7 @@ define([ _computeCellIndex: function(eventX, eventY) { var orientation = this.view.model.get('orientation'), eventOffset = (orientation === 'vertical') ? eventY : eventX, - resultView = this.view.children.find(function(view) { + resultView = this.getChildren().find(function(view) { var element = view.$el, closeOffset, farOffset; @@ -414,15 +416,24 @@ define([ _canAcceptNormalInsertion: function() { var orientation = this.view.model.get('orientation'), depth = this.view.renderOptions.depth, - childCount = this.view.children.length; + childCount = this.getChildren().length; // Note that depth is zero indexed. Root container has depth=0 return orientation === 'vertical' || (orientation === 'horizontal' && depth === 1 && childCount < this.options.columnLimit); }, _canAcceptSpecialInsertion: function() { var orientation = this.view.model.get('orientation'), depth = this.view.renderOptions.depth, - childCount = this.view.children.length; + childCount = this.getChildren().length; return depth === 0 || (depth === 1 && orientation === 'horizontal' && childCount <= this.options.columnLimit); }, + getCollectionView: function() { + return this.view.getChildView('blocks'); + }, + getChildren: function() { + return this.getCollectionView().children; + }, + getCollection: function() { + return this.getCollectionView().collection; + } }); }); diff --git a/assets/js/src/newsletter_editor/blocks/automatedLatestContent.js b/assets/js/src/newsletter_editor/blocks/automatedLatestContent.js index bdcc8bbba9..430e0a1496 100644 --- a/assets/js/src/newsletter_editor/blocks/automatedLatestContent.js +++ b/assets/js/src/newsletter_editor/blocks/automatedLatestContent.js @@ -151,8 +151,8 @@ define([ emptyContainerMessage: MailPoet.I18n.t('noPostsToDisplay'), }; this.toolsView = new Module.AutomatedLatestContentBlockToolsView({ model: this.model }); - this.toolsRegion.show(this.toolsView); - this.postsRegion.show(new ContainerView({ model: this.model.get('_container'), renderOptions: renderOptions })); + this.showChildView('toolsRegion', this.toolsView); + this.showChildView('postsRegion', new ContainerView({ model: this.model.get('_container'), renderOptions: renderOptions })); }, }); @@ -189,11 +189,6 @@ define([ "click .mailpoet_done_editing": "close", }; }, - templateHelpers: function() { - return { - model: this.model.toJSON(), - }; - }, onRender: function() { var that = this; @@ -377,7 +372,7 @@ define([ }, }); - App.on('before:start', function() { + App.on('before:start', function(App, options) { App.registerBlockType('automatedLatestContent', { blockModel: Module.AutomatedLatestContentBlockModel, blockView: Module.AutomatedLatestContentBlockView, @@ -390,7 +385,7 @@ define([ }); }); - App.on('start', function() { + App.on('start', function(App, options) { App._ALCSupervisor = new Module.ALCSupervisor(); App._ALCSupervisor.refresh(); }); diff --git a/assets/js/src/newsletter_editor/blocks/base.js b/assets/js/src/newsletter_editor/blocks/base.js index 28fc299526..7e5a172305 100644 --- a/assets/js/src/newsletter_editor/blocks/base.js +++ b/assets/js/src/newsletter_editor/blocks/base.js @@ -17,7 +17,7 @@ define([ "use strict"; var Module = {}, - AugmentedView = Marionette.LayoutView.extend({}); + AugmentedView = Marionette.View.extend({}); Module.BlockModel = SuperModel.extend({ stale: [], // Attributes to be removed upon saving @@ -82,7 +82,7 @@ define([ }, HighlightEditingBehavior: {}, }, - templateHelpers: function() { + templateContext: function() { return { model: this.model.toJSON(), viewCid: this.cid, @@ -125,6 +125,12 @@ define([ return this.model.clone(); }.bind(this); }, + disableDragging: function() { + this.$el.addClass('mailpoet_ignore_drag'); + }, + enableDragging: function() { + this.$el.removeClass('mailpoet_ignore_drag'); + }, showBlock: function() { if (this._isFirstRender) { this.transitionIn(); @@ -193,7 +199,7 @@ define([ this.on('hideTools', this.hideDeletionConfirmation, this); this.on('showSettings', this.changeSettings); }, - templateHelpers: function() { + templateContext: function() { return { model: this.model.toJSON(), viewCid: this.cid, @@ -217,7 +223,7 @@ define([ }, }); - Module.BlockSettingsView = Marionette.LayoutView.extend({ + Module.BlockSettingsView = Marionette.View.extend({ className: 'mailpoet_editor_settings', behaviors: { ColorPickerBehavior: {}, @@ -240,6 +246,11 @@ define([ MailPoet.Modal.panel(panelParams); } }, + templateContext: function() { + return { + model: this.model.toJSON() + }; + }, close: function(event) { this.destroy(); }, @@ -271,7 +282,7 @@ define([ }, }); - Module.WidgetView = Marionette.ItemView.extend({ + Module.WidgetView = Marionette.View.extend({ className: 'mailpoet_widget mailpoet_droppable_block mailpoet_droppable_widget', behaviors: { DraggableBehavior: { diff --git a/assets/js/src/newsletter_editor/blocks/button.js b/assets/js/src/newsletter_editor/blocks/button.js index dd3aa38f4a..8afafe3486 100644 --- a/assets/js/src/newsletter_editor/blocks/button.js +++ b/assets/js/src/newsletter_editor/blocks/button.js @@ -56,7 +56,7 @@ define([ }, onRender: function() { this.toolsView = new Module.ButtonBlockToolsView({ model: this.model }); - this.toolsRegion.show(this.toolsView); + this.showChildView('toolsRegion', this.toolsView); }, }); @@ -98,12 +98,11 @@ define([ "click .mailpoet_done_editing": "close", }; }, - templateHelpers: function() { - return { - model: this.model.toJSON(), + templateContext: function() { + return _.extend({}, base.BlockView.prototype.templateContext.apply(this, arguments), { availableStyles: App.getAvailableStyles().toJSON(), renderOptions: this.renderOptions, - }; + }); }, applyToAll: function() { App.getChannel().trigger('replaceAllButtonStyles', _.pick(this.model.toJSON(), 'styles', 'type')); @@ -133,7 +132,7 @@ define([ }, }); - App.on('before:start', function() { + App.on('before:start', function(App, options) { App.registerBlockType('button', { blockModel: Module.ButtonBlockModel, blockView: Module.ButtonBlockView, diff --git a/assets/js/src/newsletter_editor/blocks/container.js b/assets/js/src/newsletter_editor/blocks/container.js index c30dadcb9d..025b9e0b20 100644 --- a/assets/js/src/newsletter_editor/blocks/container.js +++ b/assets/js/src/newsletter_editor/blocks/container.js @@ -74,29 +74,43 @@ define([ }, }); - Module.ContainerBlockView = Marionette.CompositeView.extend({ - regionClass: Marionette.Region, + Module.ContainerBlocksView = Marionette.CollectionView.extend({ + className: 'mailpoet_container', + childView: function(model) { + return App.getBlockTypeView(model.get('type')); + }, + childViewOptions: function() { + var newRenderOptions = _.clone(this.renderOptions); + if (newRenderOptions.depth !== undefined) { + newRenderOptions.depth += 1; + } + return { + renderOptions: newRenderOptions + }; + }, + emptyView: function() { return Module.ContainerBlockEmptyView; }, + emptyViewOptions: function() { return { renderOptions: this.renderOptions }; }, + initialize: function(options) { + this.renderOptions = options.renderOptions; + } + }); + + Module.ContainerBlockView = base.BlockView.extend({ + regions: _.extend({}, base.BlockView.prototype.regions, { + blocks: { + el: '> .mailpoet_container', + replaceElement: true + }, + }), className: 'mailpoet_block mailpoet_container_block mailpoet_droppable_block mailpoet_droppable_layout_block', getTemplate: function() { return templates.containerBlock; }, - childViewContainer: '> .mailpoet_container', - getEmptyView: function() { return Module.ContainerBlockEmptyView; }, - emptyViewOptions: function() { return { renderOptions: this.renderOptions }; }, - modelEvents: { - 'change': 'render', - 'delete': 'deleteBlock', - }, - events: { - "mouseenter": "showTools", - "mouseleave": "hideTools", + events: _.extend({}, base.BlockView.prototype.events, { "click .mailpoet_newsletter_layer_selector": "toggleEditingLayer", - }, - regions: { - toolsRegion: '> .mailpoet_tools', - }, + }), ui: { tools: '> .mailpoet_tools' }, - behaviors: { + behaviors: _.extend({}, base.BlockView.prototype.behaviors, { ContainerDropZoneBehavior: {}, DraggableBehavior: { cloneOriginal: true, @@ -125,8 +139,7 @@ define([ return view.renderOptions.depth === 1; }, }, - HighlightEditingBehavior: {} - }, + }), onDragSubstituteBy: function() { // For two and three column layouts display their respective widgets, // otherwise always default to one column layout widget @@ -137,39 +150,12 @@ define([ return Module.OneColumnContainerWidgetView; }, - constructor: function() { - // Set the block collection to be handled by this view as well - arguments[0].collection = arguments[0].model.get('blocks'); - Marionette.CompositeView.apply(this, arguments); - this.$el.addClass('mailpoet_editor_view_' + this.cid); - }, initialize: function(options) { + base.BlockView.prototype.initialize.apply(this, arguments); + this.renderOptions = _.defaults(options.renderOptions || {}, {}); - this.on('dom:refresh', this.showBlock, this); - this._isFirstRender = true; - }, - // Determines which view type should be used for a child - getChildView: function(model) { - // TODO: If type does not have a type registered, use a generic one - return App.getBlockTypeView(model.get('type')); - }, - childViewOptions: function() { - var newRenderOptions = _.clone(this.renderOptions); - if (newRenderOptions.depth !== undefined) { - newRenderOptions.depth += 1; - } - return { - renderOptions: newRenderOptions - }; - }, - templateHelpers: function() { - return { - model: this.model.toJSON(), - viewCid: this.cid, - }; }, onRender: function() { - this._rebuildRegions(); this.toolsView = new Module.ContainerBlockToolsView({ model: this.model, tools: { @@ -179,10 +165,15 @@ define([ layerSelector: false, }, }); - this.toolsRegion.show(this.toolsView); - }, - onBeforeDestroy: function() { - this.regionManager.destroy(); + this.showChildView('toolsRegion', this.toolsView); + this.showChildView('blocks', new Module.ContainerBlocksView({ + collection: this.model.get('blocks'), + renderOptions: this.renderOptions + })); + + // TODO: Look for a better way to do this than here + // Sets child container orientation HTML class here, as child CollectionView won't have access to model and will overwrite existing region element instead + this.$('> .mailpoet_container').attr('class', 'mailpoet_container mailpoet_container_' + this.model.get('orientation')); }, showTools: function() { if (this.renderOptions.depth === 1 && !this.$el.hasClass('mailpoet_container_layer_active')) { @@ -222,76 +213,14 @@ define([ } event.stopPropagation(); }, - _buildRegions: function(regions) { - var that = this; - - var defaults = { - regionClass: this.getOption('regionClass'), - parentEl: function() { return that.$el; } - }; - - return this.regionManager.addRegions(regions, defaults); - }, - _rebuildRegions: function() { - if (this.regionManager === undefined) { - this.regionManager = new Marionette.RegionManager(); - } - this.regionManager.destroy(); - _.extend(this, this._buildRegions(this.regions)); - }, - getDropFunc: function() { - return function() { - return this.model.clone(); - }.bind(this); - }, - showBlock: function() { - if (this._isFirstRender) { - this.transitionIn(); - this._isFirstRender = false; - } - }, - deleteBlock: function() { - this.transitionOut().done(function() { - this.model.destroy(); - }.bind(this)); - }, - transitionIn: function() { - return this._transition('slideDown', 'fadeIn', 'easeIn'); - }, - transitionOut: function() { - return this._transition('slideUp', 'fadeOut', 'easeOut'); - }, - _transition: function(slideDirection, fadeDirection, easing) { - var promise = jQuery.Deferred(); - - this.$el.velocity( - slideDirection, - { - duration: 250, - easing: easing, - complete: function() { - promise.resolve(); - }.bind(this), - } - ).velocity( - fadeDirection, - { - duration: 250, - easing: easing, - queue: false, // Do not enqueue, trigger animation in parallel - } - ); - - return promise; - }, }); - Module.ContainerBlockEmptyView = Marionette.ItemView.extend({ + Module.ContainerBlockEmptyView = Marionette.View.extend({ getTemplate: function() { return templates.containerEmpty; }, initialize: function(options) { this.renderOptions = _.defaults(options.renderOptions || {}, {}); }, - templateHelpers: function() { + templateContext: function() { return { isRoot: this.renderOptions.depth === 0, emptyContainerMessage: this.renderOptions.emptyContainerMessage || '', @@ -322,12 +251,12 @@ define([ }); }, onRender: function() { - this.columnsSettingsRegion.show(this._columnsSettingsView); + this.showChildView('columnsSettingsRegion', this._columnsSettingsView); }, }); Module.ContainerBlockColumnsSettingsView = Marionette.CollectionView.extend({ - getChildView: function() { return Module.ContainerBlockColumnSettingsView; }, + childView: function() { return Module.ContainerBlockColumnSettingsView; }, childViewOptions: function(model, index) { return { columnIndex: index, @@ -335,12 +264,12 @@ define([ }, }); - Module.ContainerBlockColumnSettingsView = Marionette.ItemView.extend({ + Module.ContainerBlockColumnSettingsView = Marionette.View.extend({ getTemplate: function() { return templates.containerBlockColumnSettings; }, initialize: function(options) { this.columnNumber = (options.columnIndex || 0) + 1; }, - templateHelpers: function() { + templateContext: function() { return { model: this.model.toJSON(), columnNumber: this.columnNumber, @@ -405,7 +334,7 @@ define([ }, }); - App.on('before:start', function() { + App.on('before:start', function(App, options) { App.registerBlockType('container', { blockModel: Module.ContainerBlockModel, blockView: Module.ContainerBlockView, diff --git a/assets/js/src/newsletter_editor/blocks/divider.js b/assets/js/src/newsletter_editor/blocks/divider.js index 3834b9e5b6..e46275d09f 100644 --- a/assets/js/src/newsletter_editor/blocks/divider.js +++ b/assets/js/src/newsletter_editor/blocks/divider.js @@ -59,14 +59,14 @@ define([ this.listenTo(this.model, 'change:src change:styles.block.backgroundColor change:styles.block.borderStyle change:styles.block.borderWidth change:styles.block.borderColor applyToAll', this.render); this.listenTo(this.model, 'change:styles.block.padding', this.changePadding); }, - templateHelpers: function() { + templateContext: function() { return _.extend({ totalHeight: parseInt(this.model.get('styles.block.padding'), 10)*2 + parseInt(this.model.get('styles.block.borderWidth')) + 'px', - }, base.BlockView.prototype.templateHelpers.apply(this)); + }, base.BlockView.prototype.templateContext.apply(this)); }, onRender: function() { this.toolsView = new Module.DividerBlockToolsView({ model: this.model }); - this.toolsRegion.show(this.toolsView); + this.showChildView('toolsRegion', this.toolsView); }, onBeforeDestroy: function() { App.getChannel().off('replaceAllDividers', this._replaceDividerHandler); @@ -104,12 +104,11 @@ define([ 'change:styles.block.borderColor': 'repaintDividerStyleOptions', }; }, - templateHelpers: function() { - return { - model: this.model.toJSON(), + templateContext: function() { + return _.extend({}, base.BlockView.prototype.templateContext.apply(this, arguments), { availableStyles: App.getAvailableStyles().toJSON(), renderOptions: this.renderOptions, - }; + }); }, changeStyle: function(event) { var style = jQuery(event.currentTarget).data('style'); @@ -140,7 +139,7 @@ define([ } }, }); - App.on('before:start', function() { + App.on('before:start', function(App, options) { App.registerBlockType('divider', { blockModel: Module.DividerBlockModel, blockView: Module.DividerBlockView, diff --git a/assets/js/src/newsletter_editor/blocks/footer.js b/assets/js/src/newsletter_editor/blocks/footer.js index e1f93f2a4b..cb8e047d83 100644 --- a/assets/js/src/newsletter_editor/blocks/footer.js +++ b/assets/js/src/newsletter_editor/blocks/footer.js @@ -55,7 +55,7 @@ define([ onDragSubstituteBy: function() { return Module.FooterWidgetView; }, onRender: function() { this.toolsView = new Module.FooterBlockToolsView({ model: this.model }); - this.toolsRegion.show(this.toolsView); + this.showChildView('toolsRegion', this.toolsView); }, onTextEditorChange: function(newContent) { this.model.set('text', newContent); @@ -68,12 +68,6 @@ define([ this.enableDragging(); this.enableShowingTools(); }, - disableDragging: function() { - this.$('.mailpoet_content').addClass('mailpoet_ignore_drag'); - }, - enableDragging: function() { - this.$('.mailpoet_content').removeClass('mailpoet_ignore_drag'); - }, }); Module.FooterBlockToolsView = base.BlockToolsView.extend({ @@ -96,11 +90,10 @@ define([ "click .mailpoet_done_editing": "close", }; }, - templateHelpers: function() { - return { - model: this.model.toJSON(), + templateContext: function() { + return _.extend({}, base.BlockView.prototype.templateContext.apply(this, arguments), { availableStyles: App.getAvailableStyles().toJSON(), - }; + }); }, }); @@ -116,7 +109,7 @@ define([ }, }); - App.on('before:start', function() { + App.on('before:start', function(App, options) { App.registerBlockType('footer', { blockModel: Module.FooterBlockModel, blockView: Module.FooterBlockView, diff --git a/assets/js/src/newsletter_editor/blocks/header.js b/assets/js/src/newsletter_editor/blocks/header.js index b1d2e6c8cd..eb74ed46d0 100644 --- a/assets/js/src/newsletter_editor/blocks/header.js +++ b/assets/js/src/newsletter_editor/blocks/header.js @@ -55,7 +55,7 @@ define([ onDragSubstituteBy: function() { return Module.HeaderWidgetView; }, onRender: function() { this.toolsView = new Module.HeaderBlockToolsView({ model: this.model }); - this.toolsRegion.show(this.toolsView); + this.showChildView('toolsRegion', this.toolsView); }, onTextEditorChange: function(newContent) { this.model.set('text', newContent); @@ -68,12 +68,6 @@ define([ this.enableDragging(); this.enableShowingTools(); }, - disableDragging: function() { - this.$('.mailpoet_content').addClass('mailpoet_ignore_drag'); - }, - enableDragging: function() { - this.$('.mailpoet_content').removeClass('mailpoet_ignore_drag'); - }, }); Module.HeaderBlockToolsView = base.BlockToolsView.extend({ @@ -96,11 +90,10 @@ define([ "click .mailpoet_done_editing": "close", }; }, - templateHelpers: function() { - return { - model: this.model.toJSON(), + templateContext: function() { + return _.extend({}, base.BlockView.prototype.templateContext.apply(this, arguments), { availableStyles: App.getAvailableStyles().toJSON(), - }; + }); }, }); @@ -116,7 +109,7 @@ define([ }, }); - App.on('before:start', function() { + App.on('before:start', function(App, options) { App.registerBlockType('header', { blockModel: Module.HeaderBlockModel, blockView: Module.HeaderBlockView, diff --git a/assets/js/src/newsletter_editor/blocks/image.js b/assets/js/src/newsletter_editor/blocks/image.js index ffca97a07e..b369249448 100644 --- a/assets/js/src/newsletter_editor/blocks/image.js +++ b/assets/js/src/newsletter_editor/blocks/image.js @@ -36,17 +36,17 @@ define([ className: "mailpoet_block mailpoet_image_block mailpoet_droppable_block", getTemplate: function() { return templates.imageBlock; }, onDragSubstituteBy: function() { return Module.ImageWidgetView; }, - templateHelpers: function() { + templateContext: function() { return _.extend({ imageMissingSrc: App.getConfig().get('urls.imageMissing'), - }, base.BlockView.prototype.templateHelpers.apply(this)); + }, base.BlockView.prototype.templateContext.apply(this)); }, behaviors: _.extend({}, base.BlockView.prototype.behaviors, { ShowSettingsBehavior: {}, }), onRender: function() { this.toolsView = new Module.ImageBlockToolsView({ model: this.model }); - this.toolsRegion.show(this.toolsView); + this.showChildView('toolsRegion', this.toolsView); if (this.model.get('fullWidth')) { this.$el.addClass('mailpoet_full_image'); @@ -365,7 +365,7 @@ define([ }); Module.ImageWidgetView = ImageWidgetView; - App.on('before:start', function() { + App.on('before:start', function(App, options) { App.registerBlockType('image', { blockModel: Module.ImageBlockModel, blockView: Module.ImageBlockView, diff --git a/assets/js/src/newsletter_editor/blocks/posts.js b/assets/js/src/newsletter_editor/blocks/posts.js index 321a11b490..64590b7fb5 100644 --- a/assets/js/src/newsletter_editor/blocks/posts.js +++ b/assets/js/src/newsletter_editor/blocks/posts.js @@ -166,8 +166,8 @@ define([ this.model.reply('blockView', this.notifyAboutSelf, this); }, onRender: function() { - if (!this.toolsRegion.hasView()) { - this.toolsRegion.show(this.toolsView); + if (!this.getRegion('toolsRegion').hasView()) { + this.showChildView('toolsRegion', this.toolsView); } this.trigger('showSettings'); @@ -177,7 +177,7 @@ define([ disableDragAndDrop: true, emptyContainerMessage: MailPoet.I18n.t('noPostsToDisplay'), }; - this.postsRegion.show(new ContainerView({ model: this.model.get('_transformedPosts'), renderOptions: renderOptions })); + this.showChildView('postsRegion', new ContainerView({ model: this.model.get('_transformedPosts'), renderOptions: renderOptions })); }, notifyAboutSelf: function() { return this; @@ -202,7 +202,7 @@ define([ 'click .mailpoet_settings_posts_show_post_selection': 'switchToPostSelection', 'click .mailpoet_settings_posts_insert_selected': 'insertPosts', }, - templateHelpers: function() { + templateContext: function() { return { model: this.model.toJSON(), }; @@ -259,16 +259,24 @@ define([ }, }); - var PostSelectionSettingsView = Marionette.CompositeView.extend({ - getTemplate: function() { return templates.postSelectionPostsBlockSettings; }, - getChildView: function() { return SinglePostSelectionSettingsView; }, - childViewContainer: '.mailpoet_post_selection_container', - getEmptyView: function() { return EmptyPostSelectionSettingsView; }, + var PostsSelectionCollectionView = Marionette.CollectionView.extend({ + childView: function() { return SinglePostSelectionSettingsView; }, + emptyView: function() { return EmptyPostSelectionSettingsView; }, childViewOptions: function() { return { - blockModel: this.model, + blockModel: this.blockModel, }; }, + initialize: function(options) { + this.blockModel = options.blockModel; + }, + }); + + var PostSelectionSettingsView = Marionette.View.extend({ + getTemplate: function() { return templates.postSelectionPostsBlockSettings; }, + regions: { + posts: '.mailpoet_post_selection_container', + }, events: function() { return { 'change .mailpoet_settings_posts_content_type': _.partial(this.changeField, 'contentType'), @@ -276,21 +284,19 @@ define([ 'input .mailpoet_posts_search_term': _.partial(this.changeField, 'search'), }; }, - constructor: function() { - // Set the block collection to be handled by this view as well - arguments[0].collection = arguments[0].model.get('_availablePosts'); - Marionette.CompositeView.apply(this, arguments); - }, onRender: function() { // Dynamically update available post types CommunicationComponent.getPostTypes().done(_.bind(this._updateContentTypes, this)); + var postsView = new PostsSelectionCollectionView({ + collection: this.model.get('_availablePosts'), + blockModel: this.model + }); + + this.showChildView('posts', postsView); }, onAttach: function() { var that = this; - // Dynamically update available post types - //CommunicationComponent.getPostTypes().done(_.bind(this._updateContentTypes, this)); - this.$('.mailpoet_posts_categories_and_tags').select2({ multiple: true, allowClear: true, @@ -372,18 +378,18 @@ define([ }, }); - var EmptyPostSelectionSettingsView = Marionette.ItemView.extend({ + var EmptyPostSelectionSettingsView = Marionette.View.extend({ getTemplate: function() { return templates.emptyPostPostsBlockSettings; }, }); - var SinglePostSelectionSettingsView = Marionette.ItemView.extend({ + var SinglePostSelectionSettingsView = Marionette.View.extend({ getTemplate: function() { return templates.singlePostPostsBlockSettings; }, events: function() { return { 'change .mailpoet_select_post_checkbox': 'postSelectionChange', }; }, - templateHelpers: function() { + templateContext: function() { return { model: this.model.toJSON(), index: this._index, @@ -428,7 +434,7 @@ define([ "change .mailpoet_posts_sort_by": _.partial(this.changeField, "sortBy"), }; }, - templateHelpers: function() { + templateContext: function() { return { model: this.model.toJSON(), }; @@ -520,7 +526,7 @@ define([ }, }); - App.on('before:start', function() { + App.on('before:start', function(App, options) { App.registerBlockType('posts', { blockModel: Module.PostsBlockModel, blockView: Module.PostsBlockView, diff --git a/assets/js/src/newsletter_editor/blocks/social.js b/assets/js/src/newsletter_editor/blocks/social.js index 4abaa8eb38..3d99a128fb 100644 --- a/assets/js/src/newsletter_editor/blocks/social.js +++ b/assets/js/src/newsletter_editor/blocks/social.js @@ -17,6 +17,7 @@ define([ base = BaseBlock, SocialBlockSettingsIconSelectorView, SocialBlockSettingsIconView, + SocialBlockSettingsIconCollectionView, SocialBlockSettingsStylesView; Module.SocialIconModel = SuperModel.extend({ @@ -82,13 +83,13 @@ define([ }, }); - var SocialIconView = Marionette.ItemView.extend({ + var SocialIconView = Marionette.View.extend({ tagName: 'span', getTemplate: function() { return templates.socialIconBlock; }, modelEvents: { 'change': 'render', }, - templateHelpers: function() { + templateContext: function() { var allIconSets = App.getAvailableStyles().get('socialIconSets'); return { model: this.model.toJSON(), @@ -98,150 +99,29 @@ define([ }, }); - Module.SocialBlockView = Marionette.CompositeView.extend({ - regionClass: Marionette.Region, + Module.SocialIconCollectionView = Marionette.CollectionView.extend({ + childView: SocialIconView, + }); + + Module.SocialBlockView = base.BlockView.extend({ className: 'mailpoet_block mailpoet_social_block mailpoet_droppable_block', getTemplate: function() { return templates.socialBlock; }, - childViewContainer: '.mailpoet_social', - modelEvents: { - 'change': 'render', - 'delete': 'deleteBlock', - }, - events: { - "mouseover": "showTools", - "mouseout": "hideTools", - }, - regions: { - toolsRegion: '> .mailpoet_tools', - }, + regions: _.extend({}, base.BlockView.prototype.regions, { + icons: '.mailpoet_social' + }), ui: { tools: '> .mailpoet_tools' }, - behaviors: { - DraggableBehavior: { - cloneOriginal: true, - hideOriginal: true, - onDrop: function(options) { - // After a clone of model has been dropped, cleanup - // and destroy self - options.dragBehavior.view.model.destroy(); - }, - onDragSubstituteBy: function(behavior) { - var WidgetView, node; - // When block is being dragged, display the widget icon instead. - // This will create an instance of block's widget view and - // use it's rendered DOM element instead of the content block - if (_.isFunction(behavior.view.onDragSubstituteBy)) { - WidgetView = new (behavior.view.onDragSubstituteBy())(); - WidgetView.render(); - node = WidgetView.$el.get(0).cloneNode(true); - WidgetView.destroy(); - return node; - } - }, - }, - HighlightEditingBehavior: {}, + behaviors: _.extend({}, base.BlockView.prototype.behaviors, { ShowSettingsBehavior: {}, - }, + }), onDragSubstituteBy: function() { return Module.SocialWidgetView; }, - constructor: function() { - // Set the block collection to be handled by this view as well - arguments[0].collection = arguments[0].model.get('icons'); - Marionette.CompositeView.apply(this, arguments); - }, - initialize: function() { - this.on('showSettings', this.showSettings, this); - this.on('dom:refresh', this.showBlock, this); - this._isFirstRender = true; - }, - // Determines which view type should be used for a child - childView: SocialIconView, - templateHelpers: function() { - return { - model: this.model.toJSON(), - viewCid: this.cid, - }; - }, onRender: function() { - this._rebuildRegions(); this.toolsView = new Module.SocialBlockToolsView({ model: this.model }); - this.toolsRegion.show(this.toolsView); - }, - onBeforeDestroy: function() { - this.regionManager.destroy(); - }, - showTools: function(_event) { - this.$(this.ui.tools).addClass('mailpoet_display_tools'); - _event.stopPropagation(); - }, - hideTools: function(_event) { - this.$(this.ui.tools).removeClass('mailpoet_display_tools'); - _event.stopPropagation(); - }, - showSettings: function(options) { - this.toolsView.triggerMethod('showSettings', options); - }, - getDropFunc: function() { - return function() { - return this.model.clone(); - }.bind(this); - }, - _buildRegions: function(regions) { - var that = this; - - var defaults = { - regionClass: this.getOption('regionClass'), - parentEl: function() { return that.$el; } - }; - - return this.regionManager.addRegions(regions, defaults); - }, - _rebuildRegions: function() { - if (this.regionManager === undefined) { - this.regionManager = new Marionette.RegionManager(); - } - this.regionManager.destroy(); - _.extend(this, this._buildRegions(this.regions)); - }, - showBlock: function() { - if (this._isFirstRender) { - this.transitionIn(); - this._isFirstRender = false; - } - }, - deleteBlock: function() { - this.transitionOut().done(function() { - this.model.destroy(); - }.bind(this)); - }, - transitionIn: function() { - return this._transition('slideDown', 'fadeIn', 'easeIn'); - }, - transitionOut: function() { - return this._transition('slideUp', 'fadeOut', 'easeOut'); - }, - _transition: function(slideDirection, fadeDirection, easing) { - var promise = jQuery.Deferred(); - - this.$el.velocity( - slideDirection, - { - duration: 250, - easing: easing, - complete: function() { - promise.resolve(); - }.bind(this), - } - ).velocity( - fadeDirection, - { - duration: 250, - easing: easing, - queue: false, // Do not enqueue, trigger animation in parallel - } - ); - - return promise; + this.showChildView('toolsRegion', this.toolsView); + this.showChildView('icons', new Module.SocialIconCollectionView({ + collection: this.model.get('icons') + })) }, }); @@ -268,13 +148,13 @@ define([ this._stylesView = new SocialBlockSettingsStylesView({ model: this.model }); }, onRender: function() { - this.iconRegion.show(this._iconSelectorView); - this.stylesRegion.show(this._stylesView); + this.showChildView('iconRegion', this._iconSelectorView); + this.showChildView('stylesRegion', this._stylesView); } }); // Single icon settings view, used by the selector view - SocialBlockSettingsIconView = Marionette.ItemView.extend({ + SocialBlockSettingsIconView = Marionette.View.extend({ getTemplate: function() { return templates.socialSettingsIcon; }, events: function() { return { @@ -294,17 +174,16 @@ define([ this.$('.mailpoet_social_icon_image').attr('alt', this.model.get('text')); }, }, - templateHelpers: function() { + templateContext: function() { var icons = App.getConfig().get('socialIcons'), // Construct icon type list of format [{iconType: 'type', title: 'Title'}, ...] availableIconTypes = _.map(_.keys(icons.attributes), function(key) { return { iconType: key, title: icons.get(key).get('title') }; }), allIconSets = App.getAvailableStyles().get('socialIconSets'); - return { - model: this.model.toJSON(), + return _.extend({}, base.BlockView.prototype.templateContext.apply(this, arguments), { iconTypes: availableIconTypes, currentType: icons.get(this.model.get('iconType')).toJSON(), allIconSets: allIconSets.toJSON(), - }; + }); }, deleteIcon: function() { this.model.destroy(); @@ -321,34 +200,41 @@ define([ }, }); - // Select icons section container view - SocialBlockSettingsIconSelectorView = Marionette.CompositeView.extend({ - getTemplate: function() { return templates.socialSettingsIconSelector; }, - childView: SocialBlockSettingsIconView, + SocialBlockSettingsIconCollectionView = Marionette.CollectionView.extend({ + behaviors: { + SortableBehavior: { + items: '> div', + }, + }, childViewContainer: '#mailpoet_social_icon_selector_contents', + childView: SocialBlockSettingsIconView, + }); + + // Select icons section container view + SocialBlockSettingsIconSelectorView = Marionette.View.extend({ + getTemplate: function() { return templates.socialSettingsIconSelector; }, + regions: { + 'icons': '#mailpoet_social_icon_selector_contents' + }, events: { 'click .mailpoet_add_social_icon': 'addSocialIcon', }, modelEvents: { 'change:iconSet': 'render', }, - behaviors: { - SortableBehavior: { - items: '#mailpoet_social_icon_selector_contents > div', - }, - }, - constructor: function() { - // Set the icon collection to be handled by this view as well - arguments[0].collection = arguments[0].model.get('icons'); - Marionette.CompositeView.apply(this, arguments); - }, addSocialIcon: function() { // Add a social icon with default values - this.collection.add({}); + this.model.get('icons').add({}); + }, + onRender: function() { + this.showChildView('icons', new SocialBlockSettingsIconCollectionView({ + collection: this.model.get('icons') + })); } + }); - SocialBlockSettingsStylesView = Marionette.ItemView.extend({ + SocialBlockSettingsStylesView = Marionette.View.extend({ getTemplate: function() { return templates.socialSettingsStyles; }, modelEvents: { 'change': 'render', @@ -359,7 +245,7 @@ define([ initialize: function() { this.listenTo(this.model.get('icons'), 'add remove change', this.render); }, - templateHelpers: function() { + templateContext: function() { var allIconSets = App.getAvailableStyles().get('socialIconSets'); return { activeSet: this.model.get('iconSet'), @@ -411,7 +297,7 @@ define([ }, }); - App.on('before:start', function() { + App.on('before:start', function(App, options) { App.registerBlockType('social', { blockModel: Module.SocialBlockModel, blockView: Module.SocialBlockView, diff --git a/assets/js/src/newsletter_editor/blocks/spacer.js b/assets/js/src/newsletter_editor/blocks/spacer.js index 1dd370f4e2..50c2140dbf 100644 --- a/assets/js/src/newsletter_editor/blocks/spacer.js +++ b/assets/js/src/newsletter_editor/blocks/spacer.js @@ -50,7 +50,7 @@ define([ }, onRender: function() { this.toolsView = new Module.SpacerBlockToolsView({ model: this.model }); - this.toolsRegion.show(this.toolsView); + this.showChildView('toolsRegion', this.toolsView); }, changeHeight: function() { this.$('.mailpoet_spacer').css('height', this.model.get('styles.block.height')); @@ -87,7 +87,7 @@ define([ }, }); - App.on('before:start', function() { + App.on('before:start', function(App, options) { App.registerBlockType('spacer', { blockModel: Module.SpacerBlockModel, blockView: Module.SpacerBlockView, diff --git a/assets/js/src/newsletter_editor/blocks/text.js b/assets/js/src/newsletter_editor/blocks/text.js index 5e84f1d7fb..0d7c66e841 100644 --- a/assets/js/src/newsletter_editor/blocks/text.js +++ b/assets/js/src/newsletter_editor/blocks/text.js @@ -58,7 +58,7 @@ define([ settings: false, }, }); - this.toolsRegion.show(this.toolsView); + this.showChildView('toolsRegion', this.toolsView); }, onTextEditorChange: function(newContent) { this.model.set('text', newContent); @@ -71,13 +71,6 @@ define([ this.enableDragging(); this.enableShowingTools(); }, - - disableDragging: function() { - this.$('.mailpoet_content').addClass('mailpoet_ignore_drag'); - }, - enableDragging: function() { - this.$('.mailpoet_content').removeClass('mailpoet_ignore_drag'); - }, }); Module.TextBlockToolsView = base.BlockToolsView.extend({ @@ -100,7 +93,7 @@ define([ }, }); - App.on('before:start', function() { + App.on('before:start', function(App, options) { App.registerBlockType('text', { blockModel: Module.TextBlockModel, blockView: Module.TextBlockView, diff --git a/assets/js/src/newsletter_editor/components/communication.js b/assets/js/src/newsletter_editor/components/communication.js index 2b765b8144..5af5bc951c 100644 --- a/assets/js/src/newsletter_editor/components/communication.js +++ b/assets/js/src/newsletter_editor/components/communication.js @@ -98,7 +98,7 @@ define([ }); }; - App.on('start', function(options) { + App.on('start', function(App, options) { // Prefetch post types Module.getPostTypes(); }); diff --git a/assets/js/src/newsletter_editor/components/config.js b/assets/js/src/newsletter_editor/components/config.js index 4732d8eaaf..f93b168f39 100644 --- a/assets/js/src/newsletter_editor/components/config.js +++ b/assets/js/src/newsletter_editor/components/config.js @@ -24,7 +24,7 @@ define([ return Module._config; }; - App.on('before:start', function(options) { + App.on('before:start', function(App, options) { // Expose config methods globally App.getConfig = Module.getConfig; App.setConfig = Module.setConfig; diff --git a/assets/js/src/newsletter_editor/components/content.js b/assets/js/src/newsletter_editor/components/content.js index 54a2a0d484..4214b8bdca 100644 --- a/assets/js/src/newsletter_editor/components/content.js +++ b/assets/js/src/newsletter_editor/components/content.js @@ -67,7 +67,7 @@ define([ return _.filter(blocks, predicate); }; - App.on('before:start', function(options) { + App.on('before:start', function(App, options) { // Expose block methods globally App.registerBlockType = Module.registerBlockType; App.getBlockTypeModel = Module.getBlockTypeModel; @@ -80,7 +80,7 @@ define([ Module.newsletter = new Module.NewsletterModel(_.omit(_.clone(options.newsletter), ['body'])); }); - App.on('start', function(options) { + App.on('start', function(App, options) { var body = options.newsletter.body; var content = (_.has(body, 'content')) ? body.content : {}; @@ -97,7 +97,7 @@ define([ renderOptions: { depth: 0 }, }); - App._appView.contentRegion.show(App._contentContainerView); + App._appView.showChildView('contentRegion', App._contentContainerView); }); diff --git a/assets/js/src/newsletter_editor/components/heading.js b/assets/js/src/newsletter_editor/components/heading.js index 34560d6245..a24126dbbb 100644 --- a/assets/js/src/newsletter_editor/components/heading.js +++ b/assets/js/src/newsletter_editor/components/heading.js @@ -10,9 +10,9 @@ define([ var Module = {}; - Module.HeadingView = Marionette.ItemView.extend({ + Module.HeadingView = Marionette.View.extend({ getTemplate: function() { return templates.heading; }, - templateHelpers: function() { + templateContext: function() { return { model: this.model.toJSON(), }; @@ -28,8 +28,8 @@ define([ }, }); - App.on('start', function(options) { - App._appView.headingRegion.show(new Module.HeadingView({ model: App.getNewsletter() })); + App.on('start', function(App, options) { + App._appView.showChildView('headingRegion', new Module.HeadingView({ model: App.getNewsletter() })); }); return Module; diff --git a/assets/js/src/newsletter_editor/components/save.js b/assets/js/src/newsletter_editor/components/save.js index 2c45fa0ba2..a1746a173d 100644 --- a/assets/js/src/newsletter_editor/components/save.js +++ b/assets/js/src/newsletter_editor/components/save.js @@ -143,7 +143,7 @@ define([ }); }; - Module.SaveView = Marionette.LayoutView.extend({ + Module.SaveView = Marionette.View.extend({ getTemplate: function() { return templates.save; }, events: { 'click .mailpoet_save_button': 'save', @@ -341,7 +341,7 @@ define([ } }; - App.on('before:start', function(options) { + App.on('before:start', function(App, options) { App.save = Module.saveAndProvidePromise; App.getChannel().on('autoSave', Module.autoSave); @@ -350,9 +350,9 @@ define([ App.getChannel().on('save', function(saveResult) { App.save(saveResult); }); }); - App.on('start', function(options) { + App.on('start', function(App, options) { var saveView = new Module.SaveView(); - App._appView.bottomRegion.show(saveView); + App._appView.showChildView('bottomRegion', saveView); }); return Module; diff --git a/assets/js/src/newsletter_editor/components/sidebar.js b/assets/js/src/newsletter_editor/components/sidebar.js index cbc57def62..9fb218b186 100644 --- a/assets/js/src/newsletter_editor/components/sidebar.js +++ b/assets/js/src/newsletter_editor/components/sidebar.js @@ -52,7 +52,7 @@ define([ Module.registerLayoutWidget = function(widget) { return Module._layoutWidgets.add(widget); }; Module.getLayoutWidgets = function() { return Module._layoutWidgets; }; - var SidebarView = Marionette.LayoutView.extend({ + var SidebarView = Marionette.View.extend({ getTemplate: function() { return templates.sidebar; }, regions: { contentRegion: '.mailpoet_content_region', @@ -96,17 +96,17 @@ define([ .on('scroll', this.updateHorizontalScroll.bind(this)); }, onRender: function() { - this.contentRegion.show(new Module.SidebarWidgetsView({ - collection: App.getWidgets(), - })); - this.layoutRegion.show(new Module.SidebarLayoutWidgetsView({ - collection: App.getLayoutWidgets(), - })); - this.stylesRegion.show(new Module.SidebarStylesView({ + this.showChildView('contentRegion', new Module.SidebarWidgetsView( + App.getWidgets() + )); + this.showChildView('layoutRegion', new Module.SidebarLayoutWidgetsView( + App.getLayoutWidgets() + )); + this.showChildView('stylesRegion', new Module.SidebarStylesView({ model: App.getGlobalStyles(), availableStyles: App.getAvailableStyles(), })); - this.previewRegion.show(new Module.SidebarPreviewView()); + this.showChildView('previewRegion', new Module.SidebarPreviewView()); }, updateHorizontalScroll: function() { // Fixes the sidebar so that on narrower screens the horizontal @@ -136,15 +136,31 @@ define([ }, }); + /** + * Draggable widget collection view + */ + Module.SidebarWidgetsCollectionView = Marionette.CollectionView.extend({ + childView: function(item) { return item.get('widgetView'); } + }); + /** * Responsible for rendering draggable content widgets */ - Module.SidebarWidgetsView = Marionette.CompositeView.extend({ + Module.SidebarWidgetsView = Marionette.View.extend({ getTemplate: function() { return templates.sidebarContent; }, - getChildView: function(model) { - return model.get('widgetView'); + regions: { + widgets: '.mailpoet_region_content' }, - childViewContainer: '.mailpoet_region_content', + + initialize: function(widgets) { + this.widgets = widgets; + }, + + onRender: function() { + this.showChildView('widgets', new Module.SidebarWidgetsCollectionView({ + collection: this.widgets + })); + } }); /** @@ -153,10 +169,11 @@ define([ Module.SidebarLayoutWidgetsView = Module.SidebarWidgetsView.extend({ getTemplate: function() { return templates.sidebarLayout; }, }); + /** * Responsible for managing global styles */ - Module.SidebarStylesView = Marionette.LayoutView.extend({ + Module.SidebarStylesView = Marionette.View.extend({ getTemplate: function() { return templates.sidebarStyles; }, behaviors: { ColorPickerBehavior: {}, @@ -199,7 +216,7 @@ define([ "change #mailpoet_background_color": _.partial(this.changeColorField, 'body.backgroundColor'), }; }, - templateHelpers: function() { + templateContext: function() { return { model: this.model.toJSON(), availableStyles: this.availableStyles.toJSON(), @@ -220,7 +237,7 @@ define([ }, }); - Module.SidebarPreviewView = Marionette.LayoutView.extend({ + Module.SidebarPreviewView = Marionette.View.extend({ getTemplate: function() { return templates.sidebarPreview; }, events: { 'click .mailpoet_show_preview': 'showPreview', @@ -319,14 +336,14 @@ define([ }, }); - Module.NewsletterPreviewView = Marionette.ItemView.extend({ + Module.NewsletterPreviewView = Marionette.View.extend({ getTemplate: function() { return templates.newsletterPreview; }, initialize: function(options) { this.previewUrl = options.previewUrl; this.width = App.getConfig().get('newsletterPreview.width'); this.height = App.getConfig().get('newsletterPreview.height') }, - templateHelpers: function() { + templateContext: function() { return { previewUrl: this.previewUrl, width: this.width, @@ -335,18 +352,18 @@ define([ } }); - App.on('before:start', function(options) { + App.on('before:start', function(App, options) { App.registerWidget = Module.registerWidget; App.getWidgets = Module.getWidgets; App.registerLayoutWidget = Module.registerLayoutWidget; App.getLayoutWidgets = Module.getLayoutWidgets; }); - App.on('start', function(options) { + App.on('start', function(App, options) { var stylesModel = App.getGlobalStyles(), sidebarView = new SidebarView(); - App._appView.sidebarRegion.show(sidebarView); + App._appView.showChildView('sidebarRegion', sidebarView); }); return Module; diff --git a/assets/js/src/newsletter_editor/components/styles.js b/assets/js/src/newsletter_editor/components/styles.js index bddd8c9a8d..2b99ca1b10 100644 --- a/assets/js/src/newsletter_editor/components/styles.js +++ b/assets/js/src/newsletter_editor/components/styles.js @@ -46,11 +46,14 @@ define([ }, }); - Module.StylesView = Marionette.ItemView.extend({ + Module.StylesView = Marionette.View.extend({ getTemplate: function() { return templates.styles; }, modelEvents: { 'change': 'render', }, + serializeData: function() { + return this.model.toJSON(); + } }); Module._globalStyles = new SuperModel(); @@ -65,7 +68,7 @@ define([ return App.getConfig().get('availableStyles'); }; - App.on('before:start', function(options) { + App.on('before:start', function(App, options) { // Expose style methods to global application App.getGlobalStyles = Module.getGlobalStyles; App.setGlobalStyles = Module.setGlobalStyles; @@ -76,9 +79,9 @@ define([ this.setGlobalStyles(globalStyles); }); - App.on('start', function(options) { + App.on('start', function(App, options) { var stylesView = new Module.StylesView({ model: App.getGlobalStyles() }); - App._appView.stylesRegion.show(stylesView); + App._appView.showChildView('stylesRegion', stylesView); }); return Module; diff --git a/package.json b/package.json index cd924bc121..37b08abd40 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,8 @@ "dependencies": { "WP-JS-Hooks": "github:carldanley/WP-JS-Hooks", "backbone": "1.3.3", - "backbone.marionette": "2.4.7", - "backbone.radio": "1.0.5", + "backbone.marionette": "3.2.0", + "backbone.radio": "2.0.0", "backbone.supermodel": "1.2.0", "classnames": "^2.1.3", "codemirror": "^5.8.0", diff --git a/tests/javascript/newsletter_editor/blocks/divider.spec.js b/tests/javascript/newsletter_editor/blocks/divider.spec.js index c6e3cecfca..3e894cbae0 100644 --- a/tests/javascript/newsletter_editor/blocks/divider.spec.js +++ b/tests/javascript/newsletter_editor/blocks/divider.spec.js @@ -134,6 +134,7 @@ define([ describe('settings view', function () { global.stubChannel(EditorApplication); + global.stubConfig(EditorApplication); global.stubAvailableStyles(EditorApplication, { dividers: ['solid', 'inset'], }); diff --git a/tests/javascript/newsletter_editor/blocks/footer.spec.js b/tests/javascript/newsletter_editor/blocks/footer.spec.js index 9c462b0cf6..36f68c3ee2 100644 --- a/tests/javascript/newsletter_editor/blocks/footer.spec.js +++ b/tests/javascript/newsletter_editor/blocks/footer.spec.js @@ -8,6 +8,9 @@ define([ var model; beforeEach(function () { global.stubChannel(EditorApplication); + global.stubConfig(EditorApplication, { + blockDefaults: {}, + }); model = new (FooterBlock.FooterBlockModel)(); }); diff --git a/tests/javascript/newsletter_editor/blocks/posts.spec.js b/tests/javascript/newsletter_editor/blocks/posts.spec.js index c83bf0ea16..4065e66a38 100644 --- a/tests/javascript/newsletter_editor/blocks/posts.spec.js +++ b/tests/javascript/newsletter_editor/blocks/posts.spec.js @@ -27,6 +27,7 @@ define([ global.stubChannel(EditorApplication); global.stubConfig(EditorApplication); EditorApplication.getBlockTypeModel = sinon.stub().returns(Backbone.SuperModel); + EditorApplication.getBlockTypeView = sinon.stub().returns(Backbone.View); model = new (PostsBlock.PostsBlockModel)(); }); diff --git a/views/newsletter/templates/blocks/automatedLatestContent/settings.hbs b/views/newsletter/templates/blocks/automatedLatestContent/settings.hbs index 36afd52098..1d1458bf56 100644 --- a/views/newsletter/templates/blocks/automatedLatestContent/settings.hbs +++ b/views/newsletter/templates/blocks/automatedLatestContent/settings.hbs @@ -15,7 +15,7 @@