diff --git a/examples/demo/site/config/modules/feed_aggregator/feeds.json b/examples/demo/site/config/modules/feed_aggregator/feeds.json
index 31d1230..b1fb13e 100644
--- a/examples/demo/site/config/modules/feed_aggregator/feeds.json
+++ b/examples/demo/site/config/modules/feed_aggregator/feeds.json
@@ -1,25 +1,28 @@
{
- "ids": ["eiffel", "forum", "stackoverflow"],
+ "ids": ["eiffel", "forum"],
"feeds": {
"eiffel": {
"title": "Eiffel related posts.",
"expiration": "21600",
+ "size": 10,
"locations": [
"https://bertrandmeyer.com/feed/",
- "https://room.eiffel.com/blog/feed"
+ "https://room.eiffel.com/blog/feed",
+ "https://room.eiffel.com/article/feed",
+ "https://room.eiffel.com/library/feed"
]
, "categories": ["Eiffel"]
- ,"option_description": "disabled"
+ ,"option_description": "enabled"
},
"forum": {
- "title": "Eiffel Users Group",
- "expiration": "43200",
- "location": "https://groups.google.com/forum/feed/eiffel-users/msgs/atom.xml?num=15"
- },
- "stackoverflow": {
- "title": "Test",
- "expiration": "3600",
- "location": "http://stackoverflow.com/feeds/tag?tagnames=eiffel&sort=newest"
+ "title": "Eiffel Forum",
+ "expiration": "21600",
+ "size": 10,
+ "locations": [
+ "https://groups.google.com/forum/feed/eiffel-users/msgs/atom.xml?num=15".
+ "http://stackoverflow.com/feeds/tag?tagnames=eiffel&sort=newest"
+ ]
+ ,"option_description": "enabled"
}
}
}
diff --git a/modules/feed_aggregator/feed_aggregation.e b/modules/feed_aggregator/feed_aggregation.e
index debbad5..cabecfc 100644
--- a/modules/feed_aggregator/feed_aggregation.e
+++ b/modules/feed_aggregator/feed_aggregation.e
@@ -17,6 +17,7 @@ feature {NONE} -- Initialization
create {ARRAYED_LIST [READABLE_STRING_8]} locations.make (0)
expiration := 60*60
description_enabled := True
+ size := 10
end
feature -- Access
@@ -28,6 +29,9 @@ feature -- Access
-- Suggested expiration time in seconds (default: 1 hour).
-- If negative then never expires.
+ size: INTEGER
+ -- Number of entries to display per page.
+
description: detachable IMMUTABLE_STRING_32
-- Optional description.
@@ -58,6 +62,12 @@ feature -- Element change
expiration := nb_seconds
end
+ set_size (nb: INTEGER)
+ -- Set `size' to `nb'.
+ do
+ size := nb
+ end
+
set_description_enabled (b: BOOLEAN)
-- Set `description_enabled' to `b'.
do
diff --git a/modules/feed_aggregator/feed_aggregator_api.e b/modules/feed_aggregator/feed_aggregator_api.e
index a3a97d9..0bd870d 100644
--- a/modules/feed_aggregator/feed_aggregator_api.e
+++ b/modules/feed_aggregator/feed_aggregator_api.e
@@ -56,6 +56,11 @@ feature -- Access
agg.set_expiration (l_expiration.to_integer)
end
end
+ if attached cfg.text_item ({STRING_32} "feeds." + l_feed_id + ".size") as l_size then
+ if l_size.is_integer then
+ agg.set_size (l_size.to_integer)
+ end
+ end
if attached cfg.text_item ({STRING_32} "feeds." + l_feed_id + ".option_description") as l_description_opt then
agg.set_description_enabled (not l_description_opt.is_case_insensitive_equal_general ("disabled"))
end
diff --git a/modules/feed_aggregator/feed_aggregator_module.e b/modules/feed_aggregator/feed_aggregator_module.e
index 2bcdce4..9c1d7ef 100644
--- a/modules/feed_aggregator/feed_aggregator_module.e
+++ b/modules/feed_aggregator/feed_aggregator_module.e
@@ -219,7 +219,7 @@ feature -- Hook
else
s := a_block_id
end
- if attached feed_to_html (s, 5, True, a_response) as l_content then
+ if attached feed_to_html (s, 0, True, a_response) as l_content then
create b.make (a_block_id, Void, l_content, Void)
b.set_is_raw (True)
a_response.add_block (b, "feed_" + s)
@@ -241,130 +241,53 @@ feature -- Hook
e: FEED_ITEM
l_cache: CMS_FILE_STRING_8_CACHE
lnk: detachable FEED_LINK
- l_today: DATE
+ vis: FEED_TO_XHTML_VISITOR
+ s: STRING
do
if attached feed_aggregator_api as l_feed_api then
if attached l_feed_api.aggregation (a_feed_id) as l_agg then
create l_cache.make (a_response.api.files_location.extended (".cache").extended (name).extended ("feed__" + a_feed_id + "__" + a_count.out + "_" + with_feed_info.out))
Result := l_cache.item
if Result = Void or l_cache.expired (Void, l_agg.expiration) then
- create l_today.make_now_utc
- create Result.make_from_string ("
")
+
+ create Result.make (1024)
Result.append ("")
- if with_feed_info then
- if attached l_agg.description as l_desc then
- Result.append ("
")
- Result.append_string_general (l_desc)
- Result.append ("
")
- end
- end
- Result.append ("
")
- if attached l_feed_api.aggregation_feed (l_agg) as l_feed then
+
+ create vis.make (Result)
+ if a_count = 0 then
+ nb := l_agg.size
+ else
nb := a_count
- across
- l_feed as f_ic
- until
- nb = 0 -- If `a_count' < 0 , no limit.
- loop
- e := f_ic.item
- if l_agg.is_included (e) then
- nb := nb - 1
- Result.append ("- ")
- lnk := e.link
- if attached e.date as l_date then
- Result.append ("
")
- append_date_time_to (l_date, l_today, Result)
- Result.append ("
")
- end
- if lnk /= Void then
- Result.append ("")
- else
- check has_link: False end
- Result.append ("")
- end
- Result.append (a_response.html_encoded (e.title))
- Result.append ("")
- debug
- if attached e.categories as l_categories and then not l_categories.is_empty then
- Result.append ("")
- across
- l_categories as cats_ic
- loop
- Result.append (a_response.html_encoded (cats_ic.item))
- Result.append (" ")
- end
- Result.append ("
")
- end
- end
- if
- l_agg.description_enabled and then
- attached e.description as l_entry_desc
- then
- if l_entry_desc.is_valid_as_string_8 then
- Result.append ("")
- Result.append (l_entry_desc.as_string_8)
- Result.append ("
")
- else
- check is_html: False end
- end
- end
- Result.append (" ")
- end
- end
end
- Result.append_string ("")
- Result.append_string (a_response.link ("more ...", "feed_aggregation/" + a_response.url_encoded (a_feed_id), Void))
- Result.append_string ("")
+ vis.set_limit (nb)
+ vis.set_description_enabled (l_agg.description_enabled)
- Result.append ("
")
+ if with_feed_info then
+ create s.make_empty
+ if attached l_agg.description as l_desc then
+ s.append ("
")
+ s.append_string_general (l_desc)
+ s.append ("
")
+ end
+ vis.set_header (s)
+ end
+ create s.make_empty
+ s.append_string ("
")
+ s.append_string (a_response.link ("See more ...", "feed_aggregation/" + a_response.url_encoded (a_feed_id), Void))
+ s.append_string ("")
+ vis.set_footer (s)
-
- Result.append (" %N")
+ if attached l_feed_api.aggregation_feed (l_agg) as l_feed then
+ l_feed.accept (vis)
+ end
l_cache.put (Result)
end
end
end
end
- append_date_time_to (dt: DATE_TIME; a_today: DATE; a_output: STRING_GENERAL)
- do
- if dt.year /= a_today.year then
- a_output.append (dt.year.out)
- a_output.append (",")
- end
- a_output.append (" ")
- append_month_mmm_to (dt.month, a_output)
- a_output.append (" ")
- if dt.day < 10 then
- a_output.append ("0")
- end
- a_output.append (dt.day.out)
- end
-
- append_month_mmm_to (m: INTEGER; s: STRING_GENERAL)
- require
- 1 <= m and m <= 12
- do
- inspect m
- when 1 then s.append ("Jan")
- when 2 then s.append ("Feb")
- when 3 then s.append ("Mar")
- when 4 then s.append ("Apr")
- when 5 then s.append ("May")
- when 6 then s.append ("Jun")
- when 7 then s.append ("Jul")
- when 8 then s.append ("Aug")
- when 9 then s.append ("Sep")
- when 10 then s.append ("Oct")
- when 11 then s.append ("Nov")
- when 12 then s.append ("Dec")
- else
- -- Error
- end
- end
-
feature -- Hook
response_alter (a_response: CMS_RESPONSE)
diff --git a/modules/feed_aggregator/site/files/css/feed_aggregator.css b/modules/feed_aggregator/site/files/css/feed_aggregator.css
index abccac2..d0e322e 100644
--- a/modules/feed_aggregator/site/files/css/feed_aggregator.css
+++ b/modules/feed_aggregator/site/files/css/feed_aggregator.css
@@ -1,11 +1,14 @@
div.feed ul {
list-style: none;
position: relative;
+ padding: 0;
+ margin: 0;
width: 99%;
}
div.feed li {
/* border-top: solid 1px #ddd; */
- margin-bottom: 5px;
+ padding: 0;
+ margin: 0 0 5px 0;
}
div.feed li a {
font-weight: bold;
@@ -32,6 +35,7 @@ div.feed li:hover {
margin-bottom: 23px;
}
div.feed li:hover .description {
+ padding: 5px;
position: absolute;
height: auto;
overflow-y: scroll;
diff --git a/modules/feed_aggregator/site/files/scss/feed_aggregator.scss b/modules/feed_aggregator/site/files/scss/feed_aggregator.scss
index 90b855f..82c2b81 100644
--- a/modules/feed_aggregator/site/files/scss/feed_aggregator.scss
+++ b/modules/feed_aggregator/site/files/scss/feed_aggregator.scss
@@ -2,11 +2,14 @@ div.feed {
ul {
list-style: none;
position: relative;
+ padding: 0;
+ margin: 0;
width: 99%;
}
li {
/* border-top: solid 1px #ddd; */
- margin-bottom: 5px;
+ padding: 0;
+ margin: 0 0 5px 0;
a {
font-weight: bold;
@@ -32,6 +35,7 @@ div.feed {
&:hover {
margin-bottom: 23px;
.description {
+ padding: 5px;
position: absolute;
height: auto;
overflow-y: scroll;
diff --git a/modules/recent_changes/cms_recent_changes_module.e b/modules/recent_changes/cms_recent_changes_module.e
index 99a78a4..bf26f46 100644
--- a/modules/recent_changes/cms_recent_changes_module.e
+++ b/modules/recent_changes/cms_recent_changes_module.e
@@ -1,5 +1,5 @@
note
- description: "CMS module that bring support for recent changes."
+ description: "CMS module that brings support for recent changes."
date: "$Date: 2015-02-13 13:08:13 +0100 (ven., 13 févr. 2015) $"
revision: "$Revision: 96616 $"
@@ -19,6 +19,8 @@ inherit
CMS_HOOK_RESPONSE_ALTER
+ CMS_HOOK_BLOCK
+
create
make
@@ -49,10 +51,132 @@ feature -- Access: router
--
do
a_router.handle ("/recent_changes/", create {WSF_URI_AGENT_HANDLER}.make (agent handle_recent_changes (a_api, ?, ?)), a_router.methods_head_get)
+ a_router.handle ("/recent_changes/feed", create {WSF_URI_AGENT_HANDLER}.make (agent handle_recent_changes_feed (a_api, ?, ?)), a_router.methods_head_get)
+ end
+
+feature -- Hook
+
+ block_list: ITERABLE [like {CMS_BLOCK}.name]
+ -- List of block names, managed by current object.
+ -- If prefixed by "?", condition will be check
+ -- to determine if it should be displayed (and computed) or not.
+ do
+ Result := <<"?recent_changes">>
+ end
+
+ get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
+ -- Get block object identified by `a_block_id' and associate with `a_response'.
+ local
+ b: CMS_CONTENT_BLOCK
+ s, l_content: STRING
+ gen: FEED_TO_XHTML_VISITOR
+ do
+ if a_block_id.same_string_general ("recent_changes") then
+ create l_content.make (1024)
+ create gen.make (l_content)
+
+ create s.make_empty
+ s.append_string ("")
+ s.append_string (a_response.link ("See more ...", "recent_changes/", Void))
+ s.append_string ("")
+ gen.set_footer (s)
+
+ recent_changes_feed (a_response, 10, Void).accept (gen)
+
+ create b.make (a_block_id, Void, l_content, Void)
+ a_response.put_block (b, Void, False)
+ end
+ end
+
+ recent_changes_feed (a_response: CMS_RESPONSE; a_size: NATURAL_32; a_source: detachable READABLE_STRING_8): FEED
+ local
+ l_changes: CMS_RECENT_CHANGE_CONTAINER
+ ch: CMS_RECENT_CHANGE_ITEM
+ l_user: detachable CMS_USER
+ l_feed: FEED
+ l_feed_item: FEED_ITEM
+ lnk: FEED_LINK
+ nb: NATURAL_32
+ do
+ l_user := Void -- Public access for the feed!
+ create l_changes.make (a_size, create {DATE_TIME}.make_now_utc, a_source)
+ if attached a_response.hooks.subscribers ({CMS_RECENT_CHANGES_HOOK}) as lst then
+ across
+ lst as ic
+ loop
+ if attached {CMS_RECENT_CHANGES_HOOK} ic.item as h then
+ if attached h.recent_changes_sources as h_sources then
+ if
+ a_source = Void
+ or else across h_sources as h_ic some h_ic.item.is_case_insensitive_equal (a_source) end
+ then
+ h.populate_recent_changes (l_changes, l_user)
+ end
+ end
+ end
+ end
+ end
+ create l_feed.make ("CMS Recent changes")
+ l_feed.set_date (create {DATE_TIME}.make_now_utc)
+ nb := a_size
+ across
+ l_changes as ic
+ until
+ nb = 0
+ loop
+ ch := ic.item
+ create l_feed_item.make (ch.link.title)
+ l_feed_item.set_date (ch.date)
+ l_feed_item.set_description (ch.information)
+ l_feed_item.set_category (ch.source)
+ create lnk.make (a_response.absolute_url (ch.link.location, Void))
+ l_feed_item.links.force (lnk, "")
+ l_feed.extend (l_feed_item)
+ nb := nb - 1
+ end
+ l_feed.sort
+ Result := l_feed
end
feature -- Handler
+ handle_recent_changes_feed (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
+ local
+ r: CMS_RESPONSE
+ htdate: HTTP_DATE
+ l_content: STRING
+ l_until_date: detachable DATE_TIME
+ l_until_date_timestamp: INTEGER_64
+ l_filter_source: detachable READABLE_STRING_8
+ l_size: NATURAL_32
+ mesg: CMS_CUSTOM_RESPONSE_MESSAGE
+ do
+ if attached {WSF_STRING} req.query_parameter ("date") as p_until_date then
+ l_until_date_timestamp := p_until_date.value.to_integer_64
+ create htdate.make_from_timestamp (l_until_date_timestamp)
+ l_until_date := htdate.date_time
+ end
+ if attached {WSF_STRING} req.query_parameter ("source") as p_filter then
+ l_filter_source := p_filter.url_encoded_value
+ if l_filter_source.is_empty then
+ l_filter_source := Void
+ end
+ end
+ if attached {WSF_STRING} req.query_parameter ("size") as p_size then
+ l_size := p_size.integer_value.to_natural_32
+ end
+ if l_size = 0 then
+ l_size := 25
+ end
+
+ create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
+ create l_content.make (1024)
+ recent_changes_feed (r, l_size, l_filter_source).accept (create {ATOM_FEED_GENERATOR}.make (l_content))
+ create mesg.make ({HTTP_STATUS_CODE}.ok)
+ mesg.set_payload (l_content)
+ res.send (mesg)
+ end
+
handle_recent_changes (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local
r: CMS_RESPONSE
@@ -146,7 +270,7 @@ feature -- Handler
create l_date_field.make_with_text ("date", l_until_date_timestamp.out)
l_form.extend (l_date_field)
end
-
+
create l_submit.make_with_text ("op", "Filter")
l_form.extend (l_submit)
l_form.extend_html_text ("
")
@@ -243,7 +367,7 @@ feature -- Handler
end
l_content.append (">)))
- l_content.append ("%">More ...")
+ l_content.append ("%">See more ...")
end
end
@@ -268,6 +392,7 @@ feature -- Hooks configuration
do
a_response.hooks.subscribe_to_menu_system_alter_hook (Current)
a_response.hooks.subscribe_to_response_alter_hook (Current)
+ a_response.hooks.subscribe_to_block_hook (Current)
end
feature -- Hook
diff --git a/modules/recent_changes/recent_changes-safe.ecf b/modules/recent_changes/recent_changes-safe.ecf
index a2f8acd..0e341f5 100644
--- a/modules/recent_changes/recent_changes-safe.ecf
+++ b/modules/recent_changes/recent_changes-safe.ecf
@@ -16,6 +16,7 @@
+
diff --git a/src/hooks/cms_hook_core_manager.e b/src/hooks/cms_hook_core_manager.e
index 2772a25..18f9f03 100644
--- a/src/hooks/cms_hook_core_manager.e
+++ b/src/hooks/cms_hook_core_manager.e
@@ -141,6 +141,8 @@ feature -- Hook: block
local
bl: READABLE_STRING_8
bl_optional: BOOLEAN
+ l_ok: BOOLEAN
+ l_block_cache: detachable TUPLE [block: CMS_CACHE_BLOCK; region: READABLE_STRING_8; expired: BOOLEAN]
do
if attached subscribers ({CMS_HOOK_BLOCK}) as lst then
across
@@ -150,15 +152,24 @@ feature -- Hook: block
across
h.block_list as blst
loop
+ l_ok := False
bl := blst.item
bl_optional := bl.count > 0 and bl[1] = '?'
if bl_optional then
bl := bl.substring (2, bl.count)
if a_response.is_block_included (bl, False) then
- h.get_block_view (bl, a_response)
+ l_ok := True
end
else
- h.get_block_view (bl, a_response)
+ l_ok := True
+ end
+ if l_ok then
+ l_block_cache := a_response.block_cache (bl)
+ if l_block_cache /= Void and then not l_block_cache.expired then
+ a_response.add_block (l_block_cache.block, l_block_cache.region)
+ else
+ h.get_block_view (bl, a_response)
+ end
end
end
end
diff --git a/src/kernel/content/cms_cache_block.e b/src/kernel/content/cms_cache_block.e
new file mode 100644
index 0000000..29e885c
--- /dev/null
+++ b/src/kernel/content/cms_cache_block.e
@@ -0,0 +1,99 @@
+note
+ description: "[
+ CMS_BLOCK implemented with a `cache'
+ as caching solution.
+ ]"
+ date: "$Date: 2014-11-18 10:13:13 +0100 (mar., 18 nov. 2014) $"
+ revision: "$Revision: 96110 $"
+
+class
+ CMS_CACHE_BLOCK
+
+inherit
+ CMS_BLOCK
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_name: like name; a_cache: like cache)
+ require
+ a_name_not_blank: not a_name.is_whitespace
+ do
+ is_enabled := True
+ name := a_name
+ cache := a_cache
+ set_is_raw (True)
+ end
+
+feature -- Access
+
+ name: READABLE_STRING_8
+ --
+
+ title: detachable READABLE_STRING_32
+ --
+
+ cache: CMS_CACHE [READABLE_STRING_8]
+ -- Cache content.
+
+feature -- Status report
+
+ is_empty: BOOLEAN
+ -- Is current block empty?
+ do
+ Result := is_raw and not cache.exists
+ end
+
+ is_raw: BOOLEAN assign set_is_raw
+ -- Is raw?
+ -- If True, do not get wrapped it with block specific div
+
+feature -- Element change
+
+ set_is_raw (b: BOOLEAN)
+ do
+ is_raw := b
+ end
+
+ set_name (n: like name)
+ -- Set `name' to `n'.
+ require
+ not n.is_whitespace
+ do
+ name := n
+ end
+
+ set_title (a_title: like title)
+ -- Set `title' to `a_title'.
+ do
+ title := a_title
+ end
+
+feature -- Conversion
+
+ to_html (a_theme: CMS_THEME): STRING_8
+ do
+ debug
+ print ("REUSE CACHE for [" + name + "]!!!%N")
+ end
+ -- Why in this particular case theme is not used to generate the content?
+ if attached cache.item as l_content then
+ Result := l_content
+ else
+ Result := ""
+ check exists: False end
+ end
+ end
+note
+ copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+ source: "[
+ Eiffel Software
+ 5949 Hollister Ave., Goleta, CA 93117 USA
+ Telephone 805-685-1006, Fax 805-685-6869
+ Website http://www.eiffel.com
+ Customer support http://support.eiffel.com
+ ]"
+end
diff --git a/src/service/response/cms_response.e b/src/service/response/cms_response.e
index 3d026c5..960d3d1 100644
--- a/src/service/response/cms_response.e
+++ b/src/service/response/cms_response.e
@@ -453,6 +453,29 @@ feature -- Blocks initialization
end
end
+ block_cache (a_block_id: READABLE_STRING_8): detachable TUPLE [block: CMS_CACHE_BLOCK; region: READABLE_STRING_8; expired: BOOLEAN]
+ -- Cached version of block `a_block_id'.
+ local
+ l_cache: CMS_FILE_STRING_8_CACHE
+ do
+ if
+ attached setup.text_item ("blocks." + a_block_id + ".expiration") as nb_secs and then
+ nb_secs.is_integer
+ then
+ if attached block_region_preference (a_block_id, "none") as l_region and then not l_region.same_string_general ("none") then
+ create l_cache.make (api.files_location.extended (".cache").extended ("blocks").extended (a_block_id).appended_with_extension ("html"))
+ if
+ l_cache.exists and then
+ not l_cache.expired (Void, nb_secs.to_integer)
+ then
+ Result := [create {CMS_CACHE_BLOCK} .make (a_block_id, l_cache), l_region, False]
+ else
+ Result := [create {CMS_CACHE_BLOCK} .make (a_block_id, l_cache), l_region, True]
+ end
+ end
+ end
+ end
+
feature -- Blocks regions
regions: STRING_TABLE [CMS_BLOCK_REGION]
@@ -786,6 +809,7 @@ feature -- Generation
l_region: CMS_BLOCK_REGION
l_menu_list_prepared: ARRAYED_LIST [CMS_LINK_COMPOSITE]
l_empty_blocks: detachable ARRAYED_LIST [CMS_BLOCK]
+ l_block_html: STRING
do
-- Menu
create {CMS_LOCAL_LINK} lnk.make ("Home", "")
@@ -884,7 +908,13 @@ feature -- Generation
end
end
end
- page.add_to_region (theme.block_html (ic.item), reg_ic.item.name)
+ l_block_html := theme.block_html (ic.item)
+ if attached {CMS_CACHE_BLOCK} ic.item then
+
+ elseif attached block_cache (ic.item.name) as l_cache_block then
+ l_cache_block.block.cache.put (l_block_html)
+ end
+ page.add_to_region (l_block_html, reg_ic.item.name)
end
end