releaf-content 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +24 -0
  3. data/app/assets/javascripts/releaf/controllers/releaf/content/nodes.js +88 -0
  4. data/app/assets/stylesheets/releaf/controllers/releaf/content/nodes.scss +234 -0
  5. data/app/builders/releaf/content/builders/action_dialog.rb +60 -0
  6. data/app/builders/releaf/content/builders/dialog.rb +15 -0
  7. data/app/builders/releaf/content/builders/tree.rb +84 -0
  8. data/app/builders/releaf/content/content_type_dialog_builder.rb +74 -0
  9. data/app/builders/releaf/content/copy_dialog_builder.rb +9 -0
  10. data/app/builders/releaf/content/go_to_dialog_builder.rb +9 -0
  11. data/app/builders/releaf/content/move_dialog_builder.rb +9 -0
  12. data/app/builders/releaf/content/nodes/content_form_builder.rb +7 -0
  13. data/app/builders/releaf/content/nodes/form_builder.rb +108 -0
  14. data/app/builders/releaf/content/nodes/index_builder.rb +24 -0
  15. data/app/builders/releaf/content/nodes/toolbox_builder.rb +33 -0
  16. data/app/controllers/releaf/content/nodes_controller.rb +166 -0
  17. data/app/middleware/releaf/content/routes_reloader.rb +25 -0
  18. data/app/validators/releaf/content/node/parent_validator.rb +48 -0
  19. data/app/validators/releaf/content/node/root_validator.rb +43 -0
  20. data/app/validators/releaf/content/node/singleness_validator.rb +102 -0
  21. data/app/views/releaf/content/nodes/content_type_dialog.ruby +1 -0
  22. data/app/views/releaf/content/nodes/copy_dialog.ruby +1 -0
  23. data/app/views/releaf/content/nodes/go_to_dialog.ruby +1 -0
  24. data/app/views/releaf/content/nodes/move_dialog.ruby +1 -0
  25. data/lib/releaf-content.rb +6 -0
  26. data/lib/releaf/content/acts_as_node.rb +73 -0
  27. data/lib/releaf/content/acts_as_node/action_controller/acts/node.rb +17 -0
  28. data/lib/releaf/content/acts_as_node/active_record/acts/node.rb +55 -0
  29. data/lib/releaf/content/builders_autoload.rb +18 -0
  30. data/lib/releaf/content/engine.rb +40 -0
  31. data/lib/releaf/content/node.rb +280 -0
  32. data/lib/releaf/content/node_mapper.rb +9 -0
  33. data/lib/releaf/content/route.rb +93 -0
  34. data/lib/releaf/content/router_proxy.rb +23 -0
  35. data/releaf-content.gemspec +20 -0
  36. data/spec/builders/content/nodes/content_form_builder_spec.rb +24 -0
  37. data/spec/builders/content/nodes/form_builder_spec.rb +218 -0
  38. data/spec/builders/content/nodes/toolbox_builder_spec.rb +108 -0
  39. data/spec/controllers/releaf/content/nodes_controller_spec.rb +21 -0
  40. data/spec/features/nodes_spec.rb +239 -0
  41. data/spec/lib/releaf/content/acts_as_node_spec.rb +118 -0
  42. data/spec/lib/releaf/content/node_spec.rb +779 -0
  43. data/spec/lib/releaf/content/route_spec.rb +85 -0
  44. data/spec/middleware/routes_reloader_spec.rb +48 -0
  45. data/spec/routing/node_mapper_spec.rb +142 -0
  46. data/spec/validators/content/node/parent_validator_spec.rb +56 -0
  47. data/spec/validators/content/node/root_validator_spec.rb +69 -0
  48. data/spec/validators/content/node/singleness_validator_spec.rb +145 -0
  49. metadata +145 -0
@@ -0,0 +1,218 @@
1
+ require "rails_helper"
2
+
3
+ describe Releaf::Content::Nodes::FormBuilder, type: :class do
4
+ class FormBuilderTestHelper < ActionView::Base
5
+ include Releaf::ApplicationHelper
6
+ include Releaf::ButtonHelper
7
+ include FontAwesome::Rails::IconHelper
8
+ def controller_scope_name; end
9
+ def generate_url_releaf_content_nodes_path(args); end
10
+ end
11
+
12
+ let(:template){ FormBuilderTestHelper.new }
13
+ let(:object){ Node.new(content_type: "TextPage", slug: "b", id: 2,
14
+ parent: Node.new(content_type: "TextPage", slug: "a", id: 1)) }
15
+ let(:subject){ described_class.new(:resource, object, template, {}) }
16
+
17
+ describe "#field_names" do
18
+ it "returns hidden, node and content object fields" do
19
+ expect(subject.field_names).to eq(["node_fields_block", "content_fields_block"])
20
+ end
21
+ end
22
+
23
+ describe "#node_fields" do
24
+ it "returns array with renderable node fields" do
25
+ list = [:parent_id, :name, :content_type, :slug, :item_position, :active, :locale]
26
+ expect(subject.node_fields).to eq(list)
27
+ end
28
+ end
29
+
30
+ describe "#render_node_fields_block" do
31
+ it "renders node fields" do
32
+ allow(subject).to receive(:node_fields).and_return([1, 2])
33
+ allow(subject).to receive(:releaf_fields).with([1, 2]).and_return("x")
34
+ content = '<div class="section node-fields">x</div>'
35
+ expect(subject.render_node_fields_block).to eq(content)
36
+ end
37
+ end
38
+
39
+ describe "#render_parent_id" do
40
+ it "renders hidden parent if field for new object" do
41
+ allow(subject.object).to receive(:new_record?).and_return(true)
42
+ allow(subject).to receive(:hidden_field).with(:parent_id).and_return("x")
43
+ expect(subject.render_parent_id).to eq("x")
44
+ end
45
+
46
+ it "renders nothing for existing object" do
47
+ allow(subject.object).to receive(:new_record?).and_return(false)
48
+ expect(subject.render_parent_id).to eq(nil)
49
+ end
50
+ end
51
+
52
+ describe "#render_content_fields_block?" do
53
+ before do
54
+ subject.object.build_content
55
+ end
56
+
57
+ it "returns array of node content object fields" do
58
+ allow(object.content_class).to receive(:respond_to?).with(:acts_as_node_fields).and_return(true)
59
+ expect(subject.render_content_fields_block?).to be true
60
+ end
61
+
62
+ context "when object content class do not respond to `acts_as_node_fields`" do
63
+ it "returns nil" do
64
+ allow(object.content_class).to receive(:respond_to?).with(:acts_as_node_fields).and_return(false)
65
+ expect(subject.render_content_fields_block?).to be false
66
+ end
67
+ end
68
+ end
69
+
70
+ describe "#render_content_fields_block" do
71
+ before do
72
+ subject.object.build_content
73
+ end
74
+
75
+ it "renders content fields block" do
76
+ allow(subject).to receive(:content_builder_class).and_return("_b_")
77
+ allow(subject).to receive(:render_content_fields_block?).and_return(true)
78
+ subform = described_class.new(:resource, object, template, {})
79
+ allow(subject).to receive(:fields_for).with(:content, subject.object.content, builder: "_b_").and_yield(subform)
80
+ allow(subform).to receive(:field_names).and_return([1, 2])
81
+ allow(subform).to receive(:releaf_fields).with([1, 2]).and_return("yy")
82
+ content = '<div class="section content-fields">yy</div>'
83
+ expect(subject.render_content_fields_block).to eq(content)
84
+ end
85
+
86
+ it "casts form fields to array before passign to `releaf_fields`" do
87
+ allow(subject).to receive(:content_builder_class).and_return("_b_")
88
+ allow(subject).to receive(:render_content_fields_block?).and_return(true)
89
+ subform = described_class.new(:resource, object, template, {})
90
+ allow(subject).to receive(:fields_for).with(:content, subject.object.content, builder: "_b_").and_yield(subform)
91
+ allow(subform).to receive(:field_names).and_return({a: 1, b: 2})
92
+ expect(subform).to receive(:releaf_fields).with([[:a, 1], [:b, 2]])
93
+ subject.render_content_fields_block
94
+ end
95
+
96
+ context "when content have no fields" do
97
+ it "returns nil" do
98
+ allow(subject).to receive(:render_content_fields_block?).and_return(false)
99
+ expect(subject.render_content_fields_block).to be nil
100
+ end
101
+ end
102
+ end
103
+
104
+ describe "#content_builder_class" do
105
+ it "returns `Releaf::Content::Nodes::ContentFormBuilder`" do
106
+ expect(subject.content_builder_class).to eq(Releaf::Content::Nodes::ContentFormBuilder)
107
+ end
108
+ end
109
+
110
+ describe "#render_locale" do
111
+ context "when node node has locale select enabled" do
112
+ it "renders locale with #render_locale_options" do
113
+ allow(subject.object).to receive(:locale_selection_enabled?).and_return(true)
114
+ allow(subject).to receive(:render_locale_options).and_return(a: "b")
115
+ allow(subject).to receive(:releaf_item_field).with(:locale, options: {a: "b"}).and_return("x")
116
+ expect(subject.render_locale).to eq("x")
117
+ end
118
+ end
119
+
120
+ context "when node node does not have locale select enabled" do
121
+ it "renders locale with #render_locale_options" do
122
+ allow(subject.object).to receive(:locale_selection_enabled?).and_return(false)
123
+ expect(subject.render_locale).to be nil
124
+ end
125
+ end
126
+ end
127
+
128
+ describe "#render_locale_options" do
129
+ it "returns :select_options and :include_blank values" do
130
+ expect(subject.render_locale_options.keys).to eq([:select_options, :include_blank])
131
+ end
132
+
133
+ it ":select_options contains all available locales" do
134
+ allow(I18n).to receive(:available_locales).and_return([:lt, :et])
135
+ expect(subject.render_locale_options[:select_options]).to eq([:lt, :et])
136
+ end
137
+
138
+ context "when subject have defined locale" do
139
+ it ":include_blank is false" do
140
+ subject.object.locale = :lt
141
+ expect(subject.render_locale_options[:include_blank]).to be false
142
+ end
143
+ end
144
+
145
+ context "when subject have no locale" do
146
+ it ":include_blank is true" do
147
+ subject.object.locale = nil
148
+ expect(subject.render_locale_options[:include_blank]).to be true
149
+ end
150
+ end
151
+ end
152
+
153
+ describe "#render_content_type" do
154
+ it "renders disabled content type field with localized content type value" do
155
+ options = {disabled: true, value: "Translated content type"}
156
+ allow(I18n).to receive(:t).with("text_page", scope: "admin.content_types").and_return("Translated content type")
157
+ allow(subject).to receive(:releaf_text_field).with(:content_type, input: options).and_return("x")
158
+ expect(subject.render_content_type).to eq("x")
159
+ end
160
+ end
161
+
162
+ describe "#render_slug" do
163
+ it "renders customized field" do
164
+ controller = Releaf::BaseController.new
165
+ allow(subject).to receive(:controller).and_return(controller)
166
+ allow(subject).to receive(:slug_base_url).and_return("http://localhost/parent")
167
+ allow(subject).to receive(:url_for).with(controller: "/releaf/content/nodes", action: "generate_url", parent_id: 1, id: 2)
168
+ .and_return("http://localhost/slug-generation-url")
169
+
170
+ content = '
171
+ <div class="field type-text" data-name="slug">
172
+ <div class="label-wrap">
173
+ <label for="resource_slug">Slug</label>
174
+ </div>
175
+ <div class="value">
176
+ <input value="b" class="text" data-generator-url="http://localhost/slug-generation-url" type="text" name="resource[slug]" id="resource_slug" />
177
+ <button class="button only-icon secondary generate" title="Suggest slug" type="button" autocomplete="off">
178
+ <i class="fa fa-keyboard-o"></i>
179
+ </button>
180
+ <div class="link">
181
+ <a href="/a/b">http://localhost/parent<span>b</span>/</a>
182
+ </div>
183
+ </div>
184
+ </div>
185
+ '
186
+
187
+ expect(subject.render_slug).to match_html(content)
188
+ end
189
+ end
190
+
191
+ describe "#render_item_position" do
192
+ it "renders locale with #item_position_options" do
193
+ allow(subject).to receive(:item_position_options).and_return(a: "b")
194
+ allow(subject).to receive(:releaf_item_field).with(:item_position, options: {a: "b"}).and_return("x")
195
+ expect(subject.render_item_position).to eq("x")
196
+ end
197
+ end
198
+
199
+ describe "#item_position_options" do
200
+ before do
201
+ object.item_position = 2
202
+ allow(subject).to receive(:item_position_select_options).and_return([["a", 1], ["b", 2], ["c", 3]])
203
+ end
204
+
205
+ it "returns :select_options and :include_blank values" do
206
+ expect(subject.item_position_options.keys).to eq([:include_blank, :select_options])
207
+ end
208
+
209
+ it ":select_options correct select options" do
210
+ options = '<option value="1">a</option>'
211
+ options << "\n"
212
+ options << '<option selected="selected" value="2">b</option>'
213
+ options << "\n"
214
+ options << '<option value="3">c</option>'
215
+ expect(subject.item_position_options[:select_options]).to eq(options)
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,108 @@
1
+ require "spec_helper"
2
+
3
+ describe Releaf::Content::Nodes::ToolboxBuilder, type: :class do
4
+
5
+ class NodeToolboxBuilderTestHelper < ActionView::Base
6
+ include Releaf::ButtonHelper
7
+ include Releaf::ApplicationHelper
8
+ end
9
+
10
+ let(:template){ NodeToolboxBuilderTestHelper.new }
11
+ subject { described_class.new(template) }
12
+
13
+ let(:node){ Node.new(content_type: "TextPage", slug: "a", id: 99) }
14
+
15
+ before do
16
+ allow(subject).to receive(:resource).and_return(node)
17
+ allow(subject).to receive(:destroy_confirmation_link).and_return(:super_item)
18
+ allow(subject).to receive(:feature_available?).with(:destroy).and_return true
19
+ end
20
+
21
+ it "extends Releaf::Builders::ToolboxBuilder" do
22
+ expect(described_class.ancestors).to include Releaf::Builders::ToolboxBuilder
23
+ end
24
+
25
+ describe "#items" do
26
+
27
+ before do
28
+ allow(subject).to receive(:params).and_return({})
29
+ allow(subject).to receive(:add_child_button).and_return( :add_child_item )
30
+ allow(subject).to receive(:go_to_button).and_return( :go_to_item )
31
+ allow(subject).to receive(:copy_button).and_return( :copy_item )
32
+ allow(subject).to receive(:move_button).and_return( :move_item )
33
+ end
34
+
35
+ context "when applied to a new record" do
36
+
37
+ it "returns only items returned by parent class" do
38
+ allow(node).to receive(:new_record?).and_return true
39
+ expect(subject.items).to eq([ :super_item ])
40
+ end
41
+
42
+ end
43
+
44
+ context "when applied to an existing record" do
45
+
46
+ before do
47
+ allow(node).to receive(:new_record?).and_return false
48
+ end
49
+
50
+ it "prepends add child, go to, copy and move items to the list returned by parent class" do
51
+ expect(subject.items).to eq([ :add_child_item, :go_to_item, :copy_item, :move_item, :super_item ])
52
+ end
53
+
54
+ context "when in index context" do
55
+
56
+ it "does not include go_to_item" do
57
+ allow(subject).to receive(:params).and_return({ context: "index" })
58
+ expect(subject.items).to eq([ :add_child_item, :copy_item, :move_item, :super_item ])
59
+ end
60
+ end
61
+
62
+ end
63
+
64
+ end
65
+
66
+ describe "item methods" do
67
+
68
+ describe "#add_child_button" do
69
+ it "returns an ajaxbox link to content type dialog" do
70
+ allow(subject).to receive(:t).with('Add child').and_return('addchildxx')
71
+ allow(subject).to receive(:url_for).with(action: 'content_type_dialog', parent_id: 99).and_return('dialogurl')
72
+ html = '<a class="button ajaxbox" title="addchildxx" href="dialogurl">addchildxx</a>'
73
+ expect(subject.add_child_button).to eq(html)
74
+ end
75
+ end
76
+
77
+ describe "#go_to_button" do
78
+ it "returns an ajaxbox link to go to dialog" do
79
+ allow(subject).to receive(:t).with('Go to').and_return('gotoxx')
80
+ allow(subject).to receive(:url_for).with(action: 'go_to_dialog').and_return('dialogurl')
81
+ html = '<a class="button ajaxbox" title="gotoxx" href="dialogurl">gotoxx</a>'
82
+ expect(subject.go_to_button).to eq(html)
83
+ end
84
+ end
85
+
86
+
87
+ describe "#copy_button" do
88
+ it "returns an ajaxbox link to copy dialog" do
89
+ allow(subject).to receive(:t).with('Copy').and_return('copyxx')
90
+ allow(subject).to receive(:url_for).with(action: 'copy_dialog', id: 99).and_return('dialogurl')
91
+ html = '<a class="button ajaxbox" title="copyxx" href="dialogurl">copyxx</a>'
92
+ expect(subject.copy_button).to eq(html)
93
+ end
94
+ end
95
+
96
+
97
+ describe "#move_button" do
98
+ it "returns an ajaxbox link to move dialog" do
99
+ allow(subject).to receive(:t).with('Move').and_return('movexx')
100
+ allow(subject).to receive(:url_for).with(action: 'move_dialog', id: 99).and_return('dialogurl')
101
+ html = '<a class="button ajaxbox" title="movexx" href="dialogurl">movexx</a>'
102
+ expect(subject.move_button).to eq(html)
103
+ end
104
+ end
105
+
106
+ end
107
+
108
+ end
@@ -0,0 +1,21 @@
1
+ require 'rails_helper'
2
+
3
+ describe Releaf::Content::NodesController do
4
+ describe "#builder_scopes" do
5
+ it "adds node builder scope as first scope before default builder scopes" do
6
+ allow(subject).to receive(:application_scope).and_return("Admin")
7
+ allow(subject).to receive(:node_builder_scope).and_return("xx")
8
+ expect(subject.builder_scopes).to eq(["xx", "Releaf::Content::Nodes", "Admin::Builders"])
9
+ end
10
+ end
11
+
12
+ describe "#node_builder_scope" do
13
+ it "returns node builder scope within releaf mount location scope" do
14
+ allow(subject).to receive(:application_scope).and_return("Admin")
15
+ expect(subject.node_builder_scope).to eq("Admin::Nodes")
16
+
17
+ allow(subject).to receive(:application_scope).and_return(nil)
18
+ expect(subject.node_builder_scope).to eq("Nodes")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,239 @@
1
+ require 'rails_helper'
2
+ describe "Nodes", js: true, with_tree: true, with_root: true do
3
+ before do
4
+ Rails.cache.clear
5
+ # preload ActsAsNode classes
6
+ Rails.application.eager_load!
7
+ @user = auth_as_user
8
+ end
9
+
10
+ before with_root: true do
11
+ @lv_root = create(:home_page_node, name: "lv", locale: "lv")
12
+ end
13
+
14
+ before with_tree: true do
15
+ @how_to = create(:text_page_node, parent_id: @lv_root.id)
16
+ @about_us = create(:text_page_node, parent_id: @lv_root.id, name: "about us")
17
+ @history_node = create(:text_page_node, parent_id: @about_us.id, name: "history")
18
+
19
+ @en_root = create(:home_page_node, name: "en", locale: "en")
20
+
21
+ visit releaf_content_nodes_path
22
+ end
23
+
24
+ describe "new node" do
25
+
26
+ context "when creating node under root" do
27
+ it "creates new node in content tree" do
28
+ @en_root.destroy
29
+ click_link "Create new resource"
30
+ click_link "Home page"
31
+ expect(page).to have_css('.button', text: 'Save')
32
+ expect(page).to have_no_css('.button', text: 'Save and create another')
33
+ create_resource do
34
+ fill_in "resource_name", with: "en"
35
+ select "en", from: "Locale"
36
+ end
37
+
38
+ expect(page).to have_breadcrumbs("Releaf/content/nodes", "en")
39
+ end
40
+ end
41
+
42
+ context "when creating node under another node" do
43
+ it "creates new node" do
44
+ find('li[data-id="' + @lv_root.id.to_s + '"] > .toolbox-cell button').click
45
+ click_link "Add child"
46
+ click_link "Contacts controller"
47
+ expect(page).to have_css('.button', text: 'Save')
48
+ expect(page).to have_no_css('.button', text: 'Save and create another')
49
+ create_resource do
50
+ fill_in "resource_name", with: "Contacts"
51
+ end
52
+
53
+ expect(page).to have_breadcrumbs("Releaf/content/nodes", "lv", "Contacts")
54
+ end
55
+ end
56
+ end
57
+
58
+ describe "tree collapsing" do
59
+ context "when not opened before" do
60
+ it "does not show node's children" do
61
+ expect(page).to have_css('li[data-id="' + @lv_root.id.to_s + '"].collapsed')
62
+ end
63
+ end
64
+
65
+ context "when clicked to uncollapse node" do
66
+ it "shows node children" do
67
+ find('li[data-id="' + @lv_root.id.to_s + '"] > .collapser-cell button').click
68
+
69
+ expect(page).to have_css('li[data-id="' + @lv_root.id.to_s + '"]:not(.collapsed)')
70
+ end
71
+
72
+ it "keeps opened node children visibility permanent" do
73
+ find('li[data-id="' + @lv_root.id.to_s + '"] > .collapser-cell button').click
74
+ wait_for_settings_update("content.tree.expanded.#{@lv_root.id}")
75
+ visit releaf_content_nodes_path
76
+
77
+ expect(page).to have_css('li[data-id="' + @lv_root.id.to_s + '"]:not(.collapsed)')
78
+ end
79
+
80
+ it "keeps closed node children visibility permanent" do
81
+ find('li[data-id="' + @lv_root.id.to_s + '"] > .collapser-cell button').click
82
+ find('li[data-id="' + @lv_root.id.to_s + '"] > .collapser-cell button').click
83
+ wait_for_settings_update("content.tree.expanded.#{@lv_root.id}", false)
84
+ visit releaf_content_nodes_path
85
+
86
+ expect(page).to have_css('li[data-id="' + @lv_root.id.to_s + '"].collapsed')
87
+ end
88
+ end
89
+ end
90
+
91
+ describe "go_to node" do
92
+ before do
93
+ visit edit_releaf_content_node_path @en_root
94
+ end
95
+
96
+ context "when going to node from toolbox list" do
97
+ it "navigates to targeted node's edit view" do
98
+ expect(page).to have_no_header(text: 'lv')
99
+ open_toolbox_dialog "Go to"
100
+
101
+ click_link "lv"
102
+ expect(page).to have_header(text: 'lv')
103
+ end
104
+ end
105
+ end
106
+
107
+ describe "copy node to" do
108
+ context "when copying node" do
109
+ it "shows copied node in tree" do
110
+ find('li[data-id="' + @lv_root.id.to_s + '"] > .collapser-cell button').click
111
+ find('li[data-id="' + @about_us.id.to_s + '"] > .toolbox-cell button').click
112
+ click_link("Copy")
113
+
114
+ within_dialog do
115
+ find('label > span', text: "en").click
116
+ click_button "Copy"
117
+ end
118
+
119
+ expect(page).to have_notification("Copy succeeded")
120
+
121
+ find('li[data-id="' + @en_root.id.to_s + '"] > .collapser-cell button').click
122
+ expect(page).to have_css('li > .node-cell a', text: "about us", count: 2)
123
+ end
124
+ end
125
+
126
+ context "when copying node under itself" do
127
+ it "displays flash error message" do
128
+ find('li[data-id="' + @lv_root.id.to_s + '"] > .collapser-cell button').click
129
+ find('li[data-id="' + @about_us.id.to_s + '"] > .toolbox-cell button').click
130
+ click_link("Copy")
131
+
132
+ within_dialog do
133
+ find('label > span', text: "about us").click
134
+ click_button "Copy"
135
+ end
136
+
137
+ error_text = "Node with id #{@about_us.id} has error \"source or descendant node can't be parent of new node\""
138
+ expect(page).to have_css('.dialog .form-error-box', text: error_text)
139
+ end
140
+ end
141
+ end
142
+
143
+ describe "move node to", js: true do
144
+ context "when moving node to another parent" do
145
+ it "moves selected node to new position" do
146
+ find('li[data-id="' + @lv_root.id.to_s + '"] > .collapser-cell button').click
147
+ find('li[data-id="' + @about_us.id.to_s + '"] > .toolbox-cell button').click
148
+ click_link("Move")
149
+
150
+ within_dialog do
151
+ find('label > span', text: "en").click
152
+ click_button "Move"
153
+ end
154
+
155
+ expect(page).to have_css('.notifications .notification .message', text: "Move succeeded")
156
+ expect(page).to have_css('li > .node-cell a', text: "about us", count: 0)
157
+ find('li[data-id="' + @en_root.id.to_s + '"] > .collapser-cell button').click
158
+ expect(page).to have_css('li > .node-cell a', text: "about us", count: 1)
159
+ end
160
+ end
161
+
162
+ context "when moving node under itself" do
163
+ it "displays flash error message" do
164
+ find('li[data-id="' + @lv_root.id.to_s + '"] > .collapser-cell button').click
165
+ find('li[data-id="' + @about_us.id.to_s + '"] > .toolbox-cell button').click
166
+ click_link("Move")
167
+
168
+ within_dialog do
169
+ find('label > span', text: "about us").click
170
+ click_button "Move"
171
+ end
172
+
173
+ error_text = "Node with id #{@about_us.id} has error \"can't be parent to itself\" on attribute \"parent_id\""
174
+ expect(page).to have_css('.dialog .form-error-box', text: error_text)
175
+ end
176
+ end
177
+
178
+ end
179
+
180
+ describe "node order", with_tree: false do
181
+ def create_child parent, child_text, position=nil
182
+
183
+ visit releaf_content_nodes_path
184
+ open_toolbox_dialog 'Add child', parent, ".view-index .collection li"
185
+ within_dialog do
186
+ click_link("Text page")
187
+ end
188
+
189
+ create_resource do
190
+ fill_in 'Name', with: child_text
191
+ fill_in "Slug", with: child_text
192
+ fill_in_richtext 'Text', with: child_text
193
+ if position
194
+ select position, from: 'Item position'
195
+ end
196
+ end
197
+
198
+ end
199
+
200
+ it "creates nodes in correct order" do
201
+ create_child @lv_root, 'a'
202
+ create_child @lv_root, 'b', 'After a'
203
+ create_child @lv_root, 'c', 'After b'
204
+ create_child @lv_root, 'd', 'After b'
205
+ create_child @lv_root, 'e', 'First'
206
+
207
+ visit releaf_content_nodes_path
208
+ find('li[data-id="' + @lv_root.id.to_s + '"] > .collapser-cell button').click
209
+
210
+ within(".collection li[data-level='1'][data-id='#{@lv_root.id}'] ul") do
211
+ expect( page ).to have_content 'e a b d c'
212
+ end
213
+ end
214
+
215
+ it "by default adds new nodes as last" do
216
+ create_child @lv_root, 'a'
217
+ create_child @lv_root, 'b'
218
+ create_child @lv_root, 'c'
219
+
220
+ visit releaf_content_nodes_path
221
+ find('li[data-id="' + @lv_root.id.to_s + '"] > .collapser-cell button').click
222
+
223
+ within(".collection li[data-level='1'][data-id='#{@lv_root.id}'] ul") do
224
+ expect( page ).to have_content 'a b c'
225
+ end
226
+ end
227
+ end
228
+
229
+ describe "creating node for placeholder model", with_tree: false, with_root: false, js: false do
230
+ it "create record in association table" do
231
+ allow_any_instance_of(Releaf::Content::Node::RootValidator).to receive(:validate)
232
+ visit new_releaf_content_node_path(content_type: 'Bundle')
233
+ fill_in("resource_name", with: "placeholder model node")
234
+ expect do
235
+ click_button 'Save'
236
+ end.to change { [Node.count, Bundle.count] }.from([0, 0]).to([1, 1])
237
+ end
238
+ end
239
+ end