From a50785137a2605c617dc52a1cf410a7db483ee66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Val=C3=A9rio?= Date: Fri, 28 Jul 2023 19:10:22 +0100 Subject: [PATCH] add new example template --- index.js | 33 +++++++++-- package-lock.json | 93 +++++++++++++++++------------- package.json | 3 +- templates/headlines.handlebars | 79 +++++++++++++++++++++++++ templates/headlines.precompiled.js | 61 ++++++++++++++++++++ 5 files changed, 223 insertions(+), 46 deletions(-) create mode 100644 templates/headlines.handlebars create mode 100644 templates/headlines.precompiled.js diff --git a/index.js b/index.js index 929649f..2bee077 100644 --- a/index.js +++ b/index.js @@ -2,11 +2,27 @@ import Parser from 'rss-parser' import { Feed } from 'feed' import Handlebars from 'handlebars/runtime' import template from './templates/default.precompiled' +import * as striptags from 'striptags' -addEventListener('scheduled', event => { - event.waitUntil(handleScheduled(event)) +/** + * Extra Handlerbars template helpers + */ +Handlebars.registerHelper('isRowElemN', function(index, rowItems, n, options) { + return index % rowItems == n ? options.fn(this) : options.inverse(this) }) +/** + * Handle CRON jobs + * Where information is gathered and HTML and RSS is generated. + */ +addEventListener('scheduled', event => { + event.waitUntil(handleScheduled()) +}) + +/** + * Serve the existing generated elements. + * CACHE is used to speed up the operation. + */ addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)) }) @@ -55,10 +71,8 @@ async function handleRequest(request) { * Fetch all source feeds and generate the aggregated content * * TODO implement a faster way to fetch several sources - * - * @param {*} event */ -async function handleScheduled(event) { +async function handleScheduled() { let feeds = FEEDS.split(',') let content = [] let sources = [] @@ -167,6 +181,15 @@ function createFeed(items) { function createHTML(items, sources) { console.log(`[createHTML] building the HTML document`) let template = Handlebars.templates['default'] + let dateFormatter = new Intl.DateTimeFormat('pt-PT', { timeZone: 'UTC' }) + + for (let item of items) { + item.description = striptags(item.content).substring(0, 250) + '[...]' + item.formattedDate = item.pubDate + ? dateFormatter.format(new Date(item.pubDate)) + : '' + } + return template({ items: items, sources: sources, diff --git a/package-lock.json b/package-lock.json index 5ffbc7f..2c088e5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,8 @@ "dependencies": { "feed": "^4.2.2", "handlebars": "^4.7.7", - "rss-parser": "^3.13.0" + "rss-parser": "^3.13.0", + "striptags": "3.2.0" }, "devDependencies": { "prettier": "^1.18.2", @@ -31,9 +32,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-64": { - "version": "1.20230518.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20230518.0.tgz", - "integrity": "sha512-reApIf2/do6GjLlajU6LbRYh8gm/XcaRtzGbF8jo5IzyDSsdStmfNuvq7qssZXG92219Yp1kuTgR9+D1GGZGbg==", + "version": "1.20230717.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20230717.0.tgz", + "integrity": "sha512-NVwwAYEIJmXGnQRnrCig2i4XAYFwPPFD+324fvQGWqUyfvBXKDYF3Jkw92ZginwdojYU1W+2l2qP7t6JE9Sw0g==", "cpu": [ "x64" ], @@ -47,9 +48,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-arm64": { - "version": "1.20230518.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20230518.0.tgz", - "integrity": "sha512-1l+xdbmPddqb2YIHd1YJ3YG/Fl1nhayzcxfL30xfNS89zJn9Xn3JomM0XMD4mk0d5GruBP3q8BQZ1Uo4rRLF3A==", + "version": "1.20230717.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20230717.0.tgz", + "integrity": "sha512-toK0AadC35j0AiaXPYUq7yrAwPJR+5GLLXOXguHq5DHPqzzgD5pB9e4zlIKD+b09FAAEB6lO/k/eJSMYF/lfzA==", "cpu": [ "arm64" ], @@ -63,9 +64,9 @@ } }, "node_modules/@cloudflare/workerd-linux-64": { - "version": "1.20230518.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20230518.0.tgz", - "integrity": "sha512-/pfR+YBpMOPr2cAlwjtInil0hRZjD8KX9LqK9JkfkEiaBH8CYhnJQcOdNHZI+3OjcY09JnQtEVC5xC4nbW7Bvw==", + "version": "1.20230717.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20230717.0.tgz", + "integrity": "sha512-nxpfVzMkNLNa4hOvZ+Y7JHY13UkRf7or5tcQCRtfJ5sEhtCVGdfsOosQGnzw9G+045JUk0EKEY+gqNPRnt5u2w==", "cpu": [ "x64" ], @@ -79,9 +80,9 @@ } }, "node_modules/@cloudflare/workerd-linux-arm64": { - "version": "1.20230518.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20230518.0.tgz", - "integrity": "sha512-q3HQvn3J4uEkE0cfDAGG8zqzSZrD47cavB/Tzv4mNutqwg6B4wL3ifjtGeB55tnP2K2KL0GVmX4tObcvpUF4BA==", + "version": "1.20230717.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20230717.0.tgz", + "integrity": "sha512-jWVSJmOP0bMJ23xNONqP5x6TEDS9h/4nr0d0gULMpkfh6W9qNZNLpF8urNanXOqTM9p6rX55aBvzXsHs8Jctqw==", "cpu": [ "arm64" ], @@ -95,9 +96,9 @@ } }, "node_modules/@cloudflare/workerd-windows-64": { - "version": "1.20230518.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20230518.0.tgz", - "integrity": "sha512-vNEHKS5gKKduNOBYtQjcBopAmFT1iScuPWMZa2nJboSjOB9I/5oiVsUpSyk5Y2ARyrohXNz0y8D7p87YzTASWw==", + "version": "1.20230717.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20230717.0.tgz", + "integrity": "sha512-y9Ys8j22LMHaMdy31OyaV7Qz1Xca8MhzpBlpX4Ay6saECXYP1DZHHwtcW8pBqBU2zyGfEkErBQhyH130SSHFJg==", "cpu": [ "x64" ], @@ -717,9 +718,9 @@ "dev": true }, "node_modules/acorn": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz", - "integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -969,9 +970,9 @@ ] }, "node_modules/better-sqlite3": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-8.4.0.tgz", - "integrity": "sha512-NmsNW1CQvqMszu/CFAJ3pLct6NEFlNfuGM6vw72KHkjOD1UDnL96XNN1BMQc1hiHo8vE2GbOWQYIpZ+YM5wrZw==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-8.5.0.tgz", + "integrity": "sha512-vbPcv/Hx5WYdyNg/NbcfyaBZyv9s/NVbxb7yCeC5Bq1pVocNxeL2tZmSu3Rlm4IEOTjYdGyzWQgyx0OSdORBzw==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -1762,9 +1763,9 @@ } }, "node_modules/detect-libc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", "dev": true, "engines": { "node": ">=8" @@ -3491,9 +3492,9 @@ } }, "node_modules/miniflare": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.0.2.tgz", - "integrity": "sha512-tSwmK+JPwHsV2KR7/dSZFGtTF/2M30OShjPDY7e5lAxyGE8SkHqXn/ckjg2TVltc9B8rXCSffMnCfYW1pH7R4A==", + "version": "3.20230717.0", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20230717.0.tgz", + "integrity": "sha512-S1L3QKPEHAf7n+66b/JpWdsIusz/tlgHRnNcDztz0PfeDkWlfNPxDzrnMqv/cHm9MjzXqhz2XqFkWqZSfZJk5Q==", "dev": true, "dependencies": { "acorn": "^8.8.0", @@ -3504,10 +3505,11 @@ "glob-to-regexp": "^0.4.1", "http-cache-semantics": "^4.1.0", "kleur": "^4.1.5", + "set-cookie-parser": "^2.6.0", "source-map-support": "0.5.21", "stoppable": "^1.1.0", "undici": "^5.13.0", - "workerd": "^1.20230512.0", + "workerd": "1.20230717.0", "ws": "^8.11.0", "youch": "^3.2.2", "zod": "^3.20.6" @@ -4614,9 +4616,9 @@ } }, "node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -4637,6 +4639,12 @@ "randombytes": "^2.1.0" } }, + "node_modules/set-cookie-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", + "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==", + "dev": true + }, "node_modules/set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", @@ -5296,6 +5304,11 @@ "node": ">=0.10.0" } }, + "node_modules/striptags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/striptags/-/striptags-3.2.0.tgz", + "integrity": "sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw==" + }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -6183,9 +6196,9 @@ } }, "node_modules/workerd": { - "version": "1.20230518.0", - "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20230518.0.tgz", - "integrity": "sha512-VNmK0zoNZXrwEEx77O/oQDVUzzyDjf5kKKK8bty+FmKCd5EQJCpqi8NlRKWLGMyyYrKm86MFz0kAsreTEs7HHA==", + "version": "1.20230717.0", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20230717.0.tgz", + "integrity": "sha512-MTKF2u3pfqfpGlyaYe9BfZm8IoUwhQNe2vMWECYtv6Z8cGPJujVxcRe27ZT4l/G5lRijnnVeP3Ns3mMS9fjMsw==", "dev": true, "hasInstallScript": true, "bin": { @@ -6195,11 +6208,11 @@ "node": ">=16" }, "optionalDependencies": { - "@cloudflare/workerd-darwin-64": "1.20230518.0", - "@cloudflare/workerd-darwin-arm64": "1.20230518.0", - "@cloudflare/workerd-linux-64": "1.20230518.0", - "@cloudflare/workerd-linux-arm64": "1.20230518.0", - "@cloudflare/workerd-windows-64": "1.20230518.0" + "@cloudflare/workerd-darwin-64": "1.20230717.0", + "@cloudflare/workerd-darwin-arm64": "1.20230717.0", + "@cloudflare/workerd-linux-64": "1.20230717.0", + "@cloudflare/workerd-linux-arm64": "1.20230717.0", + "@cloudflare/workerd-windows-64": "1.20230717.0" } }, "node_modules/wrangler": { diff --git a/package.json b/package.json index 30576b9..1efbe32 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "dependencies": { "feed": "^4.2.2", "handlebars": "^4.7.7", - "rss-parser": "^3.13.0" + "rss-parser": "^3.13.0", + "striptags": "3.2.0" } } diff --git a/templates/headlines.handlebars b/templates/headlines.handlebars new file mode 100644 index 0000000..b997b9a --- /dev/null +++ b/templates/headlines.handlebars @@ -0,0 +1,79 @@ + + + + + + + {{page_title}} + + + {{!-- --}} + + + + + +
+
+
+
+

{{page_title}}

+

{{page_description}}

+
+
+
+ {{#each items}} + {{#isRowElemN @index 4 0 }} +
+ {{/isRowElemN}} +
+
+

{{title}}

+ {{formattedDate}} +
+

+ {{{description}}} +

+

+ More +

+
+ {{#isRowElemN @index 4 3}} +
+ {{/isRowElemN}} + {{/each}} +
+ + +
+
+ + Sources +
+

The content of this page is fetched from the following sources:

+

+

    + {{#each sources}} +
  • {{name}}
  • + {{/each}} +
+

+
+
+ + \ No newline at end of file diff --git a/templates/headlines.precompiled.js b/templates/headlines.precompiled.js new file mode 100644 index 0000000..da7a549 --- /dev/null +++ b/templates/headlines.precompiled.js @@ -0,0 +1,61 @@ +var Handlebars = require("handlebars/runtime"); var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; +templates['headlines'] = template({"1":function(container,depth0,helpers,partials,data) { + var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.hooks.helperMissing, alias3="function", alias4=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return ((stack1 = (lookupProperty(helpers,"isRowElemN")||(depth0 && lookupProperty(depth0,"isRowElemN"))||alias2).call(alias1,(data && lookupProperty(data,"index")),4,0,{"name":"isRowElemN","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":35,"column":8},"end":{"line":37,"column":23}}})) != null ? stack1 : "") + + "
\n
\n

" + + alias4(((helper = (helper = lookupProperty(helpers,"title") || (depth0 != null ? lookupProperty(depth0,"title") : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"title","hash":{},"data":data,"loc":{"start":{"line":40,"column":18},"end":{"line":40,"column":27}}}) : helper))) + + "

\n " + + alias4(((helper = (helper = lookupProperty(helpers,"formattedDate") || (depth0 != null ? lookupProperty(depth0,"formattedDate") : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"formattedDate","hash":{},"data":data,"loc":{"start":{"line":41,"column":21},"end":{"line":41,"column":38}}}) : helper))) + + "\n
\n

\n " + + ((stack1 = ((helper = (helper = lookupProperty(helpers,"description") || (depth0 != null ? lookupProperty(depth0,"description") : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"description","hash":{},"data":data,"loc":{"start":{"line":44,"column":14},"end":{"line":44,"column":31}}}) : helper))) != null ? stack1 : "") + + "\n

\n

\n More\n

\n
\n" + + ((stack1 = (lookupProperty(helpers,"isRowElemN")||(depth0 && lookupProperty(depth0,"isRowElemN"))||alias2).call(alias1,(data && lookupProperty(data,"index")),4,3,{"name":"isRowElemN","hash":{},"fn":container.program(4, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":50,"column":8},"end":{"line":52,"column":23}}})) != null ? stack1 : ""); +},"2":function(container,depth0,helpers,partials,data) { + return "
\n"; +},"4":function(container,depth0,helpers,partials,data) { + return "
\n"; +},"6":function(container,depth0,helpers,partials,data) { + var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.hooks.helperMissing, alias3="function", alias4=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return "
  • " + + alias4(((helper = (helper = lookupProperty(helpers,"name") || (depth0 != null ? lookupProperty(depth0,"name") : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"name","hash":{},"data":data,"loc":{"start":{"line":72,"column":37},"end":{"line":72,"column":45}}}) : helper))) + + "
  • \n"; +},"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { + var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.hooks.helperMissing, alias3="function", alias4=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return "\n\n \n \n \n \n " + + alias4(((helper = (helper = lookupProperty(helpers,"page_title") || (depth0 != null ? lookupProperty(depth0,"page_title") : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"page_title","hash":{},"data":data,"loc":{"start":{"line":7,"column":11},"end":{"line":7,"column":25}}}) : helper))) + + "\n \n \n \n \n \n \n \n
    \n
    \n
    \n
    \n

    " + + alias4(((helper = (helper = lookupProperty(helpers,"page_title") || (depth0 != null ? lookupProperty(depth0,"page_title") : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"page_title","hash":{},"data":data,"loc":{"start":{"line":29,"column":16},"end":{"line":29,"column":30}}}) : helper))) + + "

    \n

    " + + alias4(((helper = (helper = lookupProperty(helpers,"page_description") || (depth0 != null ? lookupProperty(depth0,"page_description") : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"page_description","hash":{},"data":data,"loc":{"start":{"line":30,"column":16},"end":{"line":30,"column":36}}}) : helper))) + + "

    \n
    \n
    \n
    \n" + + ((stack1 = lookupProperty(helpers,"each").call(alias1,(depth0 != null ? lookupProperty(depth0,"items") : depth0),{"name":"each","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":34,"column":6},"end":{"line":53,"column":15}}})) != null ? stack1 : "") + + "
    \n \n \n
    \n
    \n \n Sources\n
    \n

    The content of this page is fetched from the following sources:

    \n

    \n

      \n" + + ((stack1 = lookupProperty(helpers,"each").call(alias1,(depth0 != null ? lookupProperty(depth0,"sources") : depth0),{"name":"each","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":71,"column":12},"end":{"line":73,"column":21}}})) != null ? stack1 : "") + + "
    \n

    \n
    \n
    \n \n"; +},"useData":true});