pageflow 14.5.2 → 15.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of pageflow might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +44 -39
- data/admins/pageflow/membership.rb +1 -5
- data/app/assets/javascripts/pageflow/dist/react-client.js +62 -179
- data/app/assets/javascripts/pageflow/dist/react-server.js +62 -179
- data/app/assets/javascripts/pageflow/editor/api/widget_type.js +1 -0
- data/app/assets/javascripts/pageflow/editor/base.js +2 -2
- data/app/assets/javascripts/pageflow/editor/collections/files_collection.js +4 -0
- data/app/assets/javascripts/pageflow/editor/collections/nested_files_collection.js +4 -0
- data/app/assets/javascripts/pageflow/editor/initializers/setup_audio.js +1 -1
- data/app/assets/javascripts/pageflow/editor/models/encoded_file.js +1 -1
- data/app/assets/javascripts/pageflow/editor/models/image_file.js +1 -1
- data/app/assets/javascripts/pageflow/editor/models/mixins/transient_references.js +7 -7
- data/app/assets/javascripts/pageflow/editor/models/preview_entry_data.js +2 -2
- data/app/assets/javascripts/pageflow/editor/models/{uploaded_file.js → reusable_file.js} +1 -1
- data/app/assets/javascripts/pageflow/editor/models/text_track_file.js +2 -2
- data/app/assets/javascripts/pageflow/editor/models/{hosted_file.js → uploadable_file.js} +1 -1
- data/app/assets/javascripts/pageflow/editor/views/widget_types/title_loading_spinner.js +0 -3
- data/app/assets/stylesheets/pageflow/mixins/pageflow.scss +1 -1
- data/app/assets/stylesheets/pageflow/themes/default/base.scss +1 -1
- data/app/assets/stylesheets/pageflow/themes/default/loading_spinner/title.scss +50 -10
- data/app/assets/stylesheets/pageflow/themes/default/loading_spinner.scss +0 -2
- data/app/assets/stylesheets/pageflow/themes/default/player_controls/classic/info_box.scss +0 -5
- data/app/assets/stylesheets/pageflow/themes/default/player_controls/slim/info_box.scss +0 -4
- data/app/controllers/pageflow/files_controller.rb +3 -3
- data/app/helpers/pageflow/audio_files_helper.rb +18 -16
- data/app/helpers/pageflow/background_image_helper.rb +22 -17
- data/app/helpers/pageflow/entry_json_seed_helper.rb +3 -3
- data/app/helpers/pageflow/file_thumbnails_helper.rb +1 -1
- data/app/helpers/pageflow/meta_tags_helper.rb +3 -3
- data/app/helpers/pageflow/pages_helper.rb +10 -1
- data/app/helpers/pageflow/revision_file_helper.rb +27 -0
- data/app/helpers/pageflow/social_share_helper.rb +5 -3
- data/app/helpers/pageflow/social_share_links_helper.rb +1 -1
- data/app/helpers/pageflow/video_files_helper.rb +18 -13
- data/app/jobs/pageflow/{process_file_job.rb → process_image_or_text_track_job.rb} +1 -1
- data/app/models/concerns/pageflow/{uploaded_file.rb → reusable_file.rb} +59 -5
- data/app/models/concerns/pageflow/{hosted_file.rb → uploadable_file.rb} +26 -15
- data/app/models/pageflow/audio_file.rb +2 -2
- data/app/models/pageflow/draft_entry.rb +1 -1
- data/app/models/pageflow/entry.rb +0 -8
- data/app/models/pageflow/file_usage.rb +3 -1
- data/app/models/pageflow/image_file.rb +31 -29
- data/app/models/pageflow/membership.rb +4 -3
- data/app/models/pageflow/page.rb +0 -8
- data/app/models/pageflow/positioned_file.rb +3 -2
- data/app/models/pageflow/published_entry.rb +9 -3
- data/app/models/pageflow/revision.rb +6 -12
- data/app/models/pageflow/text_track_file.rb +13 -12
- data/app/models/pageflow/thumbnail_file_resolver.rb +3 -3
- data/app/models/pageflow/used_file.rb +4 -0
- data/app/models/pageflow/video_file.rb +2 -2
- data/app/models/pageflow/widget.rb +6 -12
- data/app/state_machines/pageflow/{processed_file_state_machine.rb → image_and_text_track_processing_state_machine.rb} +3 -2
- data/app/state_machines/pageflow/{encoded_file_state_machine.rb → media_encoding_state_machine.rb} +27 -19
- data/app/views/pageflow/editor/files/_file.json.jbuilder +1 -1
- data/app/views/pageflow/entries/mobile_navigation/_page.html.erb +1 -1
- data/app/views/pageflow/entries/navigation/_page.html.erb +2 -2
- data/app/views/pageflow/entries/overview/_page.html.erb +1 -1
- data/app/views/pageflow/files/_file.json.jbuilder +1 -0
- data/app/views/pageflow/social_share/_page_meta_tags.html.erb +1 -1
- data/config/locales/de.yml +0 -24
- data/config/locales/en.yml +0 -24
- data/db/migrate/20190306161431_copy_file_attributes_of_failed_uploads.rb +4 -4
- data/db/migrate/20190523151140_add_perma_id_to_file_usages.rb +13 -0
- data/lib/pageflow/built_in_widget_type.rb +0 -7
- data/lib/pageflow/built_in_widget_types_plugin.rb +0 -6
- data/lib/pageflow/user_mixin.rb +0 -6
- data/lib/pageflow/version.rb +1 -1
- data/lib/pageflow/widget_types.rb +1 -9
- data/spec/factories/{hosted_files.rb → uploadable_files.rb} +3 -3
- metadata +16 -32
- data/app/assets/javascripts/pageflow/dist/editor.js +0 -11890
- data/app/assets/javascripts/pageflow/dist/frontend.js +0 -5800
- data/app/assets/javascripts/pageflow/dist/ui.js +0 -3114
- data/app/assets/javascripts/pageflow/editor/views/widget_types/media_loading_spinner.js +0 -18
- data/app/assets/stylesheets/pageflow/themes/default/loading_spinner/media.scss +0 -56
@@ -1,3114 +0,0 @@
|
|
1
|
-
this.pageflow = this.pageflow || {};
|
2
|
-
this.pageflow._uiGlobalInterop = (function (exports, Marionette, _, $, I18n$1, Backbone, ChildViewContainer, IScroll, jquery_minicolors, wysihtml5, Cocktail) {
|
3
|
-
'use strict';
|
4
|
-
|
5
|
-
Marionette = Marionette && Marionette.hasOwnProperty('default') ? Marionette['default'] : Marionette;
|
6
|
-
_ = _ && _.hasOwnProperty('default') ? _['default'] : _;
|
7
|
-
$ = $ && $.hasOwnProperty('default') ? $['default'] : $;
|
8
|
-
I18n$1 = I18n$1 && I18n$1.hasOwnProperty('default') ? I18n$1['default'] : I18n$1;
|
9
|
-
Backbone = Backbone && Backbone.hasOwnProperty('default') ? Backbone['default'] : Backbone;
|
10
|
-
ChildViewContainer = ChildViewContainer && ChildViewContainer.hasOwnProperty('default') ? ChildViewContainer['default'] : ChildViewContainer;
|
11
|
-
IScroll = IScroll && IScroll.hasOwnProperty('default') ? IScroll['default'] : IScroll;
|
12
|
-
wysihtml5 = wysihtml5 && wysihtml5.hasOwnProperty('default') ? wysihtml5['default'] : wysihtml5;
|
13
|
-
Cocktail = Cocktail && Cocktail.hasOwnProperty('default') ? Cocktail['default'] : Cocktail;
|
14
|
-
|
15
|
-
/*global JST*/
|
16
|
-
|
17
|
-
Marionette.Renderer.render = function (template, data) {
|
18
|
-
if (_.isFunction(template)) {
|
19
|
-
return template(data);
|
20
|
-
}
|
21
|
-
|
22
|
-
if (template.indexOf('templates/') === 0) {
|
23
|
-
template = 'pageflow/editor/' + template;
|
24
|
-
}
|
25
|
-
|
26
|
-
if (!JST[template]) {
|
27
|
-
throw "Template '" + template + "' not found!";
|
28
|
-
}
|
29
|
-
|
30
|
-
return JST[template](data);
|
31
|
-
};
|
32
|
-
|
33
|
-
/**
|
34
|
-
* Returns an array of translation keys based on the `prefixes`
|
35
|
-
* option and the given `keyName`.
|
36
|
-
*
|
37
|
-
* @param {string} keyName
|
38
|
-
* Suffix to append to prefixes.
|
39
|
-
*
|
40
|
-
* @param {string[]} [options.prefixes]
|
41
|
-
* Array of translation key prefixes.
|
42
|
-
*
|
43
|
-
* @param {string} [options.fallbackPrefix]
|
44
|
-
* Optional additional prefix to form a model based translation
|
45
|
-
* key of the form
|
46
|
-
* `prefix.fallbackModelI18nKey.propertyName.keyName`.
|
47
|
-
*
|
48
|
-
* @param {string} [options.fallbackModelI18nKey]
|
49
|
-
* Required if `fallbackPrefix` option is present.
|
50
|
-
*
|
51
|
-
* @return {string[]}
|
52
|
-
* @memberof i18nUtils
|
53
|
-
* @since 12.0
|
54
|
-
*/
|
55
|
-
|
56
|
-
function attributeTranslationKeys(attributeName, keyName, options) {
|
57
|
-
var result = [];
|
58
|
-
|
59
|
-
if (options.prefixes) {
|
60
|
-
result = result.concat(_(options.prefixes).map(function (prefix) {
|
61
|
-
return prefix + '.' + attributeName + '.' + keyName;
|
62
|
-
}, this));
|
63
|
-
}
|
64
|
-
|
65
|
-
if (options && options.fallbackPrefix) {
|
66
|
-
result.push(options.fallbackPrefix + '.' + options.fallbackModelI18nKey + '.' + attributeName);
|
67
|
-
}
|
68
|
-
|
69
|
-
return result;
|
70
|
-
}
|
71
|
-
/**
|
72
|
-
* Takes the same parameters as {@link
|
73
|
-
* #i18nutilsattributetranslationkeys attributeTranslationKeys}, but returns the first existing
|
74
|
-
* translation.
|
75
|
-
*
|
76
|
-
* @return {string}
|
77
|
-
* @memberof i18nUtils
|
78
|
-
* @since 12.0
|
79
|
-
*/
|
80
|
-
|
81
|
-
function attributeTranslation(attributeName, keyName, options) {
|
82
|
-
return findTranslation(attributeTranslationKeys(attributeName, keyName, options));
|
83
|
-
}
|
84
|
-
/**
|
85
|
-
* Find the first key for which a translation exists and return the
|
86
|
-
* translation.
|
87
|
-
*
|
88
|
-
* @param {string[]} keys
|
89
|
-
* Translation key candidates.
|
90
|
-
*
|
91
|
-
* @param {string} [options.defaultValue]
|
92
|
-
* Value to return if none of the keys has a translation. Is
|
93
|
-
* treated like an HTML translation if html flag is set.
|
94
|
-
*
|
95
|
-
* @param {boolean} [options.html]
|
96
|
-
* If true, also search for keys ending in '_html' and HTML-escape
|
97
|
-
* keys that do not end in 'html'
|
98
|
-
*
|
99
|
-
* @memberof i18nUtils
|
100
|
-
* @return {string}
|
101
|
-
*/
|
102
|
-
|
103
|
-
function findTranslation(keys, options) {
|
104
|
-
options = options || {};
|
105
|
-
|
106
|
-
if (options.html) {
|
107
|
-
keys = translationKeysWithSuffix(keys, 'html');
|
108
|
-
}
|
109
|
-
|
110
|
-
return _.chain(keys).reverse().reduce(function (result, key) {
|
111
|
-
var unescapedTranslation = I18n$1.t(key, _.extend({}, options, {
|
112
|
-
defaultValue: result
|
113
|
-
}));
|
114
|
-
|
115
|
-
if (!options.html || key.match(/_html$/) || result == unescapedTranslation) {
|
116
|
-
return unescapedTranslation;
|
117
|
-
} else {
|
118
|
-
return $('<div />').text(unescapedTranslation).html();
|
119
|
-
}
|
120
|
-
}, options.defaultValue).value();
|
121
|
-
}
|
122
|
-
/**
|
123
|
-
* Return the first key for which a translation exists. Returns the
|
124
|
-
* first if non of the keys has a translation.
|
125
|
-
*
|
126
|
-
* @param {string[]} keys
|
127
|
-
* Translation key candidates.
|
128
|
-
*
|
129
|
-
* @memberof i18nUtils
|
130
|
-
* @return {string}
|
131
|
-
*/
|
132
|
-
|
133
|
-
function findKeyWithTranslation(keys) {
|
134
|
-
var missing = '_not_translated';
|
135
|
-
return _(keys).detect(function (key) {
|
136
|
-
return I18n$1.t(key, {
|
137
|
-
defaultValue: missing
|
138
|
-
}) !== missing;
|
139
|
-
}) || _.first(keys);
|
140
|
-
}
|
141
|
-
function translationKeysWithSuffix(keys, suffix) {
|
142
|
-
return _.chain(keys).map(function (key) {
|
143
|
-
return [key + '_' + suffix, key];
|
144
|
-
}).flatten().value();
|
145
|
-
}
|
146
|
-
|
147
|
-
var i18nUtils = /*#__PURE__*/Object.freeze({
|
148
|
-
__proto__: null,
|
149
|
-
attributeTranslationKeys: attributeTranslationKeys,
|
150
|
-
attributeTranslation: attributeTranslation,
|
151
|
-
findTranslation: findTranslation,
|
152
|
-
findKeyWithTranslation: findKeyWithTranslation,
|
153
|
-
translationKeysWithSuffix: translationKeysWithSuffix
|
154
|
-
});
|
155
|
-
|
156
|
-
function _arrayWithHoles(arr) {
|
157
|
-
if (Array.isArray(arr)) return arr;
|
158
|
-
}
|
159
|
-
|
160
|
-
function _iterableToArrayLimit(arr, i) {
|
161
|
-
if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
|
162
|
-
var _arr = [];
|
163
|
-
var _n = true;
|
164
|
-
var _d = false;
|
165
|
-
var _e = undefined;
|
166
|
-
|
167
|
-
try {
|
168
|
-
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
|
169
|
-
_arr.push(_s.value);
|
170
|
-
|
171
|
-
if (i && _arr.length === i) break;
|
172
|
-
}
|
173
|
-
} catch (err) {
|
174
|
-
_d = true;
|
175
|
-
_e = err;
|
176
|
-
} finally {
|
177
|
-
try {
|
178
|
-
if (!_n && _i["return"] != null) _i["return"]();
|
179
|
-
} finally {
|
180
|
-
if (_d) throw _e;
|
181
|
-
}
|
182
|
-
}
|
183
|
-
|
184
|
-
return _arr;
|
185
|
-
}
|
186
|
-
|
187
|
-
function _arrayLikeToArray(arr, len) {
|
188
|
-
if (len == null || len > arr.length) len = arr.length;
|
189
|
-
|
190
|
-
for (var i = 0, arr2 = new Array(len); i < len; i++) {
|
191
|
-
arr2[i] = arr[i];
|
192
|
-
}
|
193
|
-
|
194
|
-
return arr2;
|
195
|
-
}
|
196
|
-
|
197
|
-
function _unsupportedIterableToArray(o, minLen) {
|
198
|
-
if (!o) return;
|
199
|
-
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
|
200
|
-
var n = Object.prototype.toString.call(o).slice(8, -1);
|
201
|
-
if (n === "Object" && o.constructor) n = o.constructor.name;
|
202
|
-
if (n === "Map" || n === "Set") return Array.from(n);
|
203
|
-
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
|
204
|
-
}
|
205
|
-
|
206
|
-
function _nonIterableRest() {
|
207
|
-
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
208
|
-
}
|
209
|
-
|
210
|
-
function _slicedToArray(arr, i) {
|
211
|
-
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
|
212
|
-
}
|
213
|
-
|
214
|
-
/**
|
215
|
-
* Create object that can be passed to Marionette ui property from CSS
|
216
|
-
* module object.
|
217
|
-
*
|
218
|
-
* @param {Object} styles
|
219
|
-
* Class name mapping imported from `.module.css` file.
|
220
|
-
*
|
221
|
-
* @param {...string} classNames
|
222
|
-
* Keys from the styles object that shall be used in the ui object.
|
223
|
-
*
|
224
|
-
* @return {Object}
|
225
|
-
*
|
226
|
-
* @example
|
227
|
-
*
|
228
|
-
* // MyView.module.css
|
229
|
-
*
|
230
|
-
* .container {}
|
231
|
-
*
|
232
|
-
* // MyView.js
|
233
|
-
*
|
234
|
-
* import Marionette from 'marionette';
|
235
|
-
* import {cssModulesUtils} from 'pageflow/ui';
|
236
|
-
*
|
237
|
-
* import styles from './MyView.module.css';
|
238
|
-
*
|
239
|
-
* export const MyView = Marionette.ItemView({
|
240
|
-
* template: () => `
|
241
|
-
* <div class=${styles.container}></div>
|
242
|
-
* `,
|
243
|
-
*
|
244
|
-
* ui: cssModulesUtils.ui(styles, 'container'),
|
245
|
-
*
|
246
|
-
* onRender() {
|
247
|
-
* this.ui.container // => JQuery wrapper for container element
|
248
|
-
* }
|
249
|
-
* });
|
250
|
-
*
|
251
|
-
* @memberof cssModulesUtils
|
252
|
-
*/
|
253
|
-
function ui(styles) {
|
254
|
-
for (var _len = arguments.length, classNames = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
255
|
-
classNames[_key - 1] = arguments[_key];
|
256
|
-
}
|
257
|
-
|
258
|
-
return classNames.reduce(function (result, className) {
|
259
|
-
result[className] = selector(styles, className);
|
260
|
-
return result;
|
261
|
-
}, {});
|
262
|
-
}
|
263
|
-
/**
|
264
|
-
* Create object that can be passed to Marionette events property from CSS
|
265
|
-
* module object.
|
266
|
-
*
|
267
|
-
* @param {Object} styles
|
268
|
-
* Class name mapping imported from `.module.css` file.
|
269
|
-
*
|
270
|
-
* @param {Object} mapping
|
271
|
-
* Events mapping using keys from the `styles` instead of CSS class names.
|
272
|
-
*
|
273
|
-
* @return {Object}
|
274
|
-
*
|
275
|
-
* @example
|
276
|
-
*
|
277
|
-
* // MyView.module.css
|
278
|
-
*
|
279
|
-
* .addButton {}
|
280
|
-
*
|
281
|
-
* // MyView.js
|
282
|
-
*
|
283
|
-
* import Marionette from 'marionette';
|
284
|
-
* import {cssModulesUtils} from 'pageflow/ui';
|
285
|
-
*
|
286
|
-
* import styles from './MyView.module.css';
|
287
|
-
*
|
288
|
-
* export const MyView = Marionette.ItemView({
|
289
|
-
* template: () => `
|
290
|
-
* <button class=${styles.addButton}></button>
|
291
|
-
* `,
|
292
|
-
*
|
293
|
-
* events: cssModulesUtils.events(styles, {
|
294
|
-
* 'click addButton': () => console.log('clicked add button');
|
295
|
-
* })
|
296
|
-
* });
|
297
|
-
*
|
298
|
-
* @memberof cssModulesUtils
|
299
|
-
*/
|
300
|
-
|
301
|
-
function events(styles, mapping) {
|
302
|
-
return Object.keys(mapping).reduce(function (result, key) {
|
303
|
-
var _key$split = key.split(' '),
|
304
|
-
_key$split2 = _slicedToArray(_key$split, 2),
|
305
|
-
event = _key$split2[0],
|
306
|
-
className = _key$split2[1];
|
307
|
-
|
308
|
-
result["".concat(event, " ").concat(selector(styles, className))] = mapping[key];
|
309
|
-
return result;
|
310
|
-
}, {});
|
311
|
-
}
|
312
|
-
/**
|
313
|
-
* Generates a CSS selector from a CSS module rule.
|
314
|
-
*
|
315
|
-
* @param {Object} styles
|
316
|
-
* Class name mapping imported from `.module.css` file.
|
317
|
-
*
|
318
|
-
* @param {String} className
|
319
|
-
* Key from the `styles` object.
|
320
|
-
*
|
321
|
-
* @return {String} CSS Selector
|
322
|
-
* @memberof cssModulesUtils
|
323
|
-
*/
|
324
|
-
|
325
|
-
function selector(styles, className) {
|
326
|
-
var classNames = styles[className];
|
327
|
-
|
328
|
-
if (!classNames) {
|
329
|
-
throw new Error("Unknown class name ".concat(className, " in mapping. Knwon names: ").concat(Object.keys(styles).join(', '), "."));
|
330
|
-
}
|
331
|
-
|
332
|
-
return ".".concat(classNames.replace(/ /g, '.'));
|
333
|
-
}
|
334
|
-
|
335
|
-
var cssModulesUtils = /*#__PURE__*/Object.freeze({
|
336
|
-
__proto__: null,
|
337
|
-
ui: ui,
|
338
|
-
events: events,
|
339
|
-
selector: selector
|
340
|
-
});
|
341
|
-
|
342
|
-
// https://github.com/jashkenas/backbone/issues/2601
|
343
|
-
|
344
|
-
function BaseObject(options) {
|
345
|
-
this.initialize.apply(this, arguments);
|
346
|
-
}
|
347
|
-
|
348
|
-
_.extend(BaseObject.prototype, Backbone.Events, {
|
349
|
-
initialize: function initialize(options) {}
|
350
|
-
}); // The self-propagating extend function that Backbone classes use.
|
351
|
-
|
352
|
-
|
353
|
-
BaseObject.extend = Backbone.Model.extend;
|
354
|
-
|
355
|
-
var serverSideValidation = {
|
356
|
-
initialize: function initialize() {
|
357
|
-
var _this = this;
|
358
|
-
|
359
|
-
this.validationErrors = {};
|
360
|
-
this.listenTo(this, 'error', function (model, request) {
|
361
|
-
if (request.status === 422) {
|
362
|
-
_this.validationErrors = JSON.parse(request.responseText).errors;
|
363
|
-
|
364
|
-
_this.trigger('invalid');
|
365
|
-
}
|
366
|
-
});
|
367
|
-
this.listenTo(this, 'sync', function () {
|
368
|
-
_this.validationErrors = {};
|
369
|
-
});
|
370
|
-
}
|
371
|
-
};
|
372
|
-
|
373
|
-
var CollectionView = Marionette.View.extend({
|
374
|
-
initialize: function initialize() {
|
375
|
-
this.rendered = false;
|
376
|
-
this.itemViews = new ChildViewContainer();
|
377
|
-
this.collection.map(this.addItem, this);
|
378
|
-
this.listenTo(this.collection, 'add', this.addItem);
|
379
|
-
this.listenTo(this.collection, 'remove', this.removeItem);
|
380
|
-
this.listenTo(this.collection, 'sort', this.sort);
|
381
|
-
|
382
|
-
if (this.options.loadingViewConstructor) {
|
383
|
-
this.listenTo(this.collection, 'request', function () {
|
384
|
-
this.loading = true;
|
385
|
-
this.togglePlaceHolder();
|
386
|
-
});
|
387
|
-
this.listenTo(this.collection, 'sync', function () {
|
388
|
-
this.loading = false;
|
389
|
-
this.togglePlaceHolder();
|
390
|
-
});
|
391
|
-
}
|
392
|
-
},
|
393
|
-
render: function render() {
|
394
|
-
if (!this.rendered) {
|
395
|
-
this.$el.append(this.itemViews.map(function (itemView) {
|
396
|
-
itemView.$el.data('view', itemView);
|
397
|
-
return itemView.render().el;
|
398
|
-
}));
|
399
|
-
this.togglePlaceHolder();
|
400
|
-
this.rendered = true;
|
401
|
-
}
|
402
|
-
|
403
|
-
return this;
|
404
|
-
},
|
405
|
-
onClose: function onClose() {
|
406
|
-
this.itemViews.call('close');
|
407
|
-
this.closePlaceHolderView();
|
408
|
-
},
|
409
|
-
addItem: function addItem(item) {
|
410
|
-
var view = new this.options.itemViewConstructor(_.extend({
|
411
|
-
model: item
|
412
|
-
}, this.getItemViewOptions(item)));
|
413
|
-
this.itemViews.add(view);
|
414
|
-
|
415
|
-
if (this.rendered) {
|
416
|
-
var index = this.collection.indexOf(item);
|
417
|
-
view.render();
|
418
|
-
view.$el.data('view', view);
|
419
|
-
|
420
|
-
if (index > 0) {
|
421
|
-
this.$el.children().eq(index - 1).after(view.el);
|
422
|
-
} else {
|
423
|
-
this.$el.prepend(view.el);
|
424
|
-
}
|
425
|
-
|
426
|
-
this.togglePlaceHolder();
|
427
|
-
}
|
428
|
-
},
|
429
|
-
removeItem: function removeItem(item) {
|
430
|
-
var view = this.itemViews.findByModel(item);
|
431
|
-
|
432
|
-
if (view) {
|
433
|
-
this.itemViews.remove(view);
|
434
|
-
view.close();
|
435
|
-
this.togglePlaceHolder();
|
436
|
-
}
|
437
|
-
},
|
438
|
-
sort: function sort() {
|
439
|
-
var last = null;
|
440
|
-
this.collection.each(function (item) {
|
441
|
-
var itemView = this.itemViews.findByModel(item);
|
442
|
-
var element;
|
443
|
-
|
444
|
-
if (!itemView) {
|
445
|
-
return;
|
446
|
-
}
|
447
|
-
|
448
|
-
element = itemView.$el;
|
449
|
-
|
450
|
-
if (last) {
|
451
|
-
last.after(element);
|
452
|
-
} else {
|
453
|
-
this.$el.prepend(element);
|
454
|
-
}
|
455
|
-
|
456
|
-
last = element;
|
457
|
-
}, this);
|
458
|
-
},
|
459
|
-
getItemViewOptions: function getItemViewOptions(item) {
|
460
|
-
if (typeof this.options.itemViewOptions === 'function') {
|
461
|
-
return this.options.itemViewOptions(item);
|
462
|
-
} else {
|
463
|
-
return this.options.itemViewOptions || {};
|
464
|
-
}
|
465
|
-
},
|
466
|
-
closePlaceHolderView: function closePlaceHolderView() {
|
467
|
-
if (this.placeHolderView) {
|
468
|
-
this.placeHolderView.close();
|
469
|
-
this.placeHolderView = null;
|
470
|
-
}
|
471
|
-
},
|
472
|
-
togglePlaceHolder: function togglePlaceHolder() {
|
473
|
-
var lastPlaceholderConstructor = this.placeHolderConstructor;
|
474
|
-
this.placeHolderConstructor = this.getPlaceHolderConstructor();
|
475
|
-
|
476
|
-
if (this.itemViews.length || !this.placeHolderConstructor) {
|
477
|
-
this.closePlaceHolderView();
|
478
|
-
} else if (!this.placeHolderView || lastPlaceholderConstructor !== this.placeHolderConstructor) {
|
479
|
-
this.closePlaceHolderView();
|
480
|
-
this.placeHolderView = new this.placeHolderConstructor();
|
481
|
-
this.$el.append(this.placeHolderView.render().el);
|
482
|
-
}
|
483
|
-
},
|
484
|
-
getPlaceHolderConstructor: function getPlaceHolderConstructor() {
|
485
|
-
if (this.loading && this.options.loadingViewConstructor) {
|
486
|
-
return this.options.loadingViewConstructor;
|
487
|
-
} else if (this.options.blankSlateViewConstructor) {
|
488
|
-
return this.options.blankSlateViewConstructor;
|
489
|
-
}
|
490
|
-
}
|
491
|
-
});
|
492
|
-
|
493
|
-
var SortableCollectionView = CollectionView.extend({
|
494
|
-
render: function render() {
|
495
|
-
CollectionView.prototype.render.call(this);
|
496
|
-
this.$el.sortable({
|
497
|
-
connectWith: this.options.connectWith,
|
498
|
-
placeholder: 'sortable-placeholder',
|
499
|
-
forcePlaceholderSize: true,
|
500
|
-
delay: 200,
|
501
|
-
update: _.bind(function (event, ui) {
|
502
|
-
if (ui.item.parent().is(this.el)) {
|
503
|
-
this.updateOrder();
|
504
|
-
}
|
505
|
-
}, this),
|
506
|
-
receive: _.bind(function (event, ui) {
|
507
|
-
var view = ui.item.data('view');
|
508
|
-
this.reindexPositions();
|
509
|
-
this.itemViews.add(view);
|
510
|
-
this.collection.add(view.model);
|
511
|
-
}, this),
|
512
|
-
remove: _.bind(function (event, ui) {
|
513
|
-
var view = ui.item.data('view');
|
514
|
-
this.itemViews.remove(view);
|
515
|
-
this.collection.remove(view.model);
|
516
|
-
}, this)
|
517
|
-
});
|
518
|
-
return this;
|
519
|
-
},
|
520
|
-
addItem: function addItem(item) {
|
521
|
-
if (!this.itemViews.findByModel(item)) {
|
522
|
-
CollectionView.prototype.addItem.call(this, item);
|
523
|
-
}
|
524
|
-
},
|
525
|
-
removeItem: function removeItem(item) {
|
526
|
-
if (this.itemViews.findByModel(item)) {
|
527
|
-
CollectionView.prototype.removeItem.call(this, item);
|
528
|
-
}
|
529
|
-
},
|
530
|
-
updateOrder: function updateOrder() {
|
531
|
-
this.reindexPositions();
|
532
|
-
this.collection.sort();
|
533
|
-
this.collection.saveOrder();
|
534
|
-
},
|
535
|
-
reindexPositions: function reindexPositions() {
|
536
|
-
this.$el.children().each(function (index) {
|
537
|
-
$(this).data('view').model.set('position', index);
|
538
|
-
});
|
539
|
-
}
|
540
|
-
});
|
541
|
-
|
542
|
-
var ConfigurationEditorTabView = Marionette.View.extend({
|
543
|
-
className: 'configuration_editor_tab',
|
544
|
-
initialize: function initialize() {
|
545
|
-
this.inputs = new ChildViewContainer();
|
546
|
-
this.groups = this.options.groups || ConfigurationEditorTabView.groups;
|
547
|
-
},
|
548
|
-
input: function input(propertyName, view, options) {
|
549
|
-
this.view(view, _.extend({
|
550
|
-
placeholderModel: this.options.placeholderModel,
|
551
|
-
propertyName: propertyName,
|
552
|
-
attributeTranslationKeyPrefixes: this.options.attributeTranslationKeyPrefixes
|
553
|
-
}, options || {}));
|
554
|
-
},
|
555
|
-
view: function view(_view, options) {
|
556
|
-
this.inputs.add(new _view(_.extend({
|
557
|
-
model: this.model,
|
558
|
-
parentTab: this.options.tab
|
559
|
-
}, options || {})));
|
560
|
-
},
|
561
|
-
group: function group(name, options) {
|
562
|
-
this.groups.apply(name, this, options);
|
563
|
-
},
|
564
|
-
render: function render() {
|
565
|
-
this.inputs.each(function (input) {
|
566
|
-
this.$el.append(input.render().el);
|
567
|
-
}, this);
|
568
|
-
return this;
|
569
|
-
},
|
570
|
-
onClose: function onClose() {
|
571
|
-
if (this.inputs) {
|
572
|
-
this.inputs.call('close');
|
573
|
-
}
|
574
|
-
}
|
575
|
-
});
|
576
|
-
|
577
|
-
ConfigurationEditorTabView.Groups = function () {
|
578
|
-
var groups = {};
|
579
|
-
|
580
|
-
this.define = function (name, fn) {
|
581
|
-
if (typeof fn !== 'function') {
|
582
|
-
throw 'Group has to be function.';
|
583
|
-
}
|
584
|
-
|
585
|
-
groups[name] = fn;
|
586
|
-
};
|
587
|
-
|
588
|
-
this.apply = function (name, context, options) {
|
589
|
-
if (!(name in groups)) {
|
590
|
-
throw 'Undefined group named "' + name + '".';
|
591
|
-
}
|
592
|
-
|
593
|
-
groups[name].call(context, options || {});
|
594
|
-
};
|
595
|
-
};
|
596
|
-
|
597
|
-
ConfigurationEditorTabView.groups = new ConfigurationEditorTabView.Groups();
|
598
|
-
|
599
|
-
function template(data) {
|
600
|
-
var __p = '';
|
601
|
-
__p += '<div class="tabs_view-scroller">\n <ul class="tabs_view-headers"></ul>\n</div>\n<div class="tabs_view-container"></div>\n';
|
602
|
-
return __p
|
603
|
-
}
|
604
|
-
|
605
|
-
/*global pageflow*/
|
606
|
-
/**
|
607
|
-
* Switch between different views using tabs.
|
608
|
-
*
|
609
|
-
* @param {Object} [options]
|
610
|
-
*
|
611
|
-
* @param {string} [options.defaultTab]
|
612
|
-
* Name of the tab to enable by default.
|
613
|
-
*
|
614
|
-
* @param {string[]} [options.translationKeyPrefixes]
|
615
|
-
* List of prefixes to append tab name to. First exisiting translation is used as label.
|
616
|
-
*
|
617
|
-
* @param {string} [options.fallbackTranslationKeyPrefix]
|
618
|
-
* Translation key prefix to use if non of the `translationKeyPrefixes` result in an
|
619
|
-
* existing translation for a tab name.
|
620
|
-
*
|
621
|
-
* @param {string} [options.i18n]
|
622
|
-
* Legacy alias for `fallbackTranslationKeyPrefix`.
|
623
|
-
*
|
624
|
-
* @class
|
625
|
-
*/
|
626
|
-
|
627
|
-
var TabsView = Marionette.Layout.extend(
|
628
|
-
/* @lends TabView.prototype */
|
629
|
-
{
|
630
|
-
template: template,
|
631
|
-
className: 'tabs_view',
|
632
|
-
ui: {
|
633
|
-
headers: '.tabs_view-headers',
|
634
|
-
scroller: '.tabs_view-scroller'
|
635
|
-
},
|
636
|
-
regions: {
|
637
|
-
container: '.tabs_view-container'
|
638
|
-
},
|
639
|
-
events: {
|
640
|
-
'click .tabs_view-headers > li': function clickTabs_viewHeadersLi(event) {
|
641
|
-
this.changeTab($(event.target).data('tab-name'));
|
642
|
-
}
|
643
|
-
},
|
644
|
-
initialize: function initialize() {
|
645
|
-
this.tabFactoryFns = {};
|
646
|
-
this.tabNames = [];
|
647
|
-
this.currentTabName = null;
|
648
|
-
|
649
|
-
this._refreshScrollerOnSideBarResize();
|
650
|
-
},
|
651
|
-
tab: function tab(name, factoryFn) {
|
652
|
-
this.tabFactoryFns[name] = factoryFn;
|
653
|
-
this.tabNames.push(name);
|
654
|
-
},
|
655
|
-
onRender: function onRender() {
|
656
|
-
_.each(this.tabNames, function (name) {
|
657
|
-
var label = findTranslation(this._labelTranslationKeys(name));
|
658
|
-
this.ui.headers.append($('<li />').attr('data-tab-name', name).text(label));
|
659
|
-
}, this);
|
660
|
-
|
661
|
-
this.scroller = new IScroll(this.ui.scroller[0], {
|
662
|
-
scrollX: true,
|
663
|
-
scrollY: false,
|
664
|
-
bounce: false,
|
665
|
-
mouseWheel: true,
|
666
|
-
preventDefault: false
|
667
|
-
});
|
668
|
-
this.changeTab(this.defaultTab());
|
669
|
-
},
|
670
|
-
changeTab: function changeTab(name) {
|
671
|
-
this.container.show(this.tabFactoryFns[name]());
|
672
|
-
|
673
|
-
this._updateActiveHeader(name);
|
674
|
-
|
675
|
-
this.currentTabName = name;
|
676
|
-
},
|
677
|
-
defaultTab: function defaultTab() {
|
678
|
-
if (_.include(this.tabNames, this.options.defaultTab)) {
|
679
|
-
return this.options.defaultTab;
|
680
|
-
} else {
|
681
|
-
return _.first(this.tabNames);
|
682
|
-
}
|
683
|
-
},
|
684
|
-
|
685
|
-
/**
|
686
|
-
* Rerender current tab.
|
687
|
-
*/
|
688
|
-
refresh: function refresh() {
|
689
|
-
this.changeTab(this.currentTabName);
|
690
|
-
},
|
691
|
-
|
692
|
-
/**
|
693
|
-
* Adjust tabs scroller to changed width of view.
|
694
|
-
*/
|
695
|
-
refreshScroller: function refreshScroller() {
|
696
|
-
this.scroller.refresh();
|
697
|
-
},
|
698
|
-
toggleSpinnerOnTab: function toggleSpinnerOnTab(name, visible) {
|
699
|
-
this.$('[data-tab-name=' + name + ']').toggleClass('spinner', visible);
|
700
|
-
},
|
701
|
-
_labelTranslationKeys: function _labelTranslationKeys(name) {
|
702
|
-
var result = _.map(this.options.translationKeyPrefixes, function (prefix) {
|
703
|
-
return prefix + '.' + name;
|
704
|
-
});
|
705
|
-
|
706
|
-
if (this.options.i18n) {
|
707
|
-
result.push(this.options.i18n + '.' + name);
|
708
|
-
}
|
709
|
-
|
710
|
-
if (this.options.fallbackTranslationKeyPrefix) {
|
711
|
-
result.push(this.options.fallbackTranslationKeyPrefix + '.' + name);
|
712
|
-
}
|
713
|
-
|
714
|
-
return result;
|
715
|
-
},
|
716
|
-
_updateActiveHeader: function _updateActiveHeader(activeTabName) {
|
717
|
-
var scroller = this.scroller;
|
718
|
-
this.ui.headers.children().each(function () {
|
719
|
-
if ($(this).data('tab-name') === activeTabName) {
|
720
|
-
scroller.scrollToElement(this, 200, true);
|
721
|
-
$(this).addClass('active');
|
722
|
-
} else {
|
723
|
-
$(this).removeClass('active');
|
724
|
-
}
|
725
|
-
});
|
726
|
-
},
|
727
|
-
_refreshScrollerOnSideBarResize: function _refreshScrollerOnSideBarResize() {
|
728
|
-
if (pageflow.app) {
|
729
|
-
this.listenTo(pageflow.app, 'resize', function () {
|
730
|
-
this.scroller.refresh();
|
731
|
-
});
|
732
|
-
}
|
733
|
-
}
|
734
|
-
});
|
735
|
-
|
736
|
-
/**
|
737
|
-
* Render a inputs on multiple tabs.
|
738
|
-
*
|
739
|
-
* @param {Object} [options]
|
740
|
-
*
|
741
|
-
* @param {string} [options.model]
|
742
|
-
* Backbone model to use for input views.
|
743
|
-
*
|
744
|
-
* @param {string} [options.placeholderModel]
|
745
|
-
* Backbone model to read placeholder values from.
|
746
|
-
|
747
|
-
* @param {string} [options.tab]
|
748
|
-
* Name of the tab to enable by default.
|
749
|
-
*
|
750
|
-
* @param {string[]} [options.attributeTranslationKeyPrefixes]
|
751
|
-
* List of prefixes to use in input views for attribute based transltions.
|
752
|
-
*
|
753
|
-
* @param {string[]} [options.tabTranslationKeyPrefixes]
|
754
|
-
* List of prefixes to append tab name to. First exisiting translation is used as label.
|
755
|
-
*
|
756
|
-
* @param {string} [options.tabTranslationKeyPrefix]
|
757
|
-
* Prefixes to append tab name to.
|
758
|
-
*
|
759
|
-
* @class
|
760
|
-
*/
|
761
|
-
|
762
|
-
var ConfigurationEditorView = Marionette.View.extend({
|
763
|
-
className: 'configuration_editor',
|
764
|
-
initialize: function initialize() {
|
765
|
-
this.tabsView = new TabsView({
|
766
|
-
translationKeyPrefixes: this.options.tabTranslationKeyPrefixes || [this.options.tabTranslationKeyPrefix],
|
767
|
-
fallbackTranslationKeyPrefix: 'pageflow.ui.configuration_editor.tabs',
|
768
|
-
defaultTab: this.options.tab
|
769
|
-
});
|
770
|
-
this.configure();
|
771
|
-
},
|
772
|
-
configure: function configure() {},
|
773
|
-
tab: function tab(name, callbackOrOptions, callback) {
|
774
|
-
callback = callback || callbackOrOptions;
|
775
|
-
var options = callback ? callbackOrOptions : {};
|
776
|
-
this.tabsView.tab(name, _.bind(function () {
|
777
|
-
var tabView = new ConfigurationEditorTabView({
|
778
|
-
model: options.model || this.model,
|
779
|
-
placeholderModel: this.options.placeholderModel,
|
780
|
-
tab: name,
|
781
|
-
attributeTranslationKeyPrefixes: this.options.attributeTranslationKeyPrefixes
|
782
|
-
});
|
783
|
-
callback.call(tabView);
|
784
|
-
return tabView;
|
785
|
-
}, this));
|
786
|
-
},
|
787
|
-
|
788
|
-
/**
|
789
|
-
* Rerender current tab.
|
790
|
-
*/
|
791
|
-
refresh: function refresh() {
|
792
|
-
this.tabsView.refresh();
|
793
|
-
},
|
794
|
-
|
795
|
-
/**
|
796
|
-
* Adjust tabs scroller to changed width of view.
|
797
|
-
*/
|
798
|
-
refreshScroller: function refreshScroller() {
|
799
|
-
this.tabsView.refreshScroller();
|
800
|
-
},
|
801
|
-
render: function render() {
|
802
|
-
this.$el.append(this.subview(this.tabsView).el);
|
803
|
-
return this;
|
804
|
-
}
|
805
|
-
});
|
806
|
-
|
807
|
-
_.extend(ConfigurationEditorView, {
|
808
|
-
repository: {},
|
809
|
-
register: function register(pageTypeName, prototype) {
|
810
|
-
this.repository[pageTypeName] = ConfigurationEditorView.extend(prototype);
|
811
|
-
}
|
812
|
-
});
|
813
|
-
|
814
|
-
function template$1(data) {
|
815
|
-
var __p = '';
|
816
|
-
__p += '';
|
817
|
-
return __p
|
818
|
-
}
|
819
|
-
|
820
|
-
/**
|
821
|
-
* Base class for table cell views.
|
822
|
-
*
|
823
|
-
* Inside sub classes the name of the column options are available as
|
824
|
-
* `this.options.column`. Override the `update` method to populate the
|
825
|
-
* element.
|
826
|
-
*
|
827
|
-
* @param {Object} [options]
|
828
|
-
*
|
829
|
-
* @param {string} [options.className]
|
830
|
-
* Class attribute to apply to the cell element.
|
831
|
-
*
|
832
|
-
* @since 12.0
|
833
|
-
*/
|
834
|
-
|
835
|
-
var TableCellView = Marionette.ItemView.extend({
|
836
|
-
tagName: 'td',
|
837
|
-
template: template$1,
|
838
|
-
className: function className() {
|
839
|
-
return this.options.className;
|
840
|
-
},
|
841
|
-
onRender: function onRender() {
|
842
|
-
this.listenTo(this.getModel(), 'change:' + this.options.column.name, this.update);
|
843
|
-
this.setupContentBinding();
|
844
|
-
this.update();
|
845
|
-
},
|
846
|
-
|
847
|
-
/**
|
848
|
-
* Override in concrete cell view.
|
849
|
-
*/
|
850
|
-
update: function update() {
|
851
|
-
throw 'Not implemented';
|
852
|
-
},
|
853
|
-
|
854
|
-
/**
|
855
|
-
* Returns the column attribute's value in the row model.
|
856
|
-
*/
|
857
|
-
attributeValue: function attributeValue() {
|
858
|
-
if (typeof this.options.column.value == 'function') {
|
859
|
-
return this.options.column.value(this.model);
|
860
|
-
} else {
|
861
|
-
return this.getModel().get(this.options.column.name);
|
862
|
-
}
|
863
|
-
},
|
864
|
-
getModel: function getModel() {
|
865
|
-
if (this.options.column.configurationAttribute) {
|
866
|
-
return this.model.configuration;
|
867
|
-
} else {
|
868
|
-
return this.model;
|
869
|
-
}
|
870
|
-
},
|
871
|
-
|
872
|
-
/**
|
873
|
-
* Look up attribute specific translations based on
|
874
|
-
* `attributeTranslationKeyPrefixes` of the the parent `TableView`.
|
875
|
-
*
|
876
|
-
* @param {Object} [options]
|
877
|
-
* Interpolations to apply to the translation.
|
878
|
-
*
|
879
|
-
* @param {string} [options.defaultValue]
|
880
|
-
* Fallback value if no translation is found.
|
881
|
-
*
|
882
|
-
* @protected
|
883
|
-
*
|
884
|
-
* @example
|
885
|
-
*
|
886
|
-
* this.attribute.attributeTranslation("cell_title");
|
887
|
-
* // Looks for keys of the form:
|
888
|
-
* // <table_view_translation_key_prefix>.<column_attribute>.cell_title
|
889
|
-
*/
|
890
|
-
attributeTranslation: function attributeTranslation(keyName, options) {
|
891
|
-
return findTranslation(this.attributeTranslationKeys(keyName), options);
|
892
|
-
},
|
893
|
-
attributeTranslationKeys: function attributeTranslationKeys(keyName) {
|
894
|
-
return _(this.options.attributeTranslationKeyPrefixes || []).map(function (prefix) {
|
895
|
-
return prefix + '.' + this.options.column.name + '.' + keyName;
|
896
|
-
}, this);
|
897
|
-
},
|
898
|
-
|
899
|
-
/**
|
900
|
-
* Set up content binding to update this view upon change of
|
901
|
-
* specified attribute on this.getModel().
|
902
|
-
*
|
903
|
-
* @param {string} [options.column.contentBinding]
|
904
|
-
* Name of the attribute to which this cell's update is bound
|
905
|
-
*
|
906
|
-
* @protected
|
907
|
-
*/
|
908
|
-
setupContentBinding: function setupContentBinding() {
|
909
|
-
if (this.options.column.contentBinding) {
|
910
|
-
this.listenTo(this.getModel(), 'change:' + this.options.column.contentBinding, this.update);
|
911
|
-
this.update();
|
912
|
-
}
|
913
|
-
}
|
914
|
-
});
|
915
|
-
|
916
|
-
var TableHeaderCellView = TableCellView.extend({
|
917
|
-
tagName: 'th',
|
918
|
-
render: function render() {
|
919
|
-
this.$el.text(this.options.column.headerText || this.attributeTranslation('column_header'));
|
920
|
-
this.$el.data('columnName', this.options.column.name);
|
921
|
-
return this;
|
922
|
-
}
|
923
|
-
});
|
924
|
-
|
925
|
-
var TableRowView = Marionette.View.extend({
|
926
|
-
tagName: 'tr',
|
927
|
-
events: {
|
928
|
-
'click': function click() {
|
929
|
-
if (this.options.selection) {
|
930
|
-
this.options.selection.set(this.selectionAttribute(), this.model);
|
931
|
-
}
|
932
|
-
}
|
933
|
-
},
|
934
|
-
initialize: function initialize() {
|
935
|
-
if (this.options.selection) {
|
936
|
-
this.listenTo(this.options.selection, 'change', this.updateClassName);
|
937
|
-
}
|
938
|
-
},
|
939
|
-
render: function render() {
|
940
|
-
_(this.options.columns).each(function (column) {
|
941
|
-
this.appendSubview(new column.cellView(_.extend({
|
942
|
-
model: this.model,
|
943
|
-
column: column,
|
944
|
-
attributeTranslationKeyPrefixes: this.options.attributeTranslationKeyPrefixes
|
945
|
-
}, column.cellViewOptions || {})));
|
946
|
-
}, this);
|
947
|
-
|
948
|
-
this.updateClassName();
|
949
|
-
return this;
|
950
|
-
},
|
951
|
-
updateClassName: function updateClassName() {
|
952
|
-
this.$el.toggleClass('is_selected', this.isSelected());
|
953
|
-
},
|
954
|
-
isSelected: function isSelected() {
|
955
|
-
return this.options.selection && this.options.selection.get(this.selectionAttribute()) === this.model;
|
956
|
-
},
|
957
|
-
selectionAttribute: function selectionAttribute() {
|
958
|
-
return this.options.selectionAttribute || 'current';
|
959
|
-
}
|
960
|
-
});
|
961
|
-
|
962
|
-
function template$2(data) {
|
963
|
-
var __p = '';
|
964
|
-
__p += '<table>\n <thead>\n <tr></tr>\n </thead>\n <tbody>\n </tbody>\n</table>\n';
|
965
|
-
return __p
|
966
|
-
}
|
967
|
-
|
968
|
-
function blankSlateTemplate(data) {
|
969
|
-
var __t, __p = '';
|
970
|
-
__p += '<td colspan="' +
|
971
|
-
((__t = ( data.colSpan )) == null ? '' : __t) +
|
972
|
-
'">\n ' +
|
973
|
-
((__t = ( data.blankSlateText )) == null ? '' : __t) +
|
974
|
-
'\n</td>\n';
|
975
|
-
return __p
|
976
|
-
}
|
977
|
-
|
978
|
-
var TableView = Marionette.ItemView.extend({
|
979
|
-
tagName: 'table',
|
980
|
-
className: 'table_view',
|
981
|
-
template: template$2,
|
982
|
-
ui: {
|
983
|
-
headRow: 'thead tr',
|
984
|
-
body: 'tbody'
|
985
|
-
},
|
986
|
-
onRender: function onRender() {
|
987
|
-
var view = this;
|
988
|
-
|
989
|
-
_(this.options.columns).each(function (column) {
|
990
|
-
this.ui.headRow.append(this.subview(new TableHeaderCellView({
|
991
|
-
column: column,
|
992
|
-
attributeTranslationKeyPrefixes: this.options.attributeTranslationKeyPrefixes
|
993
|
-
})).el);
|
994
|
-
}, this);
|
995
|
-
|
996
|
-
this.subview(new CollectionView({
|
997
|
-
el: this.ui.body,
|
998
|
-
collection: this.collection,
|
999
|
-
itemViewConstructor: TableRowView,
|
1000
|
-
itemViewOptions: {
|
1001
|
-
columns: this.options.columns,
|
1002
|
-
selection: this.options.selection,
|
1003
|
-
selectionAttribute: this.options.selectionAttribute,
|
1004
|
-
attributeTranslationKeyPrefixes: this.options.attributeTranslationKeyPrefixes
|
1005
|
-
},
|
1006
|
-
blankSlateViewConstructor: Marionette.ItemView.extend({
|
1007
|
-
tagName: 'tr',
|
1008
|
-
className: 'blank_slate',
|
1009
|
-
template: blankSlateTemplate,
|
1010
|
-
serializeData: function serializeData() {
|
1011
|
-
return {
|
1012
|
-
blankSlateText: view.options.blankSlateText,
|
1013
|
-
colSpan: view.options.columns.length
|
1014
|
-
};
|
1015
|
-
}
|
1016
|
-
})
|
1017
|
-
}));
|
1018
|
-
}
|
1019
|
-
});
|
1020
|
-
|
1021
|
-
function template$3(data) {
|
1022
|
-
var __p = '';
|
1023
|
-
__p += '<span class="label">\n</span>\n';
|
1024
|
-
return __p
|
1025
|
-
}
|
1026
|
-
|
1027
|
-
var TooltipView = Marionette.ItemView.extend({
|
1028
|
-
template: template$3,
|
1029
|
-
className: 'tooltip',
|
1030
|
-
ui: {
|
1031
|
-
label: '.label'
|
1032
|
-
},
|
1033
|
-
hide: function hide() {
|
1034
|
-
this.visible = false;
|
1035
|
-
clearTimeout(this.timeout);
|
1036
|
-
this.$el.removeClass('visible');
|
1037
|
-
},
|
1038
|
-
show: function show(text, position, options) {
|
1039
|
-
options = options || {};
|
1040
|
-
this.visible = true;
|
1041
|
-
clearTimeout(this.timeout);
|
1042
|
-
this.timeout = setTimeout(_.bind(function () {
|
1043
|
-
var offsetTop;
|
1044
|
-
var offsetLeft;
|
1045
|
-
this.ui.label.text(text);
|
1046
|
-
this.$el.toggleClass('align_bottom_right', options.align === 'bottom right');
|
1047
|
-
this.$el.toggleClass('align_bottom_left', options.align === 'bottom left');
|
1048
|
-
this.$el.toggleClass('align_top_center', options.align === 'top center');
|
1049
|
-
|
1050
|
-
if (options.align === 'bottom right' || options.align === 'bottom left') {
|
1051
|
-
offsetTop = 10;
|
1052
|
-
offsetLeft = 0;
|
1053
|
-
} else if (options.align === 'top center') {
|
1054
|
-
offsetTop = -10;
|
1055
|
-
offsetLeft = 0;
|
1056
|
-
} else {
|
1057
|
-
offsetTop = -17;
|
1058
|
-
offsetLeft = 10;
|
1059
|
-
}
|
1060
|
-
|
1061
|
-
this.$el.css({
|
1062
|
-
top: position.top + offsetTop + 'px',
|
1063
|
-
left: position.left + offsetLeft + 'px'
|
1064
|
-
});
|
1065
|
-
this.$el.addClass('visible');
|
1066
|
-
}, this), 200);
|
1067
|
-
}
|
1068
|
-
});
|
1069
|
-
|
1070
|
-
/**
|
1071
|
-
* Mixin for input views handling common concerns like labels,
|
1072
|
-
* inline help, visiblity and disabling.
|
1073
|
-
*
|
1074
|
-
* ## Label and Inline Help Translations
|
1075
|
-
*
|
1076
|
-
* By default `#labelText` and `#inlineHelpText` are defined through
|
1077
|
-
* translations. If no `attributeTranslationKeyPrefixes` are given,
|
1078
|
-
* translation keys for labels and inline help are constructed from
|
1079
|
-
* the `i18nKey` of the model and the given `propertyName`
|
1080
|
-
* option. Suppose the model's `i18nKey` is "page" and the
|
1081
|
-
* `propertyName` option is "title". Then the key
|
1082
|
-
*
|
1083
|
-
* activerecord.attributes.page.title
|
1084
|
-
*
|
1085
|
-
* will be used for the label. And the key
|
1086
|
-
*
|
1087
|
-
* pageflow.ui.inline_help.page.title_html
|
1088
|
-
* pageflow.ui.inline_help.page.title
|
1089
|
-
*
|
1090
|
-
* will be used for the inline help.
|
1091
|
-
*
|
1092
|
-
* ### Attribute Translation Key Prefixes
|
1093
|
-
*
|
1094
|
-
* The `attributeTranslationKeyPrefixes` option can be used to supply
|
1095
|
-
* an array of scopes in which label and inline help translations
|
1096
|
-
* shall be looked up based on the `propertyName` option.
|
1097
|
-
*
|
1098
|
-
* Suppose the array `['some.attributes', 'fallback.attributes']` is
|
1099
|
-
* given as `attributeTranslationKeyPrefixes` option. Then, in the
|
1100
|
-
* example above, the first existing translation key is used as label:
|
1101
|
-
*
|
1102
|
-
* some.attributes.title.label
|
1103
|
-
* fallback.attributes.title.label
|
1104
|
-
* activerecord.attributes.post.title
|
1105
|
-
*
|
1106
|
-
* Accordingly, for the inline help:
|
1107
|
-
*
|
1108
|
-
* some.attributes.title.inline_help_html
|
1109
|
-
* some.attributes.title.inline_help
|
1110
|
-
* fallback.attributes.title.inline_help_html
|
1111
|
-
* fallback.attributes.title.inline_help
|
1112
|
-
* pageflow.ui.inline_help.post.title_html
|
1113
|
-
* pageflow.ui.inline_help.post.title
|
1114
|
-
*
|
1115
|
-
* This setup allows to keep all translation keys for an attribute
|
1116
|
-
* to share a common prefix:
|
1117
|
-
*
|
1118
|
-
* some:
|
1119
|
-
* attributes:
|
1120
|
-
* title:
|
1121
|
-
* label: "Label"
|
1122
|
-
* inline_help: "..."
|
1123
|
-
* inline_help_disabled: "..."
|
1124
|
-
*
|
1125
|
-
* ### Inline Help for Disabled Inputs
|
1126
|
-
*
|
1127
|
-
* For each inline help translation key, a separate key with an
|
1128
|
-
* `"_disabled"` suffix can be supplied, which provides a help string
|
1129
|
-
* that shall be displayed when the input is disabled. More specific
|
1130
|
-
* attribute translation key prefixes take precedence over suffixed
|
1131
|
-
* keys:
|
1132
|
-
*
|
1133
|
-
* some.attributes.title.inline_help_html
|
1134
|
-
* some.attributes.title.inline_help
|
1135
|
-
* some.attributes.title.inline_help_disabled_html
|
1136
|
-
* some.attributes.title.inline_help_disabled
|
1137
|
-
* fallback.attributes.title.inline_help_html
|
1138
|
-
* fallback.attributes.title.inline_help
|
1139
|
-
* fallback.attributes.title.inline_help_disabled_html
|
1140
|
-
* fallback.attributes.title.inline_help_disabled
|
1141
|
-
* pageflow.ui.inline_help.post.title_html
|
1142
|
-
* pageflow.ui.inline_help.post.title
|
1143
|
-
* pageflow.ui.inline_help.post.title_disabled_html
|
1144
|
-
* pageflow.ui.inline_help.post.title_disabled
|
1145
|
-
*
|
1146
|
-
* @param {string} options
|
1147
|
-
* Common constructor options for all views that include this mixin.
|
1148
|
-
*
|
1149
|
-
* @param {string} options.propertyName
|
1150
|
-
* Name of the attribute on the model to display and edit.
|
1151
|
-
*
|
1152
|
-
* @param {string} [options.label]
|
1153
|
-
* Label text for the input.
|
1154
|
-
*
|
1155
|
-
* @param {string[]} [options.attributeTranslationKeyPrefixes]
|
1156
|
-
* An array of prefixes to lookup translations for labels and
|
1157
|
-
* inline help texts based on attribute names.
|
1158
|
-
*
|
1159
|
-
* @param {string} [options.additionalInlineHelpText]
|
1160
|
-
* A text that will be appended to the translation based inline
|
1161
|
-
* text.
|
1162
|
-
*
|
1163
|
-
* @param {string|string[]} [options.disabledBinding]
|
1164
|
-
* Name of an attribute to control whether the input is disabled. If
|
1165
|
-
* the `disabled` and `disabledBinding` options are not set,
|
1166
|
-
* input will be disabled whenever this attribute has a truthy value.
|
1167
|
-
* When multiple attribute names are passed, the function passed to
|
1168
|
-
* the `disabled` option will receive an array of values in the same
|
1169
|
-
* order.
|
1170
|
-
*
|
1171
|
-
* @param {function|boolean} [options.disabled]
|
1172
|
-
* Render input as disabled. A Function taking the value of the
|
1173
|
-
* `disabledBinding` attribute as parameter. Input will be disabled
|
1174
|
-
* only if function returns `true`.
|
1175
|
-
*
|
1176
|
-
* @param {any} [options.disabledBindingValue]
|
1177
|
-
* Input will be disabled whenever the value of the `disabledBinding`
|
1178
|
-
* attribute equals the value of this option.
|
1179
|
-
*
|
1180
|
-
* @param {string|string[]} [options.visibleBinding]
|
1181
|
-
* Name of an attribute to control whether the input is visible. If
|
1182
|
-
* the `visible` and `visibleBindingValue` options are not set,
|
1183
|
-
* input will be visible whenever this attribute has a truthy value.
|
1184
|
-
* When multiple attribute names are passed, the function passed to
|
1185
|
-
* the `visible` option will receive an array of values in the same
|
1186
|
-
* order.
|
1187
|
-
*
|
1188
|
-
* @param {function|boolean} [options.visible]
|
1189
|
-
* A Function taking the value of the `visibleBinding` attribute as
|
1190
|
-
* parameter. Input will be visible only if function returns `true`.
|
1191
|
-
*
|
1192
|
-
* @param {any} [options.visibleBindingValue]
|
1193
|
-
* Input will be visible whenever the value of the `visibleBinding`
|
1194
|
-
* attribute equals the value of this option.
|
1195
|
-
*
|
1196
|
-
* @mixin
|
1197
|
-
*/
|
1198
|
-
|
1199
|
-
var inputView = {
|
1200
|
-
ui: {
|
1201
|
-
label: 'label',
|
1202
|
-
labelText: 'label .name',
|
1203
|
-
inlineHelp: 'label .inline_help'
|
1204
|
-
},
|
1205
|
-
|
1206
|
-
/**
|
1207
|
-
* Returns an array of translation keys based on the
|
1208
|
-
* `attributeTranslationKeyPrefixes` option and the given keyName.
|
1209
|
-
*
|
1210
|
-
* Combined with {@link #i18nutils
|
1211
|
-
* i18nUtils.findTranslation}, this can be used inside input views
|
1212
|
-
* to obtain additional translations with the same logic as for
|
1213
|
-
* labels and inline help texts.
|
1214
|
-
*
|
1215
|
-
* findTranslation(this.attributeTranslationKeys('default_value'));
|
1216
|
-
*
|
1217
|
-
* @param {string} keyName
|
1218
|
-
* Suffix to append to prefixes.
|
1219
|
-
*
|
1220
|
-
* @param {string} [options.fallbackPrefix]
|
1221
|
-
* Optional additional prefix to form a model based translation
|
1222
|
-
* key of the form `prefix.modelI18nKey.propertyName.keyName
|
1223
|
-
*
|
1224
|
-
* @return {string[]}
|
1225
|
-
* @since 0.9
|
1226
|
-
* @member
|
1227
|
-
*/
|
1228
|
-
attributeTranslationKeys: function attributeTranslationKeys$1(keyName, options) {
|
1229
|
-
return attributeTranslationKeys(this.options.propertyName, keyName, _.extend({
|
1230
|
-
prefixes: this.options.attributeTranslationKeyPrefixes,
|
1231
|
-
fallbackModelI18nKey: this.model.i18nKey
|
1232
|
-
}, options || {}));
|
1233
|
-
},
|
1234
|
-
onRender: function onRender() {
|
1235
|
-
this.$el.addClass('input');
|
1236
|
-
this.$el.addClass(this.model.modelName + '_' + this.options.propertyName);
|
1237
|
-
this.$el.data('inputPropertyName', this.options.propertyName);
|
1238
|
-
this.$el.data('labelText', this.labelText());
|
1239
|
-
this.$el.data('inlineHelpText', this.inlineHelpText());
|
1240
|
-
this.ui.labelText.text(this.labelText());
|
1241
|
-
this.updateInlineHelp();
|
1242
|
-
this.setLabelFor();
|
1243
|
-
this.setupAttributeBinding('disabled', this.updateDisabled);
|
1244
|
-
this.setupAttributeBinding('visible', this.updateVisible);
|
1245
|
-
},
|
1246
|
-
|
1247
|
-
/**
|
1248
|
-
* The label to display in the form.
|
1249
|
-
* @return {string}
|
1250
|
-
*/
|
1251
|
-
labelText: function labelText() {
|
1252
|
-
return this.options.label || this.localizedAttributeName();
|
1253
|
-
},
|
1254
|
-
localizedAttributeName: function localizedAttributeName() {
|
1255
|
-
return findTranslation(this.attributeTranslationKeys('label', {
|
1256
|
-
fallbackPrefix: 'activerecord.attributes'
|
1257
|
-
}));
|
1258
|
-
},
|
1259
|
-
updateInlineHelp: function updateInlineHelp() {
|
1260
|
-
this.ui.inlineHelp.html(this.inlineHelpText());
|
1261
|
-
|
1262
|
-
if (!this.inlineHelpText()) {
|
1263
|
-
this.ui.inlineHelp.hide();
|
1264
|
-
}
|
1265
|
-
},
|
1266
|
-
|
1267
|
-
/**
|
1268
|
-
* The inline help text for the form field.
|
1269
|
-
* @return {string}
|
1270
|
-
*/
|
1271
|
-
inlineHelpText: function inlineHelpText() {
|
1272
|
-
var keys = this.attributeTranslationKeys('inline_help', {
|
1273
|
-
fallbackPrefix: 'pageflow.ui.inline_help'
|
1274
|
-
});
|
1275
|
-
|
1276
|
-
if (this.isDisabled()) {
|
1277
|
-
keys = translationKeysWithSuffix(keys, 'disabled');
|
1278
|
-
}
|
1279
|
-
|
1280
|
-
return _.compact([findTranslation(keys, {
|
1281
|
-
defaultValue: '',
|
1282
|
-
html: true
|
1283
|
-
}), this.options.additionalInlineHelpText]).join(' ');
|
1284
|
-
},
|
1285
|
-
setLabelFor: function setLabelFor() {
|
1286
|
-
if (this.ui.input && this.ui.label.length === 1 && !this.ui.input.attr('id')) {
|
1287
|
-
var id = 'input_' + this.model.modelName + '_' + this.options.propertyName;
|
1288
|
-
this.ui.input.attr('id', id);
|
1289
|
-
this.ui.label.attr('for', id);
|
1290
|
-
}
|
1291
|
-
},
|
1292
|
-
isDisabled: function isDisabled() {
|
1293
|
-
return this.getAttributeBoundOption('disabled');
|
1294
|
-
},
|
1295
|
-
updateDisabled: function updateDisabled() {
|
1296
|
-
this.$el.toggleClass('input-disabled', !!this.isDisabled());
|
1297
|
-
this.updateInlineHelp();
|
1298
|
-
|
1299
|
-
if (this.ui.input) {
|
1300
|
-
this.updateDisabledAttribute(this.ui.input);
|
1301
|
-
}
|
1302
|
-
},
|
1303
|
-
updateDisabledAttribute: function updateDisabledAttribute(element) {
|
1304
|
-
if (this.isDisabled()) {
|
1305
|
-
element.attr('disabled', true);
|
1306
|
-
} else {
|
1307
|
-
element.removeAttr('disabled');
|
1308
|
-
}
|
1309
|
-
},
|
1310
|
-
updateVisible: function updateVisible() {
|
1311
|
-
this.$el.toggleClass('input-hidden_via_binding', this.getAttributeBoundOption('visible') === false);
|
1312
|
-
},
|
1313
|
-
setupAttributeBinding: function setupAttributeBinding(optionName, updateMethod) {
|
1314
|
-
var _this = this;
|
1315
|
-
|
1316
|
-
var binding = this.options["".concat(optionName, "Binding")];
|
1317
|
-
var view = this;
|
1318
|
-
|
1319
|
-
if (binding) {
|
1320
|
-
_.flatten([binding]).forEach(function (attribute) {
|
1321
|
-
_this.listenTo(_this.model, 'change:' + attribute, update);
|
1322
|
-
});
|
1323
|
-
}
|
1324
|
-
|
1325
|
-
update();
|
1326
|
-
|
1327
|
-
function update() {
|
1328
|
-
updateMethod.call(view, view.getAttributeBoundOption(optionName));
|
1329
|
-
}
|
1330
|
-
},
|
1331
|
-
getAttributeBoundOption: function getAttributeBoundOption(optionName) {
|
1332
|
-
var _this2 = this;
|
1333
|
-
|
1334
|
-
var binding = this.options["".concat(optionName, "Binding")];
|
1335
|
-
var bindingValueOptionName = "".concat(optionName, "BindingValue");
|
1336
|
-
var value = Array.isArray(binding) ? binding.map(function (attribute) {
|
1337
|
-
return _this2.model.get(attribute);
|
1338
|
-
}) : this.model.get(binding);
|
1339
|
-
|
1340
|
-
if (bindingValueOptionName in this.options) {
|
1341
|
-
return value === this.options[bindingValueOptionName];
|
1342
|
-
} else if (typeof this.options[optionName] === 'function') {
|
1343
|
-
return !!this.options[optionName](value);
|
1344
|
-
} else if (optionName in this.options) {
|
1345
|
-
return !!this.options[optionName];
|
1346
|
-
} else if (binding) {
|
1347
|
-
return !!value;
|
1348
|
-
}
|
1349
|
-
}
|
1350
|
-
};
|
1351
|
-
|
1352
|
-
function template$4(data) {
|
1353
|
-
var __p = '';
|
1354
|
-
__p += '<label>\n <span class="name"></span>\n <span class="inline_help"></span>\n</label>\n<div class="check_boxes_container" />\n';
|
1355
|
-
return __p
|
1356
|
-
}
|
1357
|
-
|
1358
|
-
/**
|
1359
|
-
* Input view for attributes storing configuration hashes with boolean values.
|
1360
|
-
* See {@link inputView} for further options.
|
1361
|
-
*
|
1362
|
-
* @param {Object} [options]
|
1363
|
-
*
|
1364
|
-
* @class
|
1365
|
-
*/
|
1366
|
-
|
1367
|
-
var CheckBoxGroupInputView = Marionette.ItemView.extend({
|
1368
|
-
mixins: [inputView],
|
1369
|
-
template: template$4,
|
1370
|
-
className: 'check_box_group_input',
|
1371
|
-
events: {
|
1372
|
-
'change': 'save'
|
1373
|
-
},
|
1374
|
-
ui: {
|
1375
|
-
label: 'label',
|
1376
|
-
container: '.check_boxes_container'
|
1377
|
-
},
|
1378
|
-
initialize: function initialize() {
|
1379
|
-
if (!this.options.texts) {
|
1380
|
-
if (!this.options.translationKeys) {
|
1381
|
-
var translationKeyPrefix = this.options.translationKeyPrefix || findKeyWithTranslation(this.attributeTranslationKeys('values', {
|
1382
|
-
fallbackPrefix: 'activerecord.values'
|
1383
|
-
}));
|
1384
|
-
this.options.translationKeys = _.map(this.options.values, function (value) {
|
1385
|
-
return translationKeyPrefix + '.' + value;
|
1386
|
-
}, this);
|
1387
|
-
}
|
1388
|
-
|
1389
|
-
this.options.texts = _.map(this.options.translationKeys, function (key) {
|
1390
|
-
return I18n$1.t(key);
|
1391
|
-
});
|
1392
|
-
}
|
1393
|
-
},
|
1394
|
-
onRender: function onRender() {
|
1395
|
-
this.ui.label.attr('for', this.cid);
|
1396
|
-
this.appendOptions();
|
1397
|
-
this.load();
|
1398
|
-
this.listenTo(this.model, 'change:' + this.options.propertyName, this.load);
|
1399
|
-
},
|
1400
|
-
appendOptions: function appendOptions() {
|
1401
|
-
_.each(this.options.values, function (value, index) {
|
1402
|
-
var option = '<div class="check_box">' + '<label><input type="checkbox" name="' + value + '" />' + this.options.texts[index] + '</label></div>';
|
1403
|
-
this.ui.container.append($(option));
|
1404
|
-
}, this);
|
1405
|
-
},
|
1406
|
-
save: function save() {
|
1407
|
-
var configured = {};
|
1408
|
-
|
1409
|
-
_.each(this.ui.container.find('input'), function (input) {
|
1410
|
-
configured[$(input).attr('name')] = $(input).prop('checked');
|
1411
|
-
});
|
1412
|
-
|
1413
|
-
this.model.set(this.options.propertyName, configured);
|
1414
|
-
},
|
1415
|
-
load: function load() {
|
1416
|
-
if (!this.isClosed) {
|
1417
|
-
_.each(this.options.values, function (value) {
|
1418
|
-
this.ui.container.find('input[name="' + value + '"]').prop('checked', this.model.get(this.options.propertyName)[value]);
|
1419
|
-
}, this);
|
1420
|
-
}
|
1421
|
-
}
|
1422
|
-
});
|
1423
|
-
|
1424
|
-
function template$5(data) {
|
1425
|
-
var __t, __p = '';
|
1426
|
-
__p += '<label>\n <span class="name"></span>\n <span class="inline_help"></span>\n</label>\n<a class="original" href="#" download target="_blank">\n ' +
|
1427
|
-
((__t = ( I18n.t('pageflow.ui.templates.inputs.url_display.link_text') )) == null ? '' : __t) +
|
1428
|
-
'\n</a>\n';
|
1429
|
-
return __p
|
1430
|
-
}
|
1431
|
-
|
1432
|
-
/**
|
1433
|
-
* Display view for a link to a URL, to be used like an input view.
|
1434
|
-
* See {@link inputView} for further options
|
1435
|
-
*
|
1436
|
-
* @param {Object} [options]
|
1437
|
-
*
|
1438
|
-
* @param {string} [options.propertyName]
|
1439
|
-
* Target URL for link
|
1440
|
-
*
|
1441
|
-
* @class
|
1442
|
-
*/
|
1443
|
-
|
1444
|
-
var UrlDisplayView = Marionette.ItemView.extend({
|
1445
|
-
mixins: [inputView],
|
1446
|
-
template: template$5,
|
1447
|
-
ui: {
|
1448
|
-
link: 'a'
|
1449
|
-
},
|
1450
|
-
modelEvents: {
|
1451
|
-
'change': 'update'
|
1452
|
-
},
|
1453
|
-
events: {
|
1454
|
-
'click a': function clickA(event) {
|
1455
|
-
// Ensure default is not prevented by parent event listener.
|
1456
|
-
event.stopPropagation();
|
1457
|
-
}
|
1458
|
-
},
|
1459
|
-
onRender: function onRender() {
|
1460
|
-
this.update();
|
1461
|
-
},
|
1462
|
-
update: function update() {
|
1463
|
-
var url = this.model.get('original_url');
|
1464
|
-
this.$el.toggle(this.model.isUploaded() && !_.isEmpty(url));
|
1465
|
-
this.ui.link.attr('href', url);
|
1466
|
-
}
|
1467
|
-
});
|
1468
|
-
|
1469
|
-
/**
|
1470
|
-
* Text based input view that can display a placeholder.
|
1471
|
-
*
|
1472
|
-
* @param {Object} [options]
|
1473
|
-
*
|
1474
|
-
* @param {string|function} [options.placeholder]
|
1475
|
-
* Display a placeholder string if the input is blank. Either a
|
1476
|
-
* string or a function taking the model as a first parameter and
|
1477
|
-
* returning a string.
|
1478
|
-
*
|
1479
|
-
* @param {string} [options.placeholderBinding]
|
1480
|
-
* Name of an attribute. Recompute the placeholder function whenever
|
1481
|
-
* this attribute changes.
|
1482
|
-
*
|
1483
|
-
* @param {boolean} [options.hidePlaceholderIfDisabled]
|
1484
|
-
* Do not display the placeholder if the input is disabled.
|
1485
|
-
*
|
1486
|
-
* @param {Backbone.Model} [options.placeholderModel]
|
1487
|
-
* Obtain placeholder by looking up the configured `propertyName`
|
1488
|
-
* inside a given model.
|
1489
|
-
*/
|
1490
|
-
var inputWithPlaceholderText = {
|
1491
|
-
onRender: function onRender() {
|
1492
|
-
this.updatePlaceholder();
|
1493
|
-
|
1494
|
-
if (this.options.placeholderBinding) {
|
1495
|
-
this.listenTo(this.model, 'change:' + this.options.placeholderBinding, this.updatePlaceholder);
|
1496
|
-
}
|
1497
|
-
},
|
1498
|
-
updateDisabled: function updateDisabled() {
|
1499
|
-
this.updatePlaceholder();
|
1500
|
-
},
|
1501
|
-
updatePlaceholder: function updatePlaceholder() {
|
1502
|
-
this.ui.input.attr('placeholder', this.placeholderText());
|
1503
|
-
},
|
1504
|
-
placeholderText: function placeholderText() {
|
1505
|
-
if (!this.isDisabled() || !this.options.hidePlaceholderIfDisabled) {
|
1506
|
-
if (this.options.placeholder) {
|
1507
|
-
if (typeof this.options.placeholder == 'function') {
|
1508
|
-
return this.options.placeholder(this.model);
|
1509
|
-
} else {
|
1510
|
-
return this.options.placeholder;
|
1511
|
-
}
|
1512
|
-
} else {
|
1513
|
-
return this.placeholderModelValue();
|
1514
|
-
}
|
1515
|
-
}
|
1516
|
-
|
1517
|
-
return '';
|
1518
|
-
},
|
1519
|
-
placeholderModelValue: function placeholderModelValue() {
|
1520
|
-
return this.options.placeholderModel && this.options.placeholderModel.get(this.options.propertyName);
|
1521
|
-
}
|
1522
|
-
};
|
1523
|
-
|
1524
|
-
var viewWithValidationErrorMessages = {
|
1525
|
-
onRender: function onRender() {
|
1526
|
-
this.listenTo(this.model, 'invalid sync', this.updateValidationErrorMessages);
|
1527
|
-
this.updateValidationErrorMessages();
|
1528
|
-
},
|
1529
|
-
updateValidationErrorMessages: function updateValidationErrorMessages() {
|
1530
|
-
var _this = this;
|
1531
|
-
|
1532
|
-
var errors = this.model.validationErrors && this.model.validationErrors[this.options.propertyName] || [];
|
1533
|
-
|
1534
|
-
if (errors.length) {
|
1535
|
-
this.validationErrorList = this.validationErrorList || $('<ul class="validation_error_messages" />').appendTo(this.el);
|
1536
|
-
this.validationErrorList.html('');
|
1537
|
-
errors.forEach(function (error) {
|
1538
|
-
return _this.validationErrorList.append("<li>".concat(error, "</li>"));
|
1539
|
-
});
|
1540
|
-
this.$el.addClass('invalid');
|
1541
|
-
} else if (this.validationErrorList) {
|
1542
|
-
this.validationErrorList.remove();
|
1543
|
-
this.validationErrorList = null;
|
1544
|
-
this.$el.removeClass('invalid');
|
1545
|
-
}
|
1546
|
-
}
|
1547
|
-
};
|
1548
|
-
|
1549
|
-
function template$6(data) {
|
1550
|
-
var __p = '';
|
1551
|
-
__p += '<label>\n <span class="name"></span>\n <span class="inline_help"></span>\n</label>\n<input type="text" dir="auto" />\n';
|
1552
|
-
return __p
|
1553
|
-
}
|
1554
|
-
|
1555
|
-
/**
|
1556
|
-
* Input view for a single line of text.
|
1557
|
-
*
|
1558
|
-
* See {@link inputWithPlaceholderText} for placeholder related
|
1559
|
-
* further options. See {@link inputView} for further options.
|
1560
|
-
*
|
1561
|
-
* @param {Object} [options]
|
1562
|
-
*
|
1563
|
-
* @param {boolean} [options.required=false]
|
1564
|
-
* Display an error if the input is blank.
|
1565
|
-
*
|
1566
|
-
* @param {number} [options.maxLength=255]
|
1567
|
-
* Maximum length of characters for this input. To support legacy
|
1568
|
-
* data which consists of more characters than the specified
|
1569
|
-
* maxLength, the option will only take effect for data which is
|
1570
|
-
* shorter than the specified maxLength.
|
1571
|
-
*
|
1572
|
-
* @class
|
1573
|
-
*/
|
1574
|
-
|
1575
|
-
var TextInputView = Marionette.ItemView.extend({
|
1576
|
-
mixins: [inputView, inputWithPlaceholderText, viewWithValidationErrorMessages],
|
1577
|
-
template: template$6,
|
1578
|
-
ui: {
|
1579
|
-
input: 'input'
|
1580
|
-
},
|
1581
|
-
events: {
|
1582
|
-
'change': 'onChange'
|
1583
|
-
},
|
1584
|
-
onRender: function onRender() {
|
1585
|
-
this.load();
|
1586
|
-
this.validate();
|
1587
|
-
this.listenTo(this.model, 'change:' + this.options.propertyName, this.load);
|
1588
|
-
},
|
1589
|
-
onChange: function onChange() {
|
1590
|
-
if (this.validate()) {
|
1591
|
-
this.save();
|
1592
|
-
}
|
1593
|
-
},
|
1594
|
-
onClose: function onClose() {
|
1595
|
-
if (this.validate()) {
|
1596
|
-
this.save();
|
1597
|
-
}
|
1598
|
-
},
|
1599
|
-
save: function save() {
|
1600
|
-
this.model.set(this.options.propertyName, this.ui.input.val());
|
1601
|
-
},
|
1602
|
-
load: function load() {
|
1603
|
-
var input = this.ui.input;
|
1604
|
-
input.val(this.model.get(this.options.propertyName)); // set mysql varchar length as default for non-legacy data
|
1605
|
-
|
1606
|
-
this.options.maxLength = this.options.maxLength || 255; // do not validate legacy data which length exceeds the specified maximum
|
1607
|
-
// for new and maxLength-conforming data: add validation
|
1608
|
-
|
1609
|
-
this.validateMaxLength = input.val().length <= this.options.maxLength;
|
1610
|
-
},
|
1611
|
-
validate: function validate() {
|
1612
|
-
var input = this.ui.input;
|
1613
|
-
|
1614
|
-
if (this.options.required && !input.val()) {
|
1615
|
-
this.displayValidationError(I18n$1.t('pageflow.ui.views.inputs.text_input_view.required_field'));
|
1616
|
-
return false;
|
1617
|
-
}
|
1618
|
-
|
1619
|
-
if (this.validateMaxLength && input.val().length > this.options.maxLength) {
|
1620
|
-
this.displayValidationError(I18n$1.t('pageflow.ui.views.inputs.text_input_view.max_characters_exceeded', {
|
1621
|
-
max_length: this.options.maxLength
|
1622
|
-
}));
|
1623
|
-
return false;
|
1624
|
-
} else {
|
1625
|
-
this.resetValidationError();
|
1626
|
-
return true;
|
1627
|
-
}
|
1628
|
-
},
|
1629
|
-
displayValidationError: function displayValidationError(message) {
|
1630
|
-
this.$el.addClass('invalid');
|
1631
|
-
this.ui.input.attr('title', message);
|
1632
|
-
},
|
1633
|
-
resetValidationError: function resetValidationError(message) {
|
1634
|
-
this.$el.removeClass('invalid');
|
1635
|
-
this.ui.input.attr('title', '');
|
1636
|
-
}
|
1637
|
-
});
|
1638
|
-
|
1639
|
-
/**
|
1640
|
-
* Input view for a color value in hex representation.
|
1641
|
-
* See {@link inputView} for further options
|
1642
|
-
*
|
1643
|
-
* @param {Object} [options]
|
1644
|
-
*
|
1645
|
-
* @param {string|function} [options.defaultValue]
|
1646
|
-
* Color value to display by default. The corresponding value is not
|
1647
|
-
* stored in the model. Selecting the default value when a different
|
1648
|
-
* value was set before, unsets the attribute in the model.
|
1649
|
-
*
|
1650
|
-
* @param {string} [options.defaultValueBinding]
|
1651
|
-
* Name of an attribute the default value depends on. If a function
|
1652
|
-
* is used as defaultValue option, it will be passed the value of the
|
1653
|
-
* defaultValueBinding attribute each time it changes. If no
|
1654
|
-
* defaultValue option is set, the value of the defaultValueBinding
|
1655
|
-
* attribute will be used as default value.
|
1656
|
-
*
|
1657
|
-
* @param {string[]} [options.swatches]
|
1658
|
-
* Preset color values to be displayed inside the picker drop
|
1659
|
-
* down. The default value, if present, is always used as the
|
1660
|
-
* first swatch automatically.
|
1661
|
-
*
|
1662
|
-
* @class
|
1663
|
-
*/
|
1664
|
-
|
1665
|
-
var ColorInputView = Marionette.ItemView.extend({
|
1666
|
-
mixins: [inputView],
|
1667
|
-
template: template$6,
|
1668
|
-
className: 'color_input',
|
1669
|
-
ui: {
|
1670
|
-
input: 'input'
|
1671
|
-
},
|
1672
|
-
events: {
|
1673
|
-
'mousedown': 'refreshPicker'
|
1674
|
-
},
|
1675
|
-
onRender: function onRender() {
|
1676
|
-
this.ui.input.minicolors({
|
1677
|
-
changeDelay: 200,
|
1678
|
-
change: _.bind(function (color) {
|
1679
|
-
if (color === this.defaultValue()) {
|
1680
|
-
this.model.unset(this.options.propertyName);
|
1681
|
-
} else {
|
1682
|
-
this.model.set(this.options.propertyName, color);
|
1683
|
-
}
|
1684
|
-
}, this)
|
1685
|
-
});
|
1686
|
-
this.listenTo(this.model, 'change:' + this.options.propertyName, this.load);
|
1687
|
-
|
1688
|
-
if (this.options.defaultValueBinding) {
|
1689
|
-
this.listenTo(this.model, 'change:' + this.options.defaultValueBinding, this.updateSettings);
|
1690
|
-
}
|
1691
|
-
|
1692
|
-
this.updateSettings();
|
1693
|
-
},
|
1694
|
-
updateSettings: function updateSettings() {
|
1695
|
-
this.resetSwatchesInStoredSettings();
|
1696
|
-
this.ui.input.minicolors('settings', {
|
1697
|
-
defaultValue: this.defaultValue(),
|
1698
|
-
swatches: this.getSwatches()
|
1699
|
-
});
|
1700
|
-
this.load();
|
1701
|
-
},
|
1702
|
-
// see https://github.com/claviska/jquery-minicolors/issues/287
|
1703
|
-
resetSwatchesInStoredSettings: function resetSwatchesInStoredSettings() {
|
1704
|
-
var settings = this.ui.input.data('minicolors-settings');
|
1705
|
-
|
1706
|
-
if (settings) {
|
1707
|
-
delete settings.swatches;
|
1708
|
-
this.ui.input.data('minicolors-settings', settings);
|
1709
|
-
}
|
1710
|
-
},
|
1711
|
-
load: function load() {
|
1712
|
-
this.ui.input.minicolors('value', this.model.get(this.options.propertyName) || this.defaultValue());
|
1713
|
-
this.$el.toggleClass('is_default', !this.model.has(this.options.propertyName));
|
1714
|
-
},
|
1715
|
-
refreshPicker: function refreshPicker() {
|
1716
|
-
this.ui.input.minicolors('value', {});
|
1717
|
-
},
|
1718
|
-
getSwatches: function getSwatches() {
|
1719
|
-
return _.chain([this.defaultValue(), this.options.swatches]).flatten().uniq().compact().value();
|
1720
|
-
},
|
1721
|
-
defaultValue: function defaultValue() {
|
1722
|
-
var bindingValue;
|
1723
|
-
|
1724
|
-
if (this.options.defaultValueBinding) {
|
1725
|
-
bindingValue = this.model.get(this.options.defaultValueBinding);
|
1726
|
-
}
|
1727
|
-
|
1728
|
-
if (typeof this.options.defaultValue === 'function') {
|
1729
|
-
return this.options.defaultValue(bindingValue);
|
1730
|
-
} else if ('defaultValue' in this.options) {
|
1731
|
-
return this.options.defaultValue;
|
1732
|
-
} else {
|
1733
|
-
return bindingValue;
|
1734
|
-
}
|
1735
|
-
}
|
1736
|
-
});
|
1737
|
-
|
1738
|
-
function template$7(data) {
|
1739
|
-
var __p = '';
|
1740
|
-
__p += '<label>\n <span class="name"></span>\n <span class="inline_help"></span>\n</label>\n<select></select>';
|
1741
|
-
return __p
|
1742
|
-
}
|
1743
|
-
|
1744
|
-
/**
|
1745
|
-
* A drop down with support for grouped items.
|
1746
|
-
* See {@link inputView} for further options
|
1747
|
-
*
|
1748
|
-
* @param {Object} [options]
|
1749
|
-
*
|
1750
|
-
* @param {string[]} [options.values]
|
1751
|
-
* List of possible values to persist in the attribute.
|
1752
|
-
*
|
1753
|
-
* @param {string[]} [options.texts]
|
1754
|
-
* List of display texts for drop down items.
|
1755
|
-
*
|
1756
|
-
* @param {string[]} [options.translationKeys]
|
1757
|
-
* Translation keys to obtain item texts from.
|
1758
|
-
*
|
1759
|
-
* @param {string[]} [options.translationKeyPrefix]
|
1760
|
-
* Obtain texts for items from translations by appending the item
|
1761
|
-
* value to this prefix separated by a dot. By default the
|
1762
|
-
* [`attributeTranslationKeyPrefixes` option]{@link inputView}
|
1763
|
-
* is used by appending the suffix `.values` to each candidate.
|
1764
|
-
*
|
1765
|
-
* @param {string[]} [options.groups]
|
1766
|
-
* Array of same length as `values` array, containing the display
|
1767
|
-
* name of a group header each item shall be grouped under.
|
1768
|
-
*
|
1769
|
-
* @param {Backbone.Model[]} [options.collection]
|
1770
|
-
* Create items for each model in the collection. Use the
|
1771
|
-
* `*Property` options to extract values and texts for each items
|
1772
|
-
* from the models.
|
1773
|
-
*
|
1774
|
-
* @param {string} [options.valueProperty]
|
1775
|
-
* Attribute to use as item value.
|
1776
|
-
*
|
1777
|
-
* @param {string} [options.textProperty]
|
1778
|
-
* Attribute to use as item display text.
|
1779
|
-
*
|
1780
|
-
* @param {string} [options.groupProperty]
|
1781
|
-
* Attribute to use as item group name.
|
1782
|
-
*
|
1783
|
-
* @param {string} [options.translationKeyProperty]
|
1784
|
-
* Attribute to use as translation key to obtain display text.
|
1785
|
-
*
|
1786
|
-
* @param {string} [options.groupTranslationKeyProperty]
|
1787
|
-
* Attribute to use as translation key to obtain group name.
|
1788
|
-
*
|
1789
|
-
* @param {boolean} [options.ensureValueDefined]
|
1790
|
-
* Set the attribute to the first value on view creation.
|
1791
|
-
*
|
1792
|
-
* @param {boolean} [options.includeBlank]
|
1793
|
-
* Include an item that sets the value of the attribute to a blank
|
1794
|
-
* string.
|
1795
|
-
*
|
1796
|
-
* @param {string} [options.blankText]
|
1797
|
-
* Display text for the blank item.
|
1798
|
-
*
|
1799
|
-
* @param {string} [options.blankTranslationKey]
|
1800
|
-
* Translation key to obtain display text for blank item.
|
1801
|
-
*
|
1802
|
-
* @param {string} [options.placeholderValue]
|
1803
|
-
* Include an item that sets the value of the attribute to a blank
|
1804
|
-
* string and indicate that the attribute is set to a default
|
1805
|
-
* value. Include the display name of the given value, in the
|
1806
|
-
* text. This option can be used if a fallback to the
|
1807
|
-
* `placeholderValue` occurs whenever the attribute is blank.
|
1808
|
-
*
|
1809
|
-
* @param {Backbone.Model} [options.placeholderModel]
|
1810
|
-
* Behaves like `placeholderValue`, but obtains the value by looking
|
1811
|
-
* up the `propertyName` attribute inside the given model. This
|
1812
|
-
* option can be used if a fallback to the corresponding attribute
|
1813
|
-
* value of the `placeholderModel` occurs whenever the attribute is
|
1814
|
-
* blank.
|
1815
|
-
*
|
1816
|
-
* @param {function} [options.optionDisabled]
|
1817
|
-
* Receives value and has to return boolean indicating whether
|
1818
|
-
* option is disabled.
|
1819
|
-
*
|
1820
|
-
* @class
|
1821
|
-
*/
|
1822
|
-
|
1823
|
-
var SelectInputView = Marionette.ItemView.extend({
|
1824
|
-
mixins: [inputView],
|
1825
|
-
template: template$7,
|
1826
|
-
events: {
|
1827
|
-
'change': 'save'
|
1828
|
-
},
|
1829
|
-
ui: {
|
1830
|
-
select: 'select',
|
1831
|
-
input: 'select'
|
1832
|
-
},
|
1833
|
-
initialize: function initialize() {
|
1834
|
-
if (this.options.collection) {
|
1835
|
-
this.options.values = _.pluck(this.options.collection, this.options.valueProperty);
|
1836
|
-
|
1837
|
-
if (this.options.textProperty) {
|
1838
|
-
this.options.texts = _.pluck(this.options.collection, this.options.textProperty);
|
1839
|
-
} else if (this.options.translationKeyProperty) {
|
1840
|
-
this.options.translationKeys = _.pluck(this.options.collection, this.options.translationKeyProperty);
|
1841
|
-
}
|
1842
|
-
|
1843
|
-
if (this.options.groupProperty) {
|
1844
|
-
this.options.groups = _.pluck(this.options.collection, this.options.groupProperty);
|
1845
|
-
} else if (this.options.groupTranslationKeyProperty) {
|
1846
|
-
this.options.groupTanslationKeys = _.pluck(this.options.collection, this.options.groupTranslationKeyProperty);
|
1847
|
-
}
|
1848
|
-
}
|
1849
|
-
|
1850
|
-
if (!this.options.texts) {
|
1851
|
-
if (!this.options.translationKeys) {
|
1852
|
-
var translationKeyPrefix = this.options.translationKeyPrefix || findKeyWithTranslation(this.attributeTranslationKeys('values', {
|
1853
|
-
fallbackPrefix: 'activerecord.values'
|
1854
|
-
}));
|
1855
|
-
this.options.translationKeys = _.map(this.options.values, function (value) {
|
1856
|
-
return translationKeyPrefix + '.' + value;
|
1857
|
-
}, this);
|
1858
|
-
}
|
1859
|
-
|
1860
|
-
this.options.texts = _.map(this.options.translationKeys, function (key) {
|
1861
|
-
return I18n$1.t(key);
|
1862
|
-
});
|
1863
|
-
}
|
1864
|
-
|
1865
|
-
if (!this.options.groups) {
|
1866
|
-
this.options.groups = _.map(this.options.groupTanslationKeys, function (key) {
|
1867
|
-
return I18n$1.t(key);
|
1868
|
-
});
|
1869
|
-
}
|
1870
|
-
|
1871
|
-
this.optGroups = {};
|
1872
|
-
},
|
1873
|
-
onRender: function onRender() {
|
1874
|
-
this.appendBlank();
|
1875
|
-
this.appendPlaceholder();
|
1876
|
-
this.appendOptions();
|
1877
|
-
this.load();
|
1878
|
-
this.listenTo(this.model, 'change:' + this.options.propertyName, this.load);
|
1879
|
-
|
1880
|
-
if (this.options.ensureValueDefined && !this.model.has(this.options.propertyName)) {
|
1881
|
-
this.save();
|
1882
|
-
}
|
1883
|
-
},
|
1884
|
-
appendBlank: function appendBlank() {
|
1885
|
-
if (!this.options.includeBlank) {
|
1886
|
-
return;
|
1887
|
-
}
|
1888
|
-
|
1889
|
-
if (this.options.blankTranslationKey) {
|
1890
|
-
this.options.blankText = I18n$1.t(this.options.blankTranslationKey);
|
1891
|
-
}
|
1892
|
-
|
1893
|
-
var option = document.createElement('option');
|
1894
|
-
option.value = '';
|
1895
|
-
option.text = this.options.blankText || I18n$1.t('pageflow.ui.views.inputs.select_input_view.none');
|
1896
|
-
this.ui.select.append(option);
|
1897
|
-
},
|
1898
|
-
appendPlaceholder: function appendPlaceholder() {
|
1899
|
-
if (!this.options.placeholderModel && !this.options.placeholderValue) {
|
1900
|
-
return;
|
1901
|
-
}
|
1902
|
-
|
1903
|
-
var placeholderValue = this.options.placeholderValue || this.options.placeholderModel.get(this.options.propertyName);
|
1904
|
-
var placeholderIndex = this.options.values.indexOf(placeholderValue);
|
1905
|
-
|
1906
|
-
if (placeholderIndex >= 0) {
|
1907
|
-
var option = document.createElement('option');
|
1908
|
-
option.value = '';
|
1909
|
-
option.text = I18n$1.t('pageflow.ui.views.inputs.select_input_view.placeholder', {
|
1910
|
-
text: this.options.texts[placeholderIndex]
|
1911
|
-
});
|
1912
|
-
this.ui.select.append(option);
|
1913
|
-
}
|
1914
|
-
},
|
1915
|
-
appendOptions: function appendOptions() {
|
1916
|
-
_.each(this.options.values, function (value, index) {
|
1917
|
-
var option = document.createElement('option');
|
1918
|
-
var group = this.options.groups[index];
|
1919
|
-
option.value = value;
|
1920
|
-
option.text = this.options.texts[index];
|
1921
|
-
|
1922
|
-
if (this.options.optionDisabled && this.options.optionDisabled(value)) {
|
1923
|
-
option.setAttribute('disabled', true);
|
1924
|
-
}
|
1925
|
-
|
1926
|
-
if (group) {
|
1927
|
-
option.setAttribute('data-group', group);
|
1928
|
-
this.findOrCreateOptGroup(group).append(option);
|
1929
|
-
} else {
|
1930
|
-
this.ui.select.append(option);
|
1931
|
-
}
|
1932
|
-
}, this);
|
1933
|
-
},
|
1934
|
-
findOrCreateOptGroup: function findOrCreateOptGroup(label) {
|
1935
|
-
if (!this.optGroups[label]) {
|
1936
|
-
this.optGroups[label] = $('<optgroup />', {
|
1937
|
-
label: label
|
1938
|
-
}).appendTo(this.ui.select);
|
1939
|
-
}
|
1940
|
-
|
1941
|
-
return this.optGroups[label];
|
1942
|
-
},
|
1943
|
-
save: function save() {
|
1944
|
-
this.model.set(this.options.propertyName, this.ui.select.val());
|
1945
|
-
},
|
1946
|
-
load: function load() {
|
1947
|
-
if (!this.isClosed) {
|
1948
|
-
var value = this.model.get(this.options.propertyName);
|
1949
|
-
|
1950
|
-
if (this.model.has(this.options.propertyName) && this.ui.select.find('option[value="' + value + '"]:not([disabled])').length) {
|
1951
|
-
this.ui.select.val(value);
|
1952
|
-
} else {
|
1953
|
-
this.ui.select.val(this.ui.select.find('option:not([disabled]):first').val());
|
1954
|
-
}
|
1955
|
-
}
|
1956
|
-
}
|
1957
|
-
});
|
1958
|
-
|
1959
|
-
var ExtendedSelectInputView = SelectInputView.extend({
|
1960
|
-
className: 'extended_select_input',
|
1961
|
-
initialize: function initialize() {
|
1962
|
-
SelectInputView.prototype.initialize.apply(this, arguments);
|
1963
|
-
|
1964
|
-
if (this.options.collection) {
|
1965
|
-
if (this.options.descriptionProperty) {
|
1966
|
-
this.options.descriptions = _.pluck(this.options.collection, this.options.descriptionProperty);
|
1967
|
-
} else if (this.options.descriptionTranslationKeyProperty) {
|
1968
|
-
this.options.descriptionTanslationKeys = _.pluck(this.options.collection, this.options.descriptionTranslationKeyProperty);
|
1969
|
-
}
|
1970
|
-
}
|
1971
|
-
|
1972
|
-
if (!this.options.descriptions) {
|
1973
|
-
this.options.descriptions = _.map(this.options.descriptionTanslationKeys, function (key) {
|
1974
|
-
return I18n$1.t(key);
|
1975
|
-
});
|
1976
|
-
}
|
1977
|
-
},
|
1978
|
-
onRender: function onRender() {
|
1979
|
-
var view = this,
|
1980
|
-
options = this.options;
|
1981
|
-
SelectInputView.prototype.onRender.apply(this, arguments);
|
1982
|
-
$.widget("custom.extendedselectmenu", $.ui.selectmenu, {
|
1983
|
-
_renderItem: function _renderItem(ul, item) {
|
1984
|
-
var widget = this;
|
1985
|
-
var li = $('<li>', {
|
1986
|
-
"class": item.value
|
1987
|
-
});
|
1988
|
-
var container = $('<div>', {
|
1989
|
-
"class": 'text-container'
|
1990
|
-
}).appendTo(li);
|
1991
|
-
var index = options.values.indexOf(item.value);
|
1992
|
-
|
1993
|
-
if (item.disabled) {
|
1994
|
-
li.addClass('ui-state-disabled');
|
1995
|
-
}
|
1996
|
-
|
1997
|
-
if (options.pictogramClass) {
|
1998
|
-
$('<span>', {
|
1999
|
-
"class": options.pictogramClass
|
2000
|
-
}).prependTo(li);
|
2001
|
-
}
|
2002
|
-
|
2003
|
-
$('<p>', {
|
2004
|
-
text: item.label,
|
2005
|
-
"class": 'item-text'
|
2006
|
-
}).appendTo(container);
|
2007
|
-
$('<p>', {
|
2008
|
-
text: options.descriptions[index],
|
2009
|
-
"class": 'item-description'
|
2010
|
-
}).appendTo(container);
|
2011
|
-
|
2012
|
-
if (options.helpLinkClicked) {
|
2013
|
-
$('<a>', {
|
2014
|
-
href: '#',
|
2015
|
-
title: I18n$1.t('pageflow.ui.views.extended_select_input_view.display_help')
|
2016
|
-
}).on('click', function () {
|
2017
|
-
widget.close();
|
2018
|
-
options.helpLinkClicked(item.value);
|
2019
|
-
return false;
|
2020
|
-
}).appendTo(li);
|
2021
|
-
}
|
2022
|
-
|
2023
|
-
return li.appendTo(ul);
|
2024
|
-
},
|
2025
|
-
_resizeMenu: function _resizeMenu() {
|
2026
|
-
this.menuWrap.addClass('extended_select_input_menu');
|
2027
|
-
var menuHeight = this.menu.height(),
|
2028
|
-
menuOffset = this.button.offset().top + this.button.outerHeight(),
|
2029
|
-
bodyHeight = $('body').height();
|
2030
|
-
|
2031
|
-
if (menuHeight + menuOffset > bodyHeight) {
|
2032
|
-
this.menuWrap.outerHeight(bodyHeight - menuOffset - 5).css({
|
2033
|
-
'overflow-y': 'scroll'
|
2034
|
-
});
|
2035
|
-
} else {
|
2036
|
-
this.menuWrap.css({
|
2037
|
-
height: 'initial',
|
2038
|
-
'overflow-y': 'initial'
|
2039
|
-
});
|
2040
|
-
}
|
2041
|
-
}
|
2042
|
-
});
|
2043
|
-
this.ui.select.extendedselectmenu({
|
2044
|
-
select: view.select.bind(view),
|
2045
|
-
width: '100%',
|
2046
|
-
position: {
|
2047
|
-
my: 'right top',
|
2048
|
-
at: 'right bottom'
|
2049
|
-
}
|
2050
|
-
});
|
2051
|
-
},
|
2052
|
-
select: function select(event, ui) {
|
2053
|
-
this.ui.select.val(ui.item.value);
|
2054
|
-
this.save();
|
2055
|
-
}
|
2056
|
-
});
|
2057
|
-
|
2058
|
-
function template$8(data) {
|
2059
|
-
var __t, __p = '';
|
2060
|
-
__p += '<label>\n <span class="name"></span>\n <span class="inline_help"></span>\n</label>\n\n<!-- inline style for wysihtml5 to pick up -->\n<textarea style="width: 100%;" dir="auto"></textarea>\n\n<div class="toolbar">\n <a data-wysihtml5-command="bold" title="' +
|
2061
|
-
((__t = ( I18n.t('pageflow.ui.templates.inputs.text_area_input.bold') )) == null ? '' : __t) +
|
2062
|
-
'"></a>\n <a data-wysihtml5-command="italic" title="' +
|
2063
|
-
((__t = ( I18n.t('pageflow.ui.templates.inputs.text_area_input.italic') )) == null ? '' : __t) +
|
2064
|
-
'"></a>\n <a data-wysihtml5-command="underline" title="' +
|
2065
|
-
((__t = ( I18n.t('pageflow.ui.templates.inputs.text_area_input.underline') )) == null ? '' : __t) +
|
2066
|
-
'"></a>\n <a data-wysihtml5-command="createLink" class="link_button" title="' +
|
2067
|
-
((__t = ( I18n.t('pageflow.ui.templates.inputs.text_area_input.create_link') )) == null ? '' : __t) +
|
2068
|
-
'"></a>\n <a data-wysihtml5-command="insertOrderedList" title="' +
|
2069
|
-
((__t = ( I18n.t('pageflow.ui.templates.inputs.text_area_input.insert_ordered_list') )) == null ? '' : __t) +
|
2070
|
-
'"></a>\n <a data-wysihtml5-command="insertUnorderedList" title="' +
|
2071
|
-
((__t = ( I18n.t('pageflow.ui.templates.inputs.text_area_input.insert_unordered_list') )) == null ? '' : __t) +
|
2072
|
-
'"></a>\n\n <div data-wysihtml5-dialog="createLink" class="dialog link_dialog" style="display: none;">\n <div class="link_type_select">\n <label>\n <input type="radio" name="link_type" class="url_link_radio_button">\n ' +
|
2073
|
-
((__t = ( I18n.t('pageflow.ui.templates.inputs.text_area_input.link_type.url') )) == null ? '' : __t) +
|
2074
|
-
'\n </label>\n <label>\n <input type="radio" name="link_type" class="fragment_link_radio_button">\n ' +
|
2075
|
-
((__t = ( I18n.t('pageflow.ui.templates.inputs.text_area_input.link_type.page_link') )) == null ? '' : __t) +
|
2076
|
-
'\n </label>\n </div>\n <div class="url_link_panel">\n <label>\n <span>\n ' +
|
2077
|
-
((__t = ( I18n.t('pageflow.ui.templates.inputs.text_area_input.target') )) == null ? '' : __t) +
|
2078
|
-
'\n </span>\n </label>\n <input type="text" class="display_url">\n <div class="open_in_new_tab_section">\n <label>\n <input type="checkbox" class="open_in_new_tab">\n ' +
|
2079
|
-
((__t = ( I18n.t('pageflow.ui.templates.inputs.text_area_input.open_in_new_tab') )) == null ? '' : __t) +
|
2080
|
-
'\n </label>\n <span class="inline_help">\n ' +
|
2081
|
-
((__t = ( I18n.t('pageflow.ui.templates.inputs.text_area_input.open_in_new_tab_help') )) == null ? '' : __t) +
|
2082
|
-
'\n </span>\n </div>\n </div>\n <div class="fragment_link_panel">\n <!-- LinkInputView is inserted here -->\n </div>\n\n <!-- wysihtml5 does not handle hidden fields correctly -->\n <div class="internal">\n <input type="text" data-wysihtml5-dialog-field="href" class="current_url" value="">\n <input type="text" data-wysihtml5-dialog-field="target" class="current_target" value="_blank">\n </div>\n\n <a class="button" data-wysihtml5-dialog-action="save">\n ' +
|
2083
|
-
((__t = ( I18n.t('pageflow.ui.templates.inputs.text_area_input.save') )) == null ? '' : __t) +
|
2084
|
-
'\n </a>\n <a class="button" data-wysihtml5-dialog-action="cancel">\n ' +
|
2085
|
-
((__t = ( I18n.t('pageflow.ui.templates.inputs.text_area_input.cancel') )) == null ? '' : __t) +
|
2086
|
-
'\n </a>\n\n <a data-wysihtml5-command="removeLink">' +
|
2087
|
-
((__t = ( I18n.t('pageflow.ui.templates.inputs.text_area_input.remove_link') )) == null ? '' : __t) +
|
2088
|
-
'</a>\n </div>\n</div>\n';
|
2089
|
-
return __p
|
2090
|
-
}
|
2091
|
-
|
2092
|
-
/**
|
2093
|
-
* Input view for multi line text with simple formatting options.
|
2094
|
-
* See {@link inputWithPlaceholderText} for placeholder related options.
|
2095
|
-
* See {@link inputView} for further options.
|
2096
|
-
*
|
2097
|
-
* @param {Object} [options]
|
2098
|
-
*
|
2099
|
-
* @param {string} [options.size="normal"]
|
2100
|
-
* Pass `"short"` to reduce the text area height.
|
2101
|
-
*
|
2102
|
-
* @param {boolean} [options.disableLinks=false]
|
2103
|
-
* Do not allow links inside the text.
|
2104
|
-
*
|
2105
|
-
* @param {boolean} [options.disableRichtext=false]
|
2106
|
-
* Do not provide text formatting options.
|
2107
|
-
*
|
2108
|
-
* @param {Backbone.View} [options.fragmentLinkInputView]
|
2109
|
-
* A view to select an id to use in links which only consist
|
2110
|
-
* of a url fragment. Will receive a model with a `linkId`
|
2111
|
-
* attribute.
|
2112
|
-
*
|
2113
|
-
* @class
|
2114
|
-
*/
|
2115
|
-
|
2116
|
-
var TextAreaInputView = Marionette.ItemView.extend({
|
2117
|
-
mixins: [inputView, inputWithPlaceholderText],
|
2118
|
-
template: template$8,
|
2119
|
-
ui: {
|
2120
|
-
input: 'textarea',
|
2121
|
-
toolbar: '.toolbar',
|
2122
|
-
linkButton: '.link_button',
|
2123
|
-
linkDialog: '.link_dialog',
|
2124
|
-
urlInput: '.current_url',
|
2125
|
-
targetInput: '.current_target',
|
2126
|
-
linkTypeSelection: '.link_type_select',
|
2127
|
-
urlLinkRadioButton: '.url_link_radio_button',
|
2128
|
-
fragmentLinkRadioButton: '.fragment_link_radio_button',
|
2129
|
-
urlLinkPanel: '.url_link_panel',
|
2130
|
-
displayUrlInput: '.display_url',
|
2131
|
-
openInNewTabCheckBox: '.open_in_new_tab',
|
2132
|
-
fragmentLinkPanel: '.fragment_link_panel'
|
2133
|
-
},
|
2134
|
-
events: {
|
2135
|
-
'change textarea': 'save',
|
2136
|
-
'click .url_link_radio_button': 'showUrlLinkPanel',
|
2137
|
-
'click .fragment_link_radio_button': 'showFragmentLinkPanel',
|
2138
|
-
'change .open_in_new_tab': 'setTargetFromOpenInNewTabCheckBox',
|
2139
|
-
'change .display_url': 'setUrlFromDisplayUrl'
|
2140
|
-
},
|
2141
|
-
onRender: function onRender() {
|
2142
|
-
this.ui.input.addClass(this.options.size);
|
2143
|
-
this.load();
|
2144
|
-
this.updatePlaceholder();
|
2145
|
-
this.editor = new wysihtml5.Editor(this.ui.input[0], {
|
2146
|
-
toolbar: this.ui.toolbar[0],
|
2147
|
-
autoLink: this.options.disableLinks ? 0 : 1,
|
2148
|
-
parserRules: {
|
2149
|
-
tags: {
|
2150
|
-
em: {
|
2151
|
-
unwrap: this.options.disableRichtext ? 1 : 0,
|
2152
|
-
rename_tag: "i"
|
2153
|
-
},
|
2154
|
-
strong: {
|
2155
|
-
unwrap: this.options.disableRichtext ? 1 : 0,
|
2156
|
-
rename_tag: "b"
|
2157
|
-
},
|
2158
|
-
u: {
|
2159
|
-
unwrap: this.options.disableRichtext ? 1 : 0
|
2160
|
-
},
|
2161
|
-
b: {
|
2162
|
-
unwrap: this.options.disableRichtext ? 1 : 0
|
2163
|
-
},
|
2164
|
-
i: {
|
2165
|
-
unwrap: this.options.disableRichtext ? 1 : 0
|
2166
|
-
},
|
2167
|
-
ol: {
|
2168
|
-
unwrap: this.options.enableLists ? 0 : 1
|
2169
|
-
},
|
2170
|
-
ul: {
|
2171
|
-
unwrap: this.options.enableLists ? 0 : 1
|
2172
|
-
},
|
2173
|
-
li: {
|
2174
|
-
unwrap: this.options.enableLists ? 0 : 1
|
2175
|
-
},
|
2176
|
-
br: {},
|
2177
|
-
a: {
|
2178
|
-
unwrap: this.options.disableLinks ? 1 : 0,
|
2179
|
-
check_attributes: {
|
2180
|
-
href: 'href',
|
2181
|
-
target: 'any'
|
2182
|
-
},
|
2183
|
-
set_attributes: {
|
2184
|
-
rel: 'nofollow'
|
2185
|
-
}
|
2186
|
-
}
|
2187
|
-
}
|
2188
|
-
}
|
2189
|
-
});
|
2190
|
-
|
2191
|
-
if (this.options.disableRichtext) {
|
2192
|
-
this.ui.toolbar.find('a[data-wysihtml5-command="bold"]').hide();
|
2193
|
-
this.ui.toolbar.find('a[data-wysihtml5-command="italic"]').hide();
|
2194
|
-
this.ui.toolbar.find('a[data-wysihtml5-command="underline"]').hide();
|
2195
|
-
this.ui.toolbar.find('a[data-wysihtml5-command="insertOrderedList"]').hide();
|
2196
|
-
this.ui.toolbar.find('a[data-wysihtml5-command="insertUnorderedList"]').hide();
|
2197
|
-
}
|
2198
|
-
|
2199
|
-
if (!this.options.enableLists) {
|
2200
|
-
this.ui.toolbar.find('a[data-wysihtml5-command="insertOrderedList"]').hide();
|
2201
|
-
this.ui.toolbar.find('a[data-wysihtml5-command="insertUnorderedList"]').hide();
|
2202
|
-
}
|
2203
|
-
|
2204
|
-
if (this.options.disableLinks) {
|
2205
|
-
this.ui.toolbar.find('a[data-wysihtml5-command="createLink"]').hide();
|
2206
|
-
} else {
|
2207
|
-
this.setupUrlLinkPanel();
|
2208
|
-
this.setupFragmentLinkPanel();
|
2209
|
-
}
|
2210
|
-
|
2211
|
-
this.editor.on('change', _.bind(this.save, this));
|
2212
|
-
this.editor.on('aftercommand:composer', _.bind(this.save, this));
|
2213
|
-
},
|
2214
|
-
onClose: function onClose() {
|
2215
|
-
this.editor.fire('destroy:composer');
|
2216
|
-
},
|
2217
|
-
save: function save() {
|
2218
|
-
this.model.set(this.options.propertyName, this.editor.getValue());
|
2219
|
-
},
|
2220
|
-
load: function load() {
|
2221
|
-
this.ui.input.val(this.model.get(this.options.propertyName));
|
2222
|
-
},
|
2223
|
-
setupUrlLinkPanel: function setupUrlLinkPanel() {
|
2224
|
-
this.editor.on('show:dialog', _.bind(function () {
|
2225
|
-
this.ui.linkDialog.toggleClass('for_existing_link', this.ui.linkButton.hasClass('wysihtml5-command-active'));
|
2226
|
-
var currentUrl = this.ui.urlInput.val();
|
2227
|
-
|
2228
|
-
if (currentUrl.startsWith('#')) {
|
2229
|
-
this.ui.displayUrlInput.val('');
|
2230
|
-
this.ui.openInNewTabCheckBox.prop('checked', true);
|
2231
|
-
} else {
|
2232
|
-
this.ui.displayUrlInput.val(currentUrl);
|
2233
|
-
this.ui.openInNewTabCheckBox.prop('checked', this.ui.targetInput.val() !== '_self');
|
2234
|
-
}
|
2235
|
-
}, this));
|
2236
|
-
},
|
2237
|
-
setupFragmentLinkPanel: function setupFragmentLinkPanel() {
|
2238
|
-
if (this.options.fragmentLinkInputView) {
|
2239
|
-
this.fragmentLinkModel = new Backbone.Model();
|
2240
|
-
this.listenTo(this.fragmentLinkModel, 'change', function (model, options) {
|
2241
|
-
if (!options.skipCurrentUrlUpdate) {
|
2242
|
-
this.setInputsFromFragmentLinkModel();
|
2243
|
-
}
|
2244
|
-
});
|
2245
|
-
this.editor.on('show:dialog', _.bind(function () {
|
2246
|
-
var currentUrl = this.ui.urlInput.val();
|
2247
|
-
var id = currentUrl.startsWith('#') ? currentUrl.substr(1) : null;
|
2248
|
-
this.fragmentLinkModel.set('linkId', id, {
|
2249
|
-
skipCurrentUrlUpdate: true
|
2250
|
-
});
|
2251
|
-
this.initLinkTypePanels(!id);
|
2252
|
-
}, this));
|
2253
|
-
var fragmentLinkInput = new this.options.fragmentLinkInputView({
|
2254
|
-
model: this.fragmentLinkModel,
|
2255
|
-
propertyName: 'linkId',
|
2256
|
-
label: I18n$1.t('pageflow.ui.templates.inputs.text_area_input.target'),
|
2257
|
-
hideUnsetButton: true
|
2258
|
-
});
|
2259
|
-
this.ui.fragmentLinkPanel.append(fragmentLinkInput.render().el);
|
2260
|
-
} else {
|
2261
|
-
this.ui.linkTypeSelection.hide();
|
2262
|
-
this.ui.fragmentLinkPanel.hide();
|
2263
|
-
}
|
2264
|
-
},
|
2265
|
-
initLinkTypePanels: function initLinkTypePanels(isUrlLink) {
|
2266
|
-
if (isUrlLink) {
|
2267
|
-
this.ui.urlLinkRadioButton.prop('checked', true);
|
2268
|
-
} else {
|
2269
|
-
this.ui.fragmentLinkRadioButton.prop('checked', true);
|
2270
|
-
}
|
2271
|
-
|
2272
|
-
this.ui.toolbar.toggleClass('fragment_link_panel_active', !isUrlLink);
|
2273
|
-
},
|
2274
|
-
showUrlLinkPanel: function showUrlLinkPanel() {
|
2275
|
-
this.ui.toolbar.removeClass('fragment_link_panel_active');
|
2276
|
-
this.setUrlFromDisplayUrl();
|
2277
|
-
this.setTargetFromOpenInNewTabCheckBox();
|
2278
|
-
},
|
2279
|
-
showFragmentLinkPanel: function showFragmentLinkPanel() {
|
2280
|
-
this.ui.toolbar.addClass('fragment_link_panel_active');
|
2281
|
-
this.setInputsFromFragmentLinkModel();
|
2282
|
-
},
|
2283
|
-
setInputsFromFragmentLinkModel: function setInputsFromFragmentLinkModel() {
|
2284
|
-
this.ui.urlInput.val('#' + (this.fragmentLinkModel.get('linkId') || ''));
|
2285
|
-
this.ui.targetInput.val('_self');
|
2286
|
-
},
|
2287
|
-
setUrlFromDisplayUrl: function setUrlFromDisplayUrl() {
|
2288
|
-
this.ui.urlInput.val(this.ui.displayUrlInput.val());
|
2289
|
-
},
|
2290
|
-
setTargetFromOpenInNewTabCheckBox: function setTargetFromOpenInNewTabCheckBox() {
|
2291
|
-
this.ui.targetInput.val(this.ui.openInNewTabCheckBox.is(':checked') ? '_blank' : '_self');
|
2292
|
-
}
|
2293
|
-
});
|
2294
|
-
|
2295
|
-
function _defineProperty(obj, key, value) {
|
2296
|
-
if (key in obj) {
|
2297
|
-
Object.defineProperty(obj, key, {
|
2298
|
-
value: value,
|
2299
|
-
enumerable: true,
|
2300
|
-
configurable: true,
|
2301
|
-
writable: true
|
2302
|
-
});
|
2303
|
-
} else {
|
2304
|
-
obj[key] = value;
|
2305
|
-
}
|
2306
|
-
|
2307
|
-
return obj;
|
2308
|
-
}
|
2309
|
-
|
2310
|
-
function template$9(data) {
|
2311
|
-
var __p = '';
|
2312
|
-
__p += '<label>\n <span class="name"></span>\n <span class="inline_help"></span>\n</label>\n<input type="text" />\n<div class="validation"></div>\n';
|
2313
|
-
return __p
|
2314
|
-
}
|
2315
|
-
|
2316
|
-
/**
|
2317
|
-
* Input view for URLs.
|
2318
|
-
* See {@link inputView} for further options
|
2319
|
-
*
|
2320
|
-
* @param {Object} [options]
|
2321
|
-
*
|
2322
|
-
* @param {string[]} options.supportedHosts
|
2323
|
-
* List of allowed url prefixes.
|
2324
|
-
*
|
2325
|
-
* @param {boolean} [options.required=false]
|
2326
|
-
* Display an error if the url is blank.
|
2327
|
-
*
|
2328
|
-
* @param {boolean} [options.permitHttps=false]
|
2329
|
-
* Allow urls with https protocol.
|
2330
|
-
*
|
2331
|
-
* @class
|
2332
|
-
*/
|
2333
|
-
|
2334
|
-
var UrlInputView = Marionette.Layout.extend(
|
2335
|
-
/** @lends UrlInputView.prototype */
|
2336
|
-
{
|
2337
|
-
mixins: [inputView],
|
2338
|
-
template: template$9,
|
2339
|
-
ui: {
|
2340
|
-
input: 'input',
|
2341
|
-
validation: '.validation'
|
2342
|
-
},
|
2343
|
-
events: {
|
2344
|
-
'change': 'onChange'
|
2345
|
-
},
|
2346
|
-
onRender: function onRender() {
|
2347
|
-
this.ui.validation.hide();
|
2348
|
-
this.load();
|
2349
|
-
this.validate();
|
2350
|
-
},
|
2351
|
-
onChange: function onChange() {
|
2352
|
-
var _this = this;
|
2353
|
-
|
2354
|
-
this.validate().then(function () {
|
2355
|
-
return _this.save();
|
2356
|
-
}, function () {
|
2357
|
-
return _this.saveDisplayProperty();
|
2358
|
-
});
|
2359
|
-
},
|
2360
|
-
saveDisplayProperty: function saveDisplayProperty() {
|
2361
|
-
this.model.unset(this.options.propertyName, {
|
2362
|
-
silent: true
|
2363
|
-
});
|
2364
|
-
this.model.set(this.options.displayPropertyName, this.ui.input.val());
|
2365
|
-
},
|
2366
|
-
save: function save() {
|
2367
|
-
var _this2 = this;
|
2368
|
-
|
2369
|
-
var value = this.ui.input.val();
|
2370
|
-
$.when(this.transformPropertyValue(value)).then(function (transformedValue) {
|
2371
|
-
var _this2$model$set;
|
2372
|
-
|
2373
|
-
_this2.model.set((_this2$model$set = {}, _defineProperty(_this2$model$set, _this2.options.displayPropertyName, value), _defineProperty(_this2$model$set, _this2.options.propertyName, transformedValue), _this2$model$set));
|
2374
|
-
});
|
2375
|
-
},
|
2376
|
-
load: function load() {
|
2377
|
-
this.ui.input.val(this.model.has(this.options.displayPropertyName) ? this.model.get(this.options.displayPropertyName) : this.model.get(this.options.propertyName));
|
2378
|
-
this.onLoad();
|
2379
|
-
},
|
2380
|
-
|
2381
|
-
/**
|
2382
|
-
* Override to be notified when the input has been loaded.
|
2383
|
-
*/
|
2384
|
-
onLoad: function onLoad() {},
|
2385
|
-
|
2386
|
-
/**
|
2387
|
-
* Override to validate the untransformed url. Validation error
|
2388
|
-
* message can be passed as rejected promise. Progress notifications
|
2389
|
-
* are displayed. Only valid urls are stored in the configuration.
|
2390
|
-
*
|
2391
|
-
* @return Promise
|
2392
|
-
*/
|
2393
|
-
validateUrl: function validateUrl(url) {
|
2394
|
-
return $.Deferred().resolve().promise();
|
2395
|
-
},
|
2396
|
-
|
2397
|
-
/**
|
2398
|
-
* Override to transform the property value before it is stored.
|
2399
|
-
*
|
2400
|
-
* @return Promise | String
|
2401
|
-
*/
|
2402
|
-
transformPropertyValue: function transformPropertyValue(value) {
|
2403
|
-
return value;
|
2404
|
-
},
|
2405
|
-
|
2406
|
-
/**
|
2407
|
-
* Override to change the list of supported host names.
|
2408
|
-
*/
|
2409
|
-
supportedHosts: function supportedHosts() {
|
2410
|
-
return this.options.supportedHosts;
|
2411
|
-
},
|
2412
|
-
// Host names used to be expected to include protocols. Remove
|
2413
|
-
// protocols for backwards compatilbity. Since supportedHosts
|
2414
|
-
// is supposed to be overridden in subclasses, we do it in a
|
2415
|
-
// separate method.
|
2416
|
-
supportedHostsWithoutLegacyProtocols: function supportedHostsWithoutLegacyProtocols() {
|
2417
|
-
return _.map(this.supportedHosts(), function (host) {
|
2418
|
-
return host.replace(/^https?:\/\//, '');
|
2419
|
-
});
|
2420
|
-
},
|
2421
|
-
validate: function validate(success) {
|
2422
|
-
var view = this;
|
2423
|
-
var options = this.options;
|
2424
|
-
var value = this.ui.input.val();
|
2425
|
-
|
2426
|
-
if (options.required && !value) {
|
2427
|
-
displayValidationError(I18n$1.t('pageflow.ui.views.inputs.url_input_view.required_field'));
|
2428
|
-
} else if (value && !isValidUrl(value)) {
|
2429
|
-
var errorMessage = I18n$1.t('pageflow.ui.views.inputs.url_input_view.url_hint');
|
2430
|
-
|
2431
|
-
if (options.permitHttps) {
|
2432
|
-
errorMessage = I18n$1.t('pageflow.ui.views.inputs.url_input_view.url_hint_https');
|
2433
|
-
}
|
2434
|
-
|
2435
|
-
displayValidationError(errorMessage);
|
2436
|
-
} else if (value && !hasSupportedHost(value)) {
|
2437
|
-
displayValidationError(I18n$1.t('pageflow.ui.views.inputs.url_input_view.supported_vendors') + _.map(view.supportedHosts(), function (url) {
|
2438
|
-
return '<li>' + url + '</li>';
|
2439
|
-
}).join(''));
|
2440
|
-
} else {
|
2441
|
-
return view.validateUrl(value).progress(function (message) {
|
2442
|
-
displayValidationPending(message);
|
2443
|
-
}).done(function () {
|
2444
|
-
resetValidationError();
|
2445
|
-
}).fail(function (error) {
|
2446
|
-
displayValidationError(error);
|
2447
|
-
});
|
2448
|
-
}
|
2449
|
-
|
2450
|
-
return $.Deferred().reject().promise();
|
2451
|
-
|
2452
|
-
function isValidUrl(url) {
|
2453
|
-
return options.permitHttps ? url.match(/^https?:\/\//i) : url.match(/^http:\/\//i);
|
2454
|
-
}
|
2455
|
-
|
2456
|
-
function hasSupportedHost(url) {
|
2457
|
-
return _.any(view.supportedHostsWithoutLegacyProtocols(), function (host) {
|
2458
|
-
return url.match(new RegExp('^https?://' + host));
|
2459
|
-
});
|
2460
|
-
}
|
2461
|
-
|
2462
|
-
function displayValidationError(message) {
|
2463
|
-
view.$el.addClass('invalid');
|
2464
|
-
view.ui.input.attr('aria-invalid', 'true');
|
2465
|
-
view.ui.validation.removeClass('pending').addClass('failed').html(message).show();
|
2466
|
-
}
|
2467
|
-
|
2468
|
-
function displayValidationPending(message) {
|
2469
|
-
view.$el.removeClass('invalid');
|
2470
|
-
view.ui.input.removeAttr('aria-invalid');
|
2471
|
-
view.ui.validation.removeClass('failed').addClass('pending').html(message).show();
|
2472
|
-
}
|
2473
|
-
|
2474
|
-
function resetValidationError(message) {
|
2475
|
-
view.$el.removeClass('invalid');
|
2476
|
-
view.ui.input.attr('aria-invalid', 'false');
|
2477
|
-
view.ui.validation.hide();
|
2478
|
-
}
|
2479
|
-
}
|
2480
|
-
});
|
2481
|
-
|
2482
|
-
/**
|
2483
|
-
* Input view that verifies that a certain URL is reachable via a
|
2484
|
-
* proxy. To conform with same origin restrictions, this input view
|
2485
|
-
* lets the user enter some url and saves a rewritten url where the
|
2486
|
-
* domain is replaced with some path segment.
|
2487
|
-
*
|
2488
|
-
* That way, when `/example` is setup to proxy requests to
|
2489
|
-
* `http://example.com`, the user can enter an url of the form
|
2490
|
-
* `http://example.com/some/path` but the string `/example/some/path`
|
2491
|
-
* is persisited to the database.
|
2492
|
-
*
|
2493
|
-
* See {@link inputView} for further options
|
2494
|
-
*
|
2495
|
-
* @param {Object} options
|
2496
|
-
*
|
2497
|
-
* @param {string} options.displayPropertyName
|
2498
|
-
* Attribute name to store the url entered by the user.
|
2499
|
-
*
|
2500
|
-
* @param {Object[]} options.proxies
|
2501
|
-
* List of supported proxies.
|
2502
|
-
*
|
2503
|
-
* @param {string} options.proxies[].url
|
2504
|
-
* Supported prefix of an url that can be entered by the user.
|
2505
|
-
*
|
2506
|
-
* @param {string} options.proxies[].base_path
|
2507
|
-
* Path to replace the url prefix with.
|
2508
|
-
*
|
2509
|
-
* @param {boolean} [options.required=false]
|
2510
|
-
* Display an error if the url is blank.
|
2511
|
-
*
|
2512
|
-
* @param {boolean} [options.permitHttps=false]
|
2513
|
-
* Allow urls with https protocol.
|
2514
|
-
*
|
2515
|
-
* @example
|
2516
|
-
*
|
2517
|
-
* this.input('url, ProxyUrlInputView, {
|
2518
|
-
* proxies: [
|
2519
|
-
* {
|
2520
|
-
* url: 'http://example.com',
|
2521
|
-
* base_path: '/example'
|
2522
|
-
* }
|
2523
|
-
* ]
|
2524
|
-
* });
|
2525
|
-
*
|
2526
|
-
* @class
|
2527
|
-
*/
|
2528
|
-
|
2529
|
-
var ProxyUrlInputView = UrlInputView.extend(
|
2530
|
-
/** @lends ProxyUrlInputView.prototype */
|
2531
|
-
{
|
2532
|
-
// @override
|
2533
|
-
validateUrl: function validateUrl(url) {
|
2534
|
-
var view = this;
|
2535
|
-
return $.Deferred(function (deferred) {
|
2536
|
-
deferred.notify(I18n$1.t('pageflow.ui.views.inputs.proxy_url_input_view.url_validation'));
|
2537
|
-
$.ajax({
|
2538
|
-
url: view.rewriteUrl(url),
|
2539
|
-
dataType: 'html'
|
2540
|
-
}).done(deferred.resolve).fail(function (xhr) {
|
2541
|
-
deferred.reject(I18n$1.t('pageflow.ui.views.inputs.proxy_url_input_view.http_error', {
|
2542
|
-
status: xhr.status
|
2543
|
-
}));
|
2544
|
-
});
|
2545
|
-
}).promise();
|
2546
|
-
},
|
2547
|
-
// override
|
2548
|
-
transformPropertyValue: function transformPropertyValue(url) {
|
2549
|
-
return this.rewriteUrl(url);
|
2550
|
-
},
|
2551
|
-
// override
|
2552
|
-
supportedHosts: function supportedHosts() {
|
2553
|
-
return _.pluck(this.options.proxies, 'url');
|
2554
|
-
},
|
2555
|
-
rewriteUrl: function rewriteUrl(url) {
|
2556
|
-
_.each(this.options.proxies, function (proxy) {
|
2557
|
-
url = url.replace(new RegExp('^' + proxy.url + '/?'), proxy.base_path + '/');
|
2558
|
-
});
|
2559
|
-
|
2560
|
-
return url;
|
2561
|
-
}
|
2562
|
-
});
|
2563
|
-
|
2564
|
-
function template$a(data) {
|
2565
|
-
var __p = '';
|
2566
|
-
__p += '<label>\n <span class="name"></span>\n <span class="inline_help"></span>\n</label>\n<div class="value"></div>\n<div class="slider"></div>\n';
|
2567
|
-
return __p
|
2568
|
-
}
|
2569
|
-
|
2570
|
-
/**
|
2571
|
-
* A slider for numeric inputs.
|
2572
|
-
* See {@link inputView} for options
|
2573
|
-
*
|
2574
|
-
* @param {Object} [options]
|
2575
|
-
*
|
2576
|
-
* @class
|
2577
|
-
*/
|
2578
|
-
|
2579
|
-
var SliderInputView = Marionette.ItemView.extend({
|
2580
|
-
mixins: [inputView],
|
2581
|
-
className: 'slider_input',
|
2582
|
-
template: template$a,
|
2583
|
-
ui: {
|
2584
|
-
widget: '.slider',
|
2585
|
-
value: '.value'
|
2586
|
-
},
|
2587
|
-
events: {
|
2588
|
-
'slidechange': 'save'
|
2589
|
-
},
|
2590
|
-
onRender: function onRender() {
|
2591
|
-
this.ui.widget.slider({
|
2592
|
-
animate: 'fast',
|
2593
|
-
min: 'minValue' in this.options ? this.options.minValue : 0,
|
2594
|
-
max: 'maxValue' in this.options ? this.options.maxValue : 100
|
2595
|
-
});
|
2596
|
-
this.load();
|
2597
|
-
},
|
2598
|
-
updateDisabled: function updateDisabled(disabled) {
|
2599
|
-
this.$el.toggleClass('disabled', !!disabled);
|
2600
|
-
|
2601
|
-
if (disabled) {
|
2602
|
-
this.ui.widget.slider('disable');
|
2603
|
-
} else {
|
2604
|
-
this.ui.widget.slider('enable');
|
2605
|
-
}
|
2606
|
-
},
|
2607
|
-
save: function save() {
|
2608
|
-
var value = this.ui.widget.slider('option', 'value');
|
2609
|
-
var unit = 'unit' in this.options ? this.options.unit : '%';
|
2610
|
-
this.ui.value.text(value + unit);
|
2611
|
-
this.model.set(this.options.propertyName, value);
|
2612
|
-
},
|
2613
|
-
load: function load() {
|
2614
|
-
var value;
|
2615
|
-
|
2616
|
-
if (this.model.has(this.options.propertyName)) {
|
2617
|
-
value = this.model.get(this.options.propertyName);
|
2618
|
-
} else {
|
2619
|
-
value = 'defaultValue' in this.options ? this.options.defaultValue : 0;
|
2620
|
-
}
|
2621
|
-
|
2622
|
-
this.ui.widget.slider('option', 'value', value);
|
2623
|
-
}
|
2624
|
-
});
|
2625
|
-
|
2626
|
-
function template$b(data) {
|
2627
|
-
var __p = '';
|
2628
|
-
__p += '<label>\n <span class="name"></span>\n <span class="inline_help"></span>\n</label>\n\n<textarea></textarea>\n';
|
2629
|
-
return __p
|
2630
|
-
}
|
2631
|
-
|
2632
|
-
var JsonInputView = Marionette.ItemView.extend({
|
2633
|
-
mixins: [inputView],
|
2634
|
-
template: template$b,
|
2635
|
-
className: 'json_input',
|
2636
|
-
ui: {
|
2637
|
-
input: 'textarea'
|
2638
|
-
},
|
2639
|
-
events: {
|
2640
|
-
'change': 'onChange',
|
2641
|
-
'keyup': 'validate'
|
2642
|
-
},
|
2643
|
-
onRender: function onRender() {
|
2644
|
-
this.load();
|
2645
|
-
this.validate();
|
2646
|
-
this.listenTo(this.model, 'change:' + this.options.propertyName, this.load);
|
2647
|
-
},
|
2648
|
-
onChange: function onChange() {
|
2649
|
-
if (this.validate()) {
|
2650
|
-
this.save();
|
2651
|
-
}
|
2652
|
-
},
|
2653
|
-
onClose: function onClose() {
|
2654
|
-
if (this.validate()) {
|
2655
|
-
this.save();
|
2656
|
-
}
|
2657
|
-
},
|
2658
|
-
save: function save() {
|
2659
|
-
this.model.set(this.options.propertyName, this.ui.input.val() ? JSON.parse(this.ui.input.val()) : null);
|
2660
|
-
},
|
2661
|
-
load: function load() {
|
2662
|
-
var input = this.ui.input;
|
2663
|
-
var value = this.model.get(this.options.propertyName);
|
2664
|
-
input.val(value ? JSON.stringify(value, null, 2) : '');
|
2665
|
-
},
|
2666
|
-
validate: function validate() {
|
2667
|
-
var input = this.ui.input;
|
2668
|
-
|
2669
|
-
if (input.val() && !this.isValidJson(input.val())) {
|
2670
|
-
this.displayValidationError(I18n$1.t('pageflow.ui.views.inputs.json_input_view.invalid'));
|
2671
|
-
return false;
|
2672
|
-
} else {
|
2673
|
-
this.resetValidationError();
|
2674
|
-
return true;
|
2675
|
-
}
|
2676
|
-
},
|
2677
|
-
displayValidationError: function displayValidationError(message) {
|
2678
|
-
this.$el.addClass('invalid');
|
2679
|
-
this.ui.input.attr('title', message);
|
2680
|
-
},
|
2681
|
-
resetValidationError: function resetValidationError(message) {
|
2682
|
-
this.$el.removeClass('invalid');
|
2683
|
-
this.ui.input.attr('title', '');
|
2684
|
-
},
|
2685
|
-
isValidJson: function isValidJson(text) {
|
2686
|
-
try {
|
2687
|
-
JSON.parse(text);
|
2688
|
-
return true;
|
2689
|
-
} catch (e) {
|
2690
|
-
return false;
|
2691
|
-
}
|
2692
|
-
}
|
2693
|
-
});
|
2694
|
-
|
2695
|
-
function template$c(data) {
|
2696
|
-
var __p = '';
|
2697
|
-
__p += '<input type="checkbox" />\n<label>\n <span class="name"></span>\n <span class="inline_help"></span>\n</label>';
|
2698
|
-
return __p
|
2699
|
-
}
|
2700
|
-
|
2701
|
-
/**
|
2702
|
-
* Input view for boolean values.
|
2703
|
-
* See {@link inputView} for further options
|
2704
|
-
*
|
2705
|
-
* @param {Object} [options]
|
2706
|
-
*
|
2707
|
-
* @param {boolean} [options.displayUncheckedIfDisabled=false]
|
2708
|
-
* Ignore the attribute value if the input is disabled and display
|
2709
|
-
* an unchecked check box.
|
2710
|
-
*
|
2711
|
-
* @param {boolean} [options.displayCheckedIfDisabled=false]
|
2712
|
-
* Ignore the attribute value if the input is disabled and display
|
2713
|
-
* an checked check box.
|
2714
|
-
*
|
2715
|
-
* @param {string} [options.storeInverted]
|
2716
|
-
* Display checked by default and store true in given attribute when
|
2717
|
-
* unchecked. The property name passed to `input` is only used for
|
2718
|
-
* translations.
|
2719
|
-
*
|
2720
|
-
* @class
|
2721
|
-
*/
|
2722
|
-
|
2723
|
-
var CheckBoxInputView = Marionette.ItemView.extend({
|
2724
|
-
mixins: [inputView],
|
2725
|
-
template: template$c,
|
2726
|
-
className: 'check_box_input',
|
2727
|
-
events: {
|
2728
|
-
'change': 'save'
|
2729
|
-
},
|
2730
|
-
ui: {
|
2731
|
-
input: 'input',
|
2732
|
-
label: 'label'
|
2733
|
-
},
|
2734
|
-
onRender: function onRender() {
|
2735
|
-
this.ui.label.attr('for', this.cid);
|
2736
|
-
this.ui.input.attr('id', this.cid);
|
2737
|
-
this.load();
|
2738
|
-
this.listenTo(this.model, 'change:' + this.options.propertyName, this.load);
|
2739
|
-
},
|
2740
|
-
updateDisabled: function updateDisabled() {
|
2741
|
-
this.load();
|
2742
|
-
},
|
2743
|
-
save: function save() {
|
2744
|
-
if (!this.isDisabled()) {
|
2745
|
-
var value = this.ui.input.is(':checked');
|
2746
|
-
|
2747
|
-
if (this.options.storeInverted) {
|
2748
|
-
this.model.set(this.options.storeInverted, !value);
|
2749
|
-
} else {
|
2750
|
-
this.model.set(this.options.propertyName, value);
|
2751
|
-
}
|
2752
|
-
}
|
2753
|
-
},
|
2754
|
-
load: function load() {
|
2755
|
-
if (!this.isClosed) {
|
2756
|
-
this.ui.input.prop('checked', this.displayValue());
|
2757
|
-
}
|
2758
|
-
},
|
2759
|
-
displayValue: function displayValue() {
|
2760
|
-
if (this.isDisabled() && this.options.displayUncheckedIfDisabled) {
|
2761
|
-
return false;
|
2762
|
-
} else if (this.isDisabled() && this.options.displayCheckedIfDisabled) {
|
2763
|
-
return true;
|
2764
|
-
} else if (this.options.storeInverted) {
|
2765
|
-
return !this.model.get(this.options.storeInverted);
|
2766
|
-
} else {
|
2767
|
-
return this.model.get(this.options.propertyName);
|
2768
|
-
}
|
2769
|
-
}
|
2770
|
-
});
|
2771
|
-
|
2772
|
-
/**
|
2773
|
-
* Render a separator in a {@link ConfigurationEditorView} tab.
|
2774
|
-
*
|
2775
|
-
* @example
|
2776
|
-
*
|
2777
|
-
* this.view(SeparatorView);
|
2778
|
-
*
|
2779
|
-
* @class
|
2780
|
-
*/
|
2781
|
-
|
2782
|
-
var SeparatorView = Marionette.View.extend({
|
2783
|
-
className: 'separator'
|
2784
|
-
});
|
2785
|
-
|
2786
|
-
/**
|
2787
|
-
* Render an input that is only a label. Can be used to render
|
2788
|
-
* additional inline help.
|
2789
|
-
*
|
2790
|
-
* See {@link inputView} for further options
|
2791
|
-
*
|
2792
|
-
* @class
|
2793
|
-
*/
|
2794
|
-
|
2795
|
-
var LabelOnlyView = Marionette.ItemView.extend({
|
2796
|
-
mixins: [inputView],
|
2797
|
-
template: function template() {
|
2798
|
-
return "\n <label>\n <span class=\"name\"></span>\n <span class=\"inline_help\"></span>\n </label>\n ";
|
2799
|
-
},
|
2800
|
-
ui: {
|
2801
|
-
label: 'label'
|
2802
|
-
}
|
2803
|
-
});
|
2804
|
-
|
2805
|
-
/**
|
2806
|
-
* A table cell mapping column attribute values to a list of
|
2807
|
-
* translations.
|
2808
|
-
*
|
2809
|
-
* ## Attribute Translations
|
2810
|
-
*
|
2811
|
-
* The following attribute translations are used:
|
2812
|
-
*
|
2813
|
-
* - `.cell_text.<attribute_value>` - Used as cell content.
|
2814
|
-
* - `.cell_text.blank` - Used as cell content if attribute is blank.
|
2815
|
-
* - `.cell_title.<attribute_value>` - Used as title attribute.
|
2816
|
-
* - `.cell_title.blank` - Used as title attribute if attribute is blank.
|
2817
|
-
*
|
2818
|
-
* @since 12.0
|
2819
|
-
*/
|
2820
|
-
|
2821
|
-
var EnumTableCellView = TableCellView.extend({
|
2822
|
-
className: 'enum_table_cell',
|
2823
|
-
update: function update() {
|
2824
|
-
this.$el.text(this.attributeTranslation('cell_text.' + (this.attributeValue() || 'blank')));
|
2825
|
-
this.$el.attr('title', this.attributeTranslation('cell_title.' + (this.attributeValue() || 'blank'), {
|
2826
|
-
defaultValue: ''
|
2827
|
-
}));
|
2828
|
-
}
|
2829
|
-
});
|
2830
|
-
|
2831
|
-
function template$d(data) {
|
2832
|
-
var __t, __p = '';
|
2833
|
-
__p += '<a class="remove" title="' +
|
2834
|
-
((__t = ( I18n.t('pageflow.editor.templates.row.destroy') )) == null ? '' : __t) +
|
2835
|
-
'"></a>\n';
|
2836
|
-
return __p
|
2837
|
-
}
|
2838
|
-
|
2839
|
-
/**
|
2840
|
-
* A table cell providing a button which destroys the model that the
|
2841
|
-
* current row refers to.
|
2842
|
-
*
|
2843
|
-
* ## Attribute Translations
|
2844
|
-
*
|
2845
|
-
* The following attribute translation is used:
|
2846
|
-
*
|
2847
|
-
* - `.cell_title` - Used as title attribute.
|
2848
|
-
*
|
2849
|
-
* @param {Object} [options]
|
2850
|
-
*
|
2851
|
-
* @param {function} [options.toggleDeleteButton]
|
2852
|
-
* A function with boolean return value to be called on
|
2853
|
-
* this.getModel(). Delete button will be visible only if the
|
2854
|
-
* function returns a truthy value.
|
2855
|
-
*
|
2856
|
-
* @param {boolean} [options.invertToggleDeleteButton]
|
2857
|
-
* Invert the return value of `toggleDeleteButton`?
|
2858
|
-
*
|
2859
|
-
* @since 12.0
|
2860
|
-
*/
|
2861
|
-
|
2862
|
-
var DeleteRowTableCellView = TableCellView.extend({
|
2863
|
-
className: 'delete_row_table_cell',
|
2864
|
-
template: template$d,
|
2865
|
-
ui: {
|
2866
|
-
removeButton: '.remove'
|
2867
|
-
},
|
2868
|
-
events: {
|
2869
|
-
'click .remove': 'destroy',
|
2870
|
-
'click': function click() {
|
2871
|
-
return false;
|
2872
|
-
}
|
2873
|
-
},
|
2874
|
-
showButton: function showButton() {
|
2875
|
-
if (this.options.toggleDeleteButton) {
|
2876
|
-
var context = this.getModel();
|
2877
|
-
var toggle = context[this.options.toggleDeleteButton].apply(context);
|
2878
|
-
|
2879
|
-
if (this.options.invertToggleDeleteButton) {
|
2880
|
-
return !toggle;
|
2881
|
-
} else {
|
2882
|
-
return !!toggle;
|
2883
|
-
}
|
2884
|
-
} else {
|
2885
|
-
return true;
|
2886
|
-
}
|
2887
|
-
},
|
2888
|
-
update: function update() {
|
2889
|
-
this.ui.removeButton.toggleClass('remove', this.showButton());
|
2890
|
-
this.ui.removeButton.attr('title', this.attributeTranslation('cell_title'));
|
2891
|
-
},
|
2892
|
-
destroy: function destroy() {
|
2893
|
-
this.getModel().destroy();
|
2894
|
-
}
|
2895
|
-
});
|
2896
|
-
|
2897
|
-
/**
|
2898
|
-
* A table cell representing whether the column attribute is present
|
2899
|
-
* on the row model.
|
2900
|
-
*
|
2901
|
-
* ## Attribute Translations
|
2902
|
-
*
|
2903
|
-
* The following attribute translations are used:
|
2904
|
-
*
|
2905
|
-
* - `.cell_title.present` - Used as title attribute if the attribute
|
2906
|
-
* is present. The current attribute value is provided as
|
2907
|
-
* interpolation `%{value}`.
|
2908
|
-
* - `.cell_title.blank` - Used as title attribute if the
|
2909
|
-
* attribute is blank.
|
2910
|
-
*
|
2911
|
-
* @since 12.0
|
2912
|
-
*/
|
2913
|
-
|
2914
|
-
var PresenceTableCellView = TableCellView.extend({
|
2915
|
-
className: 'presence_table_cell',
|
2916
|
-
update: function update() {
|
2917
|
-
var isPresent = !!this.attributeValue();
|
2918
|
-
this.$el.attr('title', isPresent ? this.attributeTranslation('cell_title.present', {
|
2919
|
-
value: this.attributeValue()
|
2920
|
-
}) : this.attributeTranslation('cell_title.blank'));
|
2921
|
-
this.$el.toggleClass('is_present', isPresent);
|
2922
|
-
}
|
2923
|
-
});
|
2924
|
-
|
2925
|
-
/**
|
2926
|
-
* A table cell mapping column attribute values to icons.
|
2927
|
-
*
|
2928
|
-
* ## Attribute Translations
|
2929
|
-
*
|
2930
|
-
* The following attribute translations are used:
|
2931
|
-
*
|
2932
|
-
* - `.cell_title.<attribute_value>` - Used as title attribute.
|
2933
|
-
* - `.cell_title.blank` - Used as title attribute if attribute is blank.
|
2934
|
-
*
|
2935
|
-
* @param {Object} [options]
|
2936
|
-
*
|
2937
|
-
* @param {string[]} [options.icons]
|
2938
|
-
* An array of all possible attribute values to be mapped to HTML
|
2939
|
-
* classes of the same name. A global mapping from those classes to
|
2940
|
-
* icon mixins is provided in
|
2941
|
-
* pageflow/ui/table_cells/icon_table_cell.scss.
|
2942
|
-
*
|
2943
|
-
* @since 12.0
|
2944
|
-
*/
|
2945
|
-
|
2946
|
-
var IconTableCellView = TableCellView.extend({
|
2947
|
-
className: 'icon_table_cell',
|
2948
|
-
update: function update() {
|
2949
|
-
var icon = this.attributeValue();
|
2950
|
-
var isPresent = !!this.attributeValue();
|
2951
|
-
this.removeExistingIcons();
|
2952
|
-
this.$el.attr('title', isPresent ? this.attributeTranslation('cell_title.' + icon, {
|
2953
|
-
value: this.attributeValue()
|
2954
|
-
}) : this.attributeTranslation('cell_title.blank'));
|
2955
|
-
this.$el.addClass(icon);
|
2956
|
-
},
|
2957
|
-
removeExistingIcons: function removeExistingIcons() {
|
2958
|
-
this.$el.removeClass(this.options.icons.join(' '));
|
2959
|
-
}
|
2960
|
-
});
|
2961
|
-
|
2962
|
-
/**
|
2963
|
-
* A table cell using the row model's value of the column attribute as
|
2964
|
-
* text. If attribute value is empty, use most specific default
|
2965
|
-
* available.
|
2966
|
-
*
|
2967
|
-
* @param {Object} [options]
|
2968
|
-
*
|
2969
|
-
* @param {function|string} [options.column.default]
|
2970
|
-
* A function returning a default value for display if attribute
|
2971
|
-
* value is empty.
|
2972
|
-
*
|
2973
|
-
* @param {string} [options.column.contentBinding]
|
2974
|
-
* If this is provided, the function `options.column.default`
|
2975
|
-
* receives the values of `options.column.contentBinding` and of
|
2976
|
-
* this.getModel() via its options hash. No-op if
|
2977
|
-
* `options.column.default` is not a function.
|
2978
|
-
*
|
2979
|
-
* @since 12.0
|
2980
|
-
*/
|
2981
|
-
|
2982
|
-
var TextTableCellView = TableCellView.extend({
|
2983
|
-
className: 'text_table_cell',
|
2984
|
-
update: function update() {
|
2985
|
-
this.$el.text(this._updateText());
|
2986
|
-
},
|
2987
|
-
_updateText: function _updateText() {
|
2988
|
-
if (this.attributeValue()) {
|
2989
|
-
return this.attributeValue();
|
2990
|
-
} else if (typeof this.options.column["default"] === 'function') {
|
2991
|
-
var options = {};
|
2992
|
-
|
2993
|
-
if (this.options.column.contentBinding) {
|
2994
|
-
options = {
|
2995
|
-
contentBinding: this.options.column.contentBinding,
|
2996
|
-
model: this.getModel()
|
2997
|
-
};
|
2998
|
-
}
|
2999
|
-
|
3000
|
-
return this.options.column["default"](options);
|
3001
|
-
} else if ('default' in this.options.column) {
|
3002
|
-
return this.options.column["default"];
|
3003
|
-
} else {
|
3004
|
-
return I18n$1.t('pageflow.ui.text_table_cell_view.empty');
|
3005
|
-
}
|
3006
|
-
}
|
3007
|
-
});
|
3008
|
-
|
3009
|
-
var subviewContainer = {
|
3010
|
-
subview: function subview(view) {
|
3011
|
-
this.subviews = this.subviews || new ChildViewContainer();
|
3012
|
-
this.subviews.add(view.render());
|
3013
|
-
return view;
|
3014
|
-
},
|
3015
|
-
appendSubview: function appendSubview(view) {
|
3016
|
-
return this.$el.append(this.subview(view).el);
|
3017
|
-
},
|
3018
|
-
onClose: function onClose() {
|
3019
|
-
if (this.subviews) {
|
3020
|
-
this.subviews.call('close');
|
3021
|
-
}
|
3022
|
-
}
|
3023
|
-
};
|
3024
|
-
|
3025
|
-
if (!Marionette.View.prototype.appendSubview) {
|
3026
|
-
Cocktail.mixin(Marionette.View, subviewContainer);
|
3027
|
-
}
|
3028
|
-
|
3029
|
-
var tooltipContainer = {
|
3030
|
-
events: {
|
3031
|
-
'mouseover [data-tooltip]': function mouseoverDataTooltip(event) {
|
3032
|
-
if (!this.tooltip.visible) {
|
3033
|
-
var target = $(event.currentTarget);
|
3034
|
-
var key = target.attr('data-tooltip');
|
3035
|
-
var position;
|
3036
|
-
|
3037
|
-
if (target.data('tooltipAlign') === 'bottom left') {
|
3038
|
-
position = {
|
3039
|
-
left: target.position().left,
|
3040
|
-
top: target.position().top + target.outerHeight()
|
3041
|
-
};
|
3042
|
-
} else if (target.data('tooltipAlign') === 'bottom right') {
|
3043
|
-
position = {
|
3044
|
-
left: target.position().left + target.outerWidth(),
|
3045
|
-
top: target.position().top + target.outerHeight()
|
3046
|
-
};
|
3047
|
-
} else if (target.data('tooltipAlign') === 'top center') {
|
3048
|
-
position = {
|
3049
|
-
left: target.position().left + target.outerWidth() / 2,
|
3050
|
-
top: target.position().top + 2
|
3051
|
-
};
|
3052
|
-
} else {
|
3053
|
-
position = {
|
3054
|
-
left: target.position().left + target.outerWidth(),
|
3055
|
-
top: target.position().top + target.outerHeight() / 2
|
3056
|
-
};
|
3057
|
-
}
|
3058
|
-
|
3059
|
-
this.tooltip.show(I18n$1.t(key), position, {
|
3060
|
-
align: target.data('tooltipAlign')
|
3061
|
-
});
|
3062
|
-
}
|
3063
|
-
},
|
3064
|
-
'mouseleave [data-tooltip]': function mouseleaveDataTooltip() {
|
3065
|
-
this.tooltip.hide();
|
3066
|
-
}
|
3067
|
-
},
|
3068
|
-
onRender: function onRender() {
|
3069
|
-
this.appendSubview(this.tooltip = new TooltipView());
|
3070
|
-
}
|
3071
|
-
};
|
3072
|
-
|
3073
|
-
exports.CheckBoxGroupInputView = CheckBoxGroupInputView;
|
3074
|
-
exports.CheckBoxInputView = CheckBoxInputView;
|
3075
|
-
exports.CollectionView = CollectionView;
|
3076
|
-
exports.ColorInputView = ColorInputView;
|
3077
|
-
exports.ConfigurationEditorTabView = ConfigurationEditorTabView;
|
3078
|
-
exports.ConfigurationEditorView = ConfigurationEditorView;
|
3079
|
-
exports.DeleteRowTableCellView = DeleteRowTableCellView;
|
3080
|
-
exports.EnumTableCellView = EnumTableCellView;
|
3081
|
-
exports.ExtendedSelectInputView = ExtendedSelectInputView;
|
3082
|
-
exports.IconTableCellView = IconTableCellView;
|
3083
|
-
exports.JsonInputView = JsonInputView;
|
3084
|
-
exports.LabelOnlyView = LabelOnlyView;
|
3085
|
-
exports.Object = BaseObject;
|
3086
|
-
exports.PresenceTableCellView = PresenceTableCellView;
|
3087
|
-
exports.ProxyUrlInputView = ProxyUrlInputView;
|
3088
|
-
exports.SelectInputView = SelectInputView;
|
3089
|
-
exports.SeparatorView = SeparatorView;
|
3090
|
-
exports.SliderInputView = SliderInputView;
|
3091
|
-
exports.SortableCollectionView = SortableCollectionView;
|
3092
|
-
exports.TableCellView = TableCellView;
|
3093
|
-
exports.TableHeaderCellView = TableHeaderCellView;
|
3094
|
-
exports.TableRowView = TableRowView;
|
3095
|
-
exports.TableView = TableView;
|
3096
|
-
exports.TabsView = TabsView;
|
3097
|
-
exports.TextAreaInputView = TextAreaInputView;
|
3098
|
-
exports.TextInputView = TextInputView;
|
3099
|
-
exports.TextTableCellView = TextTableCellView;
|
3100
|
-
exports.TooltipView = TooltipView;
|
3101
|
-
exports.UrlDisplayView = UrlDisplayView;
|
3102
|
-
exports.UrlInputView = UrlInputView;
|
3103
|
-
exports.cssModulesUtils = cssModulesUtils;
|
3104
|
-
exports.i18nUtils = i18nUtils;
|
3105
|
-
exports.inputView = inputView;
|
3106
|
-
exports.inputWithPlaceholderText = inputWithPlaceholderText;
|
3107
|
-
exports.serverSideValidation = serverSideValidation;
|
3108
|
-
exports.subviewContainer = subviewContainer;
|
3109
|
-
exports.tooltipContainer = tooltipContainer;
|
3110
|
-
exports.viewWithValidationErrorMessages = viewWithValidationErrorMessages;
|
3111
|
-
|
3112
|
-
return exports;
|
3113
|
-
|
3114
|
-
}({}, Backbone.Marionette, _, jQuery, I18n, Backbone, Backbone.ChildViewContainer, IScroll, jQuery, wysihtml5, Cocktail));
|