From c65265b0259bf90a3626a892da2c35340c96b55f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Mon, 18 May 2015 14:36:24 +0200 Subject: [PATCH 01/24] added blog handler that lists all blog entries --- examples/demo/modules/blog/cms_blog_module.e | 59 +++++++++++++---- .../site/themes/bootstrap/assets/css/node.css | 7 +- modules/node/handler/blog_handler.e | 64 +++++++++++++++++++ 3 files changed, 117 insertions(+), 13 deletions(-) create mode 100644 modules/node/handler/blog_handler.e diff --git a/examples/demo/modules/blog/cms_blog_module.e b/examples/demo/modules/blog/cms_blog_module.e index b75fdcd..c809fa0 100644 --- a/examples/demo/modules/blog/cms_blog_module.e +++ b/examples/demo/modules/blog/cms_blog_module.e @@ -8,11 +8,14 @@ class inherit CMS_MODULE + rename + module_api as node_api redefine register_hooks, initialize, is_installed, - install + install, + node_api end CMS_HOOK_MENU_SYSTEM_ALTER @@ -36,18 +39,19 @@ feature {CMS_API} -- Module Initialization -- local ct: CMS_BLOG_NODE_TYPE + l_node_api: like node_api do Precursor (api) + create l_node_api.make (api) + node_api := l_node_api - if attached {CMS_NODE_API} api.module_api ({NODE_MODULE}) as l_node_api then - create ct - l_node_api.add_content_type (ct) - l_node_api.add_content_type_webform_manager (create {CMS_BLOG_NODE_TYPE_WEBFORM_MANAGER}.make (ct)) - -- Add support for CMS_BLOG, which requires a storage extension to store the optional "tags" value - -- For now, we only have extension based on SQL statement. - if attached {CMS_NODE_STORAGE_SQL} l_node_api.node_storage as l_sql_node_storage then - l_sql_node_storage.register_node_storage_extension (create {CMS_NODE_STORAGE_SQL_BLOG_EXTENSION}.make (l_sql_node_storage)) - end + create ct + l_node_api.add_content_type (ct) + l_node_api.add_content_type_webform_manager (create {CMS_BLOG_NODE_TYPE_WEBFORM_MANAGER}.make (ct)) + -- Add support for CMS_BLOG, which requires a storage extension to store the optional "tags" value + -- For now, we only have extension based on SQL statement. + if attached {CMS_NODE_STORAGE_SQL} l_node_api.node_storage as l_sql_node_storage then + l_sql_node_storage.register_node_storage_extension (create {CMS_NODE_STORAGE_SQL_BLOG_EXTENSION}.make (l_sql_node_storage)) end end @@ -82,12 +86,45 @@ CREATE TABLE "blog_post_nodes"( end end +feature {CMS_API} -- Access: API + + node_api: detachable CMS_NODE_API + -- + feature -- Access: router setup_router (a_router: WSF_ROUTER; a_api: CMS_API) -- + local + l_node_api: like node_api do - a_router.handle_with_request_methods ("/blogs/", create {WSF_URI_AGENT_HANDLER}.make (agent handle_blogs (?,?, a_api)), a_router.methods_get) + l_node_api := node_api + if l_node_api = Void then + create l_node_api.make (a_api) + node_api := l_node_api + end + configure_web (a_api, l_node_api, a_router) + end + + +--feature -- Access: router + + --setup_router (a_router: WSF_ROUTER; a_api: CMS_API) + -- + -- do + -- a_router.handle_with_request_methods ("/blogs/", create {WSF_URI_AGENT_HANDLER}.make (agent handle_blogs (?,?, a_api)), a_router.methods_get) + -- end + +configure_web (a_api: CMS_API; a_node_api: CMS_NODE_API; a_router: WSF_ROUTER) + local + l_blog_handler: BLOG_HANDLER + l_uri_mapping: WSF_URI_MAPPING + do + -- TODO: for now, focused only on web interface, add REST api later. [2015-May-18] + --create l_blog_handler.make (a_api, a_node_api) + --create l_uri_mapping.make_trailing_slash_ignored ("/blogs", l_blog_handler) + --a_router.map_with_request_methods (l_uri_mapping, a_router.methods_get) + --a_router.handle_with_request_methods ("/node/{id}", l_node_handler, a_router.methods_get) end feature -- Hooks diff --git a/examples/demo/site/themes/bootstrap/assets/css/node.css b/examples/demo/site/themes/bootstrap/assets/css/node.css index 7888687..244882b 100644 --- a/examples/demo/site/themes/bootstrap/assets/css/node.css +++ b/examples/demo/site/themes/bootstrap/assets/css/node.css @@ -4,12 +4,15 @@ ul.cms-nodes { border: solid 1px #ccc; } -li.cms_type_page { +li.cms_type_page, li.cms_type_blog { border-top: dotted 1px #ccc; } li.cms_type_page a::before { content: "[page] "; } -li.cms_type_page:first-child { +li.cms_type_blog a::before { + content: "[blog] "; +} +ul.cms-nodes li:first-child { border-top: none; } diff --git a/modules/node/handler/blog_handler.e b/modules/node/handler/blog_handler.e new file mode 100644 index 0000000..3f8aef7 --- /dev/null +++ b/modules/node/handler/blog_handler.e @@ -0,0 +1,64 @@ +note + description: "Request handler related to /blogs." + author: "Dario Bösch + local + l_page: CMS_RESPONSE + s: STRING + n: CMS_NODE + lnk: CMS_LOCAL_LINK + do + -- At the moment the template is hardcoded, but we can + -- get them from the configuration file and load them into + -- the setup class. + + create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api) + l_page.add_variable (node_api.nodes, "nodes") + + + -- NOTE: for development purposes we have the following hardcode output. + create s.make_from_string ("

Blog entries:

") + if attached node_api.nodes as lst then + -- Filter out blog entries from all nodes + --if n.content_type.is_equal ("blog") then + s.append ("
    %N") + across + lst as ic + loop + n := ic.item + if n.content_type.is_equal ("blog") then + lnk := node_api.node_link (n) + s.append ("
  • ") + s.append (l_page.link (lnk.title, lnk.location, Void)) + -- s.append (l_page.link (n.title + " (#" + n.id.out + ")", node_api.node_path (n), Void)) + s.append ("
  • %N") + end + end + s.append ("
%N") + --end + end + + l_page.set_main_content (s) + l_page.add_block (create {CMS_CONTENT_BLOCK}.make ("nodes_warning", Void, "/blogs/ is not yet fully implemented
", Void), "highlighted") + l_page.execute + end + + +end From 35b186cec8bb23532b7454e93c22a18dc1e24ebf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Mon, 18 May 2015 14:39:49 +0200 Subject: [PATCH 02/24] gitignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3d99381..932c7cf 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ EIFGENs *.swp *.log* *.rc -*.bak \ No newline at end of file +*.bak +*.sqlite +Thumbs.db From f48f09bfdf6dd5a41eb997b18e3386a455aa6a8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Mon, 18 May 2015 14:49:21 +0200 Subject: [PATCH 03/24] Bugfix (blog disappeared as create option) --- examples/demo/modules/blog/cms_blog_module.e | 25 ++++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/examples/demo/modules/blog/cms_blog_module.e b/examples/demo/modules/blog/cms_blog_module.e index c809fa0..d3155b2 100644 --- a/examples/demo/modules/blog/cms_blog_module.e +++ b/examples/demo/modules/blog/cms_blog_module.e @@ -39,19 +39,18 @@ feature {CMS_API} -- Module Initialization -- local ct: CMS_BLOG_NODE_TYPE - l_node_api: like node_api do Precursor (api) - create l_node_api.make (api) - node_api := l_node_api - create ct - l_node_api.add_content_type (ct) - l_node_api.add_content_type_webform_manager (create {CMS_BLOG_NODE_TYPE_WEBFORM_MANAGER}.make (ct)) - -- Add support for CMS_BLOG, which requires a storage extension to store the optional "tags" value - -- For now, we only have extension based on SQL statement. - if attached {CMS_NODE_STORAGE_SQL} l_node_api.node_storage as l_sql_node_storage then - l_sql_node_storage.register_node_storage_extension (create {CMS_NODE_STORAGE_SQL_BLOG_EXTENSION}.make (l_sql_node_storage)) + if attached {CMS_NODE_API} api.module_api ({NODE_MODULE}) as l_node_api then + create ct + l_node_api.add_content_type (ct) + l_node_api.add_content_type_webform_manager (create {CMS_BLOG_NODE_TYPE_WEBFORM_MANAGER}.make (ct)) + -- Add support for CMS_BLOG, which requires a storage extension to store the optional "tags" value + -- For now, we only have extension based on SQL statement. + if attached {CMS_NODE_STORAGE_SQL} l_node_api.node_storage as l_sql_node_storage then + l_sql_node_storage.register_node_storage_extension (create {CMS_NODE_STORAGE_SQL_BLOG_EXTENSION}.make (l_sql_node_storage)) + end end end @@ -121,9 +120,9 @@ configure_web (a_api: CMS_API; a_node_api: CMS_NODE_API; a_router: WSF_ROUTER) l_uri_mapping: WSF_URI_MAPPING do -- TODO: for now, focused only on web interface, add REST api later. [2015-May-18] - --create l_blog_handler.make (a_api, a_node_api) - --create l_uri_mapping.make_trailing_slash_ignored ("/blogs", l_blog_handler) - --a_router.map_with_request_methods (l_uri_mapping, a_router.methods_get) + create l_blog_handler.make (a_api, a_node_api) + create l_uri_mapping.make_trailing_slash_ignored ("/blogs", l_blog_handler) + a_router.map_with_request_methods (l_uri_mapping, a_router.methods_get) --a_router.handle_with_request_methods ("/node/{id}", l_node_handler, a_router.methods_get) end From f72fcce4405b4f1a9327436f24caadc6262a9c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Mon, 18 May 2015 15:40:47 +0200 Subject: [PATCH 04/24] Link fix --- examples/demo/modules/blog/cms_blog_module.e | 2 +- modules/node/handler/blog_handler.e | 2 +- src/service/cms_api.e | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/demo/modules/blog/cms_blog_module.e b/examples/demo/modules/blog/cms_blog_module.e index d3155b2..bd34810 100644 --- a/examples/demo/modules/blog/cms_blog_module.e +++ b/examples/demo/modules/blog/cms_blog_module.e @@ -117,13 +117,13 @@ feature -- Access: router configure_web (a_api: CMS_API; a_node_api: CMS_NODE_API; a_router: WSF_ROUTER) local l_blog_handler: BLOG_HANDLER + l_node_handler: NODE_HANDLER l_uri_mapping: WSF_URI_MAPPING do -- TODO: for now, focused only on web interface, add REST api later. [2015-May-18] create l_blog_handler.make (a_api, a_node_api) create l_uri_mapping.make_trailing_slash_ignored ("/blogs", l_blog_handler) a_router.map_with_request_methods (l_uri_mapping, a_router.methods_get) - --a_router.handle_with_request_methods ("/node/{id}", l_node_handler, a_router.methods_get) end feature -- Hooks diff --git a/modules/node/handler/blog_handler.e b/modules/node/handler/blog_handler.e index 3f8aef7..a6a2934 100644 --- a/modules/node/handler/blog_handler.e +++ b/modules/node/handler/blog_handler.e @@ -47,7 +47,7 @@ feature -- HTTP Methods lnk := node_api.node_link (n) s.append ("
  • ") s.append (l_page.link (lnk.title, lnk.location, Void)) - -- s.append (l_page.link (n.title + " (#" + n.id.out + ")", node_api.node_path (n), Void)) + --s.append (l_page.link (n.title + " (#" + n.id.out + ")", node_api.node_path (n), Void)) s.append ("
  • %N") end end diff --git a/src/service/cms_api.e b/src/service/cms_api.e index 655ed43..19dbebf 100644 --- a/src/service/cms_api.e +++ b/src/service/cms_api.e @@ -273,7 +273,7 @@ feature -- Path aliases do Result := a_source if attached storage.path_alias (Result) as l_path then - Result := l_path + Result := "/" + l_path end end From 202253e414b8d896c0b79ab472e3501cca8dae3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Tue, 19 May 2015 17:28:37 +0200 Subject: [PATCH 05/24] Added summary field in edit and add mode of a node --- .../handler/cms_node_type_webform_manager.e | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/modules/node/handler/cms_node_type_webform_manager.e b/modules/node/handler/cms_node_type_webform_manager.e index f571c26..c86f2d3 100644 --- a/modules/node/handler/cms_node_type_webform_manager.e +++ b/modules/node/handler/cms_node_type_webform_manager.e @@ -15,7 +15,7 @@ feature -- Forms ... local ti: WSF_FORM_TEXT_INPUT fset: WSF_FORM_FIELD_SET - ta: WSF_FORM_TEXTAREA + ta, sum: WSF_FORM_TEXTAREA tselect: WSF_FORM_SELECT opt: WSF_FORM_SELECT_OPTION do @@ -30,6 +30,7 @@ feature -- Forms ... f.extend_html_text ("
    ") + -- Main Content create ta.make ("body") ta.set_rows (10) ta.set_cols (70) @@ -40,10 +41,24 @@ feature -- Forms ... ta.set_description ("This is the main content") ta.set_is_required (False) + -- Summary + create sum.make ("summary") + sum.set_rows (10) + sum.set_cols (70) + if a_node /= Void then + sum.set_text_value (a_node.summary) + end +-- sum.set_label ("Summary") + sum.set_description ("This is the summary") + sum.set_is_required (False) + create fset.make fset.set_legend ("Body") + -- Add summary + fset.extend (sum) + fset.extend_html_text("
    ") + -- Add content (body) fset.extend (ta) - fset.extend_html_text ("
    ") create tselect.make ("format") From 0e0cd131a566f4bcfc3b782389fb3ad86b780391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Thu, 21 May 2015 10:18:03 +0200 Subject: [PATCH 06/24] #1: Added the summary field to all nodes. It gets saved if we edit the node. On a node page the summary is shown first, then the main content. In the blog list the title and the summry is shown --- .../site/themes/bootstrap/assets/css/node.css | 5 +++ modules/node/handler/blog_handler.e | 14 +++++- .../handler/cms_node_type_webform_manager.e | 44 ++++++++++++++++--- 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/examples/demo/site/themes/bootstrap/assets/css/node.css b/examples/demo/site/themes/bootstrap/assets/css/node.css index 244882b..85b78c9 100644 --- a/examples/demo/site/themes/bootstrap/assets/css/node.css +++ b/examples/demo/site/themes/bootstrap/assets/css/node.css @@ -16,3 +16,8 @@ li.cms_type_blog a::before { ul.cms-nodes li:first-child { border-top: none; } + +.summary{ + margin-top:20px; + font-weight:bold; +} \ No newline at end of file diff --git a/modules/node/handler/blog_handler.e b/modules/node/handler/blog_handler.e index a6a2934..63786b3 100644 --- a/modules/node/handler/blog_handler.e +++ b/modules/node/handler/blog_handler.e @@ -46,8 +46,20 @@ feature -- HTTP Methods if n.content_type.is_equal ("blog") then lnk := node_api.node_link (n) s.append ("
  • ") + + -- Title with link s.append (l_page.link (lnk.title, lnk.location, Void)) - --s.append (l_page.link (n.title + " (#" + n.id.out + ")", node_api.node_path (n), Void)) + + -- Summary + if attached n.summary as l_summary then + s.append ("
    ") + if attached api.format (n.format) as f then + s.append (f.formatted_output (l_summary)) + else + s.append (l_page.formats.default_format.formatted_output (l_summary)) + end + end + s.append ("
  • %N") end end diff --git a/modules/node/handler/cms_node_type_webform_manager.e b/modules/node/handler/cms_node_type_webform_manager.e index c86f2d3..e3d8316 100644 --- a/modules/node/handler/cms_node_type_webform_manager.e +++ b/modules/node/handler/cms_node_type_webform_manager.e @@ -37,7 +37,7 @@ feature -- Forms ... if a_node /= Void then ta.set_text_value (a_node.content) end --- ta.set_label ("Body") + ta.set_label ("Content") ta.set_description ("This is the main content") ta.set_is_required (False) @@ -48,7 +48,7 @@ feature -- Forms ... if a_node /= Void then sum.set_text_value (a_node.summary) end --- sum.set_label ("Summary") + sum.set_label ("Summary") sum.set_description ("This is the summary") sum.set_is_required (False) @@ -104,7 +104,7 @@ feature -- Forms ... update_node (response: NODE_RESPONSE; fd: WSF_FORM_DATA; a_node: CMS_NODE) local - b: detachable READABLE_STRING_8 + b,s: detachable READABLE_STRING_8 f: detachable CONTENT_FORMAT do if attached fd.integer_item ("id") as l_id and then l_id > 0 then @@ -117,6 +117,12 @@ feature -- Forms ... if attached fd.string_item ("body") as l_body then b := l_body end + + -- Read out the summary field from the form data + if attached fd.string_item ("summary") as l_summary then + s := l_summary + end + if attached fd.string_item ("format") as s_format and then attached response.api.format (s_format) as f_format then f := f_format elseif a_node /= Void and then attached a_node.format as s_format and then attached response.api.format (s_format) as f_format then @@ -124,15 +130,19 @@ feature -- Forms ... else f := response.formats.default_format end + + -- Update node with summary and body content if b /= Void then - a_node.set_content (b, Void, f.name) -- FIXME: summary + a_node.set_content (b, s, f.name) end + + end new_node (response: NODE_RESPONSE; fd: WSF_FORM_DATA; a_node: detachable CMS_NODE): G -- local - b: detachable READABLE_STRING_8 + b,s: detachable READABLE_STRING_8 f: detachable CONTENT_FORMAT l_node: detachable like new_node do @@ -166,9 +176,16 @@ feature -- Forms ... end l_node.set_author (response.user) + --Summary + if attached fd.string_item ("summary") as l_summary then + s := l_summary + end + + --Content if attached fd.string_item ("body") as l_body then b := l_body end + if attached fd.string_item ("format") as s_format and then attached response.api.format (s_format) as f_format then f := f_format elseif a_node /= Void and then attached a_node.format as s_format and then attached response.api.format (s_format) as f_format then @@ -176,8 +193,10 @@ feature -- Forms ... else f := response.formats.default_format end + + -- Update node with summary and content if b /= Void then - l_node.set_content (b, Void, f.name) + l_node.set_content (b, s, f.name) end Result := l_node end @@ -216,6 +235,19 @@ feature -- Output s.append (")") end s.append ("") + + if attached a_node.summary as l_summary then + s.append ("

    ") + if attached node_api.cms_api.format (a_node.format) as f then + s.append (f.formatted_output (l_summary)) + else + s.append (a_response.formats.default_format.formatted_output (l_summary)) + end + + s.append ("

    ") + + end + if attached a_node.content as l_content then s.append ("

    ") if attached node_api.cms_api.format (a_node.format) as f then From 6a782e412d837fc85a0457aba4d54d3a4632dc0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Thu, 21 May 2015 12:03:09 +0200 Subject: [PATCH 07/24] #2 Structure of list of posts (blog)Ordered the posts by creation date. For this, I added a field to the nodes storage and api. Show the creation date and author. Styled the post and added a more link to the detail page --- .../site/themes/bootstrap/assets/css/node.css | 32 +++++++++++++++++-- modules/node/cms_node_api.e | 6 ++++ modules/node/handler/blog_handler.e | 23 +++++++++++-- modules/node/persistence/cms_node_storage_i.e | 5 +++ .../node/persistence/cms_node_storage_null.e | 6 ++++ .../node/persistence/cms_node_storage_sql.e | 30 +++++++++++++++++ 6 files changed, 97 insertions(+), 5 deletions(-) diff --git a/examples/demo/site/themes/bootstrap/assets/css/node.css b/examples/demo/site/themes/bootstrap/assets/css/node.css index 85b78c9..cc105b5 100644 --- a/examples/demo/site/themes/bootstrap/assets/css/node.css +++ b/examples/demo/site/themes/bootstrap/assets/css/node.css @@ -4,13 +4,13 @@ ul.cms-nodes { border: solid 1px #ccc; } -li.cms_type_page, li.cms_type_blog { +.cms-nodes li.cms_type_page, .cms-nodes li.cms_type_blog { border-top: dotted 1px #ccc; } li.cms_type_page a::before { content: "[page] "; } -li.cms_type_blog a::before { +.cms-nodes li.cms_type_blog a::before { content: "[blog] "; } ul.cms-nodes li:first-child { @@ -20,4 +20,32 @@ ul.cms-nodes li:first-child { .summary{ margin-top:20px; font-weight:bold; +} +.cms-blog-nodes{ + padding:0; + margin:0; +} +.cms-blog-nodes li{ + list-style: none; + display: block; + margin-top:20px; + padding-bottom:20px; + border-bottom:1px dotted black; +} + +.cms-blog-nodes li > a{ + color:black; + font-size:18px; + text-decoration: none; + display:block; + margin:6px 0; +} + +.cms-blog-nodes li > a:hover{ + color:#999; +} + +.blog_list_summary a{ + margin-top:20px; + display:block; } \ No newline at end of file diff --git a/modules/node/cms_node_api.e b/modules/node/cms_node_api.e index 8f0a8d9..ab990ea 100644 --- a/modules/node/cms_node_api.e +++ b/modules/node/cms_node_api.e @@ -212,6 +212,12 @@ feature -- Access: Node Result := node_storage.nodes end + nodes_order_created_desc: LIST[CMS_NODE] + -- List of nodes ordered by creation date (descending) + do + Result := node_storage.nodes_order_created_desc + end + recent_nodes (a_offset, a_rows: INTEGER): LIST [CMS_NODE] -- List of the `a_rows' most recent nodes starting from `a_offset'. do diff --git a/modules/node/handler/blog_handler.e b/modules/node/handler/blog_handler.e index 63786b3..58e50cf 100644 --- a/modules/node/handler/blog_handler.e +++ b/modules/node/handler/blog_handler.e @@ -24,6 +24,7 @@ feature -- HTTP Methods s: STRING n: CMS_NODE lnk: CMS_LOCAL_LINK + hdate: HTTP_DATE do -- At the moment the template is hardcoded, but we can -- get them from the configuration file and load them into @@ -35,10 +36,10 @@ feature -- HTTP Methods -- NOTE: for development purposes we have the following hardcode output. create s.make_from_string ("

    Blog entries:

    ") - if attached node_api.nodes as lst then + if attached node_api.nodes_order_created_desc as lst then -- Filter out blog entries from all nodes --if n.content_type.is_equal ("blog") then - s.append ("
      %N") + s.append ("
        %N") across lst as ic loop @@ -47,17 +48,33 @@ feature -- HTTP Methods lnk := node_api.node_link (n) s.append ("
      • ") + -- Post date (creation) + if attached n.creation_date as l_modified then + create hdate.make_from_date_time (l_modified) + s.append (hdate.yyyy_mmm_dd_string) + s.append (" ") + end + + -- Author + if attached n.author as l_author then + s.append ("by ") + s.append (l_author.name) + end + -- Title with link s.append (l_page.link (lnk.title, lnk.location, Void)) -- Summary if attached n.summary as l_summary then - s.append ("
        ") + s.append ("

        ") if attached api.format (n.format) as f then s.append (f.formatted_output (l_summary)) else s.append (l_page.formats.default_format.formatted_output (l_summary)) end + s.append ("
        ") + s.append (l_page.link ("More...", lnk.location, Void)) + s.append ("

        ") end s.append ("
      • %N") diff --git a/modules/node/persistence/cms_node_storage_i.e b/modules/node/persistence/cms_node_storage_i.e index 6090d95..2a2051b 100644 --- a/modules/node/persistence/cms_node_storage_i.e +++ b/modules/node/persistence/cms_node_storage_i.e @@ -70,6 +70,11 @@ feature -- Access deferred end + nodes_order_created_desc: LIST [CMS_NODE] + -- List of nodes ordered by creation date (descending). + deferred + end + recent_nodes (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE] -- List of recent `a_count' nodes with an offset of `lower'. deferred diff --git a/modules/node/persistence/cms_node_storage_null.e b/modules/node/persistence/cms_node_storage_null.e index 87559af..a917ec5 100644 --- a/modules/node/persistence/cms_node_storage_null.e +++ b/modules/node/persistence/cms_node_storage_null.e @@ -41,6 +41,12 @@ feature -- Access: node create {ARRAYED_LIST [CMS_NODE]} Result.make (0) end + nodes_order_created_desc: LIST[CMS_NODE] + -- List of nodes ordered descending by creation date + do + create {ARRAYED_LIST [CMS_NODE]} Result.make (0) + end + recent_nodes (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE] -- List of the `a_count' most recent nodes, starting from `a_lower'. do diff --git a/modules/node/persistence/cms_node_storage_sql.e b/modules/node/persistence/cms_node_storage_sql.e index 06ecadc..5d9c7f2 100644 --- a/modules/node/persistence/cms_node_storage_sql.e +++ b/modules/node/persistence/cms_node_storage_sql.e @@ -33,6 +33,32 @@ feature -- Access end end + nodes_order_created_desc: LIST [CMS_NODE] + -- List of nodes ordered by creation date (descending). + do + create {ARRAYED_LIST [CMS_NODE]} Result.make (0) + + error_handler.reset + write_information_log (generator + ".nodes") + + from + sql_query (sql_select_nodes_order_created_desc, Void) + sql_start + until + sql_after + loop + if attached fetch_node as l_node then + Result.force (l_node) + end + sql_forth + end +-- across +-- Result as ic +-- loop +-- fill_node (ic.item) +-- end + end + nodes: LIST [CMS_NODE] -- List of nodes. do @@ -228,6 +254,10 @@ feature {NONE} -- Queries -- SQL Query to retrieve all nodes. --| note: {CMS_NODE_API}.trashed = -1 + sql_select_nodes_order_created_desc: STRING = "SELECT * FROM Nodes WHERE status != -1 ORDER BY created DESC;" + -- SQL Query to retrieve all nodes order by descending creation date. + --| note: {CMS_NODE_API}.trashed = -1 + sql_select_node_by_id: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM Nodes WHERE nid =:nid ORDER BY revision DESC, publish DESC LIMIT 1;" sql_select_recent_nodes: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM Nodes ORDER BY nid DESC, publish DESC LIMIT :rows OFFSET :offset ;" From 4dd980963a594b27125a7607f5c010a832980240 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Thu, 21 May 2015 14:06:08 +0200 Subject: [PATCH 08/24] Moved filter of nodes of type blog to the node storage layer. This is more efficient because the result set from the query will be smaller and it will be easier to implement the pagination --- modules/node/cms_node_api.e | 4 +- modules/node/handler/blog_handler.e | 77 ++++++++++--------- modules/node/persistence/cms_node_storage_i.e | 2 +- .../node/persistence/cms_node_storage_null.e | 4 +- .../node/persistence/cms_node_storage_sql.e | 8 +- 5 files changed, 51 insertions(+), 44 deletions(-) diff --git a/modules/node/cms_node_api.e b/modules/node/cms_node_api.e index ab990ea..c811ebd 100644 --- a/modules/node/cms_node_api.e +++ b/modules/node/cms_node_api.e @@ -212,10 +212,10 @@ feature -- Access: Node Result := node_storage.nodes end - nodes_order_created_desc: LIST[CMS_NODE] + blogs_order_created_desc: LIST[CMS_NODE] -- List of nodes ordered by creation date (descending) do - Result := node_storage.nodes_order_created_desc + Result := node_storage.blogs end recent_nodes (a_offset, a_rows: INTEGER): LIST [CMS_NODE] diff --git a/modules/node/handler/blog_handler.e b/modules/node/handler/blog_handler.e index 58e50cf..1e8d67d 100644 --- a/modules/node/handler/blog_handler.e +++ b/modules/node/handler/blog_handler.e @@ -16,6 +16,15 @@ inherit create make +feature -- Settings + entries_per_page : INTEGER + -- The numbers of posts that are shown on one page. If there are more post a pagination is generated + do + -- For test reasons this is 2, so we don't have to create a lot of blog entries. + -- TODO: Set to bigger constant or load from global configuration file. + Result := 2 + end + feature -- HTTP Methods do_get (req: WSF_REQUEST; res: WSF_RESPONSE) -- @@ -35,8 +44,8 @@ feature -- HTTP Methods -- NOTE: for development purposes we have the following hardcode output. - create s.make_from_string ("

        Blog entries:

        ") - if attached node_api.nodes_order_created_desc as lst then + create s.make_from_string ("

        Blog

        ") + if attached node_api.blogs_order_created_desc as lst then -- Filter out blog entries from all nodes --if n.content_type.is_equal ("blog") then s.append ("
          %N") @@ -44,41 +53,39 @@ feature -- HTTP Methods lst as ic loop n := ic.item - if n.content_type.is_equal ("blog") then - lnk := node_api.node_link (n) - s.append ("
        • ") + lnk := node_api.node_link (n) + s.append ("
        • ") - -- Post date (creation) - if attached n.creation_date as l_modified then - create hdate.make_from_date_time (l_modified) - s.append (hdate.yyyy_mmm_dd_string) - s.append (" ") - end - - -- Author - if attached n.author as l_author then - s.append ("by ") - s.append (l_author.name) - end - - -- Title with link - s.append (l_page.link (lnk.title, lnk.location, Void)) - - -- Summary - if attached n.summary as l_summary then - s.append ("

          ") - if attached api.format (n.format) as f then - s.append (f.formatted_output (l_summary)) - else - s.append (l_page.formats.default_format.formatted_output (l_summary)) - end - s.append ("
          ") - s.append (l_page.link ("More...", lnk.location, Void)) - s.append ("

          ") - end - - s.append ("
        • %N") + -- Post date (creation) + if attached n.creation_date as l_modified then + create hdate.make_from_date_time (l_modified) + s.append (hdate.yyyy_mmm_dd_string) + s.append (" ") end + + -- Author + if attached n.author as l_author then + s.append ("by ") + s.append (l_author.name) + end + + -- Title with link + s.append (l_page.link (lnk.title, lnk.location, Void)) + + -- Summary + if attached n.summary as l_summary then + s.append ("

          ") + if attached api.format (n.format) as f then + s.append (f.formatted_output (l_summary)) + else + s.append (l_page.formats.default_format.formatted_output (l_summary)) + end + s.append ("
          ") + s.append (l_page.link ("See more...", lnk.location, Void)) + s.append ("

          ") + end + + s.append ("%N") end s.append ("
        %N") --end diff --git a/modules/node/persistence/cms_node_storage_i.e b/modules/node/persistence/cms_node_storage_i.e index 2a2051b..9b68303 100644 --- a/modules/node/persistence/cms_node_storage_i.e +++ b/modules/node/persistence/cms_node_storage_i.e @@ -70,7 +70,7 @@ feature -- Access deferred end - nodes_order_created_desc: LIST [CMS_NODE] + blogs: LIST [CMS_NODE] -- List of nodes ordered by creation date (descending). deferred end diff --git a/modules/node/persistence/cms_node_storage_null.e b/modules/node/persistence/cms_node_storage_null.e index a917ec5..c574235 100644 --- a/modules/node/persistence/cms_node_storage_null.e +++ b/modules/node/persistence/cms_node_storage_null.e @@ -41,12 +41,12 @@ feature -- Access: node create {ARRAYED_LIST [CMS_NODE]} Result.make (0) end - nodes_order_created_desc: LIST[CMS_NODE] + blogs: LIST[CMS_NODE] -- List of nodes ordered descending by creation date do create {ARRAYED_LIST [CMS_NODE]} Result.make (0) end - + recent_nodes (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE] -- List of the `a_count' most recent nodes, starting from `a_lower'. do diff --git a/modules/node/persistence/cms_node_storage_sql.e b/modules/node/persistence/cms_node_storage_sql.e index 5d9c7f2..7365f80 100644 --- a/modules/node/persistence/cms_node_storage_sql.e +++ b/modules/node/persistence/cms_node_storage_sql.e @@ -33,7 +33,7 @@ feature -- Access end end - nodes_order_created_desc: LIST [CMS_NODE] + blogs: LIST [CMS_NODE] -- List of nodes ordered by creation date (descending). do create {ARRAYED_LIST [CMS_NODE]} Result.make (0) @@ -42,7 +42,7 @@ feature -- Access write_information_log (generator + ".nodes") from - sql_query (sql_select_nodes_order_created_desc, Void) + sql_query (sql_select_blogs_order_created_desc, Void) sql_start until sql_after @@ -254,8 +254,8 @@ feature {NONE} -- Queries -- SQL Query to retrieve all nodes. --| note: {CMS_NODE_API}.trashed = -1 - sql_select_nodes_order_created_desc: STRING = "SELECT * FROM Nodes WHERE status != -1 ORDER BY created DESC;" - -- SQL Query to retrieve all nodes order by descending creation date. + sql_select_blogs_order_created_desc: STRING = "SELECT * FROM Nodes WHERE status != -1 AND type = %"blog%" ORDER BY created DESC;" + -- SQL Query to retrieve all nodes that are from the type "blog" ordered by descending creation date. --| note: {CMS_NODE_API}.trashed = -1 sql_select_node_by_id: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM Nodes WHERE nid =:nid ORDER BY revision DESC, publish DESC LIMIT 1;" From 57c2a7bccd779e26a6f37fa5ede2c3e269dff035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Thu, 21 May 2015 14:12:01 +0200 Subject: [PATCH 09/24] Removed the summary from the detail page --- .../handler/cms_node_type_webform_manager.e | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/modules/node/handler/cms_node_type_webform_manager.e b/modules/node/handler/cms_node_type_webform_manager.e index e3d8316..697e73b 100644 --- a/modules/node/handler/cms_node_type_webform_manager.e +++ b/modules/node/handler/cms_node_type_webform_manager.e @@ -236,17 +236,21 @@ feature -- Output end s.append ("") - if attached a_node.summary as l_summary then - s.append ("

        ") - if attached node_api.cms_api.format (a_node.format) as f then - s.append (f.formatted_output (l_summary)) - else - s.append (a_response.formats.default_format.formatted_output (l_summary)) - end - s.append ("

        ") + -- We don't show the summary on the detail page, since its just a short view of the full content. Otherwise we would write the same thing twice. + -- The usage of the summary is to give a short overview in the list of nodes or for the meta tag "description" - end +-- if attached a_node.summary as l_summary then +-- s.append ("

        ") +-- if attached node_api.cms_api.format (a_node.format) as f then +-- s.append (f.formatted_output (l_summary)) +-- else +-- s.append (a_response.formats.default_format.formatted_output (l_summary)) +-- end + +-- s.append ("

        ") + +-- end if attached a_node.content as l_content then s.append ("

        ") From 470b1b2e054e151a48f0367af972134a76c8779e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Thu, 21 May 2015 16:04:58 +0200 Subject: [PATCH 10/24] Restructured Blog Module All blog handlers and storage classes are detached from the nodes module. All files of the blog module are in the modules/blog folder --- examples/demo/modules/blog/cms_blog_api.e | 52 ++++++++++++++++ .../modules/blog/cms_blog_module-safe.ecf | 1 + examples/demo/modules/blog/cms_blog_module.e | 19 +----- .../demo/modules/blog}/handler/blog_handler.e | 21 ++++++- .../modules/blog/handler/cms_blog_handler.e | 16 +++++ .../blog/persistence/cms_blog_storage_i.e | 24 ++++++++ .../blog/persistence/cms_blog_storage_null.e | 31 ++++++++++ .../blog/persistence/cms_blog_storage_sql.e | 61 +++++++++++++++++++ modules/node/cms_node_api.e | 5 -- modules/node/persistence/cms_node_storage_i.e | 5 -- .../node/persistence/cms_node_storage_null.e | 6 -- .../node/persistence/cms_node_storage_sql.e | 29 --------- 12 files changed, 207 insertions(+), 63 deletions(-) create mode 100644 examples/demo/modules/blog/cms_blog_api.e rename {modules/node => examples/demo/modules/blog}/handler/blog_handler.e (89%) create mode 100644 examples/demo/modules/blog/handler/cms_blog_handler.e create mode 100644 examples/demo/modules/blog/persistence/cms_blog_storage_i.e create mode 100644 examples/demo/modules/blog/persistence/cms_blog_storage_null.e create mode 100644 examples/demo/modules/blog/persistence/cms_blog_storage_sql.e diff --git a/examples/demo/modules/blog/cms_blog_api.e b/examples/demo/modules/blog/cms_blog_api.e new file mode 100644 index 0000000..d75779b --- /dev/null +++ b/examples/demo/modules/blog/cms_blog_api.e @@ -0,0 +1,52 @@ +note + description: "API to handle nodes of type blog" + author: "Dario Bösch + do + Precursor + if attached {CMS_STORAGE_SQL_I} storage as l_storage_sql then + create {CMS_BLOG_STORAGE_SQL} node_storage.make (l_storage_sql) + else + create {CMS_BLOG_STORAGE_NULL} node_storage.make + end + initialize_node_types + end + +feature {CMS_MODULE} -- Access nodes storage. + + node_storage: CMS_BLOG_STORAGE_I + +feature -- Access node + + blogs_count: INTEGER_64 + -- Number of nodes of type blog + do + Result := node_storage.blogs_count + end + + blogs_order_created_desc: LIST[CMS_NODE] + -- List of nodes ordered by creation date (descending) + do + Result := node_storage.blogs + end + +end diff --git a/examples/demo/modules/blog/cms_blog_module-safe.ecf b/examples/demo/modules/blog/cms_blog_module-safe.ecf index bf6db6e..373775e 100644 --- a/examples/demo/modules/blog/cms_blog_module-safe.ecf +++ b/examples/demo/modules/blog/cms_blog_module-safe.ecf @@ -20,6 +20,7 @@ + diff --git a/examples/demo/modules/blog/cms_blog_module.e b/examples/demo/modules/blog/cms_blog_module.e index bd34810..1cd49dc 100644 --- a/examples/demo/modules/blog/cms_blog_module.e +++ b/examples/demo/modules/blog/cms_blog_module.e @@ -42,7 +42,7 @@ feature {CMS_API} -- Module Initialization do Precursor (api) - if attached {CMS_NODE_API} api.module_api ({NODE_MODULE}) as l_node_api then + if attached {CMS_BLOG_API} api.module_api ({NODE_MODULE}) as l_node_api then create ct l_node_api.add_content_type (ct) l_node_api.add_content_type_webform_manager (create {CMS_BLOG_NODE_TYPE_WEBFORM_MANAGER}.make (ct)) @@ -87,7 +87,7 @@ CREATE TABLE "blog_post_nodes"( feature {CMS_API} -- Access: API - node_api: detachable CMS_NODE_API + node_api: detachable CMS_BLOG_API -- feature -- Access: router @@ -114,10 +114,9 @@ feature -- Access: router -- a_router.handle_with_request_methods ("/blogs/", create {WSF_URI_AGENT_HANDLER}.make (agent handle_blogs (?,?, a_api)), a_router.methods_get) -- end -configure_web (a_api: CMS_API; a_node_api: CMS_NODE_API; a_router: WSF_ROUTER) +configure_web (a_api: CMS_API; a_node_api: CMS_BLOG_API; a_router: WSF_ROUTER) local l_blog_handler: BLOG_HANDLER - l_node_handler: NODE_HANDLER l_uri_mapping: WSF_URI_MAPPING do -- TODO: for now, focused only on web interface, add REST api later. [2015-May-18] @@ -140,16 +139,4 @@ feature -- Hooks create lnk.make ("Blogs", "/blogs/") a_menu_system.primary_menu.extend (lnk) end - -feature -- Handler - - handle_blogs (req: WSF_REQUEST; res: WSF_RESPONSE; a_api: CMS_API) - local - r: NOT_IMPLEMENTED_ERROR_CMS_RESPONSE - do - create r.make (req, res, a_api) - r.set_main_content ("Blog module is in development ...") - r.execute - end - end diff --git a/modules/node/handler/blog_handler.e b/examples/demo/modules/blog/handler/blog_handler.e similarity index 89% rename from modules/node/handler/blog_handler.e rename to examples/demo/modules/blog/handler/blog_handler.e index 1e8d67d..66efe1a 100644 --- a/modules/node/handler/blog_handler.e +++ b/examples/demo/modules/blog/handler/blog_handler.e @@ -1,6 +1,6 @@ note description: "Request handler related to /blogs." - author: "Dario Bösch " date: "$Date: 2015-05-18 13:49:99 +0100 (lun., 18 mai 2015) $" revision: "$966167$" @@ -8,14 +8,31 @@ class BLOG_HANDLER inherit - NODES_HANDLER + CMS_BLOG_HANDLER + + WSF_URI_HANDLER + rename + new_mapping as new_uri_mapping + end + + WSF_RESOURCE_HANDLER_HELPER redefine do_get end + REFACTORING_HELPER + create make +feature -- execute + + execute (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute request handler + do + execute_methods (req, res) + end + feature -- Settings entries_per_page : INTEGER -- The numbers of posts that are shown on one page. If there are more post a pagination is generated diff --git a/examples/demo/modules/blog/handler/cms_blog_handler.e b/examples/demo/modules/blog/handler/cms_blog_handler.e new file mode 100644 index 0000000..c33d834 --- /dev/null +++ b/examples/demo/modules/blog/handler/cms_blog_handler.e @@ -0,0 +1,16 @@ +note + description: "Summary description for {CMS_NODE_HANDLER}." + author: "" + date: "$Date: 2015-02-13 13:08:13 +0100 (ven., 13 févr. 2015) $" + revision: "$Revision: 96616 $" + +deferred class + CMS_BLOG_HANDLER + +inherit + CMS_MODULE_HANDLER [CMS_BLOG_API] + rename + module_api as node_api + end + +end diff --git a/examples/demo/modules/blog/persistence/cms_blog_storage_i.e b/examples/demo/modules/blog/persistence/cms_blog_storage_i.e new file mode 100644 index 0000000..21d081a --- /dev/null +++ b/examples/demo/modules/blog/persistence/cms_blog_storage_i.e @@ -0,0 +1,24 @@ +note + description: "Interface for accessing blog contents from the database." + date: "$Date: 2015-01-27 19:15:02 +0100 (mar., 27 janv. 2015) $" + revision: "$Revision: 96542 $" + +deferred class + CMS_BLOG_STORAGE_I + +inherit + CMS_NODE_STORAGE_I + +feature -- Access + + blogs_count: INTEGER_64 + -- Count of blog nodes + deferred + end + + blogs: LIST [CMS_NODE] + -- List of nodes ordered by creation date (descending). + deferred + end + +end diff --git a/examples/demo/modules/blog/persistence/cms_blog_storage_null.e b/examples/demo/modules/blog/persistence/cms_blog_storage_null.e new file mode 100644 index 0000000..fff5c0d --- /dev/null +++ b/examples/demo/modules/blog/persistence/cms_blog_storage_null.e @@ -0,0 +1,31 @@ +note + description: "Summary description for {CMS_BLOG_STORAGE_NULL}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_BLOG_STORAGE_NULL + +inherit + CMS_NODE_STORAGE_NULL + + CMS_BLOG_STORAGE_I + +create + make + +feature -- Access + + blogs_count: INTEGER_64 + -- Count of nodes. + do + end + + blogs: LIST[CMS_NODE] + -- List of nodes. + do + create {ARRAYED_LIST [CMS_NODE]} Result.make (0) + end + +end diff --git a/examples/demo/modules/blog/persistence/cms_blog_storage_sql.e b/examples/demo/modules/blog/persistence/cms_blog_storage_sql.e new file mode 100644 index 0000000..e39f103 --- /dev/null +++ b/examples/demo/modules/blog/persistence/cms_blog_storage_sql.e @@ -0,0 +1,61 @@ +note + description: "Summary description for {CMS_BLOG_STORAGE_SQL}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_BLOG_STORAGE_SQL + +inherit + CMS_NODE_STORAGE_SQL + + CMS_BLOG_STORAGE_I + +create + make + +feature -- Access + + blogs_count: INTEGER_64 + -- Count of blog nodes + do + error_handler.reset + write_information_log (generator + ".nodes_count") + sql_query (sql_select_blog_count, Void) + if sql_rows_count = 1 then + Result := sql_read_integer_64 (1) + end + end + + blogs: LIST [CMS_NODE] + -- List of nodes ordered by creation date (descending). + do + create {ARRAYED_LIST [CMS_NODE]} Result.make (0) + + error_handler.reset + write_information_log (generator + ".nodes") + + from + sql_query (sql_select_blogs_order_created_desc, Void) + sql_start + until + sql_after + loop + if attached fetch_node as l_node then + Result.force (l_node) + end + sql_forth + end + end + +feature {NONE} -- Queries + + sql_select_blog_count: STRING = "SELECT count(*) FROM Nodes WHERE status != -1 AND type = %"blog%";" + -- Nodes count (Published and not Published) + --| note: {CMS_NODE_API}.trashed = -1 + + sql_select_blogs_order_created_desc: STRING = "SELECT * FROM Nodes WHERE status != -1 AND type = %"blog%" ORDER BY created DESC;" + -- SQL Query to retrieve all nodes that are from the type "blog" ordered by descending creation date. + +end diff --git a/modules/node/cms_node_api.e b/modules/node/cms_node_api.e index c811ebd..d324d3b 100644 --- a/modules/node/cms_node_api.e +++ b/modules/node/cms_node_api.e @@ -212,11 +212,6 @@ feature -- Access: Node Result := node_storage.nodes end - blogs_order_created_desc: LIST[CMS_NODE] - -- List of nodes ordered by creation date (descending) - do - Result := node_storage.blogs - end recent_nodes (a_offset, a_rows: INTEGER): LIST [CMS_NODE] -- List of the `a_rows' most recent nodes starting from `a_offset'. diff --git a/modules/node/persistence/cms_node_storage_i.e b/modules/node/persistence/cms_node_storage_i.e index 9b68303..6090d95 100644 --- a/modules/node/persistence/cms_node_storage_i.e +++ b/modules/node/persistence/cms_node_storage_i.e @@ -70,11 +70,6 @@ feature -- Access deferred end - blogs: LIST [CMS_NODE] - -- List of nodes ordered by creation date (descending). - deferred - end - recent_nodes (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE] -- List of recent `a_count' nodes with an offset of `lower'. deferred diff --git a/modules/node/persistence/cms_node_storage_null.e b/modules/node/persistence/cms_node_storage_null.e index c574235..87559af 100644 --- a/modules/node/persistence/cms_node_storage_null.e +++ b/modules/node/persistence/cms_node_storage_null.e @@ -41,12 +41,6 @@ feature -- Access: node create {ARRAYED_LIST [CMS_NODE]} Result.make (0) end - blogs: LIST[CMS_NODE] - -- List of nodes ordered descending by creation date - do - create {ARRAYED_LIST [CMS_NODE]} Result.make (0) - end - recent_nodes (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE] -- List of the `a_count' most recent nodes, starting from `a_lower'. do diff --git a/modules/node/persistence/cms_node_storage_sql.e b/modules/node/persistence/cms_node_storage_sql.e index 7365f80..756d61d 100644 --- a/modules/node/persistence/cms_node_storage_sql.e +++ b/modules/node/persistence/cms_node_storage_sql.e @@ -33,31 +33,6 @@ feature -- Access end end - blogs: LIST [CMS_NODE] - -- List of nodes ordered by creation date (descending). - do - create {ARRAYED_LIST [CMS_NODE]} Result.make (0) - - error_handler.reset - write_information_log (generator + ".nodes") - - from - sql_query (sql_select_blogs_order_created_desc, Void) - sql_start - until - sql_after - loop - if attached fetch_node as l_node then - Result.force (l_node) - end - sql_forth - end --- across --- Result as ic --- loop --- fill_node (ic.item) --- end - end nodes: LIST [CMS_NODE] -- List of nodes. @@ -254,10 +229,6 @@ feature {NONE} -- Queries -- SQL Query to retrieve all nodes. --| note: {CMS_NODE_API}.trashed = -1 - sql_select_blogs_order_created_desc: STRING = "SELECT * FROM Nodes WHERE status != -1 AND type = %"blog%" ORDER BY created DESC;" - -- SQL Query to retrieve all nodes that are from the type "blog" ordered by descending creation date. - --| note: {CMS_NODE_API}.trashed = -1 - sql_select_node_by_id: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM Nodes WHERE nid =:nid ORDER BY revision DESC, publish DESC LIMIT 1;" sql_select_recent_nodes: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM Nodes ORDER BY nid DESC, publish DESC LIMIT :rows OFFSET :offset ;" From 802ad0626e58ab1e66e21ecd29eca866c53af7e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Thu, 21 May 2015 16:10:07 +0200 Subject: [PATCH 11/24] Bugfix: wrong API in initialisation of blog module --- examples/demo/modules/blog/cms_blog_module.e | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/demo/modules/blog/cms_blog_module.e b/examples/demo/modules/blog/cms_blog_module.e index 1cd49dc..f69c8a6 100644 --- a/examples/demo/modules/blog/cms_blog_module.e +++ b/examples/demo/modules/blog/cms_blog_module.e @@ -42,7 +42,7 @@ feature {CMS_API} -- Module Initialization do Precursor (api) - if attached {CMS_BLOG_API} api.module_api ({NODE_MODULE}) as l_node_api then + if attached {CMS_NODE_API} api.module_api ({NODE_MODULE}) as l_node_api then create ct l_node_api.add_content_type (ct) l_node_api.add_content_type_webform_manager (create {CMS_BLOG_NODE_TYPE_WEBFORM_MANAGER}.make (ct)) From fb196735b64bca277bef8d358f30b67e2fa0e6b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Fri, 22 May 2015 11:17:34 +0200 Subject: [PATCH 12/24] #3: Routet page and limited entries The blog module routes /blog/{page} and the blog handler limits the entries per page (given as a feature) and sets the offsets according to the given page number --- examples/demo/modules/blog/cms_blog_api.e | 6 ++ examples/demo/modules/blog/cms_blog_module.e | 17 +++-- .../demo/modules/blog/handler/blog_handler.e | 68 ++++++++++++++++++- .../blog/persistence/cms_blog_storage_i.e | 5 ++ .../blog/persistence/cms_blog_storage_null.e | 5 ++ .../blog/persistence/cms_blog_storage_sql.e | 29 ++++++++ 6 files changed, 118 insertions(+), 12 deletions(-) diff --git a/examples/demo/modules/blog/cms_blog_api.e b/examples/demo/modules/blog/cms_blog_api.e index d75779b..f0fb9f1 100644 --- a/examples/demo/modules/blog/cms_blog_api.e +++ b/examples/demo/modules/blog/cms_blog_api.e @@ -49,4 +49,10 @@ feature -- Access node Result := node_storage.blogs end + blogs_order_created_desc_limited (a_limit:INTEGER_32; a_offset:INTEGER_32) : LIST[CMS_NODE] + -- List of nodes ordered by creation date and limited by limit and offset + do + Result := node_storage.blogs_limited (a_limit, a_offset) + end + end diff --git a/examples/demo/modules/blog/cms_blog_module.e b/examples/demo/modules/blog/cms_blog_module.e index f69c8a6..d247566 100644 --- a/examples/demo/modules/blog/cms_blog_module.e +++ b/examples/demo/modules/blog/cms_blog_module.e @@ -106,14 +106,6 @@ feature -- Access: router end ---feature -- Access: router - - --setup_router (a_router: WSF_ROUTER; a_api: CMS_API) - -- - -- do - -- a_router.handle_with_request_methods ("/blogs/", create {WSF_URI_AGENT_HANDLER}.make (agent handle_blogs (?,?, a_api)), a_router.methods_get) - -- end - configure_web (a_api: CMS_API; a_node_api: CMS_BLOG_API; a_router: WSF_ROUTER) local l_blog_handler: BLOG_HANDLER @@ -121,8 +113,14 @@ configure_web (a_api: CMS_API; a_node_api: CMS_BLOG_API; a_router: WSF_ROUTER) do -- TODO: for now, focused only on web interface, add REST api later. [2015-May-18] create l_blog_handler.make (a_api, a_node_api) - create l_uri_mapping.make_trailing_slash_ignored ("/blogs", l_blog_handler) + + -- Let the class BLOG_HANDLER handle the requests on "/blogs" + create l_uri_mapping.make_trailing_slash_ignored("/blogs", l_blog_handler) a_router.map_with_request_methods (l_uri_mapping, a_router.methods_get) + + -- We can add a page number after /blogs/ to get older posts + a_router.handle_with_request_methods ("/blogs/{page}", l_blog_handler, a_router.methods_get) + end feature -- Hooks @@ -136,6 +134,7 @@ feature -- Hooks local lnk: CMS_LOCAL_LINK do + -- Add the link to the blog to the main menu create lnk.make ("Blogs", "/blogs/") a_menu_system.primary_menu.extend (lnk) end diff --git a/examples/demo/modules/blog/handler/blog_handler.e b/examples/demo/modules/blog/handler/blog_handler.e index 66efe1a..1b8c359 100644 --- a/examples/demo/modules/blog/handler/blog_handler.e +++ b/examples/demo/modules/blog/handler/blog_handler.e @@ -12,9 +12,18 @@ inherit WSF_URI_HANDLER rename + execute as uri_execute, new_mapping as new_uri_mapping end + WSF_URI_TEMPLATE_HANDLER + rename + execute as uri_template_execute, + new_mapping as new_uri_template_mapping + select + new_uri_template_mapping + end + WSF_RESOURCE_HANDLER_HELPER redefine do_get @@ -33,6 +42,18 @@ feature -- execute execute_methods (req, res) end + uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute request handler + do + execute (req, res) + end + + uri_template_execute (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute request handler + do + execute (req, res) + end + feature -- Settings entries_per_page : INTEGER -- The numbers of posts that are shown on one page. If there are more post a pagination is generated @@ -42,27 +63,54 @@ feature -- Settings Result := 2 end + more_than_one_page : BOOLEAN + -- Checks if all posts fit on one page (FALSE) or if more than one page is needed (TRUE) + do + Result := entries_per_page < node_api.blogs_count + end + feature -- HTTP Methods do_get (req: WSF_REQUEST; res: WSF_RESPONSE) -- local l_page: CMS_RESPONSE + l_posts: LIST[CMS_NODE] s: STRING n: CMS_NODE lnk: CMS_LOCAL_LINK hdate: HTTP_DATE + page_number:NATURAL_16 do -- At the moment the template is hardcoded, but we can -- get them from the configuration file and load them into -- the setup class. + --Check if a page is given, if not start with page 1 + if req.path_info.ends_with_general ("/blogs") then + -- No page number given, set to 0 + page_number := 1 + else + -- Read page number from get variable + page_number := page_number_path_parameter (req) + end + + -- Ensure that page is never 0 (happens if /blogs/ is routed) + if page_number = 0 then page_number := 1 end + create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api) l_page.add_variable (node_api.nodes, "nodes") - -- NOTE: for development purposes we have the following hardcode output. - create s.make_from_string ("

        Blog

        ") - if attached node_api.blogs_order_created_desc as lst then + -- Output the title. If more than one page, also output the current page number + create s.make_from_string ("

        Blog") + if more_than_one_page then + s.append (" (Page " + page_number.out + ")") + -- Get the posts from the current page (limited by entries per page) + end + s.append ("

        ") + + + if attached node_api.blogs_order_created_desc_limited (entries_per_page, (page_number-1) * entries_per_page) as lst then -- Filter out blog entries from all nodes --if n.content_type.is_equal ("blog") then s.append ("
          %N") @@ -113,5 +161,19 @@ feature -- HTTP Methods l_page.execute end +feature -- Query + + page_number_path_parameter (req: WSF_REQUEST): NATURAL_16 + -- Returns the page number from the path /blogs/{page}. It's an unsigned integere since negative pages are not allowed + local + s: STRING + do + if attached {WSF_STRING} req.path_parameter ("page") as p_page then + s := p_page.value + if s.is_natural_16 then + Result := s.to_natural_16 + end + end + end end diff --git a/examples/demo/modules/blog/persistence/cms_blog_storage_i.e b/examples/demo/modules/blog/persistence/cms_blog_storage_i.e index 21d081a..334f6b3 100644 --- a/examples/demo/modules/blog/persistence/cms_blog_storage_i.e +++ b/examples/demo/modules/blog/persistence/cms_blog_storage_i.e @@ -21,4 +21,9 @@ feature -- Access deferred end + blogs_limited (limit:INTEGER_32; offset:INTEGER_32) : LIST[CMS_NODE] + -- List of nodes ordered by creation date from limit to limit + offset + deferred + end + end diff --git a/examples/demo/modules/blog/persistence/cms_blog_storage_null.e b/examples/demo/modules/blog/persistence/cms_blog_storage_null.e index fff5c0d..328fc69 100644 --- a/examples/demo/modules/blog/persistence/cms_blog_storage_null.e +++ b/examples/demo/modules/blog/persistence/cms_blog_storage_null.e @@ -28,4 +28,9 @@ feature -- Access create {ARRAYED_LIST [CMS_NODE]} Result.make (0) end + blogs_limited (limit:INTEGER_32; offset:INTEGER_32) : LIST[CMS_NODE] + -- List of nodes ordered by creation date from limit to limit + offset + do + create {ARRAYED_LIST [CMS_NODE]} Result.make (0) + end end diff --git a/examples/demo/modules/blog/persistence/cms_blog_storage_sql.e b/examples/demo/modules/blog/persistence/cms_blog_storage_sql.e index e39f103..c7f8407 100644 --- a/examples/demo/modules/blog/persistence/cms_blog_storage_sql.e +++ b/examples/demo/modules/blog/persistence/cms_blog_storage_sql.e @@ -49,6 +49,32 @@ feature -- Access end end + blogs_limited (a_limit:INTEGER_32; a_offset:INTEGER_32) : LIST[CMS_NODE] + -- List of nodes ordered by creation date from limit to limit + offset + local + l_parameters: STRING_TABLE [detachable ANY] + do + create {ARRAYED_LIST [CMS_NODE]} Result.make (0) + + error_handler.reset + write_information_log (generator + ".nodes") + + from + create l_parameters.make (2) + l_parameters.put (a_limit, "limit") + l_parameters.put (a_offset, "offset") + sql_query (sql_blogs_limited, l_parameters) + sql_start + until + sql_after + loop + if attached fetch_node as l_node then + Result.force (l_node) + end + sql_forth + end + end + feature {NONE} -- Queries sql_select_blog_count: STRING = "SELECT count(*) FROM Nodes WHERE status != -1 AND type = %"blog%";" @@ -58,4 +84,7 @@ feature {NONE} -- Queries sql_select_blogs_order_created_desc: STRING = "SELECT * FROM Nodes WHERE status != -1 AND type = %"blog%" ORDER BY created DESC;" -- SQL Query to retrieve all nodes that are from the type "blog" ordered by descending creation date. + sql_blogs_limited: STRING = "SELECT * FROM Nodes WHERE status != -1 AND type = %"blog%" ORDER BY created DESC LIMIT :limit OFFSET :offset ;" + --- SQL Query to retrieve all node of type "blog" from limit to limit + offset + end From 1f61126d22e9f07582aded5e25c66bbcc0be482b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Fri, 22 May 2015 11:30:54 +0200 Subject: [PATCH 13/24] Configuration File added Created CMS_BLOG_CONFIG at moved the feature entries_per_page to this new class. The blog hander inherits from the config class --- examples/demo/modules/blog/cms_blog_config.e | 21 ++++++++++++++++++ .../demo/modules/blog/handler/blog_handler.e | 22 +++++++------------ .../blog/persistence/cms_blog_storage_sql.e | 8 +++---- 3 files changed, 33 insertions(+), 18 deletions(-) create mode 100644 examples/demo/modules/blog/cms_blog_config.e diff --git a/examples/demo/modules/blog/cms_blog_config.e b/examples/demo/modules/blog/cms_blog_config.e new file mode 100644 index 0000000..61a3d87 --- /dev/null +++ b/examples/demo/modules/blog/cms_blog_config.e @@ -0,0 +1,21 @@ +note + description: "Configuration class for the blog module." + author: "Dario Bösch " + date: "$Date: 2015-05-21 14:46:00 +0100$" + revision: "$Revision: 96616 $" class CMS_BLOG_STORAGE_SQL From a4c50adefa69e5704459f02caa30dadc4812f2e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Fri, 22 May 2015 11:48:20 +0200 Subject: [PATCH 14/24] #3: Calculate and show number of total pages --- .../demo/modules/blog/handler/blog_handler.e | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/examples/demo/modules/blog/handler/blog_handler.e b/examples/demo/modules/blog/handler/blog_handler.e index 4491137..c5ec75d 100644 --- a/examples/demo/modules/blog/handler/blog_handler.e +++ b/examples/demo/modules/blog/handler/blog_handler.e @@ -62,7 +62,6 @@ feature -- HTTP Methods -- local l_page: CMS_RESPONSE - l_posts: LIST[CMS_NODE] s: STRING n: CMS_NODE lnk: CMS_LOCAL_LINK @@ -92,7 +91,7 @@ feature -- HTTP Methods -- Output the title. If more than one page, also output the current page number create s.make_from_string ("

          Blog") if more_than_one_page then - s.append (" (Page " + page_number.out + ")") + s.append (" (Page " + page_number.out + " of " + pages.out + ")") -- Get the posts from the current page (limited by entries per page) end s.append ("

          ") @@ -141,6 +140,12 @@ feature -- HTTP Methods s.append ("%N") end s.append ("
        %N") + + -- Show the pagination if there are more than one page + if more_than_one_page then + s.append ("
          ") + + end --end end @@ -149,7 +154,7 @@ feature -- HTTP Methods l_page.execute end -feature -- Query +feature {NONE} -- Query more_than_one_page : BOOLEAN -- Checks if all posts fit on one page (FALSE) or if more than one page is needed (TRUE) @@ -157,6 +162,18 @@ feature -- Query Result := entries_per_page < node_api.blogs_count end + + pages : NATURAL_16 + -- Returns the number of pages needed to display all posts + require + entries_per_page > 0 + local + tmp: REAL_32 + do + tmp := node_api.blogs_count.to_real / entries_per_page.to_real; + Result := tmp.ceiling.to_natural_16 + end + page_number_path_parameter (req: WSF_REQUEST): NATURAL_16 -- Returns the page number from the path /blogs/{page}. It's an unsigned integere since negative pages are not allowed local From 027463a9100ea76bba6369b78bdcc4206710dbb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Fri, 22 May 2015 12:02:33 +0200 Subject: [PATCH 15/24] #3: added pagination links at bottom of the blog page --- .../demo/modules/blog/handler/blog_handler.e | 43 +++++++++++++------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/examples/demo/modules/blog/handler/blog_handler.e b/examples/demo/modules/blog/handler/blog_handler.e index c5ec75d..bfec0e7 100644 --- a/examples/demo/modules/blog/handler/blog_handler.e +++ b/examples/demo/modules/blog/handler/blog_handler.e @@ -66,7 +66,7 @@ feature -- HTTP Methods n: CMS_NODE lnk: CMS_LOCAL_LINK hdate: HTTP_DATE - page_number:NATURAL_16 + page_number, tmp:NATURAL_16 do -- At the moment the template is hardcoded, but we can -- get them from the configuration file and load them into @@ -81,7 +81,7 @@ feature -- HTTP Methods page_number := page_number_path_parameter (req) end - -- Ensure that page is never 0 (happens if /blogs/ is routed) + -- Ensure that page is never 0 (happens if /blogs/ is routed and then "" interpreted as 0) if page_number = 0 then page_number := 1 end create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api) @@ -96,10 +96,10 @@ feature -- HTTP Methods end s.append ("") - + -- Get the posts from the current page (given by page number and entries per page) if attached node_api.blogs_order_created_desc_limited (entries_per_page, (page_number-1) * entries_per_page) as lst then - -- Filter out blog entries from all nodes - --if n.content_type.is_equal ("blog") then + + -- List all posts of the blog s.append ("
            %N") across lst as ic @@ -108,23 +108,23 @@ feature -- HTTP Methods lnk := node_api.node_link (n) s.append ("
          • ") - -- Post date (creation) + -- Output the date of creation of the post if attached n.creation_date as l_modified then create hdate.make_from_date_time (l_modified) s.append (hdate.yyyy_mmm_dd_string) s.append (" ") end - -- Author + -- Output the author of the post if attached n.author as l_author then s.append ("by ") s.append (l_author.name) end - -- Title with link + -- Output the title of the post as a link (to the detail page) s.append (l_page.link (lnk.title, lnk.location, Void)) - -- Summary + -- Output the summary of the post and a more link to the detail page if attached n.summary as l_summary then s.append ("

            ") if attached api.format (n.format) as f then @@ -139,13 +139,32 @@ feature -- HTTP Methods s.append ("

          • %N") end + + -- End of post list s.append ("
          %N") - -- Show the pagination if there are more than one page - if more_than_one_page then - s.append ("
            ") + -- Pagination + s.append ("
            ") + -- If exist older posts show link to next page + if page_number < pages then + tmp := page_number + 1 + s.append (" << Older Posts ") end + + -- Delmiter + if page_number < pages AND page_number > 1 then + s.append (" | ") + end + + -- If exist newer posts show link to previous page + if page_number > 1 then + tmp := page_number -1 + s.append (" Newer Posts >> ") + end + + s.append ("
            ") + --end end From 261aeca3003e374483e679c6f4dfc00f965bd64b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Fri, 22 May 2015 12:34:30 +0200 Subject: [PATCH 16/24] Bugfix: Author was hidden I had to add the authors to each post after getting the list. Made a helper feature add_authors. --- examples/demo/modules/blog/cms_blog_api.e | 32 +++++++++++++++++-- .../demo/modules/blog/handler/blog_handler.e | 2 ++ .../handler/cms_node_type_webform_manager.e | 2 ++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/examples/demo/modules/blog/cms_blog_api.e b/examples/demo/modules/blog/cms_blog_api.e index f0fb9f1..4442bb7 100644 --- a/examples/demo/modules/blog/cms_blog_api.e +++ b/examples/demo/modules/blog/cms_blog_api.e @@ -46,13 +46,41 @@ feature -- Access node blogs_order_created_desc: LIST[CMS_NODE] -- List of nodes ordered by creation date (descending) do - Result := node_storage.blogs + Result := add_authors(node_storage.blogs) end blogs_order_created_desc_limited (a_limit:INTEGER_32; a_offset:INTEGER_32) : LIST[CMS_NODE] -- List of nodes ordered by creation date and limited by limit and offset + local + tmp: LIST[CMS_NODE] do - Result := node_storage.blogs_limited (a_limit, a_offset) + -- load all posts and add the authors to each post + Result := add_authors(node_storage.blogs_limited (a_limit, a_offset)) + + end + +feature {NONE} -- Helpers + + add_authors(posts: LIST[CMS_NODE]) : LIST[CMS_NODE] + -- sets the authors of all given sql results + do + Result := posts + if posts /= Void then + across + Result + as + sql_result + loop + if + sql_result.item /= Void and then + attached {CMS_PARTIAL_USER} sql_result.item.author as l_partial_author + then + if attached cms_api.user_api.user_by_id (l_partial_author.id) as l_author then + sql_result.item.set_author (l_author) + end + end + end + end end end diff --git a/examples/demo/modules/blog/handler/blog_handler.e b/examples/demo/modules/blog/handler/blog_handler.e index bfec0e7..4498368 100644 --- a/examples/demo/modules/blog/handler/blog_handler.e +++ b/examples/demo/modules/blog/handler/blog_handler.e @@ -33,6 +33,8 @@ inherit REFACTORING_HELPER + CMS_API_ACCESS + create make diff --git a/modules/node/handler/cms_node_type_webform_manager.e b/modules/node/handler/cms_node_type_webform_manager.e index 697e73b..7ee2140 100644 --- a/modules/node/handler/cms_node_type_webform_manager.e +++ b/modules/node/handler/cms_node_type_webform_manager.e @@ -54,9 +54,11 @@ feature -- Forms ... create fset.make fset.set_legend ("Body") + -- Add summary fset.extend (sum) fset.extend_html_text("
            ") + -- Add content (body) fset.extend (ta) fset.extend_html_text ("
            ") From db77c4024dd903bb000c51bfc67d5935233a803a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Fri, 22 May 2015 14:04:00 +0200 Subject: [PATCH 17/24] created blog.scss, added link to blogs/{user} Later we will list all posts of a user under the route blogs/{user} --- examples/demo/modules/blog/cms_blog_module.e | 2 +- .../demo/modules/blog/handler/blog_handler.e | 10 +++-- .../site/themes/bootstrap/assets/css/blog.css | 25 +++++++++++ .../site/themes/bootstrap/assets/css/node.css | 44 +++---------------- .../themes/bootstrap/assets/scss/blog.scss | 30 +++++++++++++ .../themes/bootstrap/assets/scss/node.scss | 22 +++++++--- examples/demo/site/themes/bootstrap/page.tpl | 4 ++ 7 files changed, 87 insertions(+), 50 deletions(-) create mode 100644 examples/demo/site/themes/bootstrap/assets/css/blog.css create mode 100644 examples/demo/site/themes/bootstrap/assets/scss/blog.scss diff --git a/examples/demo/modules/blog/cms_blog_module.e b/examples/demo/modules/blog/cms_blog_module.e index d247566..f2e795d 100644 --- a/examples/demo/modules/blog/cms_blog_module.e +++ b/examples/demo/modules/blog/cms_blog_module.e @@ -119,7 +119,7 @@ configure_web (a_api: CMS_API; a_node_api: CMS_BLOG_API; a_router: WSF_ROUTER) a_router.map_with_request_methods (l_uri_mapping, a_router.methods_get) -- We can add a page number after /blogs/ to get older posts - a_router.handle_with_request_methods ("/blogs/{page}", l_blog_handler, a_router.methods_get) + a_router.handle_with_request_methods ("/blogs/page/{page}", l_blog_handler, a_router.methods_get) end diff --git a/examples/demo/modules/blog/handler/blog_handler.e b/examples/demo/modules/blog/handler/blog_handler.e index 4498368..f23f0c0 100644 --- a/examples/demo/modules/blog/handler/blog_handler.e +++ b/examples/demo/modules/blog/handler/blog_handler.e @@ -102,7 +102,7 @@ feature -- HTTP Methods if attached node_api.blogs_order_created_desc_limited (entries_per_page, (page_number-1) * entries_per_page) as lst then -- List all posts of the blog - s.append ("
              %N") + s.append ("
                %N") across lst as ic loop @@ -120,11 +120,13 @@ feature -- HTTP Methods -- Output the author of the post if attached n.author as l_author then s.append ("by ") - s.append (l_author.name) + s.append ("" + l_author.name + "") end -- Output the title of the post as a link (to the detail page) + s.append ("") s.append (l_page.link (lnk.title, lnk.location, Void)) + s.append ("") -- Output the summary of the post and a more link to the detail page if attached n.summary as l_summary then @@ -151,7 +153,7 @@ feature -- HTTP Methods -- If exist older posts show link to next page if page_number < pages then tmp := page_number + 1 - s.append (" << Older Posts ") + s.append (" << Older Posts ") end -- Delmiter @@ -162,7 +164,7 @@ feature -- HTTP Methods -- If exist newer posts show link to previous page if page_number > 1 then tmp := page_number -1 - s.append (" Newer Posts >> ") + s.append (" Newer Posts >> ") end s.append ("") diff --git a/examples/demo/site/themes/bootstrap/assets/css/blog.css b/examples/demo/site/themes/bootstrap/assets/css/blog.css new file mode 100644 index 0000000..736608d --- /dev/null +++ b/examples/demo/site/themes/bootstrap/assets/css/blog.css @@ -0,0 +1,25 @@ +ul.cms_blog_nodes { + padding: 0; + margin: 0; +} +ul.cms_blog_nodes li.cms_type_blog { + list-style: none; + display: block; + margin-top: 20px; + padding-bottom: 20px; + border-bottom: 1px dotted black; +} +ul.cms_blog_nodes li.cms_type_blog .blog_title a { + color: black; + font-size: 18px; + text-decoration: none; + display: block; + margin: 6px 0; +} +ul.cms_blog_nodes li.cms_type_blog .blog_title a:hover { + color: #999; +} +ul.cms_blog_nodes li.cms_type_blog .blog_list_summary a { + margin-top: 20px; + display: block; +} diff --git a/examples/demo/site/themes/bootstrap/assets/css/node.css b/examples/demo/site/themes/bootstrap/assets/css/node.css index cc105b5..f4277ee 100644 --- a/examples/demo/site/themes/bootstrap/assets/css/node.css +++ b/examples/demo/site/themes/bootstrap/assets/css/node.css @@ -3,49 +3,15 @@ ul.cms-nodes { padding: 3px 3px 3px 3px; border: solid 1px #ccc; } - -.cms-nodes li.cms_type_page, .cms-nodes li.cms_type_blog { +ul.cms-nodes li { border-top: dotted 1px #ccc; } -li.cms_type_page a::before { - content: "[page] "; -} -.cms-nodes li.cms_type_blog a::before { - content: "[blog] "; -} ul.cms-nodes li:first-child { border-top: none; } - -.summary{ - margin-top:20px; - font-weight:bold; +ul.cms-nodes li.cms_type_page a::before { + content: "[page] "; } -.cms-blog-nodes{ - padding:0; - margin:0; +ul.cms-nodes li.cms_type_blog a::before { + content: "[blog] "; } -.cms-blog-nodes li{ - list-style: none; - display: block; - margin-top:20px; - padding-bottom:20px; - border-bottom:1px dotted black; -} - -.cms-blog-nodes li > a{ - color:black; - font-size:18px; - text-decoration: none; - display:block; - margin:6px 0; -} - -.cms-blog-nodes li > a:hover{ - color:#999; -} - -.blog_list_summary a{ - margin-top:20px; - display:block; -} \ No newline at end of file diff --git a/examples/demo/site/themes/bootstrap/assets/scss/blog.scss b/examples/demo/site/themes/bootstrap/assets/scss/blog.scss new file mode 100644 index 0000000..be90622 --- /dev/null +++ b/examples/demo/site/themes/bootstrap/assets/scss/blog.scss @@ -0,0 +1,30 @@ +ul.cms_blog_nodes{ + + padding:0; + margin:0; + + li.cms_type_blog{ + list-style: none; + display: block; + margin-top:20px; + padding-bottom:20px; + border-bottom:1px dotted black; + + .blog_title a{ + color:black; + font-size:18px; + text-decoration: none; + display:block; + margin:6px 0; + + &:hover{ + color:#999; + } + } + + .blog_list_summary a{ + margin-top:20px; + display:block; + } + } +} \ No newline at end of file diff --git a/examples/demo/site/themes/bootstrap/assets/scss/node.scss b/examples/demo/site/themes/bootstrap/assets/scss/node.scss index cd7408f..5cf9324 100644 --- a/examples/demo/site/themes/bootstrap/assets/scss/node.scss +++ b/examples/demo/site/themes/bootstrap/assets/scss/node.scss @@ -1,14 +1,24 @@ ul.cms-nodes { + list-style-type: none; padding: 3px 3px 3px 3px; border: solid 1px #ccc; -} -li.cms_type_page { - a::before { + + li{ + border-top: dotted 1px #ccc; + &:first-child { + border-top: none; + } + } + + li.cms_type_page a::before { content: "[page] "; } - border-top: dotted 1px #ccc; - &:first-child { - border-top: none; + + li.cms_type_blog a::before { + content: "[blog] "; } + + } + diff --git a/examples/demo/site/themes/bootstrap/page.tpl b/examples/demo/site/themes/bootstrap/page.tpl index 9bf0155..1785e28 100644 --- a/examples/demo/site/themes/bootstrap/page.tpl +++ b/examples/demo/site/themes/bootstrap/page.tpl @@ -6,6 +6,10 @@ + + + + From 2b0e1a2b845735d3df3325b66f97799315b32458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Fri, 22 May 2015 14:39:43 +0200 Subject: [PATCH 18/24] Improved structure of blog handler --- .../demo/modules/blog/handler/blog_handler.e | 142 ++++++++++++------ 1 file changed, 96 insertions(+), 46 deletions(-) diff --git a/examples/demo/modules/blog/handler/blog_handler.e b/examples/demo/modules/blog/handler/blog_handler.e index f23f0c0..72ed0d7 100644 --- a/examples/demo/modules/blog/handler/blog_handler.e +++ b/examples/demo/modules/blog/handler/blog_handler.e @@ -67,8 +67,7 @@ feature -- HTTP Methods s: STRING n: CMS_NODE lnk: CMS_LOCAL_LINK - hdate: HTTP_DATE - page_number, tmp:NATURAL_16 + page_number:NATURAL_16 do -- At the moment the template is hardcoded, but we can -- get them from the configuration file and load them into @@ -110,36 +109,17 @@ feature -- HTTP Methods lnk := node_api.node_link (n) s.append ("
              • ") - -- Output the date of creation of the post - if attached n.creation_date as l_modified then - create hdate.make_from_date_time (l_modified) - s.append (hdate.yyyy_mmm_dd_string) - s.append (" ") - end + -- Output the creation date + s.append (creation_date_html(n)) -- Output the author of the post - if attached n.author as l_author then - s.append ("by ") - s.append ("" + l_author.name + "") - end + s.append (author_html(n)) -- Output the title of the post as a link (to the detail page) - s.append ("") - s.append (l_page.link (lnk.title, lnk.location, Void)) - s.append ("") + s.append (title_html(n, l_page)) -- Output the summary of the post and a more link to the detail page - if attached n.summary as l_summary then - s.append ("

                ") - if attached api.format (n.format) as f then - s.append (f.formatted_output (l_summary)) - else - s.append (l_page.formats.default_format.formatted_output (l_summary)) - end - s.append ("
                ") - s.append (l_page.link ("See more...", lnk.location, Void)) - s.append ("

                ") - end + s.append (summary_html(n, l_page)) s.append ("
              • %N") end @@ -148,26 +128,7 @@ feature -- HTTP Methods s.append ("
              %N") -- Pagination - s.append ("
              ") - - -- If exist older posts show link to next page - if page_number < pages then - tmp := page_number + 1 - s.append (" << Older Posts ") - end - - -- Delmiter - if page_number < pages AND page_number > 1 then - s.append (" | ") - end - - -- If exist newer posts show link to previous page - if page_number > 1 then - tmp := page_number -1 - s.append (" Newer Posts >> ") - end - - s.append ("
              ") + s.append (pagination_html(page_number)) --end end @@ -210,4 +171,93 @@ feature {NONE} -- Query end end +feature {NONE} -- HTML Output + + creation_date_html (n: CMS_NODE) : STRING + -- returns the creation date. At the moment hard coded as html + local + hdate: HTTP_DATE + do + Result := "" + if attached n.creation_date as l_modified then + create hdate.make_from_date_time (l_modified) + Result.append (hdate.yyyy_mmm_dd_string) + Result.append (" ") + end + end + + author_html (n: CMS_NODE) : STRING + -- returns a html string with a link to the autors posts + do + Result := "" + if attached n.author as l_author then + Result.append ("by ") + Result.append ("" + l_author.name + "") + end + end + + title_html (n: CMS_NODE; page : CMS_RESPONSE) : STRING + -- returns a html string the title of the node that links on the detail page + local + lnk: CMS_LOCAL_LINK + do + lnk := node_api.node_link (n) + Result := "" + Result.append (page.link (lnk.title, lnk.location, Void)) + Result.append ("") + end + + summary_html (n: CMS_NODE; page : CMS_RESPONSE) : STRING + -- returns a html string with the summary of the node and a link to the detail page + local + lnk: CMS_LOCAL_LINK + do + Result := "" + lnk := node_api.node_link (n) + if attached n.summary as l_summary then + Result.append ("

              ") + if attached api.format (n.format) as f then + Result.append (f.formatted_output (l_summary)) + else + Result.append (page.formats.default_format.formatted_output (l_summary)) + end + Result.append ("
              ") + Result.append (page.link ("See more...", lnk.location, Void)) + Result.append ("

              ") + end + end + + pagination_html (page_number: NATURAL_16) : STRING + -- returns a html string with the pagination links (if necessary) + local + tmp: NATURAL_16 + do + Result := "" + if more_than_one_page then + + Result.append ("
              ") + + -- If exist older posts show link to next page + if page_number < pages then + tmp := page_number + 1 + Result.append (" << Older Posts ") + end + + -- Delmiter + if page_number < pages AND page_number > 1 then + Result.append (" | ") + end + + -- If exist newer posts show link to previous page + if page_number > 1 then + tmp := page_number -1 + Result.append (" Newer Posts >> ") + end + + Result.append ("
              ") + + end + + end + end From 601b88ab367247e764b19c59e10e3da8ec980d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Fri, 22 May 2015 15:34:32 +0200 Subject: [PATCH 19/24] blog handler optimized, blog user handler created --- examples/demo/modules/blog/cms_blog_api.e | 2 +- examples/demo/modules/blog/cms_blog_config.e | 4 +- examples/demo/modules/blog/cms_blog_module.e | 12 +- .../demo/modules/blog/handler/blog_handler.e | 166 ++++++++++-------- .../modules/blog/handler/blog_user_handler.e | 16 ++ .../blog/persistence/cms_blog_storage_i.e | 2 +- .../blog/persistence/cms_blog_storage_null.e | 2 +- .../blog/persistence/cms_blog_storage_sql.e | 2 +- 8 files changed, 121 insertions(+), 85 deletions(-) create mode 100644 examples/demo/modules/blog/handler/blog_user_handler.e diff --git a/examples/demo/modules/blog/cms_blog_api.e b/examples/demo/modules/blog/cms_blog_api.e index 4442bb7..4c279c3 100644 --- a/examples/demo/modules/blog/cms_blog_api.e +++ b/examples/demo/modules/blog/cms_blog_api.e @@ -49,7 +49,7 @@ feature -- Access node Result := add_authors(node_storage.blogs) end - blogs_order_created_desc_limited (a_limit:INTEGER_32; a_offset:INTEGER_32) : LIST[CMS_NODE] + blogs_order_created_desc_limited (a_limit:NATURAL_32; a_offset:NATURAL_32) : LIST[CMS_NODE] -- List of nodes ordered by creation date and limited by limit and offset local tmp: LIST[CMS_NODE] diff --git a/examples/demo/modules/blog/cms_blog_config.e b/examples/demo/modules/blog/cms_blog_config.e index 61a3d87..6be55d8 100644 --- a/examples/demo/modules/blog/cms_blog_config.e +++ b/examples/demo/modules/blog/cms_blog_config.e @@ -8,9 +8,9 @@ class CMS_BLOG_CONFIG -feature {BLOG_HANDLER}-- Configuration of blog handler +feature -- Configuration of blog handlers - entries_per_page : INTEGER + entries_per_page : NATURAL_32 -- The numbers of posts that are shown on one page. If there are more post a pagination is generated do -- For test reasons this is 2, so we don't have to create a lot of blog entries. diff --git a/examples/demo/modules/blog/cms_blog_module.e b/examples/demo/modules/blog/cms_blog_module.e index f2e795d..8e1f48e 100644 --- a/examples/demo/modules/blog/cms_blog_module.e +++ b/examples/demo/modules/blog/cms_blog_module.e @@ -1,7 +1,8 @@ note - description: "Summary description for {CMS_BLOG_MODULE}." - date: "$Date: 2015-02-13 13:08:13 +0100 (ven., 13 févr. 2015) $" - revision: "$Revision: 96616 $" + description: "Displays all posts (pages with type blog). It's possible to list posts by user." + author: "Dario Bösch " + date: "$Date: 2015-05-22 15:13:00 +0100 (lun., 18 mai 2015) $" + revision: "$Revision 96616$" class CMS_BLOG_MODULE @@ -109,10 +110,12 @@ feature -- Access: router configure_web (a_api: CMS_API; a_node_api: CMS_BLOG_API; a_router: WSF_ROUTER) local l_blog_handler: BLOG_HANDLER + l_blog_user_handler: BLOG_USER_HANDLER l_uri_mapping: WSF_URI_MAPPING do -- TODO: for now, focused only on web interface, add REST api later. [2015-May-18] create l_blog_handler.make (a_api, a_node_api) + create l_blog_user_handler.make (a_api, a_node_api) -- Let the class BLOG_HANDLER handle the requests on "/blogs" create l_uri_mapping.make_trailing_slash_ignored("/blogs", l_blog_handler) @@ -121,6 +124,9 @@ configure_web (a_api: CMS_API; a_node_api: CMS_BLOG_API; a_router: WSF_ROUTER) -- We can add a page number after /blogs/ to get older posts a_router.handle_with_request_methods ("/blogs/page/{page}", l_blog_handler, a_router.methods_get) + -- If a user id is given route with blog user handler + a_router.handle_with_request_methods ("/blogs/user/{user}", l_blog_user_handler, a_router.methods_get) + end feature -- Hooks diff --git a/examples/demo/modules/blog/handler/blog_handler.e b/examples/demo/modules/blog/handler/blog_handler.e index 72ed0d7..354496c 100644 --- a/examples/demo/modules/blog/handler/blog_handler.e +++ b/examples/demo/modules/blog/handler/blog_handler.e @@ -1,8 +1,8 @@ note description: "Request handler related to /blogs." author: "Dario Bösch " - date: "$Date: 2015-05-18 13:49:99 +0100 (lun., 18 mai 2015) $" - revision: "$966167$" + date: "$Date: 2015-05-18 13:49:00 +0100 (lun., 18 mai 2015) $" + revision: "$9661667$" class BLOG_HANDLER @@ -64,114 +64,128 @@ feature -- HTTP Methods -- local l_page: CMS_RESPONSE - s: STRING - n: CMS_NODE - lnk: CMS_LOCAL_LINK - page_number:NATURAL_16 + page_number:NATURAL_32 do -- At the moment the template is hardcoded, but we can -- get them from the configuration file and load them into -- the setup class. - --Check if a page is given, if not start with page 1 - if req.path_info.ends_with_general ("/blogs") then - -- No page number given, set to 0 - page_number := 1 - else - -- Read page number from get variable - page_number := page_number_path_parameter (req) - end - - -- Ensure that page is never 0 (happens if /blogs/ is routed and then "" interpreted as 0) - if page_number = 0 then page_number := 1 end + -- Read the page number from get variable + page_number := page_number_path_parameter (req) create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api) l_page.add_variable (node_api.nodes, "nodes") - - - -- Output the title. If more than one page, also output the current page number - create s.make_from_string ("

              Blog") - if more_than_one_page then - s.append (" (Page " + page_number.out + " of " + pages.out + ")") - -- Get the posts from the current page (limited by entries per page) - end - s.append ("

              ") - - -- Get the posts from the current page (given by page number and entries per page) - if attached node_api.blogs_order_created_desc_limited (entries_per_page, (page_number-1) * entries_per_page) as lst then - - -- List all posts of the blog - s.append ("
                %N") - across - lst as ic - loop - n := ic.item - lnk := node_api.node_link (n) - s.append ("
              • ") - - -- Output the creation date - s.append (creation_date_html(n)) - - -- Output the author of the post - s.append (author_html(n)) - - -- Output the title of the post as a link (to the detail page) - s.append (title_html(n, l_page)) - - -- Output the summary of the post and a more link to the detail page - s.append (summary_html(n, l_page)) - - s.append ("
              • %N") - end - - -- End of post list - s.append ("
              %N") - - -- Pagination - s.append (pagination_html(page_number)) - - --end - end - - l_page.set_main_content (s) + l_page.set_main_content (main_content_html(page_number, l_page)) l_page.add_block (create {CMS_CONTENT_BLOCK}.make ("nodes_warning", Void, "/blogs/ is not yet fully implemented
              ", Void), "highlighted") l_page.execute end -feature {NONE} -- Query +feature -- Query + + posts (page_number: NATURAL_32) : LIST[CMS_NODE] + -- The posts to list on the given page + do + Result := node_api.blogs_order_created_desc_limited (entries_per_page, (page_number-1) * entries_per_page) + end more_than_one_page : BOOLEAN -- Checks if all posts fit on one page (FALSE) or if more than one page is needed (TRUE) do - Result := entries_per_page < node_api.blogs_count + Result := entries_per_page < total_entries end - pages : NATURAL_16 + pages : NATURAL_32 -- Returns the number of pages needed to display all posts require entries_per_page > 0 local tmp: REAL_32 do - tmp := node_api.blogs_count.to_real / entries_per_page.to_real; - Result := tmp.ceiling.to_natural_16 + tmp := total_entries.to_real_32 / entries_per_page.to_real_32; + Result := tmp.ceiling.to_natural_32 end - page_number_path_parameter (req: WSF_REQUEST): NATURAL_16 - -- Returns the page number from the path /blogs/{page}. It's an unsigned integere since negative pages are not allowed + page_number_path_parameter (req: WSF_REQUEST): NATURAL_32 + -- Returns the page number from the path /blogs/{page}. It's an unsigned integer since negative pages are not allowed local s: STRING do + Result := 1 -- default if not get variable is set if attached {WSF_STRING} req.path_parameter ("page") as p_page then s := p_page.value - if s.is_natural_16 then - Result := s.to_natural_16 + if s.is_natural_32 then + if s.to_natural_32 > 1 then + Result := s.to_natural_32 + end end end end -feature {NONE} -- HTML Output + total_entries : NATURAL_32 + -- Returns the number of total entries/posts + do + Result := node_api.blogs_count.to_natural_32 + end + +feature -- HTML Output + + main_content_html (page_number: NATURAL_32; page: CMS_RESPONSE) : STRING + -- Return the content of the page as a html string + local + n: CMS_NODE + lnk: CMS_LOCAL_LINK + do + -- Output the title. If more than one page, also output the current page number + create Result.make_from_string (page_title_html(page_number)) + + -- Get the posts from the current page (given by page number and entries per page) + if attached posts(page_number) as lst then + + -- List all posts of the blog + Result.append ("
                %N") + across + lst as ic + loop + n := ic.item + lnk := node_api.node_link (n) + Result.append ("
              • ") + + -- Output the creation date + Result.append (creation_date_html(n)) + + -- Output the author of the post + Result.append (author_html(n)) + + -- Output the title of the post as a link (to the detail page) + Result.append (title_html(n, page)) + + -- Output the summary of the post and a more link to the detail page + Result.append (summary_html(n, page)) + + Result.append ("
              • %N") + end + + -- End of post list + Result.append ("
              %N") + + -- Pagination + Result.append (pagination_html(page_number)) + + --end + end + end + + page_title_html (page_number: NATURAL_32) : STRING + -- Returns the title of the page as a html string. It shows the current page number + do + create Result.make_from_string ("

              Blog") + if more_than_one_page then + Result.append (" (Page " + page_number.out + " of " + pages.out + ")") + -- Get the posts from the current page (limited by entries per page) + end + Result.append ("

              ") + end creation_date_html (n: CMS_NODE) : STRING -- returns the creation date. At the moment hard coded as html @@ -227,10 +241,10 @@ feature {NONE} -- HTML Output end end - pagination_html (page_number: NATURAL_16) : STRING + pagination_html (page_number: NATURAL_32) : STRING -- returns a html string with the pagination links (if necessary) local - tmp: NATURAL_16 + tmp: NATURAL_32 do Result := "" if more_than_one_page then diff --git a/examples/demo/modules/blog/handler/blog_user_handler.e b/examples/demo/modules/blog/handler/blog_user_handler.e new file mode 100644 index 0000000..ce065a9 --- /dev/null +++ b/examples/demo/modules/blog/handler/blog_user_handler.e @@ -0,0 +1,16 @@ +note + description: "Request handler related to /blogs/user/{id}/. Displays all posts of the given user" + author: "Dario Bösch " + date: "$Date: 2015-05-22 15:13:00 +0100 (lun., 18 mai 2015) $" + revision: "$Revision 96616$" + +class + BLOG_USER_HANDLER + +inherit + BLOG_HANDLER + +create + make + +end diff --git a/examples/demo/modules/blog/persistence/cms_blog_storage_i.e b/examples/demo/modules/blog/persistence/cms_blog_storage_i.e index 334f6b3..258052a 100644 --- a/examples/demo/modules/blog/persistence/cms_blog_storage_i.e +++ b/examples/demo/modules/blog/persistence/cms_blog_storage_i.e @@ -21,7 +21,7 @@ feature -- Access deferred end - blogs_limited (limit:INTEGER_32; offset:INTEGER_32) : LIST[CMS_NODE] + blogs_limited (limit:NATURAL_32; offset:NATURAL_32) : LIST[CMS_NODE] -- List of nodes ordered by creation date from limit to limit + offset deferred end diff --git a/examples/demo/modules/blog/persistence/cms_blog_storage_null.e b/examples/demo/modules/blog/persistence/cms_blog_storage_null.e index 328fc69..4ab0f0c 100644 --- a/examples/demo/modules/blog/persistence/cms_blog_storage_null.e +++ b/examples/demo/modules/blog/persistence/cms_blog_storage_null.e @@ -28,7 +28,7 @@ feature -- Access create {ARRAYED_LIST [CMS_NODE]} Result.make (0) end - blogs_limited (limit:INTEGER_32; offset:INTEGER_32) : LIST[CMS_NODE] + blogs_limited (limit:NATURAL_32; offset:NATURAL_32) : LIST[CMS_NODE] -- List of nodes ordered by creation date from limit to limit + offset do create {ARRAYED_LIST [CMS_NODE]} Result.make (0) diff --git a/examples/demo/modules/blog/persistence/cms_blog_storage_sql.e b/examples/demo/modules/blog/persistence/cms_blog_storage_sql.e index 5dcbf6a..758e6ba 100644 --- a/examples/demo/modules/blog/persistence/cms_blog_storage_sql.e +++ b/examples/demo/modules/blog/persistence/cms_blog_storage_sql.e @@ -49,7 +49,7 @@ feature -- Access end end - blogs_limited (a_limit:INTEGER_32; a_offset:INTEGER_32) : LIST[CMS_NODE] + blogs_limited (a_limit:NATURAL_32; a_offset:NATURAL_32) : LIST[CMS_NODE] -- List of nodes ordered by creation date from limit to limit + offset local l_parameters: STRING_TABLE [detachable ANY] From 9b169f70a71c1e6027fc1a10553d5e675aa95953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Fri, 22 May 2015 15:43:29 +0200 Subject: [PATCH 20/24] page_number global in blog_handler --- .../demo/modules/blog/handler/blog_handler.e | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/examples/demo/modules/blog/handler/blog_handler.e b/examples/demo/modules/blog/handler/blog_handler.e index 354496c..e818a23 100644 --- a/examples/demo/modules/blog/handler/blog_handler.e +++ b/examples/demo/modules/blog/handler/blog_handler.e @@ -58,13 +58,14 @@ feature -- execute execute (req, res) end +feature -- Global Variables + page_number: NATURAL_32 feature -- HTTP Methods do_get (req: WSF_REQUEST; res: WSF_RESPONSE) -- local l_page: CMS_RESPONSE - page_number:NATURAL_32 do -- At the moment the template is hardcoded, but we can -- get them from the configuration file and load them into @@ -75,19 +76,19 @@ feature -- HTTP Methods create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api) l_page.add_variable (node_api.nodes, "nodes") - l_page.set_main_content (main_content_html(page_number, l_page)) - l_page.add_block (create {CMS_CONTENT_BLOCK}.make ("nodes_warning", Void, "/blogs/ is not yet fully implemented
              ", Void), "highlighted") + l_page.set_main_content (main_content_html(l_page)) l_page.execute end feature -- Query - posts (page_number: NATURAL_32) : LIST[CMS_NODE] + posts : LIST[CMS_NODE] -- The posts to list on the given page do Result := node_api.blogs_order_created_desc_limited (entries_per_page, (page_number-1) * entries_per_page) end + more_than_one_page : BOOLEAN -- Checks if all posts fit on one page (FALSE) or if more than one page is needed (TRUE) do @@ -130,17 +131,17 @@ feature -- Query feature -- HTML Output - main_content_html (page_number: NATURAL_32; page: CMS_RESPONSE) : STRING + main_content_html (page: CMS_RESPONSE) : STRING -- Return the content of the page as a html string local n: CMS_NODE lnk: CMS_LOCAL_LINK do -- Output the title. If more than one page, also output the current page number - create Result.make_from_string (page_title_html(page_number)) + create Result.make_from_string (page_title_html) -- Get the posts from the current page (given by page number and entries per page) - if attached posts(page_number) as lst then + if attached posts as lst then -- List all posts of the blog Result.append ("
                %N") @@ -170,13 +171,13 @@ feature -- HTML Output Result.append ("
              %N") -- Pagination - Result.append (pagination_html(page_number)) + Result.append (pagination_html) --end end end - page_title_html (page_number: NATURAL_32) : STRING + page_title_html : STRING -- Returns the title of the page as a html string. It shows the current page number do create Result.make_from_string ("

              Blog") @@ -241,7 +242,7 @@ feature -- HTML Output end end - pagination_html (page_number: NATURAL_32) : STRING + pagination_html : STRING -- returns a html string with the pagination links (if necessary) local tmp: NATURAL_32 From 0bd75e7c59515857025077ad2eb5929d8c5bfb40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Fri, 22 May 2015 17:31:30 +0200 Subject: [PATCH 21/24] Added list of posts of a specific user Similar to the blog handler the blog user handler routes /blogs/users/{id}. Pagination is implemented as well --- examples/demo/modules/blog/cms_blog_api.e | 16 +++ examples/demo/modules/blog/cms_blog_module.e | 3 + .../demo/modules/blog/handler/blog_handler.e | 13 +- .../modules/blog/handler/blog_user_handler.e | 123 ++++++++++++++++++ .../blog/persistence/cms_blog_storage_i.e | 12 +- .../blog/persistence/cms_blog_storage_null.e | 13 +- .../blog/persistence/cms_blog_storage_sql.e | 52 +++++++- src/persistence/sql/cms_storage_sql_builder.e | 5 + 8 files changed, 230 insertions(+), 7 deletions(-) diff --git a/examples/demo/modules/blog/cms_blog_api.e b/examples/demo/modules/blog/cms_blog_api.e index 4c279c3..95a9509 100644 --- a/examples/demo/modules/blog/cms_blog_api.e +++ b/examples/demo/modules/blog/cms_blog_api.e @@ -43,6 +43,12 @@ feature -- Access node Result := node_storage.blogs_count end + blogs_count_from_user (user_id: INTEGER_64) : INTEGER_64 + -- Number of nodes of type blog from user with user_id + do + Result := node_storage.blogs_count_from_user(user_id) + end + blogs_order_created_desc: LIST[CMS_NODE] -- List of nodes ordered by creation date (descending) do @@ -59,6 +65,16 @@ feature -- Access node end + blogs_from_user_order_created_desc_limited (a_user_id: INTEGER_32; a_limit:NATURAL_32; a_offset:NATURAL_32) : LIST[CMS_NODE] + -- List of nodes ordered by creation date and limited by limit and offset + local + tmp: LIST[CMS_NODE] + do + -- load all posts and add the authors to each post + Result := add_authors(node_storage.blogs_from_user_limited (a_user_id, a_limit, a_offset)) + + end + feature {NONE} -- Helpers add_authors(posts: LIST[CMS_NODE]) : LIST[CMS_NODE] diff --git a/examples/demo/modules/blog/cms_blog_module.e b/examples/demo/modules/blog/cms_blog_module.e index 8e1f48e..65c47a1 100644 --- a/examples/demo/modules/blog/cms_blog_module.e +++ b/examples/demo/modules/blog/cms_blog_module.e @@ -127,6 +127,9 @@ configure_web (a_api: CMS_API; a_node_api: CMS_BLOG_API; a_router: WSF_ROUTER) -- If a user id is given route with blog user handler a_router.handle_with_request_methods ("/blogs/user/{user}", l_blog_user_handler, a_router.methods_get) + -- If a user id is given we also want to allow different pages + a_router.handle_with_request_methods ("/blogs/user/{user}/page/{page}", l_blog_user_handler, a_router.methods_get) + end feature -- Hooks diff --git a/examples/demo/modules/blog/handler/blog_handler.e b/examples/demo/modules/blog/handler/blog_handler.e index e818a23..c0a04ab 100644 --- a/examples/demo/modules/blog/handler/blog_handler.e +++ b/examples/demo/modules/blog/handler/blog_handler.e @@ -75,7 +75,6 @@ feature -- HTTP Methods page_number := page_number_path_parameter (req) create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api) - l_page.add_variable (node_api.nodes, "nodes") l_page.set_main_content (main_content_html(l_page)) l_page.execute end @@ -88,7 +87,7 @@ feature -- Query do Result := node_api.blogs_order_created_desc_limited (entries_per_page, (page_number-1) * entries_per_page) end - + more_than_one_page : BOOLEAN -- Checks if all posts fit on one page (FALSE) or if more than one page is needed (TRUE) do @@ -255,7 +254,7 @@ feature -- HTML Output -- If exist older posts show link to next page if page_number < pages then tmp := page_number + 1 - Result.append (" << Older Posts ") + Result.append (" << Older Posts ") end -- Delmiter @@ -266,7 +265,7 @@ feature -- HTML Output -- If exist newer posts show link to previous page if page_number > 1 then tmp := page_number -1 - Result.append (" Newer Posts >> ") + Result.append (" Newer Posts >> ") end Result.append ("") @@ -275,4 +274,10 @@ feature -- HTML Output end + base_path : STRING + -- the path to the page that lists all blogs + do + Result := "/blogs" + end + end diff --git a/examples/demo/modules/blog/handler/blog_user_handler.e b/examples/demo/modules/blog/handler/blog_user_handler.e index ce065a9..d20667a 100644 --- a/examples/demo/modules/blog/handler/blog_user_handler.e +++ b/examples/demo/modules/blog/handler/blog_user_handler.e @@ -9,8 +9,131 @@ class inherit BLOG_HANDLER + redefine + do_get, + posts, + total_entries, + page_title_html, + base_path + end create make + +feature -- Global Variables + + user : detachable CMS_USER + +feature -- HTTP Methods + + do_get (req: WSF_REQUEST; res: WSF_RESPONSE) + -- + local + l_error: GENERIC_VIEW_CMS_RESPONSE + do + -- Check if userID valid + if user_valid (req) then + user := load_user(req) + precursor(req, res) + else + -- Throw a bad request error if the user is not valid + create l_error.make (req, res, api) + l_error.set_main_content ("

              Error

              User with id " + user_path_parameter(req).out + " doesn't exist!") + l_error.execute + end + + end + +feature -- Query + + user_valid (req: WSF_REQUEST) : BOOLEAN + -- Returns true if a valid user id is given and a user with this id exists; otherwise returns false. + local + user_id: INTEGER_32 + do + + user_id := user_path_parameter(req) + + if user_id <= 0 then + --Given user id is not valid + Result := false + else + --Check if user with user_id exists + Result := api.user_api.user_by_id (user_id) /= Void + end + end + + load_user (req: WSF_REQUEST) : detachable CMS_USER + -- Returnes the user with the given id in the request req + require + user_valid(req) + do + Result := api.user_api.user_by_id (user_path_parameter(req)) + end + + user_path_parameter (req: WSF_REQUEST): INTEGER_32 + -- Returns the user id from the path /blogs/{user}. It's an unsigned integer since negative ids are not allowed. If no valid id can be read it returns -1 + local + s: STRING + do + if attached {WSF_STRING} req.path_parameter ("user") as user_id then + s := user_id.value + if s.is_integer_32 then + if s.to_integer_32 > 0 then + Result := s.to_integer_32 + end + end + end + end + + posts : LIST[CMS_NODE] + -- The posts to list on the given page + do + if attached user as l_user then + Result := node_api.blogs_from_user_order_created_desc_limited (l_user.id.to_integer_32, entries_per_page, (page_number-1) * entries_per_page) + else + create {ARRAYED_LIST [CMS_NODE]} Result.make (0) + end + end + + total_entries : NATURAL_32 + -- Returns the number of total entries/posts + do + if attached user as l_user then + Result := node_api.blogs_count_from_user(l_user.id).to_natural_32 + else + Result := precursor + end + + end + +feature -- HTML Output + + page_title_html : STRING + -- Returns the title of the page as a html string. It shows the current page number + do + create Result.make_from_string ("

              Posts from ") + if attached user as l_user then + Result.append(l_user.name) + else + Result.append ("unknown user") + end + if more_than_one_page then + Result.append (" (Page " + page_number.out + " of " + pages.out + ")") + -- Get the posts from the current page (limited by entries per page) + end + Result.append ("

              ") + end + + base_path : STRING + -- the path to the page that lists all blogs + do + if attached user as l_user then + Result := "/blogs/user/" + l_user.id.out + else + Result := precursor + end + end + end diff --git a/examples/demo/modules/blog/persistence/cms_blog_storage_i.e b/examples/demo/modules/blog/persistence/cms_blog_storage_i.e index 258052a..8fd8ca7 100644 --- a/examples/demo/modules/blog/persistence/cms_blog_storage_i.e +++ b/examples/demo/modules/blog/persistence/cms_blog_storage_i.e @@ -16,13 +16,23 @@ feature -- Access deferred end + blogs_count_from_user (user_id: INTEGER_64) : INTEGER_64 + -- Number of nodes of type blog from user with user_id + deferred + end + blogs: LIST [CMS_NODE] -- List of nodes ordered by creation date (descending). deferred end blogs_limited (limit:NATURAL_32; offset:NATURAL_32) : LIST[CMS_NODE] - -- List of nodes ordered by creation date from limit to limit + offset + -- List of posts ordered by creation date from offset to offset + limit + deferred + end + + blogs_from_user_limited (user_id: INTEGER_32; limit:NATURAL_32; offset:NATURAL_32) : LIST[CMS_NODE] + -- List of posts from user_id ordered by creation date from offset to offset + limit deferred end diff --git a/examples/demo/modules/blog/persistence/cms_blog_storage_null.e b/examples/demo/modules/blog/persistence/cms_blog_storage_null.e index 4ab0f0c..d208190 100644 --- a/examples/demo/modules/blog/persistence/cms_blog_storage_null.e +++ b/examples/demo/modules/blog/persistence/cms_blog_storage_null.e @@ -22,6 +22,11 @@ feature -- Access do end + blogs_count_from_user (user_id: INTEGER_64) : INTEGER_64 + -- Number of nodes of type blog from user with user_id + do + end + blogs: LIST[CMS_NODE] -- List of nodes. do @@ -29,7 +34,13 @@ feature -- Access end blogs_limited (limit:NATURAL_32; offset:NATURAL_32) : LIST[CMS_NODE] - -- List of nodes ordered by creation date from limit to limit + offset + -- List of posts ordered by creation date from offset to offset + limit + do + create {ARRAYED_LIST [CMS_NODE]} Result.make (0) + end + + blogs_from_user_limited (user_id: INTEGER_32; limit:NATURAL_32; offset:NATURAL_32) : LIST[CMS_NODE] + -- List of posts from user_id ordered by creation date from offset to offset + limit do create {ARRAYED_LIST [CMS_NODE]} Result.make (0) end diff --git a/examples/demo/modules/blog/persistence/cms_blog_storage_sql.e b/examples/demo/modules/blog/persistence/cms_blog_storage_sql.e index 758e6ba..915ad20 100644 --- a/examples/demo/modules/blog/persistence/cms_blog_storage_sql.e +++ b/examples/demo/modules/blog/persistence/cms_blog_storage_sql.e @@ -28,6 +28,21 @@ feature -- Access end end + blogs_count_from_user (user_id: INTEGER_64) : INTEGER_64 + -- Number of nodes of type blog from user with user_id + local + l_parameters: STRING_TABLE [detachable ANY] + do + error_handler.reset + write_information_log (generator + ".nodes_count") + create l_parameters.make (2) + l_parameters.put (user_id, "user") + sql_query (sql_select_blog_count_from_user, l_parameters) + if sql_rows_count = 1 then + Result := sql_read_integer_64 (1) + end + end + blogs: LIST [CMS_NODE] -- List of nodes ordered by creation date (descending). do @@ -75,16 +90,51 @@ feature -- Access end end + blogs_from_user_limited (a_user_id:INTEGER_32; a_limit:NATURAL_32; a_offset:NATURAL_32) : LIST[CMS_NODE] + -- List of posts of the author with a_user_id ordered by creation date starting at offset and limited by limit + local + l_parameters: STRING_TABLE [detachable ANY] + do + create {ARRAYED_LIST [CMS_NODE]} Result.make (0) + + error_handler.reset + write_information_log (generator + ".nodes") + + from + create l_parameters.make (2) + l_parameters.put (a_limit, "limit") + l_parameters.put (a_offset, "offset") + l_parameters.put (a_user_id, "user") + sql_query (sql_blogs_from_user_limited, l_parameters) + sql_start + until + sql_after + loop + if attached fetch_node as l_node then + Result.force (l_node) + end + sql_forth + end + end + feature {NONE} -- Queries sql_select_blog_count: STRING = "SELECT count(*) FROM Nodes WHERE status != -1 AND type = %"blog%";" -- Nodes count (Published and not Published) --| note: {CMS_NODE_API}.trashed = -1 + sql_select_blog_count_from_user: STRING = "SELECT count(*) FROM Nodes WHERE status != -1 AND type = %"blog%" AND author = :user ;" + -- Nodes count (Published and not Published) + --| note: {CMS_NODE_API}.trashed = -1 + sql_select_blogs_order_created_desc: STRING = "SELECT * FROM Nodes WHERE status != -1 AND type = %"blog%" ORDER BY created DESC;" -- SQL Query to retrieve all nodes that are from the type "blog" ordered by descending creation date. sql_blogs_limited: STRING = "SELECT * FROM Nodes WHERE status != -1 AND type = %"blog%" ORDER BY created DESC LIMIT :limit OFFSET :offset ;" - --- SQL Query to retrieve all node of type "blog" from limit to limit + offset + --- SQL Query to retrieve all node of type "blog" limited by limit and starting at offset + + sql_blogs_from_user_limited: STRING = "SELECT * FROM Nodes WHERE status != -1 AND type = %"blog%" AND author = :user ORDER BY created DESC LIMIT :limit OFFSET :offset ;" + --- SQL Query to retrieve all node of type "blog" from author with id limited by limit + offset + end diff --git a/src/persistence/sql/cms_storage_sql_builder.e b/src/persistence/sql/cms_storage_sql_builder.e index 6000207..8c9fe69 100644 --- a/src/persistence/sql/cms_storage_sql_builder.e +++ b/src/persistence/sql/cms_storage_sql_builder.e @@ -36,6 +36,11 @@ feature -- Initialization create u.make ("admin") u.set_password ("istrator#") u.set_email (a_setup.site_email) + a_storage.new_user (u) + + create u.make ("daboesch") + u.set_password ("eiffel") + u.set_email ("daboesch@student.ethz.ch") a_storage.new_user (u) --| Node From e8ff313c284a98bffcdaf34792b54db9a3e8da0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Fri, 22 May 2015 17:58:46 +0200 Subject: [PATCH 22/24] added some commments --- examples/demo/modules/blog/cms_blog_api.e | 3 ++- examples/demo/modules/blog/handler/blog_handler.e | 15 ++++++--------- .../demo/modules/blog/handler/blog_user_handler.e | 13 +++++++------ .../demo/modules/blog/handler/cms_blog_handler.e | 8 ++++---- src/persistence/sql/cms_storage_sql_builder.e | 5 ----- 5 files changed, 19 insertions(+), 25 deletions(-) diff --git a/examples/demo/modules/blog/cms_blog_api.e b/examples/demo/modules/blog/cms_blog_api.e index 95a9509..e75593c 100644 --- a/examples/demo/modules/blog/cms_blog_api.e +++ b/examples/demo/modules/blog/cms_blog_api.e @@ -1,5 +1,5 @@ note - description: "API to handle nodes of type blog" + description: "API to handle nodes of type blog. Extends the node API." author: "Dario Bösch do Precursor + -- Create the node storage for type blog if attached {CMS_STORAGE_SQL_I} storage as l_storage_sql then create {CMS_BLOG_STORAGE_SQL} node_storage.make (l_storage_sql) else diff --git a/examples/demo/modules/blog/handler/blog_handler.e b/examples/demo/modules/blog/handler/blog_handler.e index c0a04ab..536681c 100644 --- a/examples/demo/modules/blog/handler/blog_handler.e +++ b/examples/demo/modules/blog/handler/blog_handler.e @@ -1,5 +1,5 @@ note - description: "Request handler related to /blogs." + description: "Request handler related to /blogs and /blogs/{page}. Displays all posts in the blog." author: "Dario Bösch " date: "$Date: 2015-05-18 13:49:00 +0100 (lun., 18 mai 2015) $" revision: "$9661667$" @@ -67,13 +67,11 @@ feature -- HTTP Methods local l_page: CMS_RESPONSE do - -- At the moment the template is hardcoded, but we can - -- get them from the configuration file and load them into - -- the setup class. -- Read the page number from get variable page_number := page_number_path_parameter (req) + -- execute response by setting the main content create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api) l_page.set_main_content (main_content_html(l_page)) l_page.execute @@ -83,7 +81,7 @@ feature -- Query posts : LIST[CMS_NODE] - -- The posts to list on the given page + -- The posts to list on the given page ordered by date (descending) do Result := node_api.blogs_order_created_desc_limited (entries_per_page, (page_number-1) * entries_per_page) end @@ -142,7 +140,7 @@ feature -- HTML Output -- Get the posts from the current page (given by page number and entries per page) if attached posts as lst then - -- List all posts of the blog + -- Start list of posts Result.append ("
                %N") across lst as ic @@ -169,7 +167,7 @@ feature -- HTML Output -- End of post list Result.append ("
              %N") - -- Pagination + -- Pagination (older and newer links) Result.append (pagination_html) --end @@ -182,13 +180,12 @@ feature -- HTML Output create Result.make_from_string ("

              Blog") if more_than_one_page then Result.append (" (Page " + page_number.out + " of " + pages.out + ")") - -- Get the posts from the current page (limited by entries per page) end Result.append ("

              ") end creation_date_html (n: CMS_NODE) : STRING - -- returns the creation date. At the moment hard coded as html + -- returns the creation date as a html string local hdate: HTTP_DATE do diff --git a/examples/demo/modules/blog/handler/blog_user_handler.e b/examples/demo/modules/blog/handler/blog_user_handler.e index d20667a..58fff51 100644 --- a/examples/demo/modules/blog/handler/blog_user_handler.e +++ b/examples/demo/modules/blog/handler/blog_user_handler.e @@ -1,5 +1,5 @@ note - description: "Request handler related to /blogs/user/{id}/. Displays all posts of the given user" + description: "Request handler related to /blogs/user/{id}/ or /blogs/user/{id}/page/{page}. Displays all posts of the given user" author: "Dario Bösch " date: "$Date: 2015-05-22 15:13:00 +0100 (lun., 18 mai 2015) $" revision: "$Revision 96616$" @@ -35,9 +35,10 @@ feature -- HTTP Methods -- Check if userID valid if user_valid (req) then user := load_user(req) + -- Output the results, similar as in the blog hanlder (but with other queries) precursor(req, res) else - -- Throw a bad request error if the user is not valid + -- Throw a bad request error because the user is not valid create l_error.make (req, res, api) l_error.set_main_content ("

              Error

              User with id " + user_path_parameter(req).out + " doesn't exist!") l_error.execute @@ -88,7 +89,7 @@ feature -- Query end posts : LIST[CMS_NODE] - -- The posts to list on the given page + -- The posts to list on the given page. Filters out the posts of the current user do if attached user as l_user then Result := node_api.blogs_from_user_order_created_desc_limited (l_user.id.to_integer_32, entries_per_page, (page_number-1) * entries_per_page) @@ -98,7 +99,7 @@ feature -- Query end total_entries : NATURAL_32 - -- Returns the number of total entries/posts + -- Returns the number of total entries/posts of the current user do if attached user as l_user then Result := node_api.blogs_count_from_user(l_user.id).to_natural_32 @@ -111,7 +112,7 @@ feature -- Query feature -- HTML Output page_title_html : STRING - -- Returns the title of the page as a html string. It shows the current page number + -- Returns the title of the page as a html string. It shows the current page number and the name of the current user do create Result.make_from_string ("

              Posts from ") if attached user as l_user then @@ -127,7 +128,7 @@ feature -- HTML Output end base_path : STRING - -- the path to the page that lists all blogs + -- the path to the page that lists all blogs. It must include the user id do if attached user as l_user then Result := "/blogs/user/" + l_user.id.out diff --git a/examples/demo/modules/blog/handler/cms_blog_handler.e b/examples/demo/modules/blog/handler/cms_blog_handler.e index c33d834..bef34e5 100644 --- a/examples/demo/modules/blog/handler/cms_blog_handler.e +++ b/examples/demo/modules/blog/handler/cms_blog_handler.e @@ -1,8 +1,8 @@ note - description: "Summary description for {CMS_NODE_HANDLER}." - author: "" - date: "$Date: 2015-02-13 13:08:13 +0100 (ven., 13 févr. 2015) $" - revision: "$Revision: 96616 $" + description: "Deferred request handler related to /blogs/... Has an own blog api." + author: "Dario Bösch " + date: "$Date: 2015-05-18 13:49:00 +0100 (lun., 18 mai 2015) $" + revision: "$9661667$" deferred class CMS_BLOG_HANDLER diff --git a/src/persistence/sql/cms_storage_sql_builder.e b/src/persistence/sql/cms_storage_sql_builder.e index 8c9fe69..6000207 100644 --- a/src/persistence/sql/cms_storage_sql_builder.e +++ b/src/persistence/sql/cms_storage_sql_builder.e @@ -36,11 +36,6 @@ feature -- Initialization create u.make ("admin") u.set_password ("istrator#") u.set_email (a_setup.site_email) - a_storage.new_user (u) - - create u.make ("daboesch") - u.set_password ("eiffel") - u.set_email ("daboesch@student.ethz.ch") a_storage.new_user (u) --| Node From e35893fdb94a72018bd6cb784582b539f7b264d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20B=C3=B6sch?= Date: Sat, 23 May 2015 21:11:39 +0200 Subject: [PATCH 23/24] Integrated the CKEditor #7 and #8: The class CMS_EDITOR generates javascript code that replaces a textarea with a wysiwyg editor. Only a few methods have to be implemented by the subclasses, for example by CMD_EDITOR_CKEDITOR. The class CMS_FORM_TEXTAREA extends WSF_FORM_TEXTAREA with features to include the javascript from CMS_EDITOR. The most complex usage is shown in CMS_NODE_TYPE_WEBFORM_MANAGER, where the textarea is only replaced if "full_html" is selected as the desired body format. This works dynamically on the browser side as soon as the user selects another format. --- .../handler/cms_node_type_webform_manager.e | 19 ++- src/kernel/form/cms_editor.e | 108 ++++++++++++++++++ src/kernel/form/cms_editor_ckeditor.e | 37 ++++++ src/kernel/form/cms_form_textarea.e | 82 +++++++++++++ 4 files changed, 241 insertions(+), 5 deletions(-) create mode 100644 src/kernel/form/cms_editor.e create mode 100644 src/kernel/form/cms_editor_ckeditor.e create mode 100644 src/kernel/form/cms_form_textarea.e diff --git a/modules/node/handler/cms_node_type_webform_manager.e b/modules/node/handler/cms_node_type_webform_manager.e index 7ee2140..984f0d5 100644 --- a/modules/node/handler/cms_node_type_webform_manager.e +++ b/modules/node/handler/cms_node_type_webform_manager.e @@ -15,9 +15,10 @@ feature -- Forms ... local ti: WSF_FORM_TEXT_INPUT fset: WSF_FORM_FIELD_SET - ta, sum: WSF_FORM_TEXTAREA + ta, sum: CMS_FORM_TEXTAREA tselect: WSF_FORM_SELECT opt: WSF_FORM_SELECT_OPTION + full_format: FULL_HTML_CONTENT_FORMAT do create ti.make ("title") ti.set_label ("Title") @@ -30,10 +31,18 @@ feature -- Forms ... f.extend_html_text ("
              ") + -- Select field has to be initialized before textareas are replaced, because they depend on the selection of the field + create tselect.make ("format") + tselect.set_label ("Body's format") + tselect.set_is_required (True) + + + create full_format.default_create -- Main Content create ta.make ("body") ta.set_rows (10) ta.set_cols (70) + ta.show_as_editor_if_selected (tselect, full_format.name) if a_node /= Void then ta.set_text_value (a_node.content) end @@ -45,6 +54,8 @@ feature -- Forms ... create sum.make ("summary") sum.set_rows (10) sum.set_cols (70) + -- if full_html is selected + sum.show_as_editor_if_selected (tselect, full_format.name) if a_node /= Void then sum.set_text_value (a_node.summary) end @@ -58,14 +69,12 @@ feature -- Forms ... -- Add summary fset.extend (sum) fset.extend_html_text("
              ") - + -- Add content (body) fset.extend (ta) fset.extend_html_text ("
              ") - create tselect.make ("format") - tselect.set_label ("Body's format") - tselect.set_is_required (True) + across content_type.available_formats as c loop diff --git a/src/kernel/form/cms_editor.e b/src/kernel/form/cms_editor.e new file mode 100644 index 0000000..910ec42 --- /dev/null +++ b/src/kernel/form/cms_editor.e @@ -0,0 +1,108 @@ +note + description: "Class to import a WYSIWIG editor using javascript code" + author: "Dario Bösch + do + Result := "" + end + +feature -- Javascript + + javascript_replace_textarea (a_textarea : WSF_FORM_TEXTAREA) : STRING + -- + do + -- Replaces the textarea with an editor instance. Save the instance in a variable + Result := editor_variable(a_textarea) + " = CKEDITOR.replace( '" + a_textarea.name + "' );" + end + + javascript_restore_textarea (a_textarea : WSF_FORM_TEXTAREA) : STRING + -- + do + -- Replaces the textarea with an editor instance. Save the instance in a variable + Result := "if (" + editor_variable(a_textarea) + " != undefined) " + editor_variable(a_textarea) + ".destroy();" + end + +end diff --git a/src/kernel/form/cms_form_textarea.e b/src/kernel/form/cms_form_textarea.e new file mode 100644 index 0000000..4f68343 --- /dev/null +++ b/src/kernel/form/cms_form_textarea.e @@ -0,0 +1,82 @@ +note + description: "Extends the WSF form textarea with features to add a WYSIWIG editor." + author: "Dario Bösch + do + precursor(a_name) + + -- By default we don't replace the textarea by an editor + editor := False; + end + +feature -- Access + + editor : BOOLEAN + -- True if the textarea should be replaced by the editor. Default is false. + + format_field : detachable WSF_FORM_SELECT + -- Selection field for the format on that it depends, if the editor is shown or not. + + condition_value : detachable STRING + +feature -- Editor + + show_as_editor + -- The textarea will be replaced by a wysiwyg editor + do + editor := True + end + + show_as_editor_if_selected (a_select_field : WSF_FORM_SELECT; a_value : STRING) + -- Replaces the textarea only if a_select_field has a_value (or the value gets selected) + do + editor := True + format_field := a_select_field + condition_value := a_value + end + +feature -- Conversion + + + append_item_to_html (a_theme: WSF_THEME; a_html: STRING_8) + do + -- Add javascript to replace textarea with editor + precursor(a_theme, a_html) + if editor then + a_html.append (load_assets) + a_html.append ("") + end + end + +feature -- Javascript Output + + javascript_show_editor_on_full_html_select : STRING = "" + +end From c871eae10e535cb38c1b535d84d7ae6b86eae63b Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Wed, 27 May 2015 19:00:32 +0200 Subject: [PATCH 24/24] Renamed node_api and node_storage by blog_api and blog_storage in related CMS_BLOG_* classes. Mainly to avoid confusion with NODE_ classes. Merged CMS_BLOG_CONFIG with CMS_BLOG_API. In CMS_BLOG_API, prefer argument of type CMS_USER, rather than using directly user id. Added a CMS_EDITOR_CONTENT_FORMAT for now, to be the format editable by the WYSIWYG editor. Added CMS_MODULE.is_initialized: BOOLEAN to equip router, and module_api with expected preconditions. Fixed typo, especially in log output. Corrected a few routine names such as add_authors that should not be a function according to its name. Converted various function returning html content, to procedure appending html content to an output string to minimize temporary string object creation. Cosmetic: added spaces to make code easier to read, and indentation. --- examples/demo/modules/blog/cms_blog.e | 16 +- examples/demo/modules/blog/cms_blog_api.e | 99 +++++---- examples/demo/modules/blog/cms_blog_config.e | 21 -- examples/demo/modules/blog/cms_blog_module.e | 47 ++-- .../demo/modules/blog/cms_blog_node_type.e | 3 +- .../demo/modules/blog/handler/blog_handler.e | 201 +++++++++--------- .../modules/blog/handler/blog_user_handler.e | 104 +++++---- .../modules/blog/handler/cms_blog_handler.e | 9 +- .../blog/persistence/cms_blog_storage_i.e | 16 +- .../blog/persistence/cms_blog_storage_null.e | 16 +- .../blog/persistence/cms_blog_storage_sql.e | 30 +-- modules/node/cms_node_api.e | 1 - .../node/content_type/cms_page_node_type.e | 3 +- .../handler/cms_node_type_webform_manager.e | 27 ++- .../format/cms_editor_content_format.e | 31 +++ src/kernel/content/format/cms_formats.e | 9 +- src/kernel/form/cms_editor.e | 2 - src/kernel/form/cms_form_textarea.e | 27 +-- src/service/cms_api.e | 6 +- src/service/cms_module.e | 11 + 20 files changed, 376 insertions(+), 303 deletions(-) delete mode 100644 examples/demo/modules/blog/cms_blog_config.e create mode 100644 src/kernel/content/format/cms_editor_content_format.e diff --git a/examples/demo/modules/blog/cms_blog.e b/examples/demo/modules/blog/cms_blog.e index f697a1f..2d2a6d3 100644 --- a/examples/demo/modules/blog/cms_blog.e +++ b/examples/demo/modules/blog/cms_blog.e @@ -31,7 +31,13 @@ feature -- Conversion do Precursor (a_node) if attached {CMS_BLOG} a_node as l_blog then --- l_blog + if attached l_blog.tags as l_tags then + across + l_tags as ic + loop + add_tag (ic.item) + end + end end end @@ -42,7 +48,7 @@ feature -- Access Result := {CMS_BLOG_NODE_TYPE}.name end -feature -- Access: content +feature -- Access: node summary: detachable READABLE_STRING_8 -- A short summary of the node. @@ -54,10 +60,12 @@ feature -- Access: content -- Format associated with `content' and `summary'. -- For example: text, mediawiki, html, etc +feature -- Access: blog + tags: detachable ARRAYED_LIST [READABLE_STRING_32] -- Optional tags -feature -- Element change +feature -- Element change: node set_content (a_content: like content; a_summary: like summary; a_format: like format) do @@ -66,6 +74,8 @@ feature -- Element change format := a_format end +feature -- Element change: blog + add_tag (a_tag: READABLE_STRING_32) -- Set `parent' to `a_page' require diff --git a/examples/demo/modules/blog/cms_blog_api.e b/examples/demo/modules/blog/cms_blog_api.e index e75593c..c9128a9 100644 --- a/examples/demo/modules/blog/cms_blog_api.e +++ b/examples/demo/modules/blog/cms_blog_api.e @@ -8,93 +8,108 @@ class CMS_BLOG_API inherit - CMS_NODE_API + CMS_MODULE_API + rename + make as make_with_cms_api redefine - initialize, - node_storage + initialize end + REFACTORING_HELPER + create make -feature {NONE} -- Implementation +feature {NONE} -- Initialization + + make (a_api: CMS_API; a_node_api: CMS_NODE_API) + -- (from CMS_MODULE_API) + -- (export status {NONE}) + do + node_api := a_node_api + make_with_cms_api (a_api) + end initialize -- do Precursor - -- Create the node storage for type blog + + -- Create the node storage for type blog if attached {CMS_STORAGE_SQL_I} storage as l_storage_sql then - create {CMS_BLOG_STORAGE_SQL} node_storage.make (l_storage_sql) + create {CMS_BLOG_STORAGE_SQL} blog_storage.make (l_storage_sql) else - create {CMS_BLOG_STORAGE_NULL} node_storage.make + create {CMS_BLOG_STORAGE_NULL} blog_storage.make end - initialize_node_types +-- initialize_node_types end +feature {CMS_API_ACCESS, CMS_MODULE, CMS_API} -- Restricted access + + node_api: CMS_NODE_API + feature {CMS_MODULE} -- Access nodes storage. - node_storage: CMS_BLOG_STORAGE_I + blog_storage: CMS_BLOG_STORAGE_I + +feature -- Configuration of blog handlers + + entries_per_page : NATURAL_32 = 2 + -- The numbers of posts that are shown on one page. If there are more post a pagination is generated + --| For test reasons this is 2, so we don't have to create a lot of blog entries. + --| TODO: Set to bigger constant. feature -- Access node blogs_count: INTEGER_64 - -- Number of nodes of type blog + -- Number of nodes of type blog. do - Result := node_storage.blogs_count + Result := blog_storage.blogs_count end - blogs_count_from_user (user_id: INTEGER_64) : INTEGER_64 - -- Number of nodes of type blog from user with user_id + blogs_count_from_user (a_user: CMS_USER): INTEGER_64 + -- Number of nodes of type blog from user with `a_user_id'. + require + has_id: a_user.has_id do - Result := node_storage.blogs_count_from_user(user_id) + Result := blog_storage.blogs_count_from_user (a_user) end - blogs_order_created_desc: LIST[CMS_NODE] + blogs_order_created_desc: LIST [CMS_BLOG] -- List of nodes ordered by creation date (descending) do - Result := add_authors(node_storage.blogs) + Result := nodes_to_blogs (blog_storage.blogs) end - blogs_order_created_desc_limited (a_limit:NATURAL_32; a_offset:NATURAL_32) : LIST[CMS_NODE] + blogs_order_created_desc_limited (a_limit: NATURAL_32; a_offset: NATURAL_32): LIST [CMS_BLOG] -- List of nodes ordered by creation date and limited by limit and offset - local - tmp: LIST[CMS_NODE] do - -- load all posts and add the authors to each post - Result := add_authors(node_storage.blogs_limited (a_limit, a_offset)) - + -- load all posts and add the authors to each post + Result := nodes_to_blogs (blog_storage.blogs_limited (a_limit, a_offset)) end - blogs_from_user_order_created_desc_limited (a_user_id: INTEGER_32; a_limit:NATURAL_32; a_offset:NATURAL_32) : LIST[CMS_NODE] + blogs_from_user_order_created_desc_limited (a_user: CMS_USER; a_limit: NATURAL_32; a_offset: NATURAL_32) : LIST [CMS_BLOG] -- List of nodes ordered by creation date and limited by limit and offset - local - tmp: LIST[CMS_NODE] + require + has_id: a_user.has_id do - -- load all posts and add the authors to each post - Result := add_authors(node_storage.blogs_from_user_limited (a_user_id, a_limit, a_offset)) - + -- load all posts and add the authors to each post + Result := nodes_to_blogs (blog_storage.blogs_from_user_limited (a_user, a_limit, a_offset)) end feature {NONE} -- Helpers - add_authors(posts: LIST[CMS_NODE]) : LIST[CMS_NODE] - -- sets the authors of all given sql results + nodes_to_blogs (a_nodes: LIST [CMS_NODE]): ARRAYED_LIST [CMS_BLOG] + -- Convert list of nodes into a list of blog when possible. do - Result := posts - if posts /= Void then + create {ARRAYED_LIST [CMS_BLOG]} Result.make (a_nodes.count) + + if attached node_api as l_node_api then across - Result - as - sql_result + a_nodes as ic loop - if - sql_result.item /= Void and then - attached {CMS_PARTIAL_USER} sql_result.item.author as l_partial_author - then - if attached cms_api.user_api.user_by_id (l_partial_author.id) as l_author then - sql_result.item.set_author (l_author) - end + if attached {CMS_BLOG} l_node_api.full_node (ic.item) as l_blog then + Result.force (l_blog) end end end diff --git a/examples/demo/modules/blog/cms_blog_config.e b/examples/demo/modules/blog/cms_blog_config.e deleted file mode 100644 index 6be55d8..0000000 --- a/examples/demo/modules/blog/cms_blog_config.e +++ /dev/null @@ -1,21 +0,0 @@ -note - description: "Configuration class for the blog module." - author: "Dario Bösch + node_api: detachable CMS_NODE_API + feature -- Access: router setup_router (a_router: WSF_ROUTER; a_api: CMS_API) -- - local - l_node_api: like node_api do - l_node_api := node_api - if l_node_api = Void then - create l_node_api.make (a_api) - node_api := l_node_api + if attached blog_api as l_blog_api then + configure_web (a_api, l_blog_api, a_router) + else + -- Issue with api/dependencies, + -- thus Current module should not be used! + -- thus no url mapping end - configure_web (a_api, l_node_api, a_router) end - -configure_web (a_api: CMS_API; a_node_api: CMS_BLOG_API; a_router: WSF_ROUTER) + configure_web (a_api: CMS_API; a_blog_api: CMS_BLOG_API; a_router: WSF_ROUTER) + -- Configure router mapping for web interface. local l_blog_handler: BLOG_HANDLER l_blog_user_handler: BLOG_USER_HANDLER l_uri_mapping: WSF_URI_MAPPING do - -- TODO: for now, focused only on web interface, add REST api later. [2015-May-18] - create l_blog_handler.make (a_api, a_node_api) - create l_blog_user_handler.make (a_api, a_node_api) + -- TODO: for now, focused only on web interface, add REST api later. [2015-May-18] + create l_blog_handler.make (a_api, a_blog_api) + create l_blog_user_handler.make (a_api, a_blog_api) - -- Let the class BLOG_HANDLER handle the requests on "/blogs" - create l_uri_mapping.make_trailing_slash_ignored("/blogs", l_blog_handler) + -- Let the class BLOG_HANDLER handle the requests on "/blogs" + create l_uri_mapping.make_trailing_slash_ignored ("/blogs", l_blog_handler) a_router.map_with_request_methods (l_uri_mapping, a_router.methods_get) - -- We can add a page number after /blogs/ to get older posts + -- We can add a page number after /blogs/ to get older posts a_router.handle_with_request_methods ("/blogs/page/{page}", l_blog_handler, a_router.methods_get) - -- If a user id is given route with blog user handler + -- If a user id is given route with blog user handler + --| FIXME: maybe /user/{user}/blogs/ would be better. a_router.handle_with_request_methods ("/blogs/user/{user}", l_blog_user_handler, a_router.methods_get) - -- If a user id is given we also want to allow different pages + -- If a user id is given we also want to allow different pages + --| FIXME: what about /user/{user}/blogs/?page={page} ? a_router.handle_with_request_methods ("/blogs/user/{user}/page/{page}", l_blog_user_handler, a_router.methods_get) end diff --git a/examples/demo/modules/blog/cms_blog_node_type.e b/examples/demo/modules/blog/cms_blog_node_type.e index a393c41..92fd7f5 100644 --- a/examples/demo/modules/blog/cms_blog_node_type.e +++ b/examples/demo/modules/blog/cms_blog_node_type.e @@ -17,10 +17,11 @@ feature {NONE} -- Initialization default_create do Precursor - create {ARRAYED_LIST [like available_formats.item]} available_formats.make (3) + create {ARRAYED_LIST [like available_formats.item]} available_formats.make (4) available_formats.extend (create {PLAIN_TEXT_CONTENT_FORMAT}) available_formats.extend (create {FILTERED_HTML_CONTENT_FORMAT}) available_formats.extend (create {FULL_HTML_CONTENT_FORMAT}) + available_formats.extend (create {CMS_EDITOR_CONTENT_FORMAT}) end feature -- Access diff --git a/examples/demo/modules/blog/handler/blog_handler.e b/examples/demo/modules/blog/handler/blog_handler.e index 536681c..de30e17 100644 --- a/examples/demo/modules/blog/handler/blog_handler.e +++ b/examples/demo/modules/blog/handler/blog_handler.e @@ -8,8 +8,6 @@ class BLOG_HANDLER inherit - CMS_BLOG_CONFIG - CMS_BLOG_HANDLER WSF_URI_HANDLER @@ -41,60 +39,63 @@ create feature -- execute execute (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Execute request handler + -- Execute request handler for any kind of mapping. do execute_methods (req, res) end uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Execute request handler + -- Execute request handler for URI mapping. do execute (req, res) end uri_template_execute (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Execute request handler + -- Execute request handler for URI-template mapping. do execute (req, res) end feature -- Global Variables + page_number: NATURAL_32 + -- Current page number. feature -- HTTP Methods + do_get (req: WSF_REQUEST; res: WSF_RESPONSE) -- local l_page: CMS_RESPONSE do - - -- Read the page number from get variable + -- Read page number from path parameter. page_number := page_number_path_parameter (req) - -- execute response by setting the main content + -- Responding with `main_content_html (l_page)'. create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api) - l_page.set_main_content (main_content_html(l_page)) + l_page.set_main_content (main_content_html (l_page)) l_page.execute end feature -- Query - - posts : LIST[CMS_NODE] - -- The posts to list on the given page ordered by date (descending) + posts: LIST [CMS_NODE] + -- Blog posts to display on given page ordered by date (descending). do - Result := node_api.blogs_order_created_desc_limited (entries_per_page, (page_number-1) * entries_per_page) + Result := blog_api.blogs_order_created_desc_limited ( + entries_per_page, + entries_per_page * (page_number - 1) + ) end - more_than_one_page : BOOLEAN - -- Checks if all posts fit on one page (FALSE) or if more than one page is needed (TRUE) + multiple_pages_needed : BOOLEAN + -- Return if more that one page is needed to display posts. do Result := entries_per_page < total_entries end - - pages : NATURAL_32 - -- Returns the number of pages needed to display all posts + pages_count: NATURAL_32 + -- Number of pages needed to display all posts. require entries_per_page > 0 local @@ -105,7 +106,8 @@ feature -- Query end page_number_path_parameter (req: WSF_REQUEST): NATURAL_32 - -- Returns the page number from the path /blogs/{page}. It's an unsigned integer since negative pages are not allowed + -- Page number from path /blogs/{page}. + -- Unsigned integer since negative pages are not allowed. local s: STRING do @@ -120,153 +122,150 @@ feature -- Query end end - total_entries : NATURAL_32 - -- Returns the number of total entries/posts + total_entries: NATURAL_32 + -- Total number of entries/posts. do - Result := node_api.blogs_count.to_natural_32 + Result := blog_api.blogs_count.to_natural_32 end feature -- HTML Output - main_content_html (page: CMS_RESPONSE) : STRING - -- Return the content of the page as a html string + frozen main_content_html (page: CMS_RESPONSE): STRING + -- Content of the page as a html string. + do + create Result.make_empty + append_main_content_html_to (page, Result) + end + + append_main_content_html_to (page: CMS_RESPONSE; a_output: STRING) + -- Append to `a_output, the content of the page as a html string. local n: CMS_NODE lnk: CMS_LOCAL_LINK do - -- Output the title. If more than one page, also output the current page number - create Result.make_from_string (page_title_html) + -- Output the title. If more than one page, also output the current page number + append_page_title_html_to (a_output) - -- Get the posts from the current page (given by page number and entries per page) - if attached posts as lst then + -- Get the posts from the current page (given by page number and entries per page) + -- Start list of posts + a_output.append ("
                %N") + across + posts as ic + loop + n := ic.item + lnk := blog_api.node_api.node_link (n) + a_output.append ("
              • ") - -- Start list of posts - Result.append ("
                  %N") - across - lst as ic - loop - n := ic.item - lnk := node_api.node_link (n) - Result.append ("
                • ") + -- Output the creation date + append_creation_date_html_to (n, a_output) - -- Output the creation date - Result.append (creation_date_html(n)) + -- Output the author of the post + append_author_html_to (n, a_output) - -- Output the author of the post - Result.append (author_html(n)) + -- Output the title of the post as a link (to the detail page) + append_title_html_to (n, page, a_output) - -- Output the title of the post as a link (to the detail page) - Result.append (title_html(n, page)) + -- Output the summary of the post and a more link to the detail page + append_summary_html_to (n, page, a_output) - -- Output the summary of the post and a more link to the detail page - Result.append (summary_html(n, page)) - - Result.append ("
                • %N") - end - - -- End of post list - Result.append ("
                %N") - - -- Pagination (older and newer links) - Result.append (pagination_html) - - --end + a_output.append ("
              • %N") end + + -- End of post list + a_output.append ("
              %N") + + -- Pagination (older and newer links) + append_pagination_html_to (a_output) end - page_title_html : STRING - -- Returns the title of the page as a html string. It shows the current page number + append_page_title_html_to (a_output: STRING) + -- Append the title of the page as a html string to `a_output'. + -- It shows the current page number. do - create Result.make_from_string ("

              Blog") - if more_than_one_page then - Result.append (" (Page " + page_number.out + " of " + pages.out + ")") + a_output.append ("

              Blog") + if multiple_pages_needed then + a_output.append (" (Page " + page_number.out + " of " + pages_count.out + ")") end - Result.append ("

              ") + a_output.append ("

              ") end - creation_date_html (n: CMS_NODE) : STRING - -- returns the creation date as a html string + append_creation_date_html_to (n: CMS_NODE; a_output: STRING) + -- Append the creation date as a html string to `a_output'. local hdate: HTTP_DATE do - Result := "" if attached n.creation_date as l_modified then create hdate.make_from_date_time (l_modified) - Result.append (hdate.yyyy_mmm_dd_string) - Result.append (" ") + hdate.append_to_yyyy_mmm_dd_string (a_output) + a_output.append (" ") end end - author_html (n: CMS_NODE) : STRING - -- returns a html string with a link to the autors posts + append_author_html_to (n: CMS_NODE; a_output: STRING) + -- Append to `a_output', the author of node `n' as html link to author's posts. do - Result := "" if attached n.author as l_author then - Result.append ("by ") - Result.append ("" + l_author.name + "") + a_output.append ("by ") + a_output.append ("" + l_author.name + "") end end - title_html (n: CMS_NODE; page : CMS_RESPONSE) : STRING - -- returns a html string the title of the node that links on the detail page + append_title_html_to (n: CMS_NODE; page: CMS_RESPONSE; a_output: STRING) + -- Append to `a_output', the title of node `n' as html link to detail page. local lnk: CMS_LOCAL_LINK do - lnk := node_api.node_link (n) - Result := "" - Result.append (page.link (lnk.title, lnk.location, Void)) - Result.append ("") + lnk := blog_api.node_api.node_link (n) + a_output.append ("") + a_output.append (page.link (lnk.title, lnk.location, Void)) + a_output.append ("") end - summary_html (n: CMS_NODE; page : CMS_RESPONSE) : STRING + append_summary_html_to (n: CMS_NODE; page: CMS_RESPONSE; a_output: STRING) -- returns a html string with the summary of the node and a link to the detail page local lnk: CMS_LOCAL_LINK do - Result := "" - lnk := node_api.node_link (n) if attached n.summary as l_summary then - Result.append ("

              ") + lnk := blog_api.node_api.node_link (n) + a_output.append ("

              ") if attached api.format (n.format) as f then - Result.append (f.formatted_output (l_summary)) + a_output.append (f.formatted_output (l_summary)) else - Result.append (page.formats.default_format.formatted_output (l_summary)) + a_output.append (page.formats.default_format.formatted_output (l_summary)) end - Result.append ("
              ") - Result.append (page.link ("See more...", lnk.location, Void)) - Result.append ("

              ") + a_output.append ("
              ") + a_output.append (page.link ("See more...", lnk.location, Void)) + a_output.append ("

              ") end end - pagination_html : STRING - -- returns a html string with the pagination links (if necessary) + append_pagination_html_to (a_output: STRING) + -- Append to `a_output' with the pagination links (if necessary). local tmp: NATURAL_32 do - Result := "" - if more_than_one_page then + if multiple_pages_needed then + a_output.append ("
              ") - Result.append ("
              ") - - -- If exist older posts show link to next page - if page_number < pages then + -- If exist older posts show link to next page + if page_number < pages_count then tmp := page_number + 1 - Result.append (" << Older Posts ") + a_output.append (" << Older Posts ") end - -- Delmiter - if page_number < pages AND page_number > 1 then - Result.append (" | ") + -- Delimiter + if page_number < pages_count AND page_number > 1 then + a_output.append (" | ") end -- If exist newer posts show link to previous page if page_number > 1 then tmp := page_number -1 - Result.append (" Newer Posts >> ") + a_output.append (" Newer Posts >> ") end - Result.append ("
              ") - + a_output.append ("
              ") end end diff --git a/examples/demo/modules/blog/handler/blog_user_handler.e b/examples/demo/modules/blog/handler/blog_user_handler.e index 58fff51..961fe35 100644 --- a/examples/demo/modules/blog/handler/blog_user_handler.e +++ b/examples/demo/modules/blog/handler/blog_user_handler.e @@ -1,5 +1,11 @@ note - description: "Request handler related to /blogs/user/{id}/ or /blogs/user/{id}/page/{page}. Displays all posts of the given user" + description: "[ + Request handler related to + /blogs/user/{id}/ + or /blogs/user/{id}/page/{page}. + + Displays all posts of the given user + ]" author: "Dario Bösch " date: "$Date: 2015-05-22 15:13:00 +0100 (lun., 18 mai 2015) $" revision: "$Revision 96616$" @@ -13,14 +19,13 @@ inherit do_get, posts, total_entries, - page_title_html, + append_page_title_html_to, base_path end create make - feature -- Global Variables user : detachable CMS_USER @@ -30,71 +35,76 @@ feature -- HTTP Methods do_get (req: WSF_REQUEST; res: WSF_RESPONSE) -- local - l_error: GENERIC_VIEW_CMS_RESPONSE + l_error: NOT_FOUND_ERROR_CMS_RESPONSE do - -- Check if userID valid - if user_valid (req) then - user := load_user(req) - -- Output the results, similar as in the blog hanlder (but with other queries) - precursor(req, res) + user := Void + if attached user_from_request (req) as l_user then + user := l_user + -- Output the results, similar as in the blog hanlder (but with other queries) + Precursor (req, res) else - -- Throw a bad request error because the user is not valid + -- Throw a bad request error because the user is not valid create l_error.make (req, res, api) - l_error.set_main_content ("

              Error

              User with id " + user_path_parameter(req).out + " doesn't exist!") + l_error.set_main_content ("

              Error

              User with id " + user_id_path_parameter (req).out + " doesn't exist!") l_error.execute end - end feature -- Query user_valid (req: WSF_REQUEST) : BOOLEAN - -- Returns true if a valid user id is given and a user with this id exists; otherwise returns false. + -- Returns true if a valid user id is given and a user with this id exists, + -- otherwise returns false. local user_id: INTEGER_32 do - - user_id := user_path_parameter(req) + user_id := user_id_path_parameter (req) if user_id <= 0 then - --Given user id is not valid - Result := false + -- Given user id is not valid + Result := False else - --Check if user with user_id exists + --Check if user with user_id exists Result := api.user_api.user_by_id (user_id) /= Void end end - load_user (req: WSF_REQUEST) : detachable CMS_USER - -- Returnes the user with the given id in the request req - require - user_valid(req) + user_from_request (req: WSF_REQUEST): detachable CMS_USER + -- Eventual user with given id in the path of request `req'. + local + uid: like user_id_path_parameter do - Result := api.user_api.user_by_id (user_path_parameter(req)) + uid := user_id_path_parameter (req) + if uid > 0 then + Result := api.user_api.user_by_id (uid) + else + -- Missing or invalid user id. + end end - user_path_parameter (req: WSF_REQUEST): INTEGER_32 - -- Returns the user id from the path /blogs/{user}. It's an unsigned integer since negative ids are not allowed. If no valid id can be read it returns -1 + user_id_path_parameter (req: WSF_REQUEST): INTEGER_32 + -- User id from path /blogs/{user}. + -- Unsigned integer since negative ids are not allowed. + -- If no valid id can be read it returns -1 local s: STRING do - if attached {WSF_STRING} req.path_parameter ("user") as user_id then - s := user_id.value - if s.is_integer_32 then - if s.to_integer_32 > 0 then - Result := s.to_integer_32 - end + Result := -1 + if attached {WSF_STRING} req.path_parameter ("user") as l_user_id then + if l_user_id.is_integer then + Result := l_user_id.integer_value end end end - posts : LIST[CMS_NODE] - -- The posts to list on the given page. Filters out the posts of the current user + posts: LIST [CMS_BLOG] + -- Blog posts to display on given page. + -- Filters out the posts of the current user. do if attached user as l_user then - Result := node_api.blogs_from_user_order_created_desc_limited (l_user.id.to_integer_32, entries_per_page, (page_number-1) * entries_per_page) + Result := blog_api.blogs_from_user_order_created_desc_limited (l_user, entries_per_page, entries_per_page * (page_number - 1)) else - create {ARRAYED_LIST [CMS_NODE]} Result.make (0) + create {ARRAYED_LIST [CMS_BLOG]} Result.make (0) end end @@ -102,33 +112,33 @@ feature -- Query -- Returns the number of total entries/posts of the current user do if attached user as l_user then - Result := node_api.blogs_count_from_user(l_user.id).to_natural_32 + Result := blog_api.blogs_count_from_user (l_user).to_natural_32 else - Result := precursor + Result := Precursor end - end feature -- HTML Output - page_title_html : STRING + append_page_title_html_to (a_output: STRING) -- Returns the title of the page as a html string. It shows the current page number and the name of the current user do - create Result.make_from_string ("

              Posts from ") + a_output.append ("

              Posts from ") if attached user as l_user then - Result.append(l_user.name) + a_output.append (l_user.name) else - Result.append ("unknown user") + a_output.append ("unknown user") end - if more_than_one_page then - Result.append (" (Page " + page_number.out + " of " + pages.out + ")") - -- Get the posts from the current page (limited by entries per page) + if multiple_pages_needed then + a_output.append (" (Page " + page_number.out + " of " + pages_count.out + ")") + -- Get the posts from the current page (limited by entries per page) end - Result.append ("

              ") + a_output.append ("

              ") end base_path : STRING - -- the path to the page that lists all blogs. It must include the user id + -- Path to page listing all blogs. + -- If user is logged in, include user id do if attached user as l_user then Result := "/blogs/user/" + l_user.id.out diff --git a/examples/demo/modules/blog/handler/cms_blog_handler.e b/examples/demo/modules/blog/handler/cms_blog_handler.e index bef34e5..450096f 100644 --- a/examples/demo/modules/blog/handler/cms_blog_handler.e +++ b/examples/demo/modules/blog/handler/cms_blog_handler.e @@ -10,7 +10,14 @@ deferred class inherit CMS_MODULE_HANDLER [CMS_BLOG_API] rename - module_api as node_api + module_api as blog_api + end + +feature -- Access + + entries_per_page: NATURAL_32 + do + Result := blog_api.entries_per_page end end diff --git a/examples/demo/modules/blog/persistence/cms_blog_storage_i.e b/examples/demo/modules/blog/persistence/cms_blog_storage_i.e index 8fd8ca7..08c2447 100644 --- a/examples/demo/modules/blog/persistence/cms_blog_storage_i.e +++ b/examples/demo/modules/blog/persistence/cms_blog_storage_i.e @@ -16,8 +16,10 @@ feature -- Access deferred end - blogs_count_from_user (user_id: INTEGER_64) : INTEGER_64 - -- Number of nodes of type blog from user with user_id + blogs_count_from_user (a_user: CMS_USER) : INTEGER_64 + -- Number of nodes of type blog from `a_user'. + require + has_id: a_user.has_id deferred end @@ -26,13 +28,15 @@ feature -- Access deferred end - blogs_limited (limit:NATURAL_32; offset:NATURAL_32) : LIST[CMS_NODE] - -- List of posts ordered by creation date from offset to offset + limit + blogs_limited (limit: NATURAL_32; offset: NATURAL_32): LIST [CMS_NODE] + -- List of posts ordered by creation date from offset to offset + limit. deferred end - blogs_from_user_limited (user_id: INTEGER_32; limit:NATURAL_32; offset:NATURAL_32) : LIST[CMS_NODE] - -- List of posts from user_id ordered by creation date from offset to offset + limit + blogs_from_user_limited (a_user: CMS_USER; limit: NATURAL_32; offset: NATURAL_32): LIST [CMS_NODE] + -- List of posts from `a_user' ordered by creation date from offset to offset + limit. + require + has_id: a_user.has_id deferred end diff --git a/examples/demo/modules/blog/persistence/cms_blog_storage_null.e b/examples/demo/modules/blog/persistence/cms_blog_storage_null.e index d208190..40a860f 100644 --- a/examples/demo/modules/blog/persistence/cms_blog_storage_null.e +++ b/examples/demo/modules/blog/persistence/cms_blog_storage_null.e @@ -22,25 +22,25 @@ feature -- Access do end - blogs_count_from_user (user_id: INTEGER_64) : INTEGER_64 - -- Number of nodes of type blog from user with user_id + blogs_count_from_user (a_user: CMS_USER) : INTEGER_64 + -- do end - blogs: LIST[CMS_NODE] - -- List of nodes. + blogs: LIST [CMS_NODE] + -- do create {ARRAYED_LIST [CMS_NODE]} Result.make (0) end - blogs_limited (limit:NATURAL_32; offset:NATURAL_32) : LIST[CMS_NODE] - -- List of posts ordered by creation date from offset to offset + limit + blogs_limited (limit: NATURAL_32; offset: NATURAL_32) : LIST [CMS_NODE] + -- do create {ARRAYED_LIST [CMS_NODE]} Result.make (0) end - blogs_from_user_limited (user_id: INTEGER_32; limit:NATURAL_32; offset:NATURAL_32) : LIST[CMS_NODE] - -- List of posts from user_id ordered by creation date from offset to offset + limit + blogs_from_user_limited (a_user: CMS_USER; limit: NATURAL_32; offset: NATURAL_32): LIST [CMS_NODE] + -- do create {ARRAYED_LIST [CMS_NODE]} Result.make (0) end diff --git a/examples/demo/modules/blog/persistence/cms_blog_storage_sql.e b/examples/demo/modules/blog/persistence/cms_blog_storage_sql.e index 915ad20..ad07f62 100644 --- a/examples/demo/modules/blog/persistence/cms_blog_storage_sql.e +++ b/examples/demo/modules/blog/persistence/cms_blog_storage_sql.e @@ -18,25 +18,25 @@ create feature -- Access blogs_count: INTEGER_64 - -- Count of blog nodes + -- do error_handler.reset - write_information_log (generator + ".nodes_count") + write_information_log (generator + ".blogs_count") sql_query (sql_select_blog_count, Void) if sql_rows_count = 1 then Result := sql_read_integer_64 (1) end end - blogs_count_from_user (user_id: INTEGER_64) : INTEGER_64 - -- Number of nodes of type blog from user with user_id + blogs_count_from_user (a_user: CMS_USER) : INTEGER_64 + -- local l_parameters: STRING_TABLE [detachable ANY] do error_handler.reset - write_information_log (generator + ".nodes_count") + write_information_log (generator + ".blogs_count_from_user") create l_parameters.make (2) - l_parameters.put (user_id, "user") + l_parameters.put (a_user.id, "user") sql_query (sql_select_blog_count_from_user, l_parameters) if sql_rows_count = 1 then Result := sql_read_integer_64 (1) @@ -44,12 +44,12 @@ feature -- Access end blogs: LIST [CMS_NODE] - -- List of nodes ordered by creation date (descending). + -- do create {ARRAYED_LIST [CMS_NODE]} Result.make (0) error_handler.reset - write_information_log (generator + ".nodes") + write_information_log (generator + ".blogs") from sql_query (sql_select_blogs_order_created_desc, Void) @@ -64,15 +64,15 @@ feature -- Access end end - blogs_limited (a_limit:NATURAL_32; a_offset:NATURAL_32) : LIST[CMS_NODE] - -- List of nodes ordered by creation date from limit to limit + offset + blogs_limited (a_limit: NATURAL_32; a_offset: NATURAL_32): LIST [CMS_NODE] + -- local l_parameters: STRING_TABLE [detachable ANY] do create {ARRAYED_LIST [CMS_NODE]} Result.make (0) error_handler.reset - write_information_log (generator + ".nodes") + write_information_log (generator + ".blogs_limited") from create l_parameters.make (2) @@ -90,21 +90,21 @@ feature -- Access end end - blogs_from_user_limited (a_user_id:INTEGER_32; a_limit:NATURAL_32; a_offset:NATURAL_32) : LIST[CMS_NODE] - -- List of posts of the author with a_user_id ordered by creation date starting at offset and limited by limit + blogs_from_user_limited (a_user: CMS_USER; a_limit: NATURAL_32; a_offset: NATURAL_32): LIST [CMS_NODE] + -- local l_parameters: STRING_TABLE [detachable ANY] do create {ARRAYED_LIST [CMS_NODE]} Result.make (0) error_handler.reset - write_information_log (generator + ".nodes") + write_information_log (generator + ".blogs_from_user_limited") from create l_parameters.make (2) l_parameters.put (a_limit, "limit") l_parameters.put (a_offset, "offset") - l_parameters.put (a_user_id, "user") + l_parameters.put (a_user.id, "user") sql_query (sql_blogs_from_user_limited, l_parameters) sql_start until diff --git a/modules/node/cms_node_api.e b/modules/node/cms_node_api.e index d324d3b..8f0a8d9 100644 --- a/modules/node/cms_node_api.e +++ b/modules/node/cms_node_api.e @@ -212,7 +212,6 @@ feature -- Access: Node Result := node_storage.nodes end - recent_nodes (a_offset, a_rows: INTEGER): LIST [CMS_NODE] -- List of the `a_rows' most recent nodes starting from `a_offset'. do diff --git a/modules/node/content_type/cms_page_node_type.e b/modules/node/content_type/cms_page_node_type.e index 2053e0d..3fe15b3 100644 --- a/modules/node/content_type/cms_page_node_type.e +++ b/modules/node/content_type/cms_page_node_type.e @@ -17,10 +17,11 @@ feature {NONE} -- Initialization default_create do Precursor - create {ARRAYED_LIST [like available_formats.item]} available_formats.make (3) + create {ARRAYED_LIST [like available_formats.item]} available_formats.make (4) available_formats.extend (create {PLAIN_TEXT_CONTENT_FORMAT}) available_formats.extend (create {FILTERED_HTML_CONTENT_FORMAT}) available_formats.extend (create {FULL_HTML_CONTENT_FORMAT}) + available_formats.extend (create {CMS_EDITOR_CONTENT_FORMAT}) end feature -- Access diff --git a/modules/node/handler/cms_node_type_webform_manager.e b/modules/node/handler/cms_node_type_webform_manager.e index 984f0d5..3ff29a8 100644 --- a/modules/node/handler/cms_node_type_webform_manager.e +++ b/modules/node/handler/cms_node_type_webform_manager.e @@ -18,8 +18,10 @@ feature -- Forms ... ta, sum: CMS_FORM_TEXTAREA tselect: WSF_FORM_SELECT opt: WSF_FORM_SELECT_OPTION - full_format: FULL_HTML_CONTENT_FORMAT + cms_format: CMS_EDITOR_CONTENT_FORMAT do + create cms_format + create ti.make ("title") ti.set_label ("Title") ti.set_size (70) @@ -31,18 +33,16 @@ feature -- Forms ... f.extend_html_text ("
              ") - -- Select field has to be initialized before textareas are replaced, because they depend on the selection of the field + -- Select field has to be initialized before textareas are replaced, because they depend on the selection of the field create tselect.make ("format") tselect.set_label ("Body's format") tselect.set_is_required (True) - - create full_format.default_create - -- Main Content + -- Main Content create ta.make ("body") ta.set_rows (10) ta.set_cols (70) - ta.show_as_editor_if_selected (tselect, full_format.name) + ta.show_as_editor_if_selected (tselect, cms_format.name) if a_node /= Void then ta.set_text_value (a_node.content) end @@ -50,12 +50,12 @@ feature -- Forms ... ta.set_description ("This is the main content") ta.set_is_required (False) - -- Summary + -- Summary create sum.make ("summary") - sum.set_rows (10) + sum.set_rows (3) sum.set_cols (70) - -- if full_html is selected - sum.show_as_editor_if_selected (tselect, full_format.name) + -- if cms_html is selected + sum.show_as_editor_if_selected (tselect, cms_format.name) if a_node /= Void then sum.set_text_value (a_node.summary) end @@ -66,15 +66,14 @@ feature -- Forms ... create fset.make fset.set_legend ("Body") - -- Add summary + -- Add summary fset.extend (sum) fset.extend_html_text("
              ") - -- Add content (body) + -- Add content (body) fset.extend (ta) fset.extend_html_text ("
              ") - across content_type.available_formats as c loop @@ -92,7 +91,7 @@ feature -- Forms ... f.extend (fset) - -- Path aliase + -- Path alias create ti.make ("path_alias") ti.set_label ("Path") ti.set_size (70) diff --git a/src/kernel/content/format/cms_editor_content_format.e b/src/kernel/content/format/cms_editor_content_format.e new file mode 100644 index 0000000..69e256e --- /dev/null +++ b/src/kernel/content/format/cms_editor_content_format.e @@ -0,0 +1,31 @@ +note + description: "HTML Content format editable with WYSIWYG editor." + date: "$Date$" + revision: "$Revision$" + +class + CMS_EDITOR_CONTENT_FORMAT + +inherit + CONTENT_FORMAT + redefine + default_create + end + +feature {NONE} -- Initialization + + default_create + do + Precursor + create filters.make (0) + end + +feature -- Access + + name: STRING = "cms_editor" + + title: STRING_8 = "CMS HTML content" + + filters: ARRAYED_LIST [CONTENT_FILTER] + +end diff --git a/src/kernel/content/format/cms_formats.e b/src/kernel/content/format/cms_formats.e index 12132d0..199062d 100644 --- a/src/kernel/content/format/cms_formats.e +++ b/src/kernel/content/format/cms_formats.e @@ -27,10 +27,11 @@ feature -- Access once -- Can we provide an external file to read the -- supported formats? - create {ARRAYED_LIST [CONTENT_FORMAT]} Result.make (3) + create {ARRAYED_LIST [CONTENT_FORMAT]} Result.make (4) Result.force (plain_text) Result.force (full_html) Result.force (filtered_html) + Result.force (cms_html) end default_format: CONTENT_FORMAT @@ -43,6 +44,11 @@ feature -- Access create Result end + cms_html: CMS_EDITOR_CONTENT_FORMAT + once + create Result + end + full_html: FULL_HTML_CONTENT_FORMAT once create Result @@ -53,7 +59,6 @@ feature -- Access create Result end - note copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" diff --git a/src/kernel/form/cms_editor.e b/src/kernel/form/cms_editor.e index 910ec42..5913956 100644 --- a/src/kernel/form/cms_editor.e +++ b/src/kernel/form/cms_editor.e @@ -27,8 +27,6 @@ feature -- Javascript javascript_textarea_to_editor(a_textarea : WSF_FORM_TEXTAREA) : STRING -- Javascript code to display the textarea as a WYSIWIG editor as soon as the document is loaded - local - l_code : STRING do Result := javascript_ready(javascript_replace_textarea (a_textarea)) end diff --git a/src/kernel/form/cms_form_textarea.e b/src/kernel/form/cms_form_textarea.e index 4f68343..60df239 100644 --- a/src/kernel/form/cms_form_textarea.e +++ b/src/kernel/form/cms_form_textarea.e @@ -21,22 +21,22 @@ create feature -- Initialisation -make (a_name: like name) - -- - do - precursor(a_name) + make (a_name: like name) + -- + do + precursor(a_name) - -- By default we don't replace the textarea by an editor - editor := False; - end + -- By default we don't replace the textarea by an editor + editor := False; + end feature -- Access editor : BOOLEAN - -- True if the textarea should be replaced by the editor. Default is false. + -- True if the textarea should be replaced by the editor. Default is false. format_field : detachable WSF_FORM_SELECT - -- Selection field for the format on that it depends, if the editor is shown or not. + -- Selection field for the format on that it depends, if the editor is shown or not. condition_value : detachable STRING @@ -58,7 +58,6 @@ feature -- Editor feature -- Conversion - append_item_to_html (a_theme: WSF_THEME; a_html: STRING_8) do -- Add javascript to replace textarea with editor @@ -67,16 +66,12 @@ feature -- Conversion a_html.append (load_assets) a_html.append ("") end end -feature -- Javascript Output - - javascript_show_editor_on_full_html_select : STRING = "" - end diff --git a/src/service/cms_api.e b/src/service/cms_api.e index 19dbebf..c245a43 100644 --- a/src/service/cms_api.e +++ b/src/service/cms_api.e @@ -185,8 +185,10 @@ feature -- Query: module module_api (a_type: TYPE [CMS_MODULE]): detachable CMS_MODULE_API -- Enabled module API associated with module typed `a_type'. do - if attached module (a_type) as mod then - Result := mod.module_api + if attached {CMS_MODULE} module (a_type) as mod then + if mod.is_enabled then + Result := mod.module_api + end end end diff --git a/src/service/cms_module.e b/src/service/cms_module.e index adc48c6..356cb5f 100644 --- a/src/service/cms_module.e +++ b/src/service/cms_module.e @@ -32,10 +32,19 @@ feature {CMS_API} -- Module Initialization -- Initialize Current module with `api'. require is_enabled: is_enabled + is_not_initialized: not is_initialized do -- Redefine to process specific module initialization. + is_initialized := True + ensure + is_initialized: is_initialized end +feature -- Status + + is_initialized: BOOLEAN + -- Is Current module initialized? + feature {CMS_API} -- Access: API module_api: detachable CMS_MODULE_API @@ -68,6 +77,8 @@ feature -- Router setup_router (a_router: WSF_ROUTER; a_api: CMS_API) -- Setup url dispatching for Current module. + require + is_initialized: is_initialized deferred end