diff --git a/modules/node/cms_node_api.e b/modules/node/cms_node_api.e
index 7a969e5..a0a0762 100644
--- a/modules/node/cms_node_api.e
+++ b/modules/node/cms_node_api.e
@@ -329,9 +329,58 @@ feature -- Access: Node
available_parents_for_node (a_node: CMS_NODE): LIST [CMS_NODE]
- -- Given the node `a_node', return the list of possible parent nodes
+ -- List of possible parents nodes for node `a_node'.
+ -- Ensure the list of possible parent nodes does not allow a potential cycle.
do
- Result := node_storage.available_parents_for_node(a_node)
+ create {ARRAYED_LIST[CMS_NODE]}Result.make (0)
+ across node_storage.available_parents_for_node(a_node) as ic loop
+ if not has_cycle (a_node, ic.item) then
+ Result.force (ic.item)
+ end
+ end
+
+ ensure
+ not_cycle: Result.for_all (agent not_cycle (a_node, ?))
+ end
+
+feature {NONE} -- Implementation
+
+ not_cycle (a_node: CMS_NODE; a_parent: CMS_NODE): BOOLEAN
+ do
+ Result := not has_cycle (a_node, a_parent)
+ end
+
+ has_cycle (a_node: CMS_NODE; a_parent: CMS_NODE): BOOLEAN
+ -- Check if adding the node `a_parent' as parent of node `a_node' form a cycle.
+ local
+ l_flag: BOOLEAN
+ l_item: detachable CMS_PAGE
+ do
+ Result := False
+ if
+ attached {CMS_PAGE} a_node as l_page and then
+ attached {CMS_PAGE} full_node (a_parent) as l_page_parent
+ then
+ l_page.set_parent (l_page_parent)
+ from
+ l_item := l_page_parent
+ until
+ l_flag or else Result
+ loop
+ if attached l_item and then attached {CMS_PAGE} node (l_item.id) as l_parent then
+ if l_parent.id = l_page.id then
+ Result := True
+ else
+ l_item := l_parent.parent
+ end
+ else
+ l_flag := True
+ end
+ end
+ -- Set parent to void.
+ l_page.set_parent (Void)
+ end
+
end
feature -- Permission Scope: Node
diff --git a/modules/node/handler/cms_page_node_type_webform_manager.e b/modules/node/handler/cms_page_node_type_webform_manager.e
index 9f68f71..eb009ab 100644
--- a/modules/node/handler/cms_page_node_type_webform_manager.e
+++ b/modules/node/handler/cms_page_node_type_webform_manager.e
@@ -36,6 +36,12 @@ feature -- Forms ...
attached {CMS_PAGE} a_response.node_api.node (i_parent_node) as l_parent_page
then
l_node_page.set_parent (l_parent_page)
+ elseif attached {CMS_PAGE} a_node as l_node_page and then
+ attached fd.integer_item ("select_parent_node") as i_parent_node and then
+ i_parent_node = -1
+ then
+ -- Set parent to Void
+ l_node_page.set_parent (Void)
end
end
diff --git a/modules/node/handler/node_form_response.e b/modules/node/handler/node_form_response.e
index e8e54a1..8b30fcf 100644
--- a/modules/node/handler/node_form_response.e
+++ b/modules/node/handler/node_form_response.e
@@ -233,6 +233,7 @@ feature -- Form
local
l_preview: BOOLEAN
l_format: detachable CONTENT_FORMAT
+ l_selected: BOOLEAN
do
l_preview := attached {WSF_STRING} fd.item ("op") as l_op and then l_op.same_string ("Preview")
if l_preview then
@@ -254,6 +255,32 @@ feature -- Form
end
b.append ("")
end
+
+ if
+ attached fd.integer_item ("select_parent_node") as s_parent_node and then
+ s_parent_node.to_integer_64 > 0 and then
+ attached node_api.node (s_parent_node) as l_parent_node and then
+ attached node_api.node (node_id_path_parameter (request)) as l_node
+ then
+ across node_api.available_parents_for_node (l_node) as ic until l_selected loop
+ if l_parent_node.same_node (ic.item) then
+ l_selected := True
+ end
+ end
+ if not l_selected then
+ fd.report_invalid_field ("select_parent_node", "Invalid node id " + s_parent_node.out)
+ end
+ elseif
+ attached fd.integer_item ("select_parent_node") as s_parent_node and then
+ (s_parent_node = -1 or else s_parent_node = 0)
+ then
+ -- -1 is Used to unassing a parent node
+ -- 0 is not taken into account, any other input value is considered invalid.
+ else
+ fd.report_invalid_field ("select_parent_node", "Invalid node id")
+ end
+
+
end
edit_form_submit (fd: WSF_FORM_DATA; a_node: detachable CMS_NODE; a_type: CMS_NODE_TYPE [CMS_NODE]; b: STRING)
@@ -264,6 +291,7 @@ feature -- Form
l_path_alias: detachable READABLE_STRING_8
nid: INTEGER_64
do
+ fixme ("Refactor code per operacion: Preview, Save")
l_preview := attached {WSF_STRING} fd.item ("op") as l_op and then l_op.same_string ("Preview")
if not l_preview then
debug ("cms")
@@ -294,7 +322,7 @@ feature -- Form
fixme ("for now, publishing is not implemented, so let's assume any node saved is published.") -- FIXME
l_node.mark_published
- -- Save Child Page
+ -- Save parent id in current node.
nid := node_id_path_parameter (request)
if location.ends_with_general ("/add_child/page") and then
nid > 0 and then attached {CMS_PAGE} l_node as l_new_page and then
@@ -341,13 +369,10 @@ feature -- Form
f: CMS_FORM
ts: WSF_FORM_SUBMIT_INPUT
th: WSF_FORM_HIDDEN_INPUT
- tl: WSF_FORM_SELECT
- to: WSF_FORM_SELECT_OPTION
+ ti: WSF_FORM_NUMBER_INPUT
+ l_item: CMS_NODE
do
create f.make (a_url, a_name)
-
-
-
create th.make ("node-id")
if a_node /= Void then
th.set_text_value (a_node.id.out)
@@ -359,40 +384,24 @@ feature -- Form
populate_form (a_node_type, f, a_node)
f.extend_html_text ("
")
- -- Select for nodes
- create tl.make ("select_parent_node")
- create to.make ("0", "NONE")
- tl.add_option (to)
-
if attached {CMS_PAGE} a_node as l_node_page then
if attached l_node_page.parent as l_parent_node then
f.extend_html_text ("