locomotivecms 3.0.0.rc2 → 3.0.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/README.md +2 -1
  4. data/app/api/locomotive/api/entities/site_entity.rb +8 -0
  5. data/app/api/locomotive/api/exception_rescuers.rb +1 -1
  6. data/app/api/locomotive/api/forms/content_entry_form.rb +4 -3
  7. data/app/api/locomotive/api/helpers/params_helper.rb +21 -3
  8. data/app/api/locomotive/api/resources/current_site_resource.rb +1 -1
  9. data/app/api/locomotive/api/resources/site_resource.rb +2 -2
  10. data/app/assets/images/locomotive/deadend.png +0 -0
  11. data/app/assets/javascripts/locomotive/not_logged_in.js.coffee +1 -1
  12. data/app/assets/javascripts/locomotive/utils/core_ext.js +1 -1
  13. data/app/assets/javascripts/locomotive/utils/wysihtml5.js.coffee +43 -17
  14. data/app/assets/javascripts/locomotive/views/application_view.js.coffee +5 -1
  15. data/app/assets/javascripts/locomotive/views/editable_elements/edit_view.js.coffee +47 -0
  16. data/app/assets/javascripts/locomotive/views/editable_elements/iframe_view.js.coffee +59 -0
  17. data/app/assets/javascripts/locomotive/views/editable_elements/index_view.js.coffee +19 -92
  18. data/app/assets/javascripts/locomotive/views/editable_elements/page_view.js.coffee +81 -0
  19. data/app/assets/javascripts/locomotive/views/editable_elements/text_highlighter_view.js.coffee +76 -0
  20. data/app/assets/javascripts/locomotive/views/inputs/rte/edit_table_view.js.coffee +35 -0
  21. data/app/assets/javascripts/locomotive/views/inputs/rte/file_view.js.coffee +14 -10
  22. data/app/assets/javascripts/locomotive/views/inputs/rte/link_view.js.coffee +25 -15
  23. data/app/assets/javascripts/locomotive/views/inputs/rte/table_view.js.coffee +82 -0
  24. data/app/assets/javascripts/locomotive/views/inputs/rte_view.js.coffee.erb +64 -23
  25. data/app/assets/javascripts/locomotive/views/inputs/text_view.js.coffee +11 -6
  26. data/app/assets/javascripts/locomotive.js +2 -2
  27. data/app/assets/stylesheets/locomotive/application.scss +1 -3
  28. data/app/assets/stylesheets/locomotive/base/_form.scss +2 -1
  29. data/app/assets/stylesheets/locomotive/base/_typography.scss +3 -2
  30. data/app/assets/stylesheets/locomotive/base/form/_base.scss +5 -0
  31. data/app/assets/stylesheets/locomotive/base/form/_rte.scss +42 -0
  32. data/app/assets/stylesheets/locomotive/error.scss +1 -1
  33. data/app/assets/stylesheets/locomotive/globals/_mixins.scss +41 -48
  34. data/app/assets/stylesheets/locomotive/globals/_variables.scss +202 -121
  35. data/app/assets/stylesheets/locomotive/layouts/_not_logged_in.scss +8 -9
  36. data/app/assets/stylesheets/locomotive/live_editing_error.scss +19 -0
  37. data/app/assets/stylesheets/locomotive/live_editing_iframe.scss +84 -0
  38. data/app/assets/stylesheets/locomotive/unauthorized/_forms.scss +63 -0
  39. data/app/assets/stylesheets/locomotive/unauthorized/_keyframes.scss +31 -0
  40. data/app/assets/stylesheets/locomotive/unauthorized/_notify.scss +85 -0
  41. data/app/assets/stylesheets/locomotive/unauthorized/_public.scss +129 -0
  42. data/app/assets/stylesheets/locomotive/unauthorized/_type.scss +14 -0
  43. data/app/assets/stylesheets/locomotive/unauthorized/_variables.scss +54 -0
  44. data/app/assets/stylesheets/locomotive/unauthorized.scss +34 -0
  45. data/app/helpers/locomotive/dashboard_helper.rb +1 -1
  46. data/app/inputs/locomotive/rte_input.rb +12 -0
  47. data/app/models/locomotive/concerns/page/editable_elements.rb +0 -2
  48. data/app/models/locomotive/editable_element.rb +1 -1
  49. data/app/services/locomotive/content_asset_service.rb +1 -1
  50. data/app/services/locomotive/page_parsing_service.rb +4 -2
  51. data/app/views/locomotive/editable_elements/index.html.slim +1 -1
  52. data/app/views/locomotive/layouts/not_logged_in.html.slim +13 -9
  53. data/app/views/locomotive/passwords/edit.html.slim +13 -13
  54. data/app/views/locomotive/passwords/new.html.slim +14 -11
  55. data/app/views/locomotive/registrations/new.html.slim +14 -13
  56. data/app/views/locomotive/sessions/new.html.slim +14 -13
  57. data/app/views/locomotive/shared/rte/_markdown_toolbar.html.slim +0 -30
  58. data/app/views/locomotive/shared/rte/_table_popover.html.slim +17 -0
  59. data/app/views/locomotive/shared/rte/_toolbar.html.slim +48 -11
  60. data/config/initializers/simple_form.rb +2 -0
  61. data/config/locales/carrierwave.lt.yml +4 -0
  62. data/config/locales/carrierwave.nl.yml +4 -0
  63. data/config/locales/carrierwave.ru.yml +4 -0
  64. data/config/locales/default.nl.yml +13 -0
  65. data/config/locales/devise.nl.yml +61 -0
  66. data/config/locales/en.yml +28 -10
  67. data/config/locales/flash.nl.yml +79 -0
  68. data/config/locales/inputs.lt.yml +18 -0
  69. data/config/locales/inputs.nl.yml +18 -0
  70. data/config/locales/mongoid.nl.yml +47 -0
  71. data/config/locales/nl.yml +316 -0
  72. data/config/locales/simple_form.en.yml +6 -0
  73. data/config/locales/simple_form.nl.yml +148 -0
  74. data/lib/locomotive/carrierwave/asset.rb +5 -1
  75. data/lib/locomotive/dependencies.rb +0 -1
  76. data/lib/locomotive/engine.rb +7 -1
  77. data/lib/locomotive/middlewares/site.rb +14 -2
  78. data/lib/locomotive/mongoid/patches.rb +29 -0
  79. data/lib/locomotive/steam/middlewares/catch_error.rb +78 -0
  80. data/lib/locomotive/steam/middlewares/wysihtml_css.rb +32 -0
  81. data/lib/locomotive/steam_adaptor.rb +4 -7
  82. data/lib/locomotive/version.rb +1 -1
  83. data/spec/requests/locomotive/steam/cache_spec.rb +3 -3
  84. data/spec/requests/locomotive/steam/wysihtml_css_spec.rb +42 -0
  85. data/spec/requests/site_spec.rb +13 -2
  86. data/spec/support/features/session_helpers.rb +3 -3
  87. data/vendor/assets/components/locomotive/backbone/backbone.js +1894 -0
  88. data/vendor/assets/components/locomotive/underscore/underscore.js +1548 -0
  89. data/vendor/assets/components/locomotive_sources/backbone/LICENSE +22 -0
  90. data/vendor/assets/components/locomotive_sources/backbone/backbone-min.js +2 -0
  91. data/vendor/assets/components/locomotive_sources/backbone/backbone-min.map +1 -0
  92. data/vendor/assets/components/locomotive_sources/backbone/backbone.js +1894 -0
  93. data/vendor/assets/components/locomotive_sources/backbone/bower.json +8 -0
  94. data/vendor/assets/components/locomotive_sources/underscore/LICENSE +23 -0
  95. data/vendor/assets/components/locomotive_sources/underscore/README.md +22 -0
  96. data/vendor/assets/components/locomotive_sources/underscore/bower.json +7 -0
  97. data/vendor/assets/components/locomotive_sources/underscore/underscore-min.js +6 -0
  98. data/vendor/assets/components/locomotive_sources/underscore/underscore-min.map +1 -0
  99. data/vendor/assets/components/locomotive_sources/underscore/underscore.js +1548 -0
  100. data/vendor/assets/javascripts/locomotive/wysihtml5/parser_rules/advanced.js +22 -48
  101. data/vendor/assets/javascripts/locomotive/wysihtml5/parser_rules/advanced_unwrap.js +13 -12
  102. data/vendor/assets/javascripts/locomotive/wysihtml5x-toolbar.js +7324 -3862
  103. data/vendor/assets/stylesheets/locomotive/wysihtml5_editor.css +27 -1
  104. metadata +53 -28
  105. data/app/assets/stylesheets/locomotive/globals/_all.scss +0 -3
  106. data/app/assets/stylesheets/locomotive/globals/_bootstrap.scss +0 -841
  107. data/app/assets/stylesheets/locomotive/globals/_colors.scss +0 -1
  108. data/app/assets/stylesheets/locomotive/globals/_nprogress.scss +0 -3
  109. data/app/assets/stylesheets/locomotive/not_logged_in.scss +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f5fcc2bd87ac0d01a19c8ea5f798ff338f1eb8fc
4
- data.tar.gz: b189780fd9fbc5c04631715245fa79a068d355f9
3
+ metadata.gz: adb0a5ebc0f40fc62072340ff10f15d6029d14bb
4
+ data.tar.gz: c7d3971de7bd5e22fc8d32b94445e3c6ff96f2cc
5
5
  SHA512:
6
- metadata.gz: 0b3a1a9f8d51163f4c16999f78e02d9cbcde1b00875bbb8694be328d50d2afcece5af4f8eb087b6ebb0d0bae1322770f363a5100d99acd8785f148c86334762c
7
- data.tar.gz: a48ea5fc1565b9a175ae2b3e515644fed3dd15664961c75a37ab152630108cd3052db6f50bd867f21381d6601ad2dfde8420d8180f3e57d25dcc99a0e72a8231
6
+ metadata.gz: 470554e8983fb56b3d2e88bc02dd1276b21baa7153dc9afcd8c98b29e4b4ea9ecb3cbe1eef5bba2df822da81024ac1682ec29eec4c157dd4337709bcf9499ea3
7
+ data.tar.gz: e38ef2a4463cd47412a61cc2843242e843db154d8e78f0e58486939535e6318b70453c0763fb5bd6c1eaf0884bca322f65cb35730513fd2180cf4421a732fa27
data/Gemfile CHANGED
@@ -21,8 +21,8 @@ group :development do
21
21
  # gem 'custom_fields', path: '../gems/custom_fields' # for Developers
22
22
  # gem 'custom_fields', github: 'locomotivecms/custom_fields', ref: '15cceb66ed'
23
23
 
24
- # gem 'locomotivecms_steam', path: '../in_progress/steam', require: false
25
- # gem 'locomotivecms_steam', github: 'locomotivecms/steam', ref: 'c1d1120', require: false
24
+ # gem 'locomotivecms_steam', path: '../gems/steam', require: false
25
+ # gem 'locomotivecms_steam', github: 'locomotivecms/steam', ref: 'c9cb7f6', require: false
26
26
 
27
27
  # gem 'locomotive_liquid', path: '../gems/liquid' # for Developers
28
28
  # gem 'locomotivecms_solid', path: '../gems/solid' # for Developers
data/README.md CHANGED
@@ -65,9 +65,10 @@ Here is our Transifex portal page: [https://www.transifex.com/locomotive/locomot
65
65
 
66
66
  Locomotive is an open source project, we encourage contributions. If you have found a bug and want to contribute a fix, or have a new feature you would like to add, follow the steps below to get your patch into the project:
67
67
 
68
- - Install ruby and mongoDB
68
+ - Install ruby, mongoDB and phantomjs
69
69
  - Clone the project <code>git clone git@github.com:locomotivecms/engine.git</code>
70
70
  - Setup a virtual host entry for <code>test.example.com</code> to point to localhost
71
+ - Start mongodb if it is not already running
71
72
  - Run the tests <code>bundle exec rake</code>
72
73
  - Write your failing tests
73
74
  - Make the tests pass
@@ -31,6 +31,14 @@ module Locomotive
31
31
  Locomotive::Dragonfly.resize_url site.picture.url, '100x100#'
32
32
  end
33
33
 
34
+ expose :preview_url do |site, opts|
35
+ Locomotive::Engine.routes.url_helpers.preview_url(site, host: opts[:env]['HTTP_HOST'])
36
+ end
37
+
38
+ expose :sign_in_url do |site, opts|
39
+ Locomotive::Engine.routes.url_helpers.new_locomotive_account_session_url(host: opts[:env]['HTTP_HOST'])
40
+ end
41
+
34
42
  end
35
43
 
36
44
  end
@@ -8,7 +8,7 @@ module Locomotive
8
8
  included do
9
9
 
10
10
  rescue_from :all do |e|
11
- Rails.logger.error "[API]" + e.message + "\"" + e.backtrace.join("\n")
11
+ Rails.logger.error "[API] " + e.message + "\n\t" + e.backtrace.join("\n\t")
12
12
 
13
13
  error_response(message: { error: e.message }, status: 500)
14
14
  end
@@ -26,12 +26,13 @@ module Locomotive
26
26
 
27
27
  def set_many_to_many(field, value)
28
28
  if value.blank?
29
- dynamic_attributes[:"#{field.name}_ids"] = [] # reset it
29
+ dynamic_attributes[:"#{field.name.singularize}_ids"] = [] # reset it
30
30
  else
31
- dynamic_attributes[:"#{field.name}_ids"] = fetch_entry_ids(field.class_name, value).sort do |a, b|
31
+ dynamic_attributes[:"#{field.name.singularize}_ids"] = fetch_entry_ids(field.class_name, value).sort do |a, b|
32
+ # keep the original order
32
33
  (value.index(a.first.to_s) || value.index(a.last)) <=>
33
34
  (value.index(b.first.to_s) || value.index(b.last))
34
- end # keep the original order
35
+ end.map(&:first)
35
36
  end
36
37
  end
37
38
 
@@ -10,16 +10,34 @@ module Locomotive
10
10
  # Much safer than permitted_params because it also uses the current policy
11
11
  # (Pundit) to filter the parameters.
12
12
  #
13
- # Example:
13
+ # Examples:
14
14
  #
15
15
  # permitted_params_from_policy(current_site, :site)
16
16
  #
17
- def permitted_params_from_policy(object_or_class, key)
18
- _params = permitted_params[key]
17
+ # If we want to deal with ActionDispatch::Http::UploadedFile instances
18
+ # instead of hashes (which would break the permitted attributes policy).
19
+ #
20
+ # permitted_params_from_policy(current_site, :site, [:picture])
21
+ #
22
+ def permitted_params_from_policy(object_or_class, key, file_inputs = nil)
23
+ _params = permitted_params[key]
24
+
25
+ build_uploaded_files_from_params!(_params, file_inputs) if file_inputs
26
+
19
27
  _attributes = policy(object_or_class).permitted_attributes
20
28
  ::ActionController::Parameters.new(_params).permit(*_attributes)
21
29
  end
22
30
 
31
+ def build_uploaded_files_from_params!(hash, list)
32
+ list.each do |name|
33
+ file_hash = hash[name]
34
+
35
+ next unless file_hash.try(:has_key?, :tempfile)
36
+
37
+ hash[name] = ActionDispatch::Http::UploadedFile.new(file_hash)
38
+ end
39
+ end
40
+
23
41
  end
24
42
 
25
43
  end
@@ -46,7 +46,7 @@ module Locomotive
46
46
  put do
47
47
  authorize current_site, :update?
48
48
 
49
- current_site_form = Forms::SiteForm.new(permitted_params_from_policy(current_site, :site))
49
+ current_site_form = Forms::SiteForm.new(permitted_params_from_policy(current_site, :site, [:picture]))
50
50
  service.update(current_site, current_site_form.serializable_hash)
51
51
 
52
52
  present current_site, with: entity_klass
@@ -71,7 +71,7 @@ module Locomotive
71
71
  post do
72
72
  authorize Site, :create?
73
73
 
74
- site_form = Forms::SiteForm.new(permitted_params_from_policy(Locomotive::Site, :site))
74
+ site_form = Forms::SiteForm.new(permitted_params_from_policy(Locomotive::Site, :site, [:picture]))
75
75
  site = service.create!(site_form.serializable_hash)
76
76
 
77
77
  present site, with: entity_klass
@@ -98,7 +98,7 @@ module Locomotive
98
98
  site = load_site
99
99
  authorize site, :update?
100
100
 
101
- site_form = Forms::SiteForm.new(permitted_params_from_policy(site, :site))
101
+ site_form = Forms::SiteForm.new(permitted_params_from_policy(site, :site, [:picture]))
102
102
  site.assign_attributes(site_form.serializable_hash)
103
103
  site.save!
104
104
 
@@ -1,6 +1,6 @@
1
1
  #= require jquery
2
2
  #= require_self
3
- #= require underscore
3
+ #= require underscore/underscore
4
4
  #= require locomotive/bootstrap-notify
5
5
  #= require ./utils/notify
6
6
 
@@ -60,7 +60,7 @@
60
60
  doc.body.appendChild(script);
61
61
  }
62
62
 
63
- window.addStylesheet = function(doc, src, options) {
63
+ window.addStylesheet = function(doc, src) {
64
64
  var stylesheet = doc.createElement('link');
65
65
  stylesheet.style = 'text/css';
66
66
  stylesheet.href = src;
@@ -1,33 +1,23 @@
1
- # New command: strike
2
- wysihtml5.commands.strike =
3
- exec: (composer, command, param) ->
4
- wysihtml5.commands.formatInline.exec(composer, command, 'strike')
5
-
6
- state: (composer, command) ->
7
- wysihtml5.commands.formatInline.state(composer, command, 'strike')
8
-
9
- # New command: justify full
10
- # https://github.com/xing/wysihtml5/blob/56960b31adc37e07797382d8e8b10109f206b19c/src/commands/justifyFull.js
11
1
  ((wysihtml5) ->
12
- CLASS_NAME = "wysiwyg-text-align-justify"
13
- REG_EXP = /wysiwyg-text-align-[0-9a-z]+/g
14
2
 
15
- wysihtml5.commands.justifyFull =
16
- exec: (composer, command, param) ->
17
- wysihtml5.commands.formatBlock.exec(composer, 'formatBlock', null, CLASS_NAME, REG_EXP)
3
+ # New command: strike
4
+ wysihtml5.commands.strike =
5
+ exec: (composer, command) ->
6
+ wysihtml5.commands.formatInline.exec(composer, command, 'STRIKE')
18
7
 
19
8
  state: (composer, command) ->
20
- wysihtml5.commands.formatBlock.state(composer, "formatBlock", null, CLASS_NAME, REG_EXP)
9
+ wysihtml5.commands.formatInline.state(composer, command, 'STRIKE', null, null)
21
10
 
22
11
  )(wysihtml5)
23
12
 
13
+
24
14
  # New command: insert file
25
15
  ((wysihtml5) ->
26
16
 
27
17
  wysihtml5.commands.insertFile =
28
18
  exec: (composer, command, param) ->
29
19
  # do nothing
30
- console.log "[insertFile] exec(#{command}, #{param})"
20
+ # console.log "[insertFile] exec(#{command}, #{param})"
31
21
 
32
22
  state: (composer, command) ->
33
23
  # console.log "[insertFile] state(#{command})"
@@ -36,4 +26,40 @@ wysihtml5.commands.strike =
36
26
 
37
27
  )(wysihtml5)
38
28
 
29
+ # Replace command: insert table
30
+ ((wysihtml5) ->
31
+
32
+ buildHeader = (cols) ->
33
+ html = '<thead><tr>'
34
+ html += '<th><br></th>' for col in [0...cols]
35
+ html + '</tr></thead>'
36
+
37
+ buildBody = (cols, rows) ->
38
+ html = '<tbody>'
39
+ for row in [0...rows]
40
+ html += '<tr>'
41
+ html += '<td><br></td>' for col in [0...cols]
42
+ html += '</tr>'
43
+ html += '</tbody>'
44
+
45
+ wysihtml5.commands.createTable =
46
+ exec: (composer, command, options) ->
47
+ options = _.extend { cols: 3, rows: 3, class_name: '', head: true }, options
48
+
49
+ cols = parseInt(options.cols, 10)
50
+ rows = parseInt(options.rows, 10)
51
+
52
+ html = "<table class='#{options.class_name}'>"
53
+ html += buildHeader(cols) if options.head
54
+ html += buildBody(cols, rows)
55
+ html += '</table>'
56
+
57
+ composer.commands.exec('insertHTML', html)
58
+
59
+ state: (composer, command) ->
60
+ false
61
+
62
+ )(wysihtml5)
63
+
64
+
39
65
 
@@ -35,10 +35,14 @@ class Locomotive.Views.ApplicationView extends Backbone.View
35
35
  Locomotive.notify couple[1], couple[0]
36
36
 
37
37
  automatic_max_height: ->
38
- $(window).on 'resize', => @set_max_height()
38
+ $(window).on 'resize', =>
39
+ height = @set_max_height()
40
+ PubSub.publish 'application_view.resize', height: height
39
41
 
40
42
  set_max_height: ->
41
43
  max_height = $(window).height()
42
44
  height = max_height - @header_view.height()
43
45
 
44
46
  @$('> .wrapper').height(height)
47
+
48
+ height
@@ -4,6 +4,17 @@ class Locomotive.Views.EditableElements.EditView extends Locomotive.Views.Shared
4
4
 
5
5
  el: '.content > .inner'
6
6
 
7
+ events:
8
+ 'click .form-group.rte label': 'select_editable_text'
9
+ 'click .form-group.text label': 'select_editable_text'
10
+
11
+ initialize: ->
12
+ _.bindAll(@, 'highlight_form_group')
13
+
14
+ @tokens = [
15
+ PubSub.subscribe 'editable_elements.highlighted_text', @highlight_form_group
16
+ ]
17
+
7
18
  render: ->
8
19
  super
9
20
 
@@ -14,12 +25,44 @@ class Locomotive.Views.EditableElements.EditView extends Locomotive.Views.Shared
14
25
  @refresh_inputs $(data)
15
26
 
16
27
  $('.info-row select[name=block]').select2().on 'change', (event) =>
28
+ PubSub.publish 'editable_elements.block_selected', name: event.val
17
29
  @filter_elements_by(event.val)
18
30
 
19
31
  # editable control elements
20
32
  $('.editable-elements .form-group.input.select select').select2().on 'change', (event) =>
21
33
  @need_reload = true
22
34
 
35
+ select_editable_text: (event) ->
36
+ element_id = $(event.target).parents('.form-group').attr('id').replace('editable-text-', '')
37
+ PubSub.publish 'editable_elements.form_group_selected', element_id: element_id
38
+
39
+ highlight_form_group: (msg, data) ->
40
+ $form_group = $(@el).find("#editable-text-#{data.element_id}")
41
+
42
+ return false if $form_group.size() == 0
43
+
44
+ @filter_elements_by('')
45
+
46
+ highlight_effect = =>
47
+ $form_group.clearQueue().queue (next) ->
48
+ $(this).addClass('highlighted')
49
+ next()
50
+ .delay(200).queue (next) ->
51
+ $(this).removeClass('highlighted').find('input[type=text],textarea').trigger('highlight')
52
+ next()
53
+
54
+ # scroll to the form group and then highlight the textarea/input/editor
55
+ $parent = @$('.scrollable')
56
+ offset = $form_group.position().top
57
+
58
+ if offset == 0
59
+ $parent.animate { scrollTop: 0 }, 500, 'swing', highlight_effect
60
+ else if offset < 0 || offset > $parent.height()
61
+ offset = $parent.scrollTop() + offset if offset < 0
62
+ $parent.animate { scrollTop: offset }, 500, 'swing', highlight_effect
63
+ else
64
+ highlight_effect()
65
+
23
66
  refresh_inputs: ($html) ->
24
67
  @inputs = _.map @inputs, (view) =>
25
68
  return view unless view.need_refresh?
@@ -39,3 +82,7 @@ class Locomotive.Views.EditableElements.EditView extends Locomotive.Views.Shared
39
82
  $el.parent().show()
40
83
  else
41
84
  $el.parent().hide()
85
+
86
+ remove: ->
87
+ super
88
+ _.each @tokens, (token) -> PubSub.unsubscribe(token)
@@ -0,0 +1,59 @@
1
+ Locomotive.Views.EditableElements ||= {}
2
+
3
+ class Locomotive.Views.EditableElements.IframeView extends Backbone.View
4
+
5
+ el: '.preview iframe'
6
+
7
+ startup: true
8
+
9
+ initialize: ->
10
+ # shortcut
11
+ @window = $(@el)[0].contentWindow
12
+
13
+ # when the url of the iframe changes, process
14
+ $(@el).load (event) => @on_load(event)
15
+
16
+ reload: ->
17
+ $(@el).attr('src', @preview_url)
18
+
19
+ on_load: (event) ->
20
+ # Able to get the path to the edit form?
21
+ if (path = @edit_view_path())?
22
+ @preview_url = @window.document.location.href
23
+
24
+ if !@startup
25
+ History.replaceState({ live_editing: true, url: @preview_url }, '', path)
26
+ @options.parent_view.replace_edit_view(path)
27
+ else
28
+ @startup = false
29
+
30
+ @build_and_render_page_view()
31
+
32
+ edit_view_path: ->
33
+ # the browser might be unable to load the iframe because of
34
+ # the 'X-Frame-Options' option which is set to 'SAMEORIGIN'.
35
+ try
36
+ $document = $(@window.document)
37
+ return $document.find('meta[name=locomotive-editable-elements-path]').attr('content')
38
+ catch e
39
+ # reload the iframe with the previous url and display an error message
40
+ @reload()
41
+ Locomotive.notify $(@el).data('redirection-error'), 'warning'
42
+ return null
43
+
44
+ build_and_render_page_view: ->
45
+ @page_view.remove() if @page_view?
46
+ @page_view = new Locomotive.Views.EditableElements.PageView
47
+ el: $(@window.document.body)
48
+ parent_view: @
49
+ button_labels:
50
+ edit: $(@el).data('edit-label')
51
+ @page_view.render()
52
+
53
+ # insert the highlighter CSS (path to the CSS in the iframe data)
54
+ window.addStylesheet(@window.document, $(@el).data('style-path'))
55
+
56
+ remove: ->
57
+ super()
58
+ @page_view.remove() if @page_view?
59
+ _.each @tokens, (token) -> PubSub.unsubscribe(token)
@@ -8,108 +8,35 @@ class Locomotive.Views.EditableElements.IndexView extends Backbone.View
8
8
  'click .content .expand-button': 'expand_preview'
9
9
  'click .content .close-button': 'shrink_preview'
10
10
 
11
- expand_preview: (event) ->
12
- $('body').addClass('full-width-preview')
13
-
14
- shrink_preview: (event) ->
15
- $('body').removeClass('full-width-preview')
16
-
17
11
  initialize: ->
18
- _.bindAll(@, 'refresh_elements', 'refresh_image', 'refresh_image_on_remove', 'refresh_text', 'reload_page')
19
-
20
12
  view_options = if $('body').hasClass('live-editing') then {} else { el: '.main' }
21
13
 
22
- @startup = true
23
- @edit_view = new Locomotive.Views.EditableElements.EditView(view_options)
24
- @pubsub_text_token = PubSub.subscribe('inputs.text_changed', @refresh_text)
14
+ @tokens = [
15
+ PubSub.subscribe 'editable_elements.highlighted_text', @shrink_preview
16
+ ]
25
17
 
26
- @pubsub_image_changed_token = PubSub.subscribe('inputs.image_changed', @refresh_image)
27
- @pubsub_image_removed_token = PubSub.subscribe('inputs.image_removed', @refresh_image_on_remove)
28
- @pubsub_pages_sorted_token = PubSub.subscribe('pages.sorted', @reload_page)
29
-
30
- $('.preview iframe').load (event) => @on_iframe_load(event)
18
+ # order is important here
19
+ @views = [
20
+ new Locomotive.Views.EditableElements.EditView(view_options),
21
+ new Locomotive.Views.EditableElements.IframeView(parent_view: @)
22
+ ]
31
23
 
32
24
  render: ->
33
25
  super()
34
- @edit_view.render()
35
-
36
- refresh_elements: (type, view, callback) ->
37
- $parent_view = $(view.el).parent()
38
- element_id = $parent_view.find('input[name*="[id]"]').val()
39
-
40
- $iframe_document = $($('iframe')[0].contentWindow.document)
41
-
42
- callback($iframe_document.find("*[data-element-id=#{element_id}]"), element_id, $iframe_document)
43
-
44
- refresh_image_on_remove: (msg, data) ->
45
- data.url = $(data.view.el).parent().find('input[name*="[default_source_url]"]').val()
46
- @refresh_image(msg, data)
47
-
48
- refresh_image: (msg, data) ->
49
- @refresh_elements 'image', data.view, ($elements, element_id, $iframe_document) ->
50
- current_image_url = data.view.$('input[name*="[content]"]').val()
51
- image_url = data.url || current_image_url
26
+ _.invoke @views, 'render'
52
27
 
53
- if $elements.size() > 0
54
- $elements.each ->
55
- if this.nodeName == 'IMG'
56
- $(this).attr('src', image_url)
57
- else
58
- $(this).css("background-image", "url('" + image_url + "')")
59
- else
60
- # looking for DIVs with background-url property matching the previous image url
61
- $el = $iframe_document.find("*[style*='#{current_image_url}']").attr('data-element-id', element_id)
62
- $el.css("background-image", "url('" + image_url + "')")
63
-
64
- # looking for IMGs with src attribute matching the previous image url
65
- $el = $iframe_document.find("img[src*='#{current_image_url}']").attr('data-element-id', element_id)
66
- $el.attr('src', image_url)
67
-
68
- refresh_text: (msg, data) ->
69
- @refresh_elements 'text', data.view, ($elements) ->
70
- $elements.each -> $(this).html(data.content)
71
-
72
- reload_page: (event) ->
73
- $iframe = $('.preview iframe')
74
- $target_window = $iframe[0].contentWindow
75
- $iframe.attr('src', @preview_url)
76
-
77
- on_iframe_load: (event) ->
78
- $iframe = $('.preview iframe')
79
- $target_window = $iframe[0].contentWindow
80
- editable_elements_path = null
81
-
82
- # unable to display the iframe in the frame because it set 'X-Frame-Options' to 'SAMEORIGIN'
83
- try
84
- $iframe_document = $($target_window.document)
85
- editable_elements_path = $iframe_document.find('meta[name=locomotive-editable-elements-path]').attr('content')
86
- catch e
87
- # reload the iframe with the previous url and display an error message
88
- $iframe.attr('src', @preview_url)
89
- Locomotive.notify $iframe.data('redirection-error'), 'warning'
90
- return
91
-
92
- # store the url
93
- @preview_url = $('.preview iframe')[0].contentWindow.document.location.href
28
+ expand_preview: (event) ->
29
+ $('body').addClass('full-width-preview')
94
30
 
95
- if editable_elements_path? && @startup == false
96
- History.replaceState({ live_editing: true, url: @preview_url }, '', editable_elements_path)
97
- @replace_edit_view(editable_elements_path)
98
- else
99
- @startup = false
31
+ shrink_preview: (event) ->
32
+ $('body').removeClass('full-width-preview')
100
33
 
101
34
  replace_edit_view: (url) ->
102
- $(@edit_view.el).load url, =>
103
- @edit_view.remove()
104
- @edit_view = new Locomotive.Views.EditableElements.EditView()
105
- @edit_view.render()
35
+ $(@views[0].el).load url, =>
36
+ @views[0].remove()
37
+ (@views[0] = new Locomotive.Views.EditableElements.EditView()).render()
106
38
 
107
39
  remove: ->
108
- super
109
-
110
- @edit_view.remove()
111
-
112
- PubSub.unsubscribe(@pubsub_image_changed_token)
113
- PubSub.unsubscribe(@pubsub_image_removed_token)
114
- PubSub.unsubscribe(@pubsub_text_token)
115
- PubSub.unsubscribe(@pubsub_pages_sorted_token)
40
+ super()
41
+ _.each @tokens, (token) -> PubSub.unsubscribe(token)
42
+ _.invoke @views, 'remove'
@@ -0,0 +1,81 @@
1
+ Locomotive.Views.EditableElements ||= {}
2
+
3
+ class Locomotive.Views.EditableElements.PageView extends Backbone.View
4
+
5
+ initialize: ->
6
+ _.bindAll(@, 'refresh_all', 'refresh_text', 'refresh_image', 'refresh_image_on_remove', 'scroll_to_block', 'scroll_to_element')
7
+
8
+ # Global event subscriptions
9
+ @tokens = [
10
+ PubSub.subscribe 'editable_elements.block_selected', @scroll_to_block
11
+ PubSub.subscribe 'editable_elements.form_group_selected', @scroll_to_element
12
+ PubSub.subscribe 'inputs.text_changed', @refresh_text,
13
+ PubSub.subscribe 'inputs.image_changed', @refresh_image,
14
+ PubSub.subscribe 'inputs.image_removed', @refresh_image_on_remove,
15
+ PubSub.subscribe 'pages.sorted', @refresh_all
16
+ ]
17
+
18
+ # create the highlighter view
19
+ @views = [new Locomotive.Views.EditableElements.TextHighLighterView(el: @el, button_labels: @options.button_labels)]
20
+
21
+ render: ->
22
+ # render the highlighter view
23
+ _.invoke @views, 'render'
24
+
25
+ scroll_to_block: (msg, data) ->
26
+ @_scroll_to @$("span.locomotive-block-anchor[data-element-id=\"#{data.name}\"]")
27
+
28
+ scroll_to_element: (msg, data) ->
29
+ @_scroll_to @$("span.locomotive-editable-text[data-element-id=\"#{data.element_id}\"]")
30
+
31
+ _scroll_to: (element) ->
32
+ return false if element.size() == 0
33
+ $(@el).animate({ scrollTop: element.offset().top }, 500)
34
+
35
+ refresh_all: (msg, data) ->
36
+ @options.parent_view.reload()
37
+
38
+ refresh_text: (msg, data) ->
39
+ @refresh_elements 'text', data.view, ($elements) ->
40
+ $elements.each -> $(this).html(data.content)
41
+
42
+ refresh_image_on_remove: (msg, data) ->
43
+ data.url = $(data.view.el).parent().find('input[name*="[default_source_url]"]').val()
44
+ @refresh_image(msg, data)
45
+
46
+ refresh_image: (msg, data) ->
47
+ @refresh_elements 'image', data.view, ($elements, element_id) =>
48
+ current_image_url = data.view.$('input[name*="[content]"]').val()
49
+ image_url = data.url || current_image_url
50
+
51
+ if $elements.size() > 0
52
+ @replace_images($elements, image_url)
53
+ else
54
+ @replace_images_identified_by_url(current_image_url, image_url, element_id)
55
+
56
+ refresh_elements: (type, view, callback) ->
57
+ $form_view = $(view.el).parent()
58
+ element_id = $form_view.find('input[name*="[id]"]').val()
59
+
60
+ callback($(@el).find("*[data-element-id=#{element_id}]"), element_id)
61
+
62
+ replace_images: (images, new_image_url) ->
63
+ images.each ->
64
+ if this.nodeName == 'IMG'
65
+ $(this).attr('src', new_image_url)
66
+ else
67
+ $(this).css("background-image", "url('" + new_image_url + "')")
68
+
69
+ replace_images_identified_by_url: (current_image_url, new_image_url, element_id) ->
70
+ # looking for DIVs with background-url property matching the previous image url
71
+ $el = $(@el).find("*[style*='#{current_image_url}']").attr('data-element-id', element_id)
72
+ $el.css("background-image", "url('" + new_image_url + "')")
73
+
74
+ # looking for IMGs with src attribute matching the previous image url
75
+ $el = $(@el).find("img[src*='#{current_image_url}']").attr('data-element-id', element_id)
76
+ $el.attr('src', new_image_url)
77
+
78
+ remove: ->
79
+ super()
80
+ _.each @tokens, (token) -> PubSub.unsubscribe(token)
81
+ _.invoke @views, 'remove'