PageSourceSearch

https://mijn.host/includes/themes/mijn.host/assets/js/pages/home.js?v=1789478442

js mijn.host collected 2026-09-24 21:27:37 UTC 6,190 bytes, 178 lines download raw bytes

1/**
2 * Home page (/) JavaScript.
3 *
4 * Extracted from html/index.html as part of the strict CSP rollout. Loads
5 * the latest blog posts via the cpfeed RSS endpoint and lazy-loads
6 * domain_checker.js on window load.
7 *
8 * The URL to lazy-load is read from `<body data-domain-checker-src="...">`
9 * so the script stays free of Twig interpolation.
10 */
11(function ($) {
12
13    if (!$) {
14        return;
15    }
16
17    $(function () {
18
19        loadBlogPosts();
20
21    });
22
23    function loadBlogPosts() {
24
25        $('#blog-feed').empty();
26        $('#blog-feed').append(
27            '<div class="pt-3 pb-4 w-100 text-center"><i class="fas fa-circle-notch fa-lg fa-spin"></i></div>'
28        );
29
30        // Apex host: /blog is not proxied on env subdomains (dev.mijn.host / dev.my.host).
31        var objBlog = window.mhBlogLocale ? window.mhBlogLocale() : { host: 'mijn.host', lang: 'nl', homeUrl: 'https://mijn.host/blog/' };
32        var RSS_URL = 'https://' + objBlog.host + '/blog/feed/?feed=cpfeed&lang=' + encodeURIComponent( objBlog.lang );
33        var maxArticles          = 3;
34        var maxArticlesCounter   = 0;
35        var blogsResponseOk      = false;
36
37        fetch(RSS_URL)
38            .then(function (response) {
39                blogsResponseOk = !!response.ok;
40                return response.text();
41            })
42            .then(function (str) {
43                // Strip style attributes before parse: DOMParser still applies CSP to them.
44                return new window.DOMParser().parseFromString(stripInlineStyles(str), 'text/xml');
45            })
46            .then(function (data) {
47
48                if (blogsResponseOk) {
49
50                    $('#blog-feed').empty();
51
52                    var items = data.querySelectorAll('item');
53                    var html  = '';
54
55                    items.forEach(function (article) {
56
57                        maxArticlesCounter++;
58
59                        if (maxArticlesCounter <= maxArticles) {
60                            html += '<article class="col-sm-6 col-lg-4 blog-item h-auto">' +
61                                '    <div class="blog-item-holder">' +
62                                '        ' + getThumbnailHtml(article) +
63                                '        <div class="blog-posts">' +
64                                '            <h3 class="h5">' + getArticleHtml(article, 'title') + '</h3>' +
65                                '            <div class="date-holder">' + getArticleHtml(article, 'pubDate') + '</div>' +
66                                '            <p>' + getArticleHtml(article, 'description') + '</p>' +
67                                '            <p><a href="' + getArticleText(article, 'link') + '" class="btn btn-clean dark-gray">' + window.t('Lees dit bericht') + ' <i class="fas fa-chevron-right"></i></a></p>' +
68                                '        </div>' +
69                                '    </div>' +
70                                '</article>';
71                        }
72
73                    });
74
75                    $('#blog-feed').append(html);
76
77                } else {
78                    $('#blog-feed').empty();
79                    $('#blog-feed').append(
80                        '<div class="w-100 pt-3 pb-4 d-flex justify-content-center">' + window.t('Geen blogs gevonden.') + '</div>'
81                    );
82                }
83
84            })
85            .catch(function () {
86                $('#blog-feed').empty();
87                $('#blog-feed').append(
88                    '<div class="w-100 pt-3 pb-4 d-flex justify-content-center">' + window.t('Geen blogs gevonden.') + '</div>'
89                );
90            });
91
92    }
93
94    /**
95     * Remove HTML style attributes so CSP style-src (nonce, no 'unsafe-inline') is not violated.
96     *
97     * @param {string} strHtml
98     * @return {string}
99     */
100    function stripInlineStyles(strHtml) {
101
102        if (typeof strHtml !== 'string') {
103            return strHtml;
104        }
105
106        return strHtml
107            .replace(/\sstyle\s*=\s*"[^"]*"/gi, '')
108            .replace(/\sstyle\s*=\s*'[^']*'/gi, '')
109            .replace(/\sstyle\s*=\s*[^\s>]+/gi, '');
110
111    }
112
113    function getArticleHtml(article, selector) {
114        var element = article.querySelector(selector);
115
116        return element ? element.innerHTML : '';
117    }
118
119    function getArticleText(article, selector) {
120        var element = article.querySelector(selector);
121
122        return element ? element.textContent : '';
123    }
124
125    function getThumbnailHtml(article) {
126        var thumbnail = article.querySelector('thumbnail');
127
128        if (!thumbnail) {
129            return '';
130        }
131
132        var strHtml = stripInlineStyles(thumbnail.innerHTML);
133        var strTitle = getArticleText(article, 'title');
134
135        // Decorative empty alt plus a title attribute is announced twice by some screen readers.
136        // Use the post title as alt instead.
137        return strHtml.replace(/<img\b([^>]*)>/i, function (strMatch, strAttrs) {
138            var strCleanAttrs = strAttrs
139                .replace(/\s+alt\s*=\s*("[^"]*"|'[^']*')/i, '')
140                .replace(/\s+title\s*=\s*("[^"]*"|'[^']*')/i, '');
141
142            return '<img alt="' + escapeHtmlAttr(strTitle) + '"' + strCleanAttrs + '>';
143        });
144    }
145
146    /**
147     * Escape a string for use inside a double-quoted HTML attribute.
148     *
149     * @param {string} strValue
150     * @return {string}
151     */
152    function escapeHtmlAttr(strValue) {
153        return String(strValue)
154            .replace(/&/g, '&amp;')
155            .replace(/"/g, '&quot;')
156            .replace(/</g, '&lt;')
157            .replace(/>/g, '&gt;');
158    }
159
160    function downloadJSAtOnload2() {
161        var src = document.body.getAttribute('data-domain-checker-src');
162        if (!src) {
163            return;
164        }
165        var element = document.createElement('script');
166        element.src = src;
167        document.body.appendChild(element);
168    }
169
170    if (window.addEventListener) {
171        window.addEventListener('load', downloadJSAtOnload2, false);
172    } else if (window.attachEvent) {
173        window.attachEvent('onload', downloadJSAtOnload2);
174    } else {
175        window.onload = downloadJSAtOnload2;
176    }
177
178})(window.jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.