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;