pageflow 15.2.2 → 15.6.1

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.

Files changed (213) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -118
  3. data/README.md +2 -3
  4. data/admins/pageflow/accounts.rb +1 -98
  5. data/admins/pageflow/entry.rb +21 -1
  6. data/admins/pageflow/entry_templates.rb +140 -0
  7. data/admins/pageflow/membership.rb +12 -0
  8. data/admins/pageflow/user.rb +5 -5
  9. data/app/assets/javascripts/pageflow/admin/entries.js +65 -0
  10. data/app/assets/javascripts/pageflow/admin/users.js +1 -1
  11. data/app/assets/javascripts/pageflow/asset_urls.js.erb +1 -0
  12. data/app/assets/javascripts/pageflow/base.js +0 -12
  13. data/app/assets/javascripts/pageflow/components.js +2 -6
  14. data/app/assets/javascripts/pageflow/dist/ui.js +178 -55
  15. data/app/assets/javascripts/pageflow/editor/vendor.js +1 -0
  16. data/app/assets/javascripts/pageflow/vendor.js +12 -10
  17. data/app/assets/stylesheets/pageflow/base.scss +0 -7
  18. data/app/assets/stylesheets/pageflow/editor/base.scss +5 -2
  19. data/app/assets/stylesheets/pageflow/editor/composables.scss +5 -1
  20. data/app/assets/stylesheets/pageflow/editor/drop_down_button.scss +1 -1
  21. data/app/assets/stylesheets/pageflow/editor/emulation_mode_button.scss +44 -55
  22. data/app/assets/stylesheets/pageflow/editor/help.scss +2 -2
  23. data/app/assets/stylesheets/pageflow/editor/select_button.scss +1 -1
  24. data/app/assets/stylesheets/pageflow/editor/sidebar_footer.scss +1 -1
  25. data/app/assets/stylesheets/pageflow/entries.scss +1 -1
  26. data/app/assets/stylesheets/pageflow/loading_spinner.scss +4 -1
  27. data/app/assets/stylesheets/pageflow/navigation_mobile.scss +4 -4
  28. data/app/assets/stylesheets/pageflow/themes/default/anchors.scss +1 -1
  29. data/app/assets/stylesheets/pageflow/themes/default/logo/variant/watermark.scss +1 -1
  30. data/app/assets/stylesheets/pageflow/themes/default/page.scss +7 -0
  31. data/app/assets/stylesheets/pageflow/themes/default/page/anchors.scss +1 -1
  32. data/app/assets/stylesheets/pageflow/themes/default/player_controls/classic/control_bar.scss +1 -1
  33. data/app/assets/stylesheets/pageflow/themes/default/player_controls/classic/info_box.scss +1 -1
  34. data/app/assets/stylesheets/pageflow/themes/default/player_controls/shared/menu_bar.scss +2 -2
  35. data/app/assets/stylesheets/pageflow/themes/default/player_controls/slim/control_bar.scss +2 -2
  36. data/app/assets/stylesheets/pageflow/themes/default/player_controls/slim/info_box.scss +1 -1
  37. data/app/assets/stylesheets/pageflow/themes/default/player_controls/slim/quality_menu.scss +2 -2
  38. data/app/assets/stylesheets/pageflow/themes/default/player_controls/waveform/wave.scss +1 -1
  39. data/app/assets/stylesheets/pageflow/ui/forms.scss +9 -2
  40. data/app/assets/stylesheets/pageflow/ui/input/extended_select_input.scss +2 -2
  41. data/app/assets/stylesheets/pageflow/ui/tooltip.scss +17 -3
  42. data/app/helpers/pageflow/admin/entries_helper.rb +16 -0
  43. data/app/helpers/pageflow/structured_data_helper.rb +0 -2
  44. data/app/models/pageflow/account.rb +21 -1
  45. data/app/models/pageflow/account_role_query.rb +1 -1
  46. data/app/models/pageflow/chapter.rb +3 -9
  47. data/app/models/pageflow/entry.rb +9 -2
  48. data/app/models/pageflow/entry_duplicate.rb +1 -0
  49. data/app/models/pageflow/entry_template.rb +16 -2
  50. data/app/models/pageflow/managed_user_query.rb +1 -1
  51. data/app/models/pageflow/page.rb +1 -4
  52. data/app/models/pageflow/revision.rb +0 -4
  53. data/app/models/pageflow/storyline.rb +2 -9
  54. data/app/policies/pageflow/account_policy.rb +10 -0
  55. data/app/policies/pageflow/entry_template_policy.rb +5 -1
  56. data/app/policies/pageflow/folder_policy.rb +2 -2
  57. data/app/policies/pageflow/membership_policy.rb +2 -2
  58. data/app/policies/pageflow/theming_policy.rb +2 -2
  59. data/app/policies/pageflow/user_policy.rb +1 -1
  60. data/app/views/admin/accounts/_entry_template_details.html.arb +7 -5
  61. data/app/views/admin/accounts/_form.html.erb +3 -49
  62. data/app/views/admin/entries/_attributes_table.html.arb +5 -0
  63. data/app/views/admin/entries/_not_allowed_to_see_entry_types.json.jbuilder +2 -0
  64. data/app/views/admin/entries/entry_types.json.jbuilder +4 -0
  65. data/app/views/admin/entry_templates/_form.html.erb +58 -0
  66. data/app/views/admin/users/_not_allowed_to_see_user_quota.html.erb +3 -0
  67. data/app/views/components/pageflow/admin/entry_templates_tab.rb +48 -0
  68. data/app/views/pageflow/admin/initial_passwords/edit.html.erb +2 -1
  69. data/app/views/pageflow/admin/users/_quota_exhausted.html.erb +1 -1
  70. data/app/views/pageflow/themes/_theme.json.jbuilder +1 -1
  71. data/app/views/pageflow/video_files/_video_file.json.jbuilder +8 -1
  72. data/config/initializers/admin_resource_tabs.rb +5 -0
  73. data/config/initializers/help_entries.rb +1 -5
  74. data/config/initializers/revision_components.rb +5 -0
  75. data/config/locales/de.yml +88 -155
  76. data/config/locales/en.yml +79 -143
  77. data/db/migrate/20200515112500_add_constraints_to_entry_templates.rb +21 -0
  78. data/db/migrate/20200807135200_rename_pageflow_entry_template_entry_type_to_entry_type_name.rb +7 -0
  79. data/entry_types/paged/app/assets/javascripts/pageflow_paged/components.js +7 -0
  80. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/editor.js +1528 -1349
  81. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/frontend.js +9258 -0
  82. data/{app/assets/javascripts/pageflow → entry_types/paged/app/assets/javascripts/pageflow_paged}/dist/react-client.js +1 -1
  83. data/{app/assets/javascripts/pageflow → entry_types/paged/app/assets/javascripts/pageflow_paged}/dist/react-server.js +3 -3
  84. data/entry_types/paged/app/assets/javascripts/pageflow_paged/frontend.js +6 -0
  85. data/entry_types/paged/app/assets/javascripts/pageflow_paged/server_rendering.js +9 -0
  86. data/entry_types/paged/app/assets/javascripts/pageflow_paged/vendor.js +9 -0
  87. data/entry_types/paged/app/assets/javascripts/pageflow_paged/videojs.js +6 -0
  88. data/entry_types/paged/app/controllers/pageflow_paged/application_controller.rb +2 -2
  89. data/{app/helpers/pageflow → entry_types/paged/app/helpers/pageflow_paged}/page_background_asset_helper.rb +4 -3
  90. data/{app/helpers/pageflow → entry_types/paged/app/helpers/pageflow_paged}/react_server_side_rendering_helper.rb +23 -2
  91. data/entry_types/paged/app/views/layouts/pageflow_paged/_loading_spinner_inline_script.html.erb +1 -0
  92. data/entry_types/paged/app/views/layouts/pageflow_paged/application.html.erb +3 -3
  93. data/entry_types/paged/app/views/pageflow_paged/editor/entries/_head.html.erb +4 -2
  94. data/entry_types/paged/app/views/pageflow_paged/entries/_entry.html.erb +1 -1
  95. data/{app/views/pageflow → entry_types/paged/app/views/pageflow_paged}/page_background_asset/_element.html.erb +0 -0
  96. data/{app/views/pageflow → entry_types/paged/app/views/pageflow_paged}/react/_widget.html.erb +0 -0
  97. data/{app/views/pageflow → entry_types/paged/app/views/pageflow_paged}/react/page.html.erb +0 -0
  98. data/entry_types/paged/config/initializers/features.rb +1 -1
  99. data/entry_types/paged/config/initializers/help_entries.rb +17 -0
  100. data/entry_types/paged/config/locales/new/help.de.yml +162 -0
  101. data/entry_types/paged/config/locales/new/help.en.yml +153 -0
  102. data/entry_types/paged/lib/pageflow_paged/engine.rb +13 -0
  103. data/entry_types/paged/lib/pageflow_paged/plugin.rb +5 -1
  104. data/entry_types/paged/lib/pageflow_paged/react.rb +12 -0
  105. data/{lib/pageflow → entry_types/paged/lib/pageflow_paged}/react/page_type.rb +2 -2
  106. data/{lib/pageflow → entry_types/paged/lib/pageflow_paged}/react/widget_type.rb +2 -2
  107. data/entry_types/paged/lib/tasks/pageflow_paged_tasks.rake +7 -0
  108. data/entry_types/paged/vendor/assets/javascripts/development/pageflow_paged/vendor/react-server.js +20613 -0
  109. data/entry_types/paged/vendor/assets/javascripts/development/pageflow_paged/vendor/react.js +21495 -0
  110. data/{vendor/assets/javascripts → entry_types/paged/vendor/assets/javascripts/pageflow_paged/vendor}/dash.all.min.js +0 -0
  111. data/{vendor/assets/javascripts → entry_types/paged/vendor/assets/javascripts/pageflow_paged/vendor}/videojs-dash.js +0 -0
  112. data/{vendor/assets/javascripts → entry_types/paged/vendor/assets/javascripts/pageflow_paged/vendor}/videojs.js +0 -0
  113. data/entry_types/paged/vendor/assets/javascripts/production/pageflow_paged/vendor/react-server.js +24 -0
  114. data/entry_types/paged/vendor/assets/javascripts/production/pageflow_paged/vendor/react.js +24 -0
  115. data/entry_types/scrolled/app/assets/javascripts/pageflow_scrolled/legacy.js +0 -0
  116. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/chapters_controller.rb +2 -2
  117. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/content_elements_controller.rb +14 -4
  118. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/sections_controller.rb +2 -2
  119. data/entry_types/scrolled/app/controllers/pageflow_scrolled/entries_controller.rb +10 -0
  120. data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/seed_html_helper.rb +7 -0
  121. data/entry_types/scrolled/app/helpers/pageflow_scrolled/entry_json_seed_helper.rb +2 -0
  122. data/entry_types/scrolled/app/helpers/pageflow_scrolled/favicon_helper.rb +21 -0
  123. data/entry_types/scrolled/app/helpers/pageflow_scrolled/react_server_side_rendering_helper.rb +40 -0
  124. data/entry_types/scrolled/app/helpers/pageflow_scrolled/themes_helper.rb +36 -0
  125. data/entry_types/scrolled/app/models/pageflow_scrolled/chapter.rb +3 -9
  126. data/entry_types/scrolled/app/models/pageflow_scrolled/content_element.rb +37 -2
  127. data/entry_types/scrolled/app/models/pageflow_scrolled/section.rb +3 -9
  128. data/entry_types/scrolled/app/models/pageflow_scrolled/storyline.rb +1 -9
  129. data/entry_types/scrolled/app/views/pageflow_scrolled/editor/content_elements/batch.json.jbuilder +2 -0
  130. data/entry_types/scrolled/app/views/pageflow_scrolled/editor/entries/_head.html.erb +1 -7
  131. data/entry_types/scrolled/app/views/pageflow_scrolled/entries/_global_notices.html.erb +10 -0
  132. data/entry_types/scrolled/app/views/pageflow_scrolled/entries/show.html.erb +28 -11
  133. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry.json.jbuilder +3 -0
  134. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_theme.json.jbuilder +8 -0
  135. data/entry_types/scrolled/app/views/pageflow_scrolled/favicons/_entry.html.erb +10 -0
  136. data/entry_types/scrolled/config/initializers/help_entries.rb +16 -0
  137. data/entry_types/scrolled/config/locales/de.yml +669 -0
  138. data/entry_types/scrolled/config/locales/en.yml +488 -0
  139. data/entry_types/scrolled/config/routes.rb +1 -0
  140. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/install_generator.rb +76 -6
  141. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/favicons/android-chrome-192x192.png +0 -0
  142. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/favicons/android-chrome-512x512.png +0 -0
  143. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/favicons/apple-touch-icon.png +0 -0
  144. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/favicons/browserconfig.xml +9 -0
  145. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/favicons/favicon-16x16.png +0 -0
  146. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/favicons/favicon-32x32.png +0 -0
  147. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/favicons/favicon.ico +0 -0
  148. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/favicons/mstile-150x150.png +0 -0
  149. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/favicons/safari-pinned-tab.svg +46 -0
  150. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/favicons/site.webmanifest +19 -0
  151. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/logoDesktop.svg +56 -0
  152. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/logoMobile.svg +22 -0
  153. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/unmute.mp3 +0 -0
  154. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/themes_plugin.rb.tt +26 -0
  155. data/entry_types/scrolled/lib/pageflow_scrolled/engine.rb +6 -0
  156. data/entry_types/scrolled/lib/pageflow_scrolled/plugin.rb +3 -1
  157. data/entry_types/scrolled/lib/pageflow_scrolled/seeds.rb +90 -30
  158. data/entry_types/scrolled/lib/tasks/pageflow_scrolled/create_bundle_symlinks_for_yarn.rake +33 -0
  159. data/entry_types/scrolled/lib/tasks/pageflow_scrolled/dummy.rake +8 -0
  160. data/entry_types/scrolled/lib/tasks/pageflow_scrolled/storybook.rake +173 -0
  161. data/entry_types/scrolled/package/config/webpack.js +11 -0
  162. data/entry_types/scrolled/package/contentElements-editor.js +316 -185
  163. data/entry_types/scrolled/package/contentElements-frontend.css +1 -0
  164. data/entry_types/scrolled/package/contentElements-frontend.js +940 -304
  165. data/entry_types/scrolled/package/editor.js +2930 -371
  166. data/entry_types/scrolled/package/frontend-server.js +228 -0
  167. data/entry_types/scrolled/package/frontend/EditableText-7093fd0e.js +1071 -0
  168. data/entry_types/scrolled/package/frontend/Viewer-e49e7807.js +387 -0
  169. data/entry_types/scrolled/package/frontend/Wavesurfer-0adf5667.js +375 -0
  170. data/entry_types/scrolled/package/frontend/components-6a6793ca.js +2534 -0
  171. data/entry_types/scrolled/package/frontend/getPrototypeOf-63c7c8e8.js +86 -0
  172. data/entry_types/scrolled/package/frontend/i18n-4dc6c377.js +1092 -0
  173. data/entry_types/scrolled/package/frontend/index.css +9 -0
  174. data/entry_types/scrolled/package/frontend/index.js +5686 -0
  175. data/entry_types/scrolled/package/frontend/useBrowserFeature-91a4c29d.js +33 -0
  176. data/entry_types/scrolled/package/package.json +30 -9
  177. data/entry_types/scrolled/spec/fixtures/audio.m4a +0 -0
  178. data/entry_types/scrolled/spec/fixtures/video.mp4 +0 -0
  179. data/lib/generators/pageflow/initializer/templates/pageflow.rb +14 -9
  180. data/lib/pageflow/ability_mixin.rb +14 -2
  181. data/lib/pageflow/configuration.rb +6 -5
  182. data/lib/pageflow/entry_export_import/revision_serialization.rb +15 -13
  183. data/lib/pageflow/entry_export_import/revision_serialization/import.rb +18 -26
  184. data/lib/pageflow/entry_type_configuration.rb +2 -0
  185. data/lib/pageflow/global_config_api.rb +5 -4
  186. data/lib/pageflow/nested_revision_component.rb +49 -0
  187. data/lib/pageflow/react.rb +4 -2
  188. data/lib/pageflow/revision_component.rb +6 -2
  189. data/lib/pageflow/themes.rb +4 -0
  190. data/lib/pageflow/user_mixin.rb +2 -1
  191. data/lib/pageflow/version.rb +1 -1
  192. data/{packages/pageflow → package}/config/jest/index.js +8 -2
  193. data/{packages/pageflow → package}/config/jest/transformers/jst.js +0 -0
  194. data/{packages/pageflow → package}/config/jest/transformers/upwardBabel.js +0 -0
  195. data/{packages/pageflow → package}/config/webpack.js +7 -0
  196. data/{packages/pageflow → package}/editor.js +482 -1130
  197. data/package/frontend.js +2553 -0
  198. data/{packages/pageflow → package}/package.json +3 -0
  199. data/{packages/pageflow → package}/testHelpers.js +114 -13
  200. data/{packages/pageflow → package}/ui.js +178 -55
  201. data/spec/factories/accounts.rb +3 -1
  202. data/spec/factories/entry_templates.rb +1 -0
  203. data/spec/factories/published_entries.rb +6 -1
  204. data/spec/factories/test_revision_components.rb +4 -0
  205. metadata +95 -36
  206. data/app/assets/javascripts/pageflow/dist/frontend.js +0 -5800
  207. data/app/assets/javascripts/pageflow/videojs.js +0 -6
  208. data/config/initializers/entry_types.rb +0 -4
  209. data/entry_types/scrolled/config/locales/new/de.yml +0 -269
  210. data/entry_types/scrolled/config/locales/new/en.yml +0 -264
  211. data/entry_types/scrolled/lib/tasks/pageflow_scrolled_tasks.rake +0 -96
  212. data/entry_types/scrolled/package/frontend.js +0 -2879
  213. data/packages/pageflow/config/jest/transformers/cssModules.js +0 -1
@@ -13,6 +13,7 @@
13
13
  "eslint-plugin-import": "^2.18.2",
14
14
  "eslint-plugin-jest": "^23.0.4",
15
15
  "jest": "^24.9.0",
16
+ "jest-css-modules-processor": "^0.0.9",
16
17
  "jest-jquery-matchers": "^2.1.0",
17
18
  "jest-sinon": "^1.0.0",
18
19
  "sinon": "^7.5.0"
@@ -22,6 +23,8 @@
22
23
  "lint": "eslint ."
23
24
  },
24
25
  "dependencies": {
26
+ "backbone-events-standalone": "^0.2.7",
27
+ "classlist.js": "^1.1.20150312",
25
28
  "core-js": "^3.4.1",
26
29
  "i18n-js": "^3.5.1"
27
30
  }
@@ -249,15 +249,6 @@ var ColorInput = Base.extend({
249
249
  }
250
250
  });
251
251
 
252
- var SelectInput = Base.extend({
253
- selector: 'select',
254
- values: function values() {
255
- return this.$el.find('option').map(function () {
256
- return $(this).attr('value');
257
- }).get();
258
- }
259
- });
260
-
261
252
  function _defineProperty(obj, key, value) {
262
253
  if (key in obj) {
263
254
  Object.defineProperty(obj, key, {
@@ -273,9 +264,81 @@ function _defineProperty(obj, key, value) {
273
264
  return obj;
274
265
  }
275
266
 
276
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
267
+ function ownKeys(object, enumerableOnly) {
268
+ var keys = Object.keys(object);
269
+
270
+ if (Object.getOwnPropertySymbols) {
271
+ var symbols = Object.getOwnPropertySymbols(object);
272
+ if (enumerableOnly) symbols = symbols.filter(function (sym) {
273
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
274
+ });
275
+ keys.push.apply(keys, symbols);
276
+ }
277
+
278
+ return keys;
279
+ }
280
+
281
+ function _objectSpread2(target) {
282
+ for (var i = 1; i < arguments.length; i++) {
283
+ var source = arguments[i] != null ? arguments[i] : {};
284
+
285
+ if (i % 2) {
286
+ ownKeys(Object(source), true).forEach(function (key) {
287
+ _defineProperty(target, key, source[key]);
288
+ });
289
+ } else if (Object.getOwnPropertyDescriptors) {
290
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
291
+ } else {
292
+ ownKeys(Object(source)).forEach(function (key) {
293
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
294
+ });
295
+ }
296
+ }
297
+
298
+ return target;
299
+ }
300
+
301
+ var Base$1 = Base.extend({
302
+ selector: '.input'
303
+ });
304
+
305
+ Base$1.findByPropertyName = function (propertyName, options) {
306
+ return this.findBy(function (el) {
307
+ return el.data('inputPropertyName') === propertyName;
308
+ }, _objectSpread2({
309
+ predicateName: "input property name '".concat(propertyName, "'")
310
+ }, options));
311
+ };
312
+
313
+ var RadioButtonGroupInput = Base$1.extend({
314
+ values: function values() {
315
+ return this.$el.find('input').map(function () {
316
+ return $(this).attr('value');
317
+ }).get();
318
+ },
319
+ enabledValues: function enabledValues() {
320
+ return this.$el.find('input:not([disabled])').map(function () {
321
+ return $(this).attr('value');
322
+ }).get();
323
+ }
324
+ });
325
+
326
+ var SelectInput = Base$1.extend({
327
+ value: function value() {
328
+ return this.$el.find('select').val();
329
+ },
330
+ values: function values() {
331
+ return this.$el.find('option').map(function () {
332
+ return $(this).attr('value');
333
+ }).get();
334
+ },
335
+ enabledValues: function enabledValues() {
336
+ return this.$el.find('option:not([disabled])').map(function () {
337
+ return $(this).attr('value');
338
+ }).get();
339
+ }
340
+ });
277
341
 
278
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
279
342
  /**
280
343
  * Build editor Backbone models for tests.
281
344
  */
@@ -314,7 +377,7 @@ var factories = {
314
377
 
315
378
  ensureFileTypes(options);
316
379
  ensureFilesCollections(options);
317
- var entry = new model(_objectSpread({
380
+ var entry = new model(_objectSpread2({
318
381
  id: 1
319
382
  }, attributes), _.extend({
320
383
  storylines: new Backbone.Collection(),
@@ -551,6 +614,44 @@ function ensureFilesCollections(options) {
551
614
  }
552
615
  }
553
616
 
617
+ var state = window.pageflow || {};
618
+
619
+ /**
620
+ * Setup global state for testing Backbone editro components.
621
+ *
622
+ * For some editor components like (some views or models) it's easier
623
+ * to depend on the global mutable state (available via the `$state`
624
+ * module alias) instead of injecting dependencies. This helper can be
625
+ * used to test these components in isolation.
626
+ *
627
+ * @param {Object} mapping -
628
+ * Properties to set on the global state. Functions as values will
629
+ * be evaluated and the return value will be assigned instead.
630
+ */
631
+
632
+ var setupGlobals = function setupGlobals(mapping) {
633
+ var globalsBackup;
634
+ beforeEach(function () {
635
+ if (globalsBackup) {
636
+ throw new Error('There can only be one setupGlobals call per test.');
637
+ }
638
+
639
+ globalsBackup = {};
640
+
641
+ _.each(mapping, function (value, key) {
642
+ globalsBackup[key] = state[key];
643
+ state[key] = typeof value === 'function' ? value.call(this) : value;
644
+ });
645
+ });
646
+ afterEach(function () {
647
+ _.each(mapping, function (_, key) {
648
+ state[key] = globalsBackup[key];
649
+ });
650
+
651
+ globalsBackup = null;
652
+ });
653
+ };
654
+
554
655
  /**
555
656
  * Define translations to use in tests.
556
657
  *
@@ -628,4 +729,4 @@ function keysWithDotsToNestedObjects(translations) {
628
729
  }, {});
629
730
  }
630
731
 
631
- export { ColorInput, ConfigurationEditor, ConfigurationEditorTab, DropDownButton, FileMetaDataTable, FileStageItem, FileThumbnail, ReferenceInput, SelectInput, StaticThumbnail, Table, Tabs, ThemeItem, factories, useFakeTranslations };
732
+ export { ColorInput, ConfigurationEditor, ConfigurationEditorTab, DropDownButton, FileMetaDataTable, FileStageItem, FileThumbnail, RadioButtonGroupInput, ReferenceInput, SelectInput, StaticThumbnail, Table, Tabs, ThemeItem, factories, setupGlobals, useFakeTranslations };
@@ -155,10 +155,7 @@ function _arrayWithHoles(arr) {
155
155
  }
156
156
 
157
157
  function _iterableToArrayLimit(arr, i) {
158
- if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) {
159
- return;
160
- }
161
-
158
+ if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
162
159
  var _arr = [];
163
160
  var _n = true;
164
161
  var _d = false;
@@ -184,12 +181,31 @@ function _iterableToArrayLimit(arr, i) {
184
181
  return _arr;
185
182
  }
186
183
 
184
+ function _arrayLikeToArray(arr, len) {
185
+ if (len == null || len > arr.length) len = arr.length;
186
+
187
+ for (var i = 0, arr2 = new Array(len); i < len; i++) {
188
+ arr2[i] = arr[i];
189
+ }
190
+
191
+ return arr2;
192
+ }
193
+
194
+ function _unsupportedIterableToArray(o, minLen) {
195
+ if (!o) return;
196
+ if (typeof o === "string") return _arrayLikeToArray(o, minLen);
197
+ var n = Object.prototype.toString.call(o).slice(8, -1);
198
+ if (n === "Object" && o.constructor) n = o.constructor.name;
199
+ if (n === "Map" || n === "Set") return Array.from(n);
200
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
201
+ }
202
+
187
203
  function _nonIterableRest() {
188
- throw new TypeError("Invalid attempt to destructure non-iterable instance");
204
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
189
205
  }
190
206
 
191
207
  function _slicedToArray(arr, i) {
192
- return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
208
+ return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
193
209
  }
194
210
 
195
211
  /**
@@ -271,7 +287,7 @@ function ui(styles) {
271
287
  * <button class=${styles.addButton}></button>
272
288
  * `,
273
289
  *
274
- * events: cssModulesUtils.ui(styles, {
290
+ * events: cssModulesUtils.events(styles, {
275
291
  * 'click addButton': () => console.log('clicked add button');
276
292
  * })
277
293
  * });
@@ -1006,10 +1022,14 @@ var TooltipView = Marionette.ItemView.extend({
1006
1022
  this.ui.label.text(text);
1007
1023
  this.$el.toggleClass('align_bottom_right', options.align === 'bottom right');
1008
1024
  this.$el.toggleClass('align_bottom_left', options.align === 'bottom left');
1025
+ this.$el.toggleClass('align_top_center', options.align === 'top center');
1009
1026
 
1010
1027
  if (options.align === 'bottom right' || options.align === 'bottom left') {
1011
1028
  offsetTop = 10;
1012
1029
  offsetLeft = 0;
1030
+ } else if (options.align === 'top center') {
1031
+ offsetTop = -10;
1032
+ offsetLeft = 0;
1013
1033
  } else {
1014
1034
  offsetTop = -17;
1015
1035
  offsetLeft = 10;
@@ -1117,13 +1137,30 @@ var TooltipView = Marionette.ItemView.extend({
1117
1137
  * A text that will be appended to the translation based inline
1118
1138
  * text.
1119
1139
  *
1120
- * @param {boolean} [options.disabled]
1121
- * Render input as disabled.
1140
+ * @param {string|string[]} [options.disabledBinding]
1141
+ * Name of an attribute to control whether the input is disabled. If
1142
+ * the `disabled` and `disabledBinding` options are not set,
1143
+ * input will be disabled whenever this attribute has a truthy value.
1144
+ * When multiple attribute names are passed, the function passed to
1145
+ * the `disabled` option will receive an array of values in the same
1146
+ * order.
1147
+ *
1148
+ * @param {function|boolean} [options.disabled]
1149
+ * Render input as disabled. A Function taking the value of the
1150
+ * `disabledBinding` attribute as parameter. Input will be disabled
1151
+ * only if function returns `true`.
1152
+ *
1153
+ * @param {any} [options.disabledBindingValue]
1154
+ * Input will be disabled whenever the value of the `disabledBinding`
1155
+ * attribute equals the value of this option.
1122
1156
  *
1123
- * @param {string} [options.visibleBinding]
1157
+ * @param {string|string[]} [options.visibleBinding]
1124
1158
  * Name of an attribute to control whether the input is visible. If
1125
1159
  * the `visible` and `visibleBindingValue` options are not set,
1126
1160
  * input will be visible whenever this attribute has a truthy value.
1161
+ * When multiple attribute names are passed, the function passed to
1162
+ * the `visible` option will receive an array of values in the same
1163
+ * order.
1127
1164
  *
1128
1165
  * @param {function|boolean} [options.visible]
1129
1166
  * A Function taking the value of the `visibleBinding` attribute as
@@ -1178,15 +1215,10 @@ var inputView = {
1178
1215
  this.$el.data('labelText', this.labelText());
1179
1216
  this.$el.data('inlineHelpText', this.inlineHelpText());
1180
1217
  this.ui.labelText.text(this.labelText());
1181
- this.ui.inlineHelp.html(this.inlineHelpText());
1182
-
1183
- if (!this.inlineHelpText()) {
1184
- this.ui.inlineHelp.hide();
1185
- }
1186
-
1218
+ this.updateInlineHelp();
1187
1219
  this.setLabelFor();
1188
- this.updateDisabled();
1189
- this.setupVisibleBinding();
1220
+ this.setupAttributeBinding('disabled', this.updateDisabled);
1221
+ this.setupAttributeBinding('visible', this.updateVisible);
1190
1222
  },
1191
1223
 
1192
1224
  /**
@@ -1201,6 +1233,13 @@ var inputView = {
1201
1233
  fallbackPrefix: 'activerecord.attributes'
1202
1234
  }));
1203
1235
  },
1236
+ updateInlineHelp: function updateInlineHelp() {
1237
+ this.ui.inlineHelp.html(this.inlineHelpText());
1238
+
1239
+ if (!this.inlineHelpText()) {
1240
+ this.ui.inlineHelp.hide();
1241
+ }
1242
+ },
1204
1243
 
1205
1244
  /**
1206
1245
  * The inline help text for the form field.
@@ -1211,7 +1250,7 @@ var inputView = {
1211
1250
  fallbackPrefix: 'pageflow.ui.inline_help'
1212
1251
  });
1213
1252
 
1214
- if (this.options.disabled) {
1253
+ if (this.isDisabled()) {
1215
1254
  keys = translationKeysWithSuffix(keys, 'disabled');
1216
1255
  }
1217
1256
 
@@ -1227,40 +1266,61 @@ var inputView = {
1227
1266
  this.ui.label.attr('for', id);
1228
1267
  }
1229
1268
  },
1269
+ isDisabled: function isDisabled() {
1270
+ return this.getAttributeBoundOption('disabled');
1271
+ },
1230
1272
  updateDisabled: function updateDisabled() {
1273
+ this.updateInlineHelp();
1274
+
1231
1275
  if (this.ui.input) {
1232
1276
  this.updateDisabledAttribute(this.ui.input);
1233
1277
  }
1234
1278
  },
1235
1279
  updateDisabledAttribute: function updateDisabledAttribute(element) {
1236
- if (this.options.disabled) {
1280
+ if (this.isDisabled()) {
1237
1281
  element.attr('disabled', true);
1238
1282
  } else {
1239
1283
  element.removeAttr('disabled');
1240
1284
  }
1241
1285
  },
1242
- setupVisibleBinding: function setupVisibleBinding() {
1286
+ updateVisible: function updateVisible() {
1287
+ this.$el.toggleClass('input-hidden_via_binding', this.getAttributeBoundOption('visible') === false);
1288
+ },
1289
+ setupAttributeBinding: function setupAttributeBinding(optionName, updateMethod) {
1290
+ var _this = this;
1291
+
1292
+ var binding = this.options["".concat(optionName, "Binding")];
1243
1293
  var view = this;
1244
1294
 
1245
- if (this.options.visibleBinding) {
1246
- this.listenTo(this.model, 'change:' + this.options.visibleBinding, updateVisible);
1247
- updateVisible(this.model, this.model.get(this.options.visibleBinding));
1295
+ if (binding) {
1296
+ _.flatten([binding]).forEach(function (attribute) {
1297
+ _this.listenTo(_this.model, 'change:' + attribute, update);
1298
+ });
1248
1299
  }
1249
1300
 
1250
- function updateVisible(model, value) {
1251
- view.$el.toggleClass('input-hidden_via_binding', !isVisible(value));
1301
+ update();
1302
+
1303
+ function update() {
1304
+ updateMethod.call(view, view.getAttributeBoundOption(optionName));
1252
1305
  }
1306
+ },
1307
+ getAttributeBoundOption: function getAttributeBoundOption(optionName) {
1308
+ var _this2 = this;
1253
1309
 
1254
- function isVisible(value) {
1255
- if ('visibleBindingValue' in view.options) {
1256
- return value === view.options.visibleBindingValue;
1257
- } else if (typeof view.options.visible === 'function') {
1258
- return !!view.options.visible(value);
1259
- } else if ('visible' in view.options) {
1260
- return !!view.options.visible;
1261
- } else {
1262
- return !!value;
1263
- }
1310
+ var binding = this.options["".concat(optionName, "Binding")];
1311
+ var bindingValueOptionName = "".concat(optionName, "BindingValue");
1312
+ var value = Array.isArray(binding) ? binding.map(function (attribute) {
1313
+ return _this2.model.get(attribute);
1314
+ }) : this.model.get(binding);
1315
+
1316
+ if (bindingValueOptionName in this.options) {
1317
+ return value === this.options[bindingValueOptionName];
1318
+ } else if (typeof this.options[optionName] === 'function') {
1319
+ return !!this.options[optionName](value);
1320
+ } else if (optionName in this.options) {
1321
+ return !!this.options[optionName];
1322
+ } else if (binding) {
1323
+ return !!value;
1264
1324
  }
1265
1325
  }
1266
1326
  };
@@ -1411,11 +1471,14 @@ var inputWithPlaceholderText = {
1411
1471
  this.listenTo(this.model, 'change:' + this.options.placeholderBinding, this.updatePlaceholder);
1412
1472
  }
1413
1473
  },
1474
+ updateDisabled: function updateDisabled() {
1475
+ this.updatePlaceholder();
1476
+ },
1414
1477
  updatePlaceholder: function updatePlaceholder() {
1415
1478
  this.ui.input.attr('placeholder', this.placeholderText());
1416
1479
  },
1417
1480
  placeholderText: function placeholderText() {
1418
- if (!this.options.disabled || !this.options.hidePlaceholderIfDisabled) {
1481
+ if (!this.isDisabled() || !this.options.hidePlaceholderIfDisabled) {
1419
1482
  if (this.options.placeholder) {
1420
1483
  if (typeof this.options.placeholder == 'function') {
1421
1484
  return this.options.placeholder(this.model);
@@ -1426,6 +1489,8 @@ var inputWithPlaceholderText = {
1426
1489
  return this.placeholderModelValue();
1427
1490
  }
1428
1491
  }
1492
+
1493
+ return '';
1429
1494
  },
1430
1495
  placeholderModelValue: function placeholderModelValue() {
1431
1496
  return this.options.placeholderModel && this.options.placeholderModel.get(this.options.propertyName);
@@ -1578,12 +1643,22 @@ var ColorInputView = Marionette.ItemView.extend({
1578
1643
  this.updateSettings();
1579
1644
  },
1580
1645
  updateSettings: function updateSettings() {
1646
+ this.resetSwatchesInStoredSettings();
1581
1647
  this.ui.input.minicolors('settings', {
1582
1648
  defaultValue: this.defaultValue(),
1583
1649
  swatches: this.getSwatches()
1584
1650
  });
1585
1651
  this.load();
1586
1652
  },
1653
+ // see https://github.com/claviska/jquery-minicolors/issues/287
1654
+ resetSwatchesInStoredSettings: function resetSwatchesInStoredSettings() {
1655
+ var settings = this.ui.input.data('minicolors-settings');
1656
+
1657
+ if (settings) {
1658
+ delete settings.swatches;
1659
+ this.ui.input.data('minicolors-settings', settings);
1660
+ }
1661
+ },
1587
1662
  load: function load() {
1588
1663
  this.ui.input.minicolors('value', this.model.get(this.options.propertyName) || this.defaultValue());
1589
1664
  this.$el.toggleClass('is_default', !this.model.has(this.options.propertyName));
@@ -1689,6 +1764,10 @@ return __p
1689
1764
  * value of the `placeholderModel` occurs whenever the attribute is
1690
1765
  * blank.
1691
1766
  *
1767
+ * @param {function} [options.optionDisabled]
1768
+ * Receives value and has to return boolean indicating whether
1769
+ * option is disabled.
1770
+ *
1692
1771
  * @class
1693
1772
  */
1694
1773
 
@@ -1791,6 +1870,10 @@ var SelectInputView = Marionette.ItemView.extend({
1791
1870
  option.value = value;
1792
1871
  option.text = this.options.texts[index];
1793
1872
 
1873
+ if (this.options.optionDisabled && this.options.optionDisabled(value)) {
1874
+ option.setAttribute('disabled', true);
1875
+ }
1876
+
1794
1877
  if (group) {
1795
1878
  option.setAttribute('data-group', group);
1796
1879
  this.findOrCreateOptGroup(group).append(option);
@@ -1815,10 +1898,10 @@ var SelectInputView = Marionette.ItemView.extend({
1815
1898
  if (!this.isClosed) {
1816
1899
  var value = this.model.get(this.options.propertyName);
1817
1900
 
1818
- if (this.model.has(this.options.propertyName) && this.ui.select.find('option[value="' + value + '"]').length) {
1901
+ if (this.model.has(this.options.propertyName) && this.ui.select.find('option[value="' + value + '"]:not([disabled])').length) {
1819
1902
  this.ui.select.val(value);
1820
1903
  } else {
1821
- this.ui.select.val(this.ui.select.find('option:first').val());
1904
+ this.ui.select.val(this.ui.select.find('option:not([disabled]):first').val());
1822
1905
  }
1823
1906
  }
1824
1907
  }
@@ -1947,7 +2030,7 @@ __p += '<label>\n <span class="name"></span>\n <span class="inline_help"></spa
1947
2030
  ((__t = ( I18n.t('pageflow.ui.templates.inputs.text_area_input.open_in_new_tab') )) == null ? '' : __t) +
1948
2031
  '\n </label>\n <span class="inline_help">\n ' +
1949
2032
  ((__t = ( I18n.t('pageflow.ui.templates.inputs.text_area_input.open_in_new_tab_help') )) == null ? '' : __t) +
1950
- '\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="http://">\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 ' +
2033
+ '\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 ' +
1951
2034
  ((__t = ( I18n.t('pageflow.ui.templates.inputs.text_area_input.save') )) == null ? '' : __t) +
1952
2035
  '\n </a>\n <a class="button" data-wysihtml5-dialog-action="cancel">\n ' +
1953
2036
  ((__t = ( I18n.t('pageflow.ui.templates.inputs.text_area_input.cancel') )) == null ? '' : __t) +
@@ -2094,7 +2177,7 @@ var TextAreaInputView = Marionette.ItemView.extend({
2094
2177
  var currentUrl = this.ui.urlInput.val();
2095
2178
 
2096
2179
  if (currentUrl.startsWith('#')) {
2097
- this.ui.displayUrlInput.val('http://');
2180
+ this.ui.displayUrlInput.val('');
2098
2181
  this.ui.openInNewTabCheckBox.prop('checked', true);
2099
2182
  } else {
2100
2183
  this.ui.displayUrlInput.val(currentUrl);
@@ -2160,6 +2243,21 @@ var TextAreaInputView = Marionette.ItemView.extend({
2160
2243
  }
2161
2244
  });
2162
2245
 
2246
+ function _defineProperty(obj, key, value) {
2247
+ if (key in obj) {
2248
+ Object.defineProperty(obj, key, {
2249
+ value: value,
2250
+ enumerable: true,
2251
+ configurable: true,
2252
+ writable: true
2253
+ });
2254
+ } else {
2255
+ obj[key] = value;
2256
+ }
2257
+
2258
+ return obj;
2259
+ }
2260
+
2163
2261
  function template$9(data) {
2164
2262
  var __p = '';
2165
2263
  __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';
@@ -2202,24 +2300,32 @@ var UrlInputView = Marionette.Layout.extend(
2202
2300
  this.validate();
2203
2301
  },
2204
2302
  onChange: function onChange() {
2205
- var view = this;
2206
- this.saveDisplayProperty();
2207
- this.validate().done(function () {
2208
- view.save();
2303
+ var _this = this;
2304
+
2305
+ this.validate().then(function () {
2306
+ return _this.save();
2307
+ }, function () {
2308
+ return _this.saveDisplayProperty();
2209
2309
  });
2210
2310
  },
2211
2311
  saveDisplayProperty: function saveDisplayProperty() {
2312
+ this.model.unset(this.options.propertyName, {
2313
+ silent: true
2314
+ });
2212
2315
  this.model.set(this.options.displayPropertyName, this.ui.input.val());
2213
- this.model.unset(this.options.propertyName);
2214
2316
  },
2215
2317
  save: function save() {
2216
- var view = this;
2217
- $.when(this.transformPropertyValue(this.ui.input.val())).then(function (value) {
2218
- view.model.set(view.options.propertyName, value);
2318
+ var _this2 = this;
2319
+
2320
+ var value = this.ui.input.val();
2321
+ $.when(this.transformPropertyValue(value)).then(function (transformedValue) {
2322
+ var _this2$model$set;
2323
+
2324
+ _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));
2219
2325
  });
2220
2326
  },
2221
2327
  load: function load() {
2222
- this.ui.input.val(this.model.get(this.options.displayPropertyName));
2328
+ this.ui.input.val(this.model.has(this.options.displayPropertyName) ? this.model.get(this.options.displayPropertyName) : this.model.get(this.options.propertyName));
2223
2329
  this.onLoad();
2224
2330
  },
2225
2331
 
@@ -2428,6 +2534,15 @@ var SliderInputView = Marionette.ItemView.extend({
2428
2534
  });
2429
2535
  this.load();
2430
2536
  },
2537
+ updateDisabled: function updateDisabled(disabled) {
2538
+ this.$el.toggleClass('disabled', !!disabled);
2539
+
2540
+ if (disabled) {
2541
+ this.ui.widget.slider('disable');
2542
+ } else {
2543
+ this.ui.widget.slider('enable');
2544
+ }
2545
+ },
2431
2546
  save: function save() {
2432
2547
  var value = this.ui.widget.slider('option', 'value');
2433
2548
  var unit = 'unit' in this.options ? this.options.unit : '%';
@@ -2552,8 +2667,11 @@ var CheckBoxInputView = Marionette.ItemView.extend({
2552
2667
  this.load();
2553
2668
  this.listenTo(this.model, 'change:' + this.options.propertyName, this.load);
2554
2669
  },
2670
+ updateDisabled: function updateDisabled() {
2671
+ this.load();
2672
+ },
2555
2673
  save: function save() {
2556
- if (!this.options.disabled) {
2674
+ if (!this.isDisabled()) {
2557
2675
  this.model.set(this.options.propertyName, this.ui.input.is(':checked'));
2558
2676
  }
2559
2677
  },
@@ -2563,7 +2681,7 @@ var CheckBoxInputView = Marionette.ItemView.extend({
2563
2681
  }
2564
2682
  },
2565
2683
  displayValue: function displayValue() {
2566
- if (this.options.disabled && this.options.displayUncheckedIfDisabled) {
2684
+ if (this.isDisabled() && this.options.displayUncheckedIfDisabled) {
2567
2685
  return false;
2568
2686
  } else {
2569
2687
  return this.model.get(this.options.propertyName);
@@ -2796,8 +2914,8 @@ var tooltipContainer = {
2796
2914
  events: {
2797
2915
  'mouseover [data-tooltip]': function mouseoverDataTooltip(event) {
2798
2916
  if (!this.tooltip.visible) {
2799
- var target = $(event.target);
2800
- var key = target.data('tooltip');
2917
+ var target = $(event.currentTarget);
2918
+ var key = target.attr('data-tooltip');
2801
2919
  var position;
2802
2920
 
2803
2921
  if (target.data('tooltipAlign') === 'bottom left') {
@@ -2810,6 +2928,11 @@ var tooltipContainer = {
2810
2928
  left: target.position().left + target.outerWidth(),
2811
2929
  top: target.position().top + target.outerHeight()
2812
2930
  };
2931
+ } else if (target.data('tooltipAlign') === 'top center') {
2932
+ position = {
2933
+ left: target.position().left + target.outerWidth() / 2,
2934
+ top: target.position().top + 2
2935
+ };
2813
2936
  } else {
2814
2937
  position = {
2815
2938
  left: target.position().left + target.outerWidth(),
@@ -2822,7 +2945,7 @@ var tooltipContainer = {
2822
2945
  });
2823
2946
  }
2824
2947
  },
2825
- 'mouseout [data-tooltip]': function mouseoutDataTooltip() {
2948
+ 'mouseleave [data-tooltip]': function mouseleaveDataTooltip() {
2826
2949
  this.tooltip.hide();
2827
2950
  }
2828
2951
  },