app/assets/javascripts/pageflow/dist/editor.js in pageflow-15.1.0.beta6 vs app/assets/javascripts/pageflow/dist/editor.js in pageflow-15.1.0.rc0

- old
+ new

@@ -184,10 +184,52 @@ 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 @@ -214,36 +256,112 @@ * 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] = ".".concat(styles[className]); + result[className] = selector(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 + ui: ui, + events: events, + selector: selector }); // https://github.com/jashkenas/backbone/issues/2601 function BaseObject(options) { this.initialize.apply(this, arguments); } @@ -1086,10 +1204,12 @@ }, onRender: function onRender() { this.$el.addClass('input'); this.$el.addClass(this.model.modelName + '_' + this.options.propertyName); this.$el.data('inputPropertyName', this.options.propertyName); + this.$el.data('labelText', this.labelText()); + this.$el.data('inlineHelpText', this.inlineHelpText()); this.ui.labelText.text(this.labelText()); this.ui.inlineHelp.html(this.inlineHelpText()); if (!this.inlineHelpText()) { this.ui.inlineHelp.hide(); @@ -3386,10 +3506,66 @@ 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; @@ -3476,10 +3652,19 @@ * @memberof editor */ this.failures = new FailuresAPI(); /** + * Tracking records that are currently being saved. + * + * @returns {SavingRecordsCollection} + * @memberof editor + * @since edge + */ + + this.savingRecords = new SavingRecordsCollection(); + /** * Set up editor integration for page types. * @memberof editor */ this.pageTypes = new PageTypes(); @@ -3521,11 +3706,13 @@ * 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 = options; + this.entryType = _objectSpread({ + name: name + }, options); }, createEntryModel: function createEntryModel(seed, options) { var entry = new this.entryType.entryModel(seed.entry, options); if (entry.setupFromEntryTypeSeed) { @@ -3735,10 +3922,83 @@ 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$1.entryType.name, resources].join('/'); + } + var formDataUtils = { fromModel: function fromModel(model) { var object = {}; object[model.modelName] = model.toJSON(); return this.fromObject(object); @@ -3842,11 +4102,11 @@ clear: function clear() { this.parent.remove(this.models); this.reset(); }, url: function url() { - return this.parentModel.url() + _$1.result(this.parent, 'url'); + return this.parentModel.url() + (_$1.result(this.parent, 'urlSuffix') || _$1.result(this.parent, 'url')); }, dispose: function dispose() { this.stopListening(); this.reset(); } @@ -4151,33 +4411,62 @@ }); 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; + this._destroyed = 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, { wait: true, success: function success() { model._destroying = false; + model._destroyed = true; }, error: function error() { model._destroying = false; } }); }, + + /** + * Get whether the model is currently being destroyed. + */ isDestroying: function isDestroying() { return this._destroying; + }, + + /** + * Get whether the model has been destroyed. + */ + isDestroyed: function isDestroyed() { + return this._destroyed; } }; + /** + * 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; @@ -5632,10 +5921,80 @@ return '/page_links/' + pageLink.id; }; }; editor$1.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() && (!this.isDestroying || !this.isDestroying()) && (!this.isDestroyed || !this.isDestroyed()) && 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()) { @@ -5995,10 +6354,65 @@ 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 edge + */ + + 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; @@ -6214,54 +6628,10 @@ 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', @@ -6438,28 +6808,91 @@ return new BackButtonDecoratorView({ view: new ConfirmEncodingView(options) }); }; - var failureIndicatingView = { - modelEvents: { - 'change:failed': 'updateFailIndicator' - }, - events: { - 'click .retry': function clickRetry() { + /** + * 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() { editor$1.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()); + } } - }, - onRender: function onRender() { - this.updateFailIndicator(); - }, - updateFailIndicator: function updateFailIndicator() { - this.$el.toggleClass('failed', this.model.isFailed()); - this.$el.find('.failure .message').text(this.model.getFailureMessage()); + }; + } + + var failureIndicatingView = modelLifecycleTrackingView({ + classNames: { + failed: 'failed', + failureMessage: 'failure .message', + retryButton: 'retry' } - }; + }); function template$k(data) { var __t, __p = ''; __p += '<a class="back">' + ((__t = ( I18n.t('pageflow.editor.templates.edit_chapter.outline') )) == null ? '' : __t) + @@ -7648,11 +8081,12 @@ var state = this.options.state || {}; var features = this.options.features || {}; var editor = this.options.editor || {}; var configurationEditor = new ConfigurationEditorView({ model: entry.metadata.configuration, - tab: this.options.tab + tab: this.options.tab, + attributeTranslationKeyPrefixes: ['pageflow.entry_types.' + editor.entryType.name + '.editor.entry_metadata_configuration_attributes'] }); configurationEditor.tab('general', function () { this.input('title', TextInputView, { placeholder: entry.get('entry_title'), model: entry.metadata @@ -7681,11 +8115,14 @@ placeholder: state.config.defaultKeywordsMetaTag, model: entry.metadata }); }); configurationEditor.tab('widgets', function () { - editor.entryType.appearanceInputs && editor.entryType.appearanceInputs(this, entry, state.theming); + editor.entryType.appearanceInputs && editor.entryType.appearanceInputs(this, { + entry: entry, + theming: state.theming + }); entry.widgets && this.view(EditWidgetsView, { model: entry, widgetTypes: editor.widgetTypes }); @@ -7990,32 +8427,16 @@ }); this.appendSubview(configurationEditor); } }); - 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'); - } + var loadable = modelLifecycleTrackingView({ + classNames: { + creating: 'creating', + destroying: 'destroying' } - }; + }); function template$F(data) { var __p = ''; __p += '<span class="file_thumbnail"></span>\n\n<span class="file_name"></span>\n'; return __p @@ -10128,20 +10549,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(state.savingRecords, 'add', this.update); - this.listenTo(state.savingRecords, 'remove', this.update); + this.listenTo(editor$1.savingRecords, 'add', this.update); + this.listenTo(editor$1.savingRecords, 'remove', this.update); this.listenTo(editor$1.failures, 'add', this.update); this.listenTo(editor$1.failures, 'remove', this.update); this.update(); this.notifyConfirmableFilesCount(); }, update: function update() { this.$el.toggleClass('failed', !editor$1.failures.isEmpty()); - this.$el.toggleClass('saving', !state.savingRecords.isEmpty()); + this.$el.toggleClass('saving', !editor$1.savingRecords.isEmpty()); this.ui.failedCount.text(editor$1.failures.count()); }, notifyUploadCount: function notifyUploadCount(model, uploadCount) { this.$el.toggleClass('uploading', uploadCount > 0); this.ui.uploadingCount.text(uploadCount); @@ -10516,10 +10937,105 @@ 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 edge + */ + + var EditConfigurationView = Marionette.Layout.extend({ + className: 'edit_configuration_view', + 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$1.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 @@ -11021,13 +11537,12 @@ state.storylines.saveOrder(); }, 100)); editor$1.failures.watch(state.entry); editor$1.failures.watch(state.pages); editor$1.failures.watch(state.chapters); - state.savingRecords = new SavingRecordsCollection(); - state.savingRecords.watch(state.pages); - state.savingRecords.watch(state.chapters); + editor$1.savingRecords.watch(state.pages); + editor$1.savingRecords.watch(state.chapters); pageflow.events.trigger('seed:loaded'); }); app.addInitializer(function (options) { state.fileUploader = new FileUploader({ @@ -11189,10 +11704,11 @@ 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; @@ -11212,10 +11728,11 @@ 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; @@ -11232,10 +11749,11 @@ 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; @@ -11246,11 +11764,10 @@ 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; @@ -11274,11 +11791,10 @@ 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; @@ -11328,22 +11844,25 @@ 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$1; + 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;