app/assets/javascripts/pageflow/dist/editor.js in pageflow-15.1.0.beta3 vs app/assets/javascripts/pageflow/dist/editor.js in pageflow-15.1.0.beta4

- old
+ new

@@ -184,52 +184,10 @@ attributeTranslation: attributeTranslation, findTranslation: findTranslation, findKeyWithTranslation: findKeyWithTranslation, translationKeysWithSuffix: translationKeysWithSuffix }); - - function _arrayWithHoles(arr) { - if (Array.isArray(arr)) return arr; - } - - function _iterableToArrayLimit(arr, i) { - if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { - return; - } - - var _arr = []; - var _n = true; - var _d = false; - var _e = undefined; - - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - - if (i && _arr.length === i) break; - } - } catch (err) { - _d = true; - _e = err; - } finally { - try { - if (!_n && _i["return"] != null) _i["return"](); - } finally { - if (_d) throw _e; - } - } - - return _arr; - } - - function _nonIterableRest() { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); - } - - function _slicedToArray(arr, i) { - return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); - } /** * Create object that can be passed to Marionette ui property from CSS * module object. * * @param {Object} styles @@ -256,112 +214,36 @@ * export const MyView = Marionette.ItemView({ * template: () => ` * <div class=${styles.container}></div> * `, * - * ui: cssModulesUtils.ui(styles, 'container'), + * ui: cssModulesUtils.ui(styles, 'container'); * * onRender() { * this.ui.container // => JQuery wrapper for container element * } * }); * * @memberof cssModulesUtils */ - function ui(styles) { for (var _len = arguments.length, classNames = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { classNames[_key - 1] = arguments[_key]; } return classNames.reduce(function (result, className) { - result[className] = selector(styles, className); + result[className] = ".".concat(styles[className]); return result; }, {}); } - /** - * Create object that can be passed to Marionette events property from CSS - * module object. - * - * @param {Object} styles - * Class name mapping imported from `.module.css` file. - * - * @param {Object} mapping - * Events mapping using keys from the `styles` instead of CSS class names. - * - * @return {Object} - * - * @example - * - * // MyView.module.css - * - * .addButton {} - * - * // MyView.js - * - * import Marionette from 'marionette'; - * import {cssModulesUtils} from 'pageflow/ui'; - * - * import styles from './MyView.module.css'; - * - * export const MyView = Marionette.ItemView({ - * template: () => ` - * <button class=${styles.addButton}></button> - * `, - * - * events: cssModulesUtils.ui(styles, { - * 'click addButton': () => console.log('clicked add button'); - * }) - * }); - * - * @memberof cssModulesUtils - */ - - function events(styles, mapping) { - return Object.keys(mapping).reduce(function (result, key) { - var _key$split = key.split(' '), - _key$split2 = _slicedToArray(_key$split, 2), - event = _key$split2[0], - className = _key$split2[1]; - - result["".concat(event, " ").concat(selector(styles, className))] = mapping[key]; - return result; - }, {}); - } - /** - * Generates a CSS selector from a CSS module rule. - * - * @param {Object} styles - * Class name mapping imported from `.module.css` file. - * - * @param {String} className - * Key from the `styles` object. - * - * @return {String} CSS Selector - * @memberof cssModulesUtils - */ - - - function selector(styles, className) { - var classNames = styles[className]; - - if (!classNames) { - throw new Error("Unknown class name ".concat(className, " in mapping. Knwon names: ").concat(Object.keys(styles).join(', '), ".")); - } - - return ".".concat(classNames.replace(/ /g, '.')); - } - var cssModulesUtils = /*#__PURE__*/ Object.freeze({ __proto__: null, - ui: ui, - events: events, - selector: selector + ui: ui }); // https://github.com/jashkenas/backbone/issues/2601 function BaseObject(options) { this.initialize.apply(this, arguments); } @@ -3504,66 +3386,10 @@ args.unshift(this.pageTypes); return _$1[method].apply(_$1, args); }; }); - // different model types. Backbone.Collection tries to merge records - // if they have the same id. - - var MultiCollection = function MultiCollection() { - this.records = {}; - this.length = 0; - }; - - _$1.extend(MultiCollection.prototype, { - add: function add(record) { - if (!this.records[record.cid]) { - this.records[record.cid] = record; - this.length = _$1.keys(this.records).length; - this.trigger('add', record); - } - }, - remove: function remove(record) { - if (this.records[record.cid]) { - delete this.records[record.cid]; - this.length = _$1.keys(this.records).length; - this.trigger('remove', record); - } - }, - isEmpty: function isEmpty() { - return this.length === 0; - } - }); - - _$1.extend(MultiCollection.prototype, Backbone.Events); - - MultiCollection.extend = Backbone.Collection.extend; - - /** - * Watch Backbone collections to track which models are currently - * being saved. Used to update the notifications view displaying - * saving status/failutes. - */ - - var SavingRecordsCollection = MultiCollection.extend({ - /** - * Listen to events of models in collection to track when they are - * being saved. - * - * @param {Backbone.Collection} collection - Collection to watch. - */ - watch: function watch(collection) { - var that = this; - this.listenTo(collection, 'request', function (model, xhr) { - that.add(model); - xhr.always(function () { - that.remove(model); - }); - }); - } - }); - var WidgetType = BaseObject.extend({ initialize: function initialize(serverSideConfig, clientSideConfig) { this.name = serverSideConfig.name; this.translationKey = serverSideConfig.translationKey; this.configurationEditorView = clientSideConfig.configurationEditorView; @@ -3650,19 +3476,10 @@ * @memberof editor */ this.failures = new FailuresAPI(); /** - * Tracking records that are currently being saved. - * - * @returns {SavingRecordsCollection} - * @memberof editor - * @since 15.1 - */ - - this.savingRecords = new SavingRecordsCollection(); - /** * Set up editor integration for page types. * @memberof editor */ this.pageTypes = new PageTypes(); @@ -3704,13 +3521,11 @@ * Backbone view that will render the live preview of the entry. * @param {function} options.EntryOutlineView * Backbone view that will be rendered in the side bar. */ registerEntryType: function registerEntryType(name, options) { - this.entryType = _objectSpread({ - name: name - }, options); + this.entryType = options; }, createEntryModel: function createEntryModel(seed, options) { var entry = new this.entryType.entryModel(seed.entry, options); if (entry.setupFromEntryTypeSeed) { @@ -3898,13 +3713,11 @@ if (!this.fileSelectionHandlers[handlerName]) { throw 'Unknown FileSelectionHandler ' + handlerName; } var payloadJson = JSON.parse(decodeURIComponent(encodedPayload)); - return new this.fileSelectionHandlers[handlerName](_objectSpread({}, payloadJson, { - entry: state.entry - })); + return new this.fileSelectionHandlers[handlerName](payloadJson); }, createPageConfigurationEditorView: function createPageConfigurationEditorView(page, options) { var view = this.pageTypes.findByPage(page).createConfigurationEditorView(_$1.extend(options, { model: page.configuration })); @@ -3922,83 +3735,10 @@ alert('Error while starting editor.'); }); }); }; - /** - * Mixins for Backbone models and collections that use entry type - * specific editor controllers registered via the `editor_app` entry - * type option. - */ - - var entryTypeEditorControllerUrls = { - /** - * Mixins for Backbone collections that defines `url` method. - * - * @param {Object} options - * @param {String} options.resources - Path suffix of the controller route - * - * @example - * - * import {editor, entryTypeEditorControllerUrls} from 'pageflow/editor'; - * - * editor.registerEntryType('test', { - // ... - }); - * - * export const ItemsCollection = Backbone.Collection.extend({ - * mixins: [entryTypeEditorControllerUrls.forCollection({resources: 'items'}) - * }); - * - * new ItemsCollection().url() // => '/editor/entries/10/test/items' - */ - forCollection: function forCollection(_ref) { - var resources = _ref.resources; - return { - url: function url() { - return entryTypeEditorControllerUrl(resources); - }, - urlSuffix: function urlSuffix() { - return "/".concat(resources); - } - }; - }, - - /** - * Mixins for Backbone models that defines `urlRoot` method. - * - * @param {Object} options - * @param {String} options.resources - Path suffix of the controller route - * - * @example - * - * import {editor, entryTypeEditorControllerUrls} from 'pageflow/editor'; - * - * editor.registerEntryType('test', { - // ... - }); - * - * export const Item = Backbone.Model.extend({ - * mixins: [entryTypeEditorControllerUrls.forModel({resources: 'items'}) - * }); - * - * new Item({id: 20}).url() // => '/editor/entries/10/test/items/20' - */ - forModel: function forModel(_ref2) { - var resources = _ref2.resources; - return { - urlRoot: function urlRoot() { - return this.isNew() ? this.collection.url() : entryTypeEditorControllerUrl(resources); - } - }; - } - }; - - function entryTypeEditorControllerUrl(resources) { - return [state.entry.url(), editor.entryType.name, resources].join('/'); - } - var formDataUtils = { fromModel: function fromModel(model) { var object = {}; object[model.modelName] = model.toJSON(); return this.fromObject(object); @@ -4102,11 +3842,11 @@ clear: function clear() { this.parent.remove(this.models); this.reset(); }, url: function url() { - return this.parentModel.url() + (_$1.result(this.parent, 'urlSuffix') || _$1.result(this.parent, 'url')); + return this.parentModel.url() + _$1.result(this.parent, 'url'); }, dispose: function dispose() { this.stopListening(); this.reset(); } @@ -4411,26 +4151,14 @@ }); app.on('mixin:configuration', function (mixin) { Cocktail.mixin(Configuration, mixin); }); - /** - * Remove model from collection only after the `DELETE` request has - * succeeded. Still allow tracking that the model is being destroyed - * by triggering a `destroying` event and adding a `isDestroying` - * method. - */ - var delayedDestroying = { initialize: function initialize() { this._destroying = false; }, - - /** - * Trigger `destroying` event and send `DELETE` request. Only remove - * model from collection once the request is done. - */ destroyWithDelay: function destroyWithDelay() { var model = this; this._destroying = true; this.trigger('destroying', this); return Backbone.Model.prototype.destroy.call(this, { @@ -4441,23 +4169,15 @@ error: function error() { model._destroying = false; } }); }, - - /** - * Get whether the model is currently being destroyed. - */ isDestroying: function isDestroying() { return this._destroying; } }; - /** - * Mixin for Backbone models that shall be watched by {@link - * modelLifecycleTrackingView} mixin. - */ var failureTracking = { initialize: function initialize() { this._saveFailed = false; this.listenTo(this, 'sync', function () { this._saveFailed = false; @@ -5050,27 +4770,13 @@ return ''; } }); - var EntryMetadataConfiguration = Configuration.extend({ - modelName: 'entry_metadata_configuration', - i18nKey: 'pageflow/entry_metadata_configuration', - defaults: {} - }); - - var EntryMetadata = Configuration.extend({ + var EntryConfiguration = Configuration.extend({ modelName: 'entry', - i18nKey: 'pageflow/entry', - defaults: {}, - initialize: function initialize(attributes, options) { - this.configuration = new EntryMetadataConfiguration(_$1.clone(attributes.configuration) || {}); - this.listenTo(this.configuration, 'change', function () { - this.trigger('change'); - this.parent.save(); - }); - } + i18nKey: 'pageflow/entry' }); var StorylineConfiguration = Configuration.extend({ modelName: 'storyline', i18nKey: 'pageflow/storyline', @@ -5245,20 +4951,20 @@ isPositionable: function isPositionable() { return this.isReady(); } }); - var EntryMetadataFileSelectionHandler = function EntryMetadataFileSelectionHandler(options) { + var EntryConfigurationFileSelectionHandler = function EntryConfigurationFileSelectionHandler(options) { this.call = function (file) { - state.entry.metadata.setReference(options.attributeName, file); + state.entry.configuration.setReference(options.attributeName, file); }; this.getReferer = function () { return '/meta_data/' + (options.returnToTab || 'general'); }; }; - editor.registerFileSelectionHandler('entryMetadata', EntryMetadataFileSelectionHandler); + editor.registerFileSelectionHandler('entryConfiguration', EntryConfigurationFileSelectionHandler); var EntryPublication = Backbone.Model.extend({ paramRoot: 'entry_publication', quota: function quota() { return new Backbone.Model(this.get('quota') || {}); @@ -5911,80 +5617,10 @@ return '/page_links/' + pageLink.id; }; }; editor.registerFileSelectionHandler('pageLink', PageLinkFileSelectionHandler); - /** - * Mixins for models with a nested configuration model. - * - * Triggers events on the parent model of the form - * `change:configuration` and `change:configuration:<attribute>`, when - * the configuration changes. - * - * @param {Object} [options] - * @param {Function} [options.configurationModel] - - * Backbone model to use for nested configuration model. - * @param {Boolean} [options.autoSave] - - * Save model when configuration changes. - * @param {Boolean|Array<String>} [options.includeAttributesInJSON] - - * Include all or specific attributes of the parent model in the - * data returned by `toJSON` besides the `configuration` property. - * @returns {Object} - Mixin to be included in model. - * - * @example - * - * import {configurationContainer} from 'pageflow/editor'; - * - * const Section = Backbone.Model.extend({ - * mixins: [configurationContainer({autoSave: true})] - * }); - * - * const section = new Section({configuration: {some: 'value'}}); - * section.configuration.get('some') // => 'value'; - */ - - function configurationContainer() { - var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, - configurationModel = _ref.configurationModel, - autoSave = _ref.autoSave, - includeAttributesInJSON = _ref.includeAttributesInJSON; - - configurationModel = configurationModel || Configuration.extend({ - defaults: {} - }); - return { - initialize: function initialize() { - this.configuration = new configurationModel(this.get('configuration')); - this.configuration.parent = this; - this.listenTo(this.configuration, 'change', function () { - if (!this.isNew() && autoSave) { - this.save(); - } - - this.trigger('change:configuration', this); - - _$1.chain(this.configuration.changed).keys().each(function (name) { - this.trigger('change:configuration:' + name, this, this.configuration.get(name)); - }, this); - }); - }, - toJSON: function toJSON() { - var attributes = {}; - - if (includeAttributesInJSON === true) { - attributes = _$1.clone(this.attributes); - } else if (includeAttributesInJSON) { - attributes = _$1.pick(this.attributes, includeAttributesInJSON); - } - - return _$1.extend(attributes, { - configuration: this.configuration.toJSON() - }); - } - }; - } - var persistedPromise = { persisted: function persisted() { var model = this; this._persistedDeferred = this._persistedDeferred || $.Deferred(function (deferred) { if (model.isNew()) { @@ -6064,12 +5700,12 @@ i18nKey: 'pageflow/entry', collectionName: 'entries', mixins: [filesCountWatcher, polling, failureTracking], initialize: function initialize(attributes, options) { options = options || {}; - this.metadata = new EntryMetadata(this.get('metadata') || {}); - this.metadata.parent = this; + this.configuration = new EntryConfiguration(this.get('configuration') || {}); + this.configuration.parent = this; this.themes = options.themes || state.themes; this.files = options.files || state.files; this.fileTypes = options.fileTypes || editor.fileTypes; this.storylines = options.storylines || state.storylines; this.storylines.parentModel = this; @@ -6087,28 +5723,25 @@ this.pages.sort(); }); this.listenTo(this.chapters, 'sort', function () { this.pages.sort(); }); - this.listenTo(this.metadata, 'change', function () { - this.trigger('change:metadata'); + this.listenTo(this.configuration, 'change', function () { + this.trigger('change:configuration'); this.save(); }); - this.listenTo(this.metadata, 'change:locale', function () { + this.listenTo(this.configuration, 'change:locale', function () { this.once('sync', function () { // No other way of updating page templates used in // EntryPreviewView at the moment. location.reload(); }); }); }, getTheme: function getTheme() { - return this.themes.findByName(this.metadata.get('theme_name')); + return this.themes.findByName(this.configuration.get('theme_name')); }, - supportsPhoneEmulation: function supportsPhoneEmulation() { - return pageflow.features.isEnabled('editor_emulation_mode'); - }, addStoryline: function addStoryline(attributes) { var storyline = this.buildStoryline(attributes); storyline.save(); return storyline; }, @@ -6186,14 +5819,11 @@ }, options)); delete response[fileType.collectionName]; }, this); }, toJSON: function toJSON() { - var metadataJSON = this.metadata.toJSON(); - var configJSON = this.metadata.configuration.toJSON(); - metadataJSON.configuration = configJSON; - return metadataJSON; + return this.configuration.toJSON(); } }); var AuthenticationProvider = BaseObject.extend({ authenticate: function authenticate(parent, provider) { @@ -6347,65 +5977,10 @@ comparator: function comparator(chapter) { return chapter.get('position'); } }); - /** - * A Backbone collection that is automatically updated to only - * contain models with a foreign key matching the id of a parent - * model. - * - * @param {Object} options - * @param {Backbone.Model} options.parentModel - - * Model whose id is compared to foreign keys. - * @param {Backbone.Collection} options.parent - - * Collection to filter items with matching foreign key from. - * @param {String} options.foreignKeyAttribute - - * Attribute to compare to id of parent model. - * @param {String} options.parentReferenceAttribute - - * Set reference to parent model on models in collection. - * - * @since 15.1 - */ - - var ForeignKeySubsetCollection = SubsetCollection.extend({ - mixins: [orderedCollection], - constructor: function constructor(options) { - var parent = options.parent; - var parentModel = options.parentModel; - SubsetCollection.prototype.constructor.call(this, { - parent: parent, - parentModel: parentModel, - filter: function filter(item) { - return !parentModel.isNew() && item.get(options.foreignKeyAttribute) === parentModel.id; - }, - comparator: function comparator(item) { - return item.get('position'); - } - }); - this.listenTo(this, 'add', function (model) { - if (options.parentReferenceAttribute) { - model[options.parentReferenceAttribute] = parentModel; - } - - model.set(options.foreignKeyAttribute, parentModel.id); - }); - this.listenTo(parentModel, 'destroy', function () { - this.clear(); - }); - - if (options.parentReferenceAttribute) { - this.each(function (model) { - return model[options.parentReferenceAttribute] = parentModel; - }); - this.listenTo(this, 'remove', function (model) { - model[options.parentReferenceAttribute] = null; - }); - } - } - }); - var PageLinksCollection = Backbone.Collection.extend({ model: PageLink, initialize: function initialize(models, options) { this.configuration = options.configuration; this.page = options.configuration.page; @@ -6621,10 +6196,54 @@ return model; } }; Cocktail.mixin(Backbone.Collection, addAndReturnModel); + // different model types. Backbone.Collection tries to merge records + // if they have the same id. + + var MultiCollection = function MultiCollection() { + this.records = {}; + this.length = 0; + }; + + _$1.extend(MultiCollection.prototype, { + add: function add(record) { + if (!this.records[record.cid]) { + this.records[record.cid] = record; + this.length = _$1.keys(this.records).length; + this.trigger('add', record); + } + }, + remove: function remove(record) { + if (this.records[record.cid]) { + delete this.records[record.cid]; + this.length = _$1.keys(this.records).length; + this.trigger('remove', record); + } + }, + isEmpty: function isEmpty() { + return this.length === 0; + } + }); + + _$1.extend(MultiCollection.prototype, Backbone.Events); + + MultiCollection.extend = Backbone.Collection.extend; + + var SavingRecordsCollection = MultiCollection.extend({ + watch: function watch(collection) { + var that = this; + this.listenTo(collection, 'request', function (model, xhr) { + that.add(model); + xhr.always(function () { + that.remove(model); + }); + }); + } + }); + var SidebarRouter = Marionette.AppRouter.extend({ appRoutes: { 'page_links/:id': 'pageLink', 'pages/:id': 'page', 'pages/:id/:tab': 'page', @@ -6664,11 +6283,10 @@ }, onRender: function onRender() { this.outlet.show(this.options.view); }, goBack: function goBack() { - this.options.view.onGoBack && this.options.view.onGoBack(); editor.navigate('/', { trigger: true }); } }); @@ -6802,91 +6420,28 @@ return new BackButtonDecoratorView({ view: new ConfirmEncodingView(options) }); }; - /** - * Mixin for Marionette Views that sets css class names according to - * life cycle events of its model. - * - * @param {Object} options - * @param {Object} options.classNames - * @param {String} options.classNames.creating - - * Class name to add to root element while model is still being created. - * @param {String} options.classNames.destroying - - * Class name to add to root element while model is being destroyed. - * @param {String} options.classNames.failed - - * Class name to add to root element while model is in failed state. - * Model needs to include {@link failureTracking} mixin. - * @param {String} options.classNames.failureMessage - - * Class name of the element that shall be updated with the failure - * message. Model needs to include {@link failureTracking} mixin. - * @param {String} options.classNames.retryButton - - * Class name of the element that shall act as a retry button. - */ - - function modelLifecycleTrackingView(_ref) { - var classNames = _ref.classNames; - return { - events: _defineProperty({}, "click .".concat(classNames.retryButton), function click() { + var failureIndicatingView = { + modelEvents: { + 'change:failed': 'updateFailIndicator' + }, + events: { + 'click .retry': function clickRetry() { editor.failures.retry(); return false; - }), - initialize: function initialize() { - var _this = this; - - if (classNames.creating) { - this.listenTo(this.model, 'change:id', function () { - this.$el.removeClass(classNames.creating); - }); - } - - if (classNames.destroying) { - this.listenTo(this.model, 'destroying', function () { - this.$el.addClass(classNames.destroying); - }); - this.listenTo(this.model, 'error', function () { - this.$el.removeClass(classNames.destroying); - }); - } - - if (classNames.failed || classNames.failureMessage) { - this.listenTo(this.model, 'change:failed', function () { - return _this.updateFailIndicator(); - }); - } - }, - render: function render() { - if (this.model.isNew()) { - this.$el.addClass(classNames.creating); - } - - if (this.model.isDestroying && this.model.isDestroying()) { - this.$el.addClass(classNames.destroying); - } - - this.updateFailIndicator(); - }, - updateFailIndicator: function updateFailIndicator() { - if (classNames.failed) { - this.$el.toggleClass(classNames.failed, this.model.isFailed()); - } - - if (classNames.failureMessage) { - this.$el.find(".".concat(classNames.failureMessage)).text(this.model.getFailureMessage()); - } } - }; - } - - var failureIndicatingView = modelLifecycleTrackingView({ - classNames: { - failed: 'failed', - failureMessage: 'failure .message', - retryButton: 'retry' + }, + onRender: function onRender() { + this.updateFailIndicator(); + }, + updateFailIndicator: function updateFailIndicator() { + this.$el.toggleClass('failed', this.model.isFailed()); + this.$el.find('.failure .message').text(this.model.getFailureMessage()); } - }); + }; function template$k(data) { var __t, __p = ''; __p += '<a class="back">' + ((__t = ( I18n.t('pageflow.editor.templates.edit_chapter.outline') )) == null ? '' : __t) + @@ -8071,41 +7626,34 @@ 'click a.back': 'goBack' }, onRender: function onRender() { var entry = this.model; var configurationEditor = new ConfigurationEditorView({ - model: entry.metadata.configuration, + model: entry.configuration, tab: this.options.tab }); configurationEditor.tab('general', function () { this.input('title', TextInputView, { - placeholder: entry.get('entry_title'), - model: entry.metadata + placeholder: entry.get('entry_title') }); this.input('locale', SelectInputView, { values: state.config.availablePublicLocales, texts: _$1.map(state.config.availablePublicLocales, function (locale) { return I18n$1.t('pageflow.public._language', { locale: locale }); - }), - model: entry.metadata + }) }); - this.input('credits', TextAreaInputView, { - model: entry.metadata - }); + this.input('credits', TextAreaInputView); this.input('author', TextInputView, { - placeholder: state.config.defaultAuthorMetaTag, - model: entry.metadata + placeholder: state.config.defaultAuthorMetaTag }); this.input('publisher', TextInputView, { - placeholder: state.config.defaultPublisherMetaTag, - model: entry.metadata + placeholder: state.config.defaultPublisherMetaTag }); this.input('keywords', TextInputView, { - placeholder: state.config.defaultKeywordsMetaTag, - model: entry.metadata + placeholder: state.config.defaultKeywordsMetaTag }); }); configurationEditor.tab('widgets', function () { editor.entryType.appearanceInputs && editor.entryType.appearanceInputs(this, entry, state.theming); entry.widgets && this.view(EditWidgetsView, { @@ -8121,29 +7669,25 @@ } }); configurationEditor.tab('social', function () { this.input('share_image_id', FileInputView, { collection: state.imageFiles, - fileSelectionHandler: 'entryMetadata', - model: entry.metadata + fileSelectionHandler: 'entryConfiguration' }); this.input('summary', TextAreaInputView, { disableRichtext: true, - disableLinks: true, - model: entry.metadata + disableLinks: true }); this.input('share_url', TextInputView, { - placeholder: state.entry.get('pretty_url'), - model: entry.metadata + placeholder: state.entry.get('pretty_url') }); this.input('share_providers', CheckBoxGroupInputView, { values: state.config.availableShareProviders, - translationKeyPrefix: 'activerecord.values.pageflow/entry.share_providers', - model: entry.metadata + translationKeyPrefix: 'activerecord.values.pageflow/entry.share_providers' }); }); - this.listenTo(entry.metadata, 'change:theme_name', function () { + this.listenTo(entry.configuration, 'change:theme_name', function () { configurationEditor.refresh(); }); this.formContainer.show(configurationEditor); }, goBack: function goBack() { @@ -8413,16 +7957,32 @@ }); this.appendSubview(configurationEditor); } }); - var loadable = modelLifecycleTrackingView({ - classNames: { - creating: 'creating', - destroying: 'destroying' + var loadable = { + modelEvents: { + 'change:id': function changeId() { + this.$el.removeClass('creating'); + }, + destroying: function destroying() { + this.$el.addClass('destroying'); + }, + error: function error() { + this.$el.removeClass('destroying'); + } + }, + render: function render() { + if (this.model.isNew()) { + this.$el.addClass('creating'); + } + + if (this.model.isDestroying && this.model.isDestroying()) { + this.$el.addClass('destroying'); + } } - }); + }; function template$F(data) { var __p = ''; __p += '<span class="file_thumbnail"></span>\n\n<span class="file_name"></span>\n'; return __p @@ -10132,25 +9692,25 @@ events: { 'click .emulation_mode_button-desktop a': function clickEmulation_mode_buttonDesktopA() { this.model.unset('emulation_mode'); }, 'click .emulation_mode_button-phone a': function clickEmulation_mode_buttonPhoneA() { - if (this.model.get('emulation_mode_disabled')) { + if (!this.model.get('current_page_supports_emulation_mode')) { return; } this.model.set('emulation_mode', 'phone'); } }, modelEvents: { - 'change:emulation_mode change:emulation_mode_disabled': 'update' + 'change:emulation_mode change:current_page_supports_emulation_mode': 'update' }, onRender: function onRender() { this.update(); }, update: function update() { - this.ui.phoneItem.toggleClass('disabled', !!this.model.get('emulation_mode_disabled')); + this.ui.phoneItem.toggleClass('disabled', !this.model.get('current_page_supports_emulation_mode')); this.ui.phoneItem.toggleClass('active', this.model.has('emulation_mode')); this.ui.desktopItem.toggleClass('active', !this.model.has('emulation_mode')); this.ui.phoneDisplay.toggleClass('active', this.model.has('emulation_mode')); this.ui.desktopDisplay.toggleClass('active', !this.model.has('emulation_mode')); } @@ -10174,11 +9734,11 @@ }); var SidebarFooterView = Marionette.View.extend({ className: 'sidebar_footer', render: function render() { - if (this.model.supportsPhoneEmulation()) { + if (pageflow.features.isEnabled('editor_emulation_mode')) { this.appendSubview(new EmulationModeButtonView({ model: this.model })); } @@ -10532,20 +10092,20 @@ } }, onRender: function onRender() { this.listenTo(state.entry, 'change:uploading_files_count', this.notifyUploadCount); this.listenTo(state.entry, 'change:confirmable_files_count', this.notifyConfirmableFilesCount); - this.listenTo(editor.savingRecords, 'add', this.update); - this.listenTo(editor.savingRecords, 'remove', this.update); + this.listenTo(state.savingRecords, 'add', this.update); + this.listenTo(state.savingRecords, 'remove', this.update); this.listenTo(editor.failures, 'add', this.update); this.listenTo(editor.failures, 'remove', this.update); this.update(); this.notifyConfirmableFilesCount(); }, update: function update() { this.$el.toggleClass('failed', !editor.failures.isEmpty()); - this.$el.toggleClass('saving', !editor.savingRecords.isEmpty()); + this.$el.toggleClass('saving', !state.savingRecords.isEmpty()); this.ui.failedCount.text(editor.failures.count()); }, notifyUploadCount: function notifyUploadCount(model, uploadCount) { this.$el.toggleClass('uploading', uploadCount > 0); this.ui.uploadingCount.text(uploadCount); @@ -10920,104 +10480,10 @@ ConfirmUploadView.open = function (options) { app.dialogRegion.show(new ConfirmUploadView(options)); }; - /** - * Base view to edit configuration container models. Extend and - * override the `configure` method which receives a {@link - * ConfigurationEditorView} to define the tabs and inputs that shall - * be displayed. - * - * Add a `translationKeyPrefix` property to the prototype and define - * the following translations: - * - * * `<translationKeyPrefix>.tabs`: used as `tabTranslationKeyPrefix` - * of the `ConfigurationEditorView`. - * - * * `<translationKeyPrefix>.attributes`: used as one of the - * `attributeTranslationKeyPrefixes` of the - * `ConfigurationEditorView`. - * - * * `<translationKeyPrefix>.back` (optional): Back button label. - * - * * `<translationKeyPrefix>.destroy` (optional): Destroy button - * label. - * - * * `<translationKeyPrefix>.confirm_destroy` (optional): Confirm - * message displayed before destroying. - * - * * `<translationKeyPrefix>.save_error` (optional): Header of the - * failure message that is displayed if the model cannot be saved. - * - * * `<translationKeyPrefix>.retry` (optional): Label of the retry - * button of the failure message. - * - * @param {Object} options - * @param {Backbone.Model} options.model - - * Model including the {@link configurationContainer}, - * {@link failureTracking} and {@link delayedDestroying} mixins. - * - * @since 15.1 - */ - - var EditConfigurationView = Marionette.Layout.extend({ - template: function template(_ref) { - var t = _ref.t; - return "\n <a class=\"back\">".concat(t('back'), "</a>\n <a class=\"destroy\">").concat(t('destroy'), "</a>\n\n <div class=\"failure\">\n <p>").concat(t('save_error'), "</p>\n <p class=\"message\"></p>\n <a class=\"retry\" href=\"\">").concat(t('retry'), "</a>\n </div>\n\n <div class=\"configuration_container\"></div>\n "); - }, - serializeData: function serializeData() { - var _this = this; - - return { - t: function t(key) { - return _this.t(key); - } - }; - }, - mixins: [failureIndicatingView], - regions: { - configurationContainer: '.configuration_container' - }, - events: { - 'click a.back': 'goBack', - 'click a.destroy': 'destroy' - }, - onRender: function onRender() { - var translationKeyPrefix = _$1.result(this, 'translationKeyPrefix'); - - this.configurationEditor = new ConfigurationEditorView({ - tabTranslationKeyPrefix: "".concat(translationKeyPrefix, ".tabs"), - attributeTranslationKeyPrefixes: ["".concat(translationKeyPrefix, ".attributes")], - model: this.model.configuration - }); - this.configure(this.configurationEditor); - this.configurationContainer.show(this.configurationEditor); - }, - onShow: function onShow() { - this.configurationEditor.refreshScroller(); - }, - destroy: function destroy() { - if (window.confirm(this.t('confirm_destroy'))) { - this.model.destroyWithDelay(); - this.goBack(); - } - }, - goBack: function goBack() { - editor.navigate('/', { - trigger: true - }); - }, - t: function t(suffix) { - var translationKeyPrefix = _$1.result(this, 'translationKeyPrefix'); - - return I18n$1.t("".concat(translationKeyPrefix, ".").concat(suffix), { - defaultValue: I18n$1.t("pageflow.editor.views.edit_configuration.".concat(suffix)) - }); - } - }); - ConfigurationEditorView.register('audio', { configure: function configure() { this.tab('general', function () { this.group('general', { supportsTextPositionCenter: true @@ -11317,11 +10783,11 @@ this.tab('loading_spinner', function () { this.view(InfoBoxView, { text: I18n$1.t('pageflow.editor.title_loading_spinner.widget_type_info_box_text') }); this.input('title', TextInputView, { - placeholder: state.entry.metadata.get('title') || state.entry.get('entry_title') + placeholder: state.entry.configuration.get('title') || state.entry.get('entry_title') }); this.input('subtitle', TextInputView); this.input('custom_background_image_id', FileInputView, { collection: 'image_files', fileSelectionHandler: 'widgetConfiguration' @@ -11519,12 +10985,13 @@ state.storylines.saveOrder(); }, 100)); editor.failures.watch(state.entry); editor.failures.watch(state.pages); editor.failures.watch(state.chapters); - editor.savingRecords.watch(state.pages); - editor.savingRecords.watch(state.chapters); + state.savingRecords = new SavingRecordsCollection(); + state.savingRecords.watch(state.pages); + state.savingRecords.watch(state.chapters); pageflow.events.trigger('seed:loaded'); }); app.addInitializer(function (options) { state.fileUploader = new FileUploader({ @@ -11577,11 +11044,11 @@ } }); state.entry.on('use:files', function () { pageflow.stylesheet.reload('entry'); }); - state.entry.metadata.on('change:theme_name', function () { + state.entry.configuration.on('change:theme_name', function () { var theme = state.entry.getTheme(); pageflow.stylesheet.update('theme', theme.get('stylesheet_path')); }); }); @@ -11686,11 +11153,10 @@ exports.DisabledAtmoIndicatorView = DisabledAtmoIndicatorView; exports.DropDownButtonItemListView = DropDownButtonItemListView; exports.DropDownButtonItemView = DropDownButtonItemView; exports.DropDownButtonView = DropDownButtonView; exports.EditChapterView = EditChapterView; - exports.EditConfigurationView = EditConfigurationView; exports.EditEntryView = EditEntryView; exports.EditFileView = EditFileView; exports.EditLock = EditLock; exports.EditLockContainer = EditLockContainer; exports.EditMetaDataView = EditMetaDataView; @@ -11703,18 +11169,17 @@ exports.EditorView = EditorView; exports.EmulationModeButtonView = EmulationModeButtonView; exports.EncodedFile = EncodedFile; exports.EncodingConfirmation = EncodingConfirmation; exports.Entry = Entry; - exports.EntryMetadata = EntryMetadata; - exports.EntryMetadataFileSelectionHandler = EntryMetadataFileSelectionHandler; + exports.EntryConfiguration = EntryConfiguration; + exports.EntryConfigurationFileSelectionHandler = EntryConfigurationFileSelectionHandler; exports.EntryPublication = EntryPublication; exports.EntryPublicationQuotaDecoratorView = EntryPublicationQuotaDecoratorView; exports.EnumTableCellView = EnumTableCellView; exports.ExplorerFileItemView = ExplorerFileItemView; exports.ExtendedSelectInputView = ExtendedSelectInputView; - exports.Failure = Failure; exports.FileConfiguration = FileConfiguration; exports.FileImport = FileImport; exports.FileInputView = FileInputView; exports.FileItemView = FileItemView; exports.FileMetaDataItemValueView = FileMetaDataItemValueView; @@ -11731,11 +11196,10 @@ exports.FilesCollection = FilesCollection; exports.FilesExplorerView = FilesExplorerView; exports.FilesImporterView = FilesImporterView; exports.FilesView = FilesView; exports.FilteredFilesView = FilteredFilesView; - exports.ForeignKeySubsetCollection = ForeignKeySubsetCollection; exports.HelpButtonView = HelpButtonView; exports.HelpImageView = HelpImageView; exports.HelpView = HelpView; exports.IconTableCellView = IconTableCellView; exports.ImageFile = ImageFile; @@ -11746,10 +11210,11 @@ exports.ListItemView = ListItemView; exports.ListView = ListView; exports.LoadingView = LoadingView; exports.LockedView = LockedView; exports.ModelThumbnailView = ModelThumbnailView; + exports.MultiCollection = MultiCollection; exports.NestedFilesCollection = NestedFilesCollection; exports.NestedFilesView = NestedFilesView; exports.NestedTypeError = NestedTypeError; exports.NotificationsView = NotificationsView; exports.Object = BaseObject; @@ -11773,10 +11238,11 @@ exports.PreviewEntryData = PreviewEntryData; exports.ProxyUrlInputView = ProxyUrlInputView; exports.PublishEntryView = PublishEntryView; exports.ReferenceInputView = ReferenceInputView; exports.ReusableFile = ReusableFile; + exports.SavingRecordsCollection = SavingRecordsCollection; exports.Scaffold = Scaffold; exports.ScrollingView = ScrollingView; exports.SelectButtonView = SelectButtonView; exports.SelectInputView = SelectInputView; exports.SidebarController = SidebarController; @@ -11826,25 +11292,22 @@ exports.WidgetTypes = WidgetTypes; exports.WidgetsCollection = WidgetsCollection; exports.addAndReturnModel = addAndReturnModel; exports.app = app; exports.authenticationProvider = authenticationProvider; - exports.configurationContainer = configurationContainer; exports.cssModulesUtils = cssModulesUtils; exports.delayedDestroying = delayedDestroying; exports.dialogView = dialogView; exports.editor = editor; - exports.entryTypeEditorControllerUrls = entryTypeEditorControllerUrls; exports.failureIndicatingView = failureIndicatingView; exports.failureTracking = failureTracking; exports.fileWithType = fileWithType; exports.filesCountWatcher = filesCountWatcher; exports.formDataUtils = formDataUtils; exports.i18nUtils = i18nUtils; exports.inputView = inputView; exports.inputWithPlaceholderText = inputWithPlaceholderText; exports.loadable = loadable; - exports.modelLifecycleTrackingView = modelLifecycleTrackingView; exports.orderedCollection = orderedCollection; exports.persistedPromise = persistedPromise; exports.polling = polling; exports.retryable = retryable; exports.selectableView = selectableView;