Make notifications framework CSP compliant
Change-Id: I95411f646053d76219908b91e9f0921c17280c28
diff --git a/Changes b/Changes
index c107578..98225df 100755
--- a/Changes
+++ b/Changes
@@ -14,6 +14,7 @@
- defer main script.
- Introduce X-Frame-Options header.
- Introduce X-XSS-Protection header.
+ - Support CSP in notifications framework.
0.40 2020-12-17
- Modernize ES and fix in-loops.
diff --git a/dev/demo/all.html b/dev/demo/all.html
index 3aa40ca..0d0fee3 100644
--- a/dev/demo/all.html
+++ b/dev/demo/all.html
@@ -14,7 +14,7 @@
//]]></script>
<script data-main="alldemo.js" src="../js/lib/require.js" async="async"></script>
</head>
- <body>
+ <body class="no-js">
<div id="kalamar-bg"></div>
<header>
<a href="/" class="logo" tabindex="-1"><h1><span>KorAP - Corpus Analysis Platform</span></h1></a>
@@ -281,11 +281,10 @@
var KorAP = KorAP || {};
KorAP.URL = 'http://localhost:3000';
</script>
- <script>//<![CDATA[
-KorAP.Notifications = [];
-KorAP.Notifications.push(["warn","767: Case insensitivity is currently not supported for this layer"]);
-KorAP.Notifications.push(["error","404: Not Found (remote)"]);
-//]]>
- </script>
+ <div id="notifications">
+ <div class="notify notify-warn" data-type="warn">Error</div>
+ <div class="notify notify-error" data-type="error">Hmmm</div>
+ <div class="notify notify-success" data-type="success" data-src="Kustvakt">Hmmm</div>
+ </div>
</body>
</html>
diff --git a/dev/js/src/init.js b/dev/js/src/init.js
index 91084cf..ef6dfcf 100644
--- a/dev/js/src/init.js
+++ b/dev/js/src/init.js
@@ -92,7 +92,7 @@
KorAP.tourshowR = function(){
tourClass.gTshowResults().start();
};
-
+
domReady(function (event) {
var obj = {};
@@ -105,15 +105,19 @@
/**
* Release notifications
*/
- if (KorAP.Notifications !== undefined) {
- KorAP.Notifications.forEach(function(n) {
- var msg = n[1];
- if (n[2]) {
- msg += '<code class="src">'+n[2]+'</code>';
+ d.querySelectorAll('#notifications div.notify').forEach(
+ function(e) {
+ let msg = e.textContent;
+
+ let src = e.getAttribute('data-src');
+ if (src) {
+ msg += '<code class="src">'+src+'</code>';
};
- alertifyClass.log(msg, n[0], 10000);
- });
- };
+
+ let type = e.getAttribute('data-type') || "error";
+ alertifyClass.log(msg, type, 10000);
+ }
+ );
/**
* Replace Virtual Corpus field
diff --git a/dev/scss/main/alertify.scss b/dev/scss/main/alertify.scss
index be2f656..3c329b7 100644
--- a/dev/scss/main/alertify.scss
+++ b/dev/scss/main/alertify.scss
@@ -21,4 +21,28 @@
.alertify-log-error {
background-color: $alert-red;
+}
+
+#notifications {
+ display: none;
+}
+
+// TODO:
+// This differs from alertify messages and should be united
+div.notify {
+ position: relative;
+ margin: .5em auto;
+ display: block;
+ padding: .5em;
+
+ border-radius: $standard-border-radius;
+ max-width: 30em;
+ background-color: $alert-red;
+ color: $nearly-white;
+ &.notify-success {
+ background-color: $ids-green-1
+ }
+ &.notify-warn {
+ background-color: $ids-orange-2
+ }
}
\ No newline at end of file
diff --git a/dev/scss/no-js.scss b/dev/scss/no-js.scss
index c5f6410..985ac48 100644
--- a/dev/scss/no-js.scss
+++ b/dev/scss/no-js.scss
@@ -5,6 +5,10 @@
*/
body.no-js {
+ #notifications {
+ display: block !important;
+ }
+
// Aside in noscript mode
aside {
position: relative;
diff --git a/lib/Kalamar/Plugin/Notifications.pm b/lib/Kalamar/Plugin/Notifications.pm
index 8b6df94..6be4256 100644
--- a/lib/Kalamar/Plugin/Notifications.pm
+++ b/lib/Kalamar/Plugin/Notifications.pm
@@ -12,26 +12,17 @@
return '' unless @$notify_array;
- # Start JavaScript snippet
- my $js .= qq{<script>//<![CDATA[\n};
- $js .= "KorAP.Notifications = [];\n";
- my $noscript = "<noscript>";
-
- # Add notifications
+ my $s = '';
foreach (@$notify_array) {
- $js .= 'KorAP.Notifications.push([';
- $js .= quote($_->[0]) . ',' . quote($_->[-1]);
+ $s .= qq{<div class="notify notify-} . $_->[0] . '"';
+ $s .= ' data-type=' . quote($_->[0]);
if (ref $_->[1] && ref $_->[1] eq 'HASH') {
- $js .= ',' . quote($_->[1]->{src}) if $_->[1]->{src};
+ $s .= ' data-src=' . quote($_->[1]->{src}) if $_->[1]->{src};
};
- $js .= "]);\n";
-
- $noscript .= qq{<div class="notify notify-} . $_->[0] . '">' .
- xml_escape($_->[-1]) .
- "</div>\n";
+ $s .= '>' . xml_escape($_->[-1]) . "</div>\n";
};
+ return b('<div id="notifications">' . $s . '</div>');
- return b($js . "//]]>\n</script>\n" . $noscript . '</noscript>');
};
diff --git a/t/plugin/notifications.t b/t/plugin/notifications.t
new file mode 100644
index 0000000..9291d01
--- /dev/null
+++ b/t/plugin/notifications.t
@@ -0,0 +1,31 @@
+use Mojolicious;
+use Test::Mojo;
+use Test::More;
+
+my $app = Mojolicious->new;
+my $t = Test::Mojo->new($app);
+
+# Client notifications
+$app->plugin(Notifications => {
+ 'Kalamar::Plugin::Notifications' => 1,
+ JSON => 1,
+ HTML => 1
+});
+
+my $c = $app->build_controller;
+
+is($c->notifications('Kalamar::Plugin::Notifications'), '');
+
+$c->notify(warn => 'Error');
+$c->notify('warn' => 20, 'Hmmm');
+$c->notify('success' => {src => 'Kustvakt'}, 'Hmmm');
+
+my $n = $c->notifications('Kalamar::Plugin::Notifications');
+
+like($n, qr!^<div id="notifications">.*</div>$!s);
+like($n, qr!<div class="notify notify-warn" data-type="warn">Error</div>!);
+like($n, qr!<div class="notify notify-warn" data-type="warn">Hmmm</div>!);
+like($n, qr!<div class="notify notify-success" data-type="success" data-src="Kustvakt">Hmmm</div>!);
+
+done_testing;
+__END__
diff --git a/t/query.t b/t/query.t
index 73e488c..227dbf1 100644
--- a/t/query.t
+++ b/t/query.t
@@ -194,19 +194,19 @@
# Query with failing parameters
$t->get_ok('/?q=fantastisch&ql=Fabelsprache')
->status_is(400)
- ->text_is('noscript div.notify-error', 'Parameter "ql" invalid')
+ ->text_is('#notifications div.notify-error', 'Parameter "ql" invalid')
->element_exists('#search')
- ->element_count_is('noscript div.notify-error', 1)
+ ->element_count_is('#notifications div.notify-error', 1)
;
$t->get_ok('/?q=fantastisch&cutoff=no')
->status_is(400)
- ->text_is('noscript div.notify-error', 'Parameter "cutoff" invalid')
- ->element_count_is('noscript div.notify-error', 1)
+ ->text_is('#notifications div.notify-error', 'Parameter "cutoff" invalid')
+ ->element_count_is('#notifications div.notify-error', 1)
;
$t->get_ok('/?q=fantastisch&p=hui&o=hui&count=-8')
->status_is(400)
- ->text_like('noscript div.notify-error', qr!Parameter ".+?" invalid!)
- ->element_count_is('noscript div.notify-error', 3)
+ ->text_like('#notifications div.notify-error', qr!Parameter ".+?" invalid!)
+ ->element_count_is('#notifications div.notify-error', 3)
;
# Query too long
@@ -214,20 +214,20 @@
$t->get_ok('/?q=' . $long_query)
->status_is(400)
->text_is('#error','')
- ->text_like('noscript div.notify-error', qr!Parameter ".+?" invalid!)
+ ->text_like('#notifications div.notify-error', qr!Parameter ".+?" invalid!)
;
# Query with timeout
$t->get_ok('/?q=timeout')
->status_is(200)
- ->text_like('noscript div.notify-warn', qr!Response time exceeded!)
+ ->text_like('#notifications div.notify-warn', qr!Response time exceeded!)
->text_is('#total-results', '> 4,274,841');
;
# Do not cache
$t->get_ok('/?q=timeout')
->status_is(200)
- # ->text_like('noscript div.notify-warning', qr!Response time exceeded!)
+ # ->text_like('#notifications div.notify-warning', qr!Response time exceeded!)
->element_exists("input#cq")
->element_exists_not("input#cq[value]")
->text_is('#total-results', '> 4,274,841');