Mibew Messenger built.
diff --git a/src/composer.json b/src/composer.json
new file mode 100644
index 00000000..a85f70a8
--- /dev/null
+++ b/src/composer.json
@@ -0,0 +1,8 @@
+{
+ "require": {
+ "xamin/handlebars.php": "dev-master#5b188ce19e9b07170238c82bd34051a31bdeebbf"
+ },
+ "config": {
+ "vendor-dir": "mibew/vendor"
+ }
+}
\ No newline at end of file
diff --git a/src/mibew/b.php b/src/mibew/b.php
index a5536140..f364917a 100644
--- a/src/mibew/b.php
+++ b/src/mibew/b.php
@@ -33,7 +33,8 @@ if ($referer && isset($_SESSION['threadid'])) {
$msg = getstring2_(
"chat.client.visited.page",
array($referer),
- $thread->locale
+ $thread->locale,
+ true
);
$thread->postMessage(Thread::KIND_FOR_AGENT, $msg);
}
diff --git a/src/mibew/install/index.php b/src/mibew/install/index.php
index eff567b1..8bae8eab 100644
--- a/src/mibew/install/index.php
+++ b/src/mibew/install/index.php
@@ -34,6 +34,9 @@ require_once(MIBEW_FS_ROOT.'/libs/config.php');
*/
define('MIBEW_CONFIG_WEB_ROOT', $mibewroot);
+// Initialize external dependencies
+require_once(MIBEW_FS_ROOT . '/vendor/autoload.php');
+
// Try to get actual base URL of the Mibew
$requestUri = $_SERVER["REQUEST_URI"];
if (!preg_match('/^(.*)\\/install(\\/[^\\/\\\\]*)?$/', $requestUri, $matches)) {
@@ -55,8 +58,9 @@ require_once(MIBEW_FS_ROOT.'/libs/common/misc.php');
require_once(MIBEW_FS_ROOT.'/libs/common/response.php');
require_once(MIBEW_FS_ROOT.'/libs/common/string.php');
require_once(MIBEW_FS_ROOT.'/libs/classes/Mibew/Style/StyleInterface.php');
-require_once(MIBEW_FS_ROOT.'/libs/classes/Mibew/Style/Style.php');
+require_once(MIBEW_FS_ROOT.'/libs/classes/Mibew/Style/AbstractStyle.php');
require_once(MIBEW_FS_ROOT.'/libs/classes/Mibew/Style/PageStyle.php');
+require_once(MIBEW_FS_ROOT.'/libs/classes/Mibew/Handlebars/HelpersSet.php');
// Include database structure
require_once(MIBEW_FS_ROOT.'/install/dbinfo.php');
diff --git a/src/mibew/js/compiled/default_app.js b/src/mibew/js/compiled/default_app.js
index 1f7cf1f2..08d08445 100644
--- a/src/mibew/js/compiled/default_app.js
+++ b/src/mibew/js/compiled/default_app.js
@@ -1,13 +1,3 @@
-/*
- Copyright 2005-2013 the original author or authors.
- Licensed under the Apache License, Version 2.0 (the "License").
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
-*/
-(function(){var k=Handlebars.template,l=Handlebars.templates=Handlebars.templates||{};l.default_control=k(function(a,b,e,h,f){this.compilerInfo=[4,">= 1.0.0"];e=this.merge(e,a.helpers);f=f||{};h=this.escapeExpression;a="";(e=e.title)?e=e.call(b,{hash:{},data:f}):(e=b.title,e="function"===typeof e?e.apply(b):e);return a+=h(e)+" "});l.message=k(function(a,b,e,h,f){this.compilerInfo=[4,">= 1.0.0"];e=this.merge(e,a.helpers);f=f||{};var c,g=this.escapeExpression,j=e.helperMissing;a={hash:{},
-data:f};a=""+(g((c=e.formatTime||b.formatTime,c?c.call(b,b.created,a):j.call(b,"formatTime",b.created,a)))+" \n");if((c=e["if"].call(b,b.name,{hash:{},inverse:this.noop,fn:this.program(1,function(a,c){var b,d;b="";(d=e.name)?d=d.call(a,{hash:{},data:c}):(d=a.name,d="function"===typeof d?d.apply(a):d);return b+=g(d)+" : "},f),data:f}))||0===c)a+=c;a+="\n";if((c=e["if"].call(b,b.allowFormatting,{hash:{},inverse:this.program(5,function(a,b){var c,d;d={hash:{},data:b};return g((c=e.apply||a.apply,c?c.call(a,a.message,"urlReplace, nl2br",d):j.call(a,"apply",a.message,"urlReplace, nl2br",d)))},f),fn:this.program(3,function(a,c){var b,d;d={hash:{},data:c};return g((b=e.apply||a.apply,b?b.call(a,a.message,"urlReplace, nl2br, allowTags",d):j.call(a,
-"apply",a.message,"urlReplace, nl2br, allowTags",d)))},f),data:f}))||0===c)a+=c;return a+=" "})})();
/*
Copyright 2005-2013 the original author or authors.
Licensed under the Apache License, Version 2.0 (the "License").
diff --git a/src/mibew/js/compiled/users_app.js b/src/mibew/js/compiled/users_app.js
index eb5c4637..a86fb390 100644
--- a/src/mibew/js/compiled/users_app.js
+++ b/src/mibew/js/compiled/users_app.js
@@ -1,37 +1,3 @@
-/*
- Copyright 2005-2013 the original author or authors.
- Licensed under the Apache License, Version 2.0 (the "License").
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
-*/
-(function(){var l=Handlebars.template,m=Handlebars.templates=Handlebars.templates||{};m.agent=l(function(c,b,e,a,d){this.compilerInfo=[4,">= 1.0.0"];e=this.merge(e,c.helpers);d=d||{};var f=e.helperMissing,h=this.escapeExpression;c=' ';(a=e.name)?a=a.call(b,{hash:{},data:d}):(a=b.name,a="function"===typeof a?a.apply(b):a);c+=h(a);if((a=e.unless.call(b,b.isLast,{hash:{},inverse:this.noop,
-fn:this.program(9,function(){return","},d),data:d}))||0===a)c+=a;return c});m.no_threads=l(function(c,b,e,a,d){this.compilerInfo=[4,">= 1.0.0"];e=this.merge(e,c.helpers);d=d||{};var f;c=e.helperMissing;a=this.escapeExpression;d={hash:{},data:d};return b=''+(a((f=e.L10n||b.L10n,f?f.call(b,"clients.no_clients",d):c.call(b,"L10n","clients.no_clients",d)))+" ")});m.no_visitors=l(function(c,b,e,a,d){this.compilerInfo=[4,">= 1.0.0"];e=this.merge(e,c.helpers);d=d||
-{};var f;c=e.helperMissing;a=this.escapeExpression;d={hash:{},data:d};return b=''+(a((f=e.L10n||b.L10n,f?f.call(b,"visitors.no_visitors",d):c.call(b,"L10n","visitors.no_visitors",d)))+" ")});m.queued_thread=l(function(c,b,e,a,d){this.compilerInfo=[4,">= 1.0.0"];e=this.merge(e,c.helpers);d=d||{};var f=e.helperMissing,h=this.escapeExpression;c='\n ';if((a=e["if"].call(b,b.ban,{hash:{},inverse:this.noop,fn:this.program(5,function(a,c){var b,g;b={hash:{},data:c};
-return b=""+(h((g=e.L10n||a.L10n,g?g.call(a,"chat.client.spam.prefix",b):f.call(a,"L10n","chat.client.spam.prefix",b)))+" ")},d),data:d}))||0===a)c+=a;(a=e.userName)?a=a.call(b,{hash:{},data:d}):(a=b.userName,a="function"===typeof a?a.apply(b):a);c+=h(a)+" \n ";if((a=e["if"].call(b,b.firstMessage,{hash:{},inverse:this.noop,fn:this.program(7,function(a,b){var c,g;c='"},d),data:d}))||0===a)c+=a;c+='\n \n\n \n ';if((a=e["if"].call(b,b.canOpen,{hash:{},inverse:this.noop,fn:this.program(9,function(a,c){var b,g;b={hash:{},data:c};return b='\n
\n ')},d),data:d}))||0===a)c+=a;c+="\n ";if((a=e["if"].call(b,b.canView,{hash:{},inverse:this.noop,fn:this.program(11,function(a,b){var c,g;c={hash:{},data:b};return c='\n
\n ')},d),data:d}))||0===
-a)c+=a;c+="\n ";if((a=e["if"].call(b,b.tracked,{hash:{},inverse:this.noop,fn:this.program(13,function(a,c){var b,g;b={hash:{},data:c};return b='\n
\n ')},d),data:d}))||0===a)c+=a;c+="\n ";if((a=e["if"].call(b,b.canBan,{hash:{},inverse:this.noop,fn:this.program(15,function(a,b){var c,g;c={hash:{},data:b};
-return c='\n
\n ')},d),data:d}))||0===a)c+=a;c+='\n
\n
\n \n';if((a=e["if"].call(b,b.userIp,{hash:{},inverse:this.program(19,function(a,c){var b;(b=e.remote)?b=b.call(a,{hash:{},data:c}):(b=a.remote,b="function"===typeof b?b.apply(a):b);return h(b)},
-d),fn:this.program(17,function(a,b){var c,g;c='';(g=e.remote)?g=g.call(a,{hash:{},data:b}):(g=a.remote,g="function"===typeof g?g.apply(a):g);return c+=h(g)+" "},d),data:d}))||0===a)c+=a;c+=' \n';(a=e.stateDesc)?a=a.call(b,{hash:{},data:d}):(a=b.stateDesc,a="function"===typeof a?a.apply(b):a);c+=h(a)+' \n';(a=e.agentName)?a=a.call(b,{hash:{},data:d}):(a=b.agentName,a="function"===typeof a?
-a.apply(b):a);c+=h(a)+' \n \n';if((a=e.unless.call(b,b.chatting,{hash:{},inverse:this.program(23,function(){return"-"},d),fn:this.program(21,function(a,b){var c,g;c=' '},d),data:d}))||0===a)c+=a;c+=' \n';if((a=e["if"].call(b,b.ban,{hash:{},inverse:this.program(27,function(a,b){var c;(c=e.userAgent)?c=c.call(a,{hash:{},data:b}):(c=a.userAgent,c="function"===typeof c?c.apply(a):c);return h(c)},d),fn:this.program(25,function(a){var c;return h((c=(c=a.ban,null==c||!1===c?c:c.reason),"function"===typeof c?c.apply(a):c))},d),data:d}))||0===a)c+=a;return c+" "});m.status_panel=l(function(c,b,e,a,d){this.compilerInfo=
-[4,">= 1.0.0"];e=this.merge(e,c.helpers);d=d||{};var f,h=e.helperMissing,j=this.escapeExpression;c='';(a=e.message)?a=a.call(b,{hash:{},data:d}):(a=b.message,a="function"===typeof a?a.apply(b):a);c+=j(a);if((f=e["if"].call(b,(a=b.agent,null==a||!1===a?a:a.away),{hash:{},inverse:this.program(3,function(a,c){var b,d;d={hash:{},data:c};return j((b=e.L10n||a.L10n,b?b.call(a,"pending.status.online",d):h.call(a,"L10n","pending.status.online",d)))},d),fn:this.program(1,function(a,c){var b,
-d;d={hash:{},data:c};return j((b=e.L10n||a.L10n,b?b.call(a,"pending.status.away",d):h.call(a,"L10n","pending.status.away",d)))},d),data:d}))||0===f)c+=f;c+='
';if((f=e["if"].call(b,(a=b.agent,null==a||!1===a?a:a.away),{hash:{},inverse:this.program(7,function(a,c){var b,d;d={hash:{},data:c};return j((b=e.L10n||a.L10n,b?b.call(a,"pending.status.setaway",d):h.call(a,"L10n","pending.status.setaway",d)))},d),fn:this.program(5,function(a,
-c){var b,d;d={hash:{},data:c};return j((b=e.L10n||a.L10n,b?b.call(a,"pending.status.setonline",d):h.call(a,"L10n","pending.status.setonline",d)))},d),data:d}))||0===f)c+=f;return c+" "});m.threads_collection=l(function(c,b,e,a,d){this.compilerInfo=[4,">= 1.0.0"];e=this.merge(e,c.helpers);d=d||{};var f,h=e.helperMissing,j=this.escapeExpression;a={hash:{},data:d};c='\n\n\n '+(j((f=e.L10n||b.L10n,f?f.call(b,"pending.table.head.name",
-a):h.call(b,"L10n","pending.table.head.name",a)))+" \n ");a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"pending.table.head.actions",a):h.call(b,"L10n","pending.table.head.actions",a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"pending.table.head.contactid",a):h.call(b,"L10n","pending.table.head.contactid",a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"pending.table.head.state",a):h.call(b,"L10n","pending.table.head.state",
-a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"pending.table.head.operator",a):h.call(b,"L10n","pending.table.head.operator",a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"pending.table.head.total",a):h.call(b,"L10n","pending.table.head.total",a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"pending.table.head.waittime",a):h.call(b,"L10n","pending.table.head.waittime",a)))+" \n ";a={hash:{},data:d};
-return c+=j((f=e.L10n||b.L10n,f?f.call(b,"pending.table.head.etc",a):h.call(b,"L10n","pending.table.head.etc",a)))+' \n \n \n\n\n \n
'});m.visitor=l(function(c,b,e,a,d){function f(){return"-"}this.compilerInfo=[4,">= 1.0.0"];e=this.merge(e,c.helpers);d=d||{};var h,j=e.helperMissing,k=this.escapeExpression;c='\n ';if((a=e.unless.call(b,b.invitationInfo,{hash:{},inverse:this.program(3,function(a,c){var b;(b=e.userName)?
-b=b.call(a,{hash:{},data:c}):(b=a.userName,b="function"===typeof b?b.apply(a):b);return k(b)},d),fn:this.program(1,function(a,b){var c,d;c={hash:{},data:b};c='');(d=e.userName)?d=d.call(a,{hash:{},data:b}):(d=a.userName,d="function"===typeof d?d.apply(a):d);return c+=k(d)+" "},d),data:d}))||0===a)c+=a;h={hash:{},data:d};c=c+'\n \n\n \n
\n \n');if((a=e["if"].call(b,b.userIp,{hash:{},inverse:this.program(7,function(a,c){var b;(b=e.remote)?b=b.call(a,{hash:{},data:c}):(b=a.remote,b="function"===typeof b?b.apply(a):b);return k(b)},d),fn:this.program(5,function(a,b){var c,d;c='';
-(d=e.remote)?d=d.call(a,{hash:{},data:b}):(d=a.remote,d="function"===typeof d?d.apply(a):d);return c+=k(d)+" "},d),data:d}))||0===a)c+=a;c+=' \n \n \n';if((a=e["if"].call(b,b.invitationInfo,{hash:{},inverse:this.program(11,f,d),fn:this.program(9,function(a){var b;return k((b=(b=a.invitationInfo,null==b||!1===b?b:b.agentName),"function"===typeof b?b.apply(a):b))},d),data:d}))||0===a)c+=a;c+=' \n';if((a=e["if"].call(b,b.invitationInfo,{hash:{},inverse:this.program(11,f,d),fn:this.program(13,function(a){var b;return a=""+(' ')},d),data:d}))||0===a)c+=a;c+=' \n';(a=e.invitations)?a=a.call(b,{hash:{},data:d}):(a=b.invitations,a="function"===typeof a?a.apply(b):a);c+=k(a)+" / ";(a=e.chats)?a=a.call(b,{hash:{},data:d}):(a=b.chats,a="function"===typeof a?a.apply(b):a);c+=k(a)+' \n';(a=e.userAgent)?a=a.call(b,{hash:{},data:d}):(a=b.userAgent,a="function"===typeof a?a.apply(b):a);return c+=k(a)+" "});
-m.visitors_collection=l(function(c,b,e,a,d){this.compilerInfo=[4,">= 1.0.0"];e=this.merge(e,c.helpers);d=d||{};var f,h=e.helperMissing,j=this.escapeExpression;a={hash:{},data:d};c='\n\n\n '+(j((f=e.L10n||b.L10n,f?f.call(b,"visitors.table.head.name",a):h.call(b,"L10n","visitors.table.head.name",a)))+" \n ");a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"visitors.table.head.actions",a):h.call(b,"L10n",
-"visitors.table.head.actions",a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"visitors.table.head.contactid",a):h.call(b,"L10n","visitors.table.head.contactid",a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"visitors.table.head.firsttimeonsite",a):h.call(b,"L10n","visitors.table.head.firsttimeonsite",a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"visitors.table.head.lasttimeonsite",a):h.call(b,"L10n","visitors.table.head.lasttimeonsite",
-a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"visitors.table.head.invited.by",a):h.call(b,"L10n","visitors.table.head.invited.by",a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"visitors.table.head.invitationtime",a):h.call(b,"L10n","visitors.table.head.invitationtime",a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"visitors.table.head.invitations",a):h.call(b,"L10n","visitors.table.head.invitations",a)))+" \n ";
-a={hash:{},data:d};return c+=j((f=e.L10n||b.L10n,f?f.call(b,"visitors.table.head.etc",a):h.call(b,"L10n","visitors.table.head.etc",a)))+' \n \n \n\n \n
'})})();
/*
Copyright 2005-2013 the original author or authors.
Licensed under the Apache License, Version 2.0 (the "License").
diff --git a/src/mibew/js/templates/compiled/users_app.tpl.js b/src/mibew/js/templates/compiled/users_app.tpl.js
deleted file mode 100644
index 8b6ca101..00000000
--- a/src/mibew/js/templates/compiled/users_app.tpl.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- Copyright 2005-2013 the original author or authors.
- Licensed under the Apache License, Version 2.0 (the "License").
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
-*/
-(function(){var l=Handlebars.template,m=Handlebars.templates=Handlebars.templates||{};m.agent=l(function(c,b,e,a,d){this.compilerInfo=[4,">= 1.0.0"];e=this.merge(e,c.helpers);d=d||{};var f=e.helperMissing,h=this.escapeExpression;c=' ';(a=e.name)?a=a.call(b,{hash:{},data:d}):(a=b.name,a="function"===typeof a?a.apply(b):a);c+=h(a);if((a=e.unless.call(b,b.isLast,{hash:{},inverse:this.noop,
-fn:this.program(9,function(){return","},d),data:d}))||0===a)c+=a;return c});m.no_threads=l(function(c,b,e,a,d){this.compilerInfo=[4,">= 1.0.0"];e=this.merge(e,c.helpers);d=d||{};var f;c=e.helperMissing;a=this.escapeExpression;d={hash:{},data:d};return b=''+(a((f=e.L10n||b.L10n,f?f.call(b,"clients.no_clients",d):c.call(b,"L10n","clients.no_clients",d)))+" ")});m.no_visitors=l(function(c,b,e,a,d){this.compilerInfo=[4,">= 1.0.0"];e=this.merge(e,c.helpers);d=d||
-{};var f;c=e.helperMissing;a=this.escapeExpression;d={hash:{},data:d};return b=''+(a((f=e.L10n||b.L10n,f?f.call(b,"visitors.no_visitors",d):c.call(b,"L10n","visitors.no_visitors",d)))+" ")});m.queued_thread=l(function(c,b,e,a,d){this.compilerInfo=[4,">= 1.0.0"];e=this.merge(e,c.helpers);d=d||{};var f=e.helperMissing,h=this.escapeExpression;c='\n ';if((a=e["if"].call(b,b.ban,{hash:{},inverse:this.noop,fn:this.program(5,function(a,c){var b,g;b={hash:{},data:c};
-return b=""+(h((g=e.L10n||a.L10n,g?g.call(a,"chat.client.spam.prefix",b):f.call(a,"L10n","chat.client.spam.prefix",b)))+" ")},d),data:d}))||0===a)c+=a;(a=e.userName)?a=a.call(b,{hash:{},data:d}):(a=b.userName,a="function"===typeof a?a.apply(b):a);c+=h(a)+" \n ";if((a=e["if"].call(b,b.firstMessage,{hash:{},inverse:this.noop,fn:this.program(7,function(a,b){var c,g;c='"},d),data:d}))||0===a)c+=a;c+='\n \n\n \n ';if((a=e["if"].call(b,b.canOpen,{hash:{},inverse:this.noop,fn:this.program(9,function(a,c){var b,g;b={hash:{},data:c};return b='\n
\n ')},d),data:d}))||0===a)c+=a;c+="\n ";if((a=e["if"].call(b,b.canView,{hash:{},inverse:this.noop,fn:this.program(11,function(a,b){var c,g;c={hash:{},data:b};return c='\n
\n ')},d),data:d}))||0===
-a)c+=a;c+="\n ";if((a=e["if"].call(b,b.tracked,{hash:{},inverse:this.noop,fn:this.program(13,function(a,c){var b,g;b={hash:{},data:c};return b='\n
\n ')},d),data:d}))||0===a)c+=a;c+="\n ";if((a=e["if"].call(b,b.canBan,{hash:{},inverse:this.noop,fn:this.program(15,function(a,b){var c,g;c={hash:{},data:b};
-return c='\n
\n ')},d),data:d}))||0===a)c+=a;c+='\n
\n
\n \n';if((a=e["if"].call(b,b.userIp,{hash:{},inverse:this.program(19,function(a,c){var b;(b=e.remote)?b=b.call(a,{hash:{},data:c}):(b=a.remote,b="function"===typeof b?b.apply(a):b);return h(b)},
-d),fn:this.program(17,function(a,b){var c,g;c='';(g=e.remote)?g=g.call(a,{hash:{},data:b}):(g=a.remote,g="function"===typeof g?g.apply(a):g);return c+=h(g)+" "},d),data:d}))||0===a)c+=a;c+=' \n';(a=e.stateDesc)?a=a.call(b,{hash:{},data:d}):(a=b.stateDesc,a="function"===typeof a?a.apply(b):a);c+=h(a)+' \n';(a=e.agentName)?a=a.call(b,{hash:{},data:d}):(a=b.agentName,a="function"===typeof a?
-a.apply(b):a);c+=h(a)+' \n \n';if((a=e.unless.call(b,b.chatting,{hash:{},inverse:this.program(23,function(){return"-"},d),fn:this.program(21,function(a,b){var c,g;c=' '},d),data:d}))||0===a)c+=a;c+=' \n';if((a=e["if"].call(b,b.ban,{hash:{},inverse:this.program(27,function(a,b){var c;(c=e.userAgent)?c=c.call(a,{hash:{},data:b}):(c=a.userAgent,c="function"===typeof c?c.apply(a):c);return h(c)},d),fn:this.program(25,function(a){var c;return h((c=(c=a.ban,null==c||!1===c?c:c.reason),"function"===typeof c?c.apply(a):c))},d),data:d}))||0===a)c+=a;return c+" "});m.status_panel=l(function(c,b,e,a,d){this.compilerInfo=
-[4,">= 1.0.0"];e=this.merge(e,c.helpers);d=d||{};var f,h=e.helperMissing,j=this.escapeExpression;c='';(a=e.message)?a=a.call(b,{hash:{},data:d}):(a=b.message,a="function"===typeof a?a.apply(b):a);c+=j(a);if((f=e["if"].call(b,(a=b.agent,null==a||!1===a?a:a.away),{hash:{},inverse:this.program(3,function(a,c){var b,d;d={hash:{},data:c};return j((b=e.L10n||a.L10n,b?b.call(a,"pending.status.online",d):h.call(a,"L10n","pending.status.online",d)))},d),fn:this.program(1,function(a,c){var b,
-d;d={hash:{},data:c};return j((b=e.L10n||a.L10n,b?b.call(a,"pending.status.away",d):h.call(a,"L10n","pending.status.away",d)))},d),data:d}))||0===f)c+=f;c+='
';if((f=e["if"].call(b,(a=b.agent,null==a||!1===a?a:a.away),{hash:{},inverse:this.program(7,function(a,c){var b,d;d={hash:{},data:c};return j((b=e.L10n||a.L10n,b?b.call(a,"pending.status.setaway",d):h.call(a,"L10n","pending.status.setaway",d)))},d),fn:this.program(5,function(a,
-c){var b,d;d={hash:{},data:c};return j((b=e.L10n||a.L10n,b?b.call(a,"pending.status.setonline",d):h.call(a,"L10n","pending.status.setonline",d)))},d),data:d}))||0===f)c+=f;return c+" "});m.threads_collection=l(function(c,b,e,a,d){this.compilerInfo=[4,">= 1.0.0"];e=this.merge(e,c.helpers);d=d||{};var f,h=e.helperMissing,j=this.escapeExpression;a={hash:{},data:d};c='\n\n\n '+(j((f=e.L10n||b.L10n,f?f.call(b,"pending.table.head.name",
-a):h.call(b,"L10n","pending.table.head.name",a)))+" \n ");a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"pending.table.head.actions",a):h.call(b,"L10n","pending.table.head.actions",a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"pending.table.head.contactid",a):h.call(b,"L10n","pending.table.head.contactid",a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"pending.table.head.state",a):h.call(b,"L10n","pending.table.head.state",
-a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"pending.table.head.operator",a):h.call(b,"L10n","pending.table.head.operator",a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"pending.table.head.total",a):h.call(b,"L10n","pending.table.head.total",a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"pending.table.head.waittime",a):h.call(b,"L10n","pending.table.head.waittime",a)))+" \n ";a={hash:{},data:d};
-return c+=j((f=e.L10n||b.L10n,f?f.call(b,"pending.table.head.etc",a):h.call(b,"L10n","pending.table.head.etc",a)))+' \n \n \n\n\n \n
'});m.visitor=l(function(c,b,e,a,d){function f(){return"-"}this.compilerInfo=[4,">= 1.0.0"];e=this.merge(e,c.helpers);d=d||{};var h,j=e.helperMissing,k=this.escapeExpression;c='\n ';if((a=e.unless.call(b,b.invitationInfo,{hash:{},inverse:this.program(3,function(a,c){var b;(b=e.userName)?
-b=b.call(a,{hash:{},data:c}):(b=a.userName,b="function"===typeof b?b.apply(a):b);return k(b)},d),fn:this.program(1,function(a,b){var c,d;c={hash:{},data:b};c='');(d=e.userName)?d=d.call(a,{hash:{},data:b}):(d=a.userName,d="function"===typeof d?d.apply(a):d);return c+=k(d)+" "},d),data:d}))||0===a)c+=a;h={hash:{},data:d};c=c+'\n \n\n \n
\n \n');if((a=e["if"].call(b,b.userIp,{hash:{},inverse:this.program(7,function(a,c){var b;(b=e.remote)?b=b.call(a,{hash:{},data:c}):(b=a.remote,b="function"===typeof b?b.apply(a):b);return k(b)},d),fn:this.program(5,function(a,b){var c,d;c='';
-(d=e.remote)?d=d.call(a,{hash:{},data:b}):(d=a.remote,d="function"===typeof d?d.apply(a):d);return c+=k(d)+" "},d),data:d}))||0===a)c+=a;c+=' \n \n \n';if((a=e["if"].call(b,b.invitationInfo,{hash:{},inverse:this.program(11,f,d),fn:this.program(9,function(a){var b;return k((b=(b=a.invitationInfo,null==b||!1===b?b:b.agentName),"function"===typeof b?b.apply(a):b))},d),data:d}))||0===a)c+=a;c+=' \n';if((a=e["if"].call(b,b.invitationInfo,{hash:{},inverse:this.program(11,f,d),fn:this.program(13,function(a){var b;return a=""+(' ')},d),data:d}))||0===a)c+=a;c+=' \n';(a=e.invitations)?a=a.call(b,{hash:{},data:d}):(a=b.invitations,a="function"===typeof a?a.apply(b):a);c+=k(a)+" / ";(a=e.chats)?a=a.call(b,{hash:{},data:d}):(a=b.chats,a="function"===typeof a?a.apply(b):a);c+=k(a)+' \n';(a=e.userAgent)?a=a.call(b,{hash:{},data:d}):(a=b.userAgent,a="function"===typeof a?a.apply(b):a);return c+=k(a)+" "});
-m.visitors_collection=l(function(c,b,e,a,d){this.compilerInfo=[4,">= 1.0.0"];e=this.merge(e,c.helpers);d=d||{};var f,h=e.helperMissing,j=this.escapeExpression;a={hash:{},data:d};c='\n\n\n '+(j((f=e.L10n||b.L10n,f?f.call(b,"visitors.table.head.name",a):h.call(b,"L10n","visitors.table.head.name",a)))+" \n ");a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"visitors.table.head.actions",a):h.call(b,"L10n",
-"visitors.table.head.actions",a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"visitors.table.head.contactid",a):h.call(b,"L10n","visitors.table.head.contactid",a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"visitors.table.head.firsttimeonsite",a):h.call(b,"L10n","visitors.table.head.firsttimeonsite",a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"visitors.table.head.lasttimeonsite",a):h.call(b,"L10n","visitors.table.head.lasttimeonsite",
-a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"visitors.table.head.invited.by",a):h.call(b,"L10n","visitors.table.head.invited.by",a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"visitors.table.head.invitationtime",a):h.call(b,"L10n","visitors.table.head.invitationtime",a)))+" \n ";a={hash:{},data:d};c+=j((f=e.L10n||b.L10n,f?f.call(b,"visitors.table.head.invitations",a):h.call(b,"L10n","visitors.table.head.invitations",a)))+" \n ";
-a={hash:{},data:d};return c+=j((f=e.L10n||b.L10n,f?f.call(b,"visitors.table.head.etc",a):h.call(b,"L10n","visitors.table.head.etc",a)))+' \n \n \n\n \n
'})})();
diff --git a/src/mibew/libs/chat.php b/src/mibew/libs/chat.php
index a5a6457a..47d73e69 100644
--- a/src/mibew/libs/chat.php
+++ b/src/mibew/libs/chat.php
@@ -723,14 +723,15 @@ function chat_start_for_user(
Thread::KIND_FOR_AGENT,
getstring2(
'chat.visitor.invitation.accepted',
- array($operator_name)
+ array($operator_name),
+ true
)
);
} else {
if ($referrer) {
$thread->postMessage(
Thread::KIND_FOR_AGENT,
- getstring2('chat.came.from', array($referrer))
+ getstring2('chat.came.from', array($referrer), true)
);
}
if ($requested_operator && !$requested_operator_online) {
@@ -738,11 +739,12 @@ function chat_start_for_user(
Thread::KIND_INFO,
getstring2(
'chat.requested_operator.offline',
- array(get_operator_name($requested_operator))
+ array(get_operator_name($requested_operator)),
+ true
)
);
} else {
- $thread->postMessage(Thread::KIND_INFO, getstring('chat.wait'));
+ $thread->postMessage(Thread::KIND_INFO, getstring('chat.wait', true));
}
}
@@ -750,7 +752,7 @@ function chat_start_for_user(
if ($info) {
$thread->postMessage(
Thread::KIND_FOR_AGENT,
- getstring2('chat.visitor.info', array($info))
+ getstring2('chat.visitor.info', array($info), true)
);
}
diff --git a/src/mibew/libs/classes/Mibew/Handlebars/HelpersSet.php b/src/mibew/libs/classes/Mibew/Handlebars/HelpersSet.php
new file mode 100644
index 00000000..5f4df721
--- /dev/null
+++ b/src/mibew/libs/classes/Mibew/Handlebars/HelpersSet.php
@@ -0,0 +1,573 @@
+helpersList();
+ }
+
+ /**
+ * A helper for string localization.
+ *
+ * Example of usage:
+ *
+ * {{l10n "localization.string" arg1 arg2 arg3}}
+ *
+ * where:
+ * - "localization.string" is localization constant.
+ * - arg* are arguments that will be passed to getlocal2 function. There
+ * can be arbitrary number of such arguments.
+ */
+ public function localizationHelper($template, $context, $args, $source)
+ {
+ // Check if there is at least one argument
+ $parsed_arguments = $template->parseArguments($args);
+ if (empty($parsed_arguments)) {
+ return '';
+ }
+
+ $text = $context->get(array_shift($parsed_arguments));
+
+ // We need to escape extra arguments passed to the helper. Thus we need
+ // to get escape function and its arguments from the template engine.
+ $escape_func = $template->getEngine()->getEscape();
+ $escape_args = $template->getEngine()->getEscapeArgs();
+
+ // Check if there are any other arguments passed into helper and escape
+ // them.
+ $local_args = array();
+ foreach ($parsed_arguments as $parsed_argument) {
+ // Get locale argument string and add it to escape function
+ // arguments.
+ array_unshift($escape_args, $context->get($parsed_argument));
+
+ // Escape locale argument's value
+ $local_args[] = call_user_func_array(
+ $escape_func,
+ array_values($escape_args)
+ );
+
+ // Remove locale argument's value from escape function argument
+ array_shift($escape_args);
+ }
+
+ if (empty($local_args)) {
+ $result = getlocal($text);
+ } else {
+ $result = getlocal2($text, $local_args);
+ }
+
+ return new \Handlebars\SafeString($result);
+ }
+
+ /**
+ * Conditional helper that checks if two values are equal or not.
+ *
+ * Example of usage:
+ *
+ * {{#ifEqual first second}}
+ * The first argument is equal to the second one.
+ * {{else}}
+ * The arguments are not equal.
+ * {{/ifEqual}}
+ *
+ */
+ public function ifEqualHelper($template, $context, $args, $source)
+ {
+ $parsed_args = $template->parseArguments($args);
+ if (empty($parsed_args) || count($parsed_args) < 2) {
+ return '';
+ }
+
+ $condition = ($context->get($parsed_args[0]) == $context->get($parsed_args[1]));
+
+ if ($condition) {
+ $template->setStopToken('else');
+ $buffer = $template->render($context);
+ $template->setStopToken(false);
+ } else {
+ $template->setStopToken('else');
+ $template->discard();
+ $template->setStopToken(false);
+ $buffer = $template->render($context);
+ }
+
+ return $buffer;
+ }
+
+ /**
+ * Conditional helper that checks if at least one argumet can be treated as
+ * "true" value.
+ *
+ * Example of usage:
+ *
+ * {{#ifAny first second third}}
+ * At least one of argument can be threated as "true".
+ * {{else}}
+ * All values are "falsy"
+ * {{/ifAny}}
+ *
+ */
+ public function ifAnyHelper($template, $context, $args, $source)
+ {
+ $parsed_args = $template->parseArguments($args);
+ if (empty($parsed_args)) {
+ return '';
+ }
+
+ $condition = false;
+ foreach ($parsed_args as $parsed_arg) {
+ $value = $context->get($parsed_arg);
+
+ if ($value instanceof \Handlebars\String) {
+ // We need to get internal string. Casting any object of
+ // \Handlebars\String will have positive result even for those
+ // with empty internal strings.
+ $value = $value->getString();
+ }
+
+ if ($value) {
+ $condition = true;
+ break;
+ }
+ }
+
+ if ($condition) {
+ $template->setStopToken('else');
+ $buffer = $template->render($context);
+ $template->setStopToken(false);
+ } else {
+ $template->setStopToken('else');
+ $template->discard();
+ $template->setStopToken(false);
+ $buffer = $template->render($context);
+ }
+
+ return $buffer;
+ }
+
+ /**
+ * A helper for templates inheritance.
+ *
+ * Example of usage:
+ *
+ * {{#extends "parentTemplateName"}}
+ * {{#override "blockName"}}
+ * Overridden first block
+ * {{/override}}
+ *
+ * {{#override "anotherBlockName"}}
+ * Overridden second block
+ * {{/override}}
+ * {{/extends}}
+ *
+ */
+ public function extendsHelper($template, $context, $args, $source)
+ {
+ // Get name of the parent template
+ $parsed_args = $template->parseArguments($args);
+ if (empty($parsed_args)) {
+ return '';
+ }
+ $parent_template = $context->get(array_shift($parsed_args));
+
+ // Render content inside "extends" block to override blocks
+ $template->render($context);
+
+ // We need to another instance of \Handlebars\Template to render parent
+ // template. It can be got from Handlebars engine, so get the latter.
+ $handlebars = $template->getEngine();
+
+ // Render the parent template
+ return $handlebars->render($parent_template, $context);
+ }
+
+ /**
+ * A helper for defining default content of a block.
+ *
+ * Example of usage:
+ *
+ * {{#block "blockName"}}
+ * Default content for the block
+ * {{/block}}
+ *
+ */
+ public function blockHelper($template, $context, $args, $source)
+ {
+ // Get block name
+ $parsed_args = $template->parseArguments($args);
+ if (empty($parsed_args)) {
+ return '';
+ }
+ $block_name = $context->get(array_shift($parsed_args));
+
+ // If the block is not overridden render and show the default value
+ if (!isset($this->blocksStorage[$block_name])) {
+ return $template->render($context);
+ }
+
+ // Show overridden content
+ return $this->blocksStorage[$block_name];
+ }
+
+ /**
+ * A helper for overriding content of a block.
+ *
+ * Example of usage:
+ *
+ * {{#extends "parentTemplateName"}}
+ * {{#override "blockName"}}
+ * Overridden first block
+ * {{/override}}
+ *
+ * {{#override "anotherBlockName"}}
+ * Overridden second block
+ * {{/override}}
+ * {{/extends}}
+ *
+ */
+ public function overrideHelper($template, $context, $args, $source)
+ {
+ // Get block name
+ $parsed_args = $template->parseArguments($args);
+ if (empty($parsed_args)) {
+ return '';
+ }
+ $block_name = $context->get(array_shift($parsed_args));
+
+ // We need to provide unlimited inheritence level. Rendering is started
+ // from the deepest level template. If the content is in the block
+ // storage it is related with the deepest level template. Thus we do not
+ // need to override it.
+ if (!isset($this->blocksStorage[$block_name])) {
+ $this->blocksStorage[$block_name] = $template->render($context);
+ }
+ }
+
+ /**
+ * Conditional helper that checks if block overridden or not.
+ *
+ * Example of usage:
+ *
+ * {{#ifOverridden "blockName"}}
+ * The block was overridden
+ * {{else}}
+ * The block was not overridden
+ * {{/ifOverriden}}
+ *
+ */
+ public function ifOverriddenHelper($template, $context, $args, $source)
+ {
+ // Get block name
+ $parsed_args = $template->parseArguments($args);
+ if (empty($parsed_args)) {
+ return '';
+ }
+ $block_name = $context->get(array_shift($parsed_args));
+
+ // Check condition and render blocks
+ if (isset($this->blocksStorage[$block_name])) {
+ $template->setStopToken('else');
+ $buffer = $template->render($context);
+ $template->setStopToken(false);
+ } else {
+ $template->setStopToken('else');
+ $template->discard();
+ $template->setStopToken(false);
+ $buffer = $template->render($context);
+ }
+
+ return $buffer;
+ }
+
+ /**
+ * Conditional helper that checks if block overridden or not.
+ *
+ * Example of usage:
+ *
+ * {{#unlessOverridden "blockName"}}
+ * The block was not overridden
+ * {{else}}
+ * The block was overridden
+ * {{/unlessOverriden}}
+ *
+ */
+ public function unlessOverriddenHelper($template, $context, $args, $source)
+ {
+ // Get block name
+ $parsed_args = $template->parseArguments($args);
+ if (empty($parsed_args)) {
+ return '';
+ }
+ $block_name = $context->get(array_shift($parsed_args));
+
+ // Check condition and render blocks
+ if (!isset($this->blocksStorage[$block_name])) {
+ $template->setStopToken('else');
+ $buffer = $template->render($context);
+ $template->setStopToken(false);
+ } else {
+ $template->setStopToken('else');
+ $template->discard();
+ $template->setStopToken(false);
+ $buffer = $template->render($context);
+ }
+
+ return $buffer;
+ }
+
+ /**
+ * Generates markup with hidden input tag for CSRF token.
+ *
+ * Example of usage:
+ *
+ * {{csrfTokenInput}}
+ *
+ */
+ public function csrfTokenInputHelper()
+ {
+ return new \Handlebars\SafeString(get_csrf_token_input());
+ }
+
+ /**
+ * Generates CSRF taken formated prepared to insert in URLs.
+ *
+ * Example of usage:
+ *
+ * {{csrfTokenInUrl}}
+ *
+ */
+ public function csrfTokenInUrlHelper()
+ {
+ return new \Handlebars\SafeString(get_csrf_token_in_url());
+ }
+
+ /**
+ * Generates pagination block.
+ *
+ * Example of usage:
+ *
+ * {{generatePagination stylePath paginationInfo bottom}}
+ *
+ * where:
+ * - "stylePath" is expression for path to current style.
+ * - "paginationInfo" is 'info' key from the result of setup_pagination
+ * function.
+ * - "bottom": optional argument that indicate if pagination block shoud
+ * be generated for a page bottom or not. If specified and equal to
+ * string "false" then boolean false will be passed into
+ * generate_pagination. In all other cases boolean true will be used.
+ */
+ public function generatePaginationHelper($template, $context, $args, $source)
+ {
+ $parsed_args = $template->parseArguments($args);
+ if (empty($parsed_args) || count($parsed_args) < 2) {
+ return '';
+ }
+
+ $stylePath = $context->get($parsed_args[0]);
+ $pagination_info = $context->get($parsed_args[1]);
+ $bottom = empty($parsed_args[2]) ? true : $context->get($parsed_args[2]);
+
+ $pagination = generate_pagination(
+ $stylePath,
+ $pagination_info,
+ ($bottom === "false") ? false : true
+ );
+
+ return new \Handlebars\SafeString($pagination);
+ }
+
+ /**
+ * Escapes special characters to use result as a valid JavaScript string
+ * enclosed with single quotes (') or duouble quotes (").
+ *
+ * Example of usage:
+ *
+ * var a = "{{#jsString}}some string to escape{{/jsString}}";
+ *
+ */
+ public function jsStringHelper($template, $context, $args, $source)
+ {
+ return str_replace("\n", "\\n", addslashes($template->render($context)));
+ }
+
+ /**
+ * Helper for repeating content.
+ *
+ * Example of usage:
+ *
+ * {{#repeat times}}content to repeat{{/repeat}}
+ *
+ */
+ public function repeatHelper($template, $context, $args, $source)
+ {
+ $parsed_args = $template->parseArguments($args);
+ if (empty($parsed_args)) {
+ return '';
+ }
+
+ $times = intval($context->get($parsed_args[0]));
+ $string = $template->render($context);
+
+ return str_repeat($string, $times);
+ }
+
+ /**
+ * Helper for replacing substrings.
+ *
+ * Example of usage:
+ *
+ * {{#replace search replacement}}target content{{/replace}}
+ *
+ */
+ public function replaceHelper($template, $context, $args, $source)
+ {
+ $parsed_args = $template->parseArguments($args);
+ if (empty($parsed_args) || count($parsed_args) < 2) {
+ return '';
+ }
+
+ $search = $context->get($parsed_args[0]);
+ $replacement = $context->get($parsed_args[1]);
+ $subject = $template->render($context);
+
+ return str_replace($search, $replacement, $subject);
+ }
+
+ /**
+ * Format date using internal format.
+ *
+ * Example of usage:
+ *
+ * {{formatDate unixTimestamp}}
+ *
+ */
+ public function formatDateHelper($template, $context, $args, $source)
+ {
+ $parsed_args = $template->parseArguments($args);
+ if (empty($parsed_args)) {
+ return '';
+ }
+
+ $timestamp = intval($context->get($parsed_args[0]));
+
+ return date_to_text($timestamp);
+ }
+
+ /**
+ * Format date difference using internal format.
+ *
+ * Example of usage:
+ *
+ * {{formatDateDiff seconds}}
+ *
+ */
+ public function formatDateDiffHelper($template, $context, $args, $source)
+ {
+ $parsed_args = $template->parseArguments($args);
+ if (empty($parsed_args)) {
+ return '';
+ }
+
+ $seconds = intval($context->get($parsed_args[0]));
+
+ return date_diff_to_text($seconds);
+ }
+
+ /**
+ * Cut string if it exceeds specified length.
+ *
+ * Example of usage:
+ *
+ * {{cutString string length}}
+ *
+ */
+ public function cutStringHelper($template, $context, $args, $source)
+ {
+ $parsed_args = $template->parseArguments($args);
+ if (empty($parsed_args) || count($parsed_args) < 2) {
+ return '';
+ }
+
+ $string = $context->get($parsed_args[0]);
+ $length = intval($context->get($parsed_args[1]));
+
+ return substr($string, 0, $length);
+ }
+
+ /**
+ * Actually builds helpers list.
+ *
+ * @return array List of helpers
+ */
+ protected function helpersList()
+ {
+ return array(
+ 'l10n' => array($this, 'localizationHelper'),
+ 'extends' => array($this, 'extendsHelper'),
+ 'block' => array($this, 'blockHelper'),
+ 'override' => array($this, 'overrideHelper'),
+ 'ifOverridden' => array($this, 'ifOverriddenHelper'),
+ 'unlessOverridden' => array($this, 'unlessOverriddenHelper'),
+ 'ifEqual' => array($this, 'ifEqualHelper'),
+ 'ifAny' => array($this, 'ifAnyHelper'),
+ 'generatePagination' => array($this, 'generatePaginationHelper'),
+ 'jsString' => array($this, 'jsStringHelper'),
+ 'repeat' => array($this, 'repeatHelper'),
+ 'replace' => array($this, 'replaceHelper'),
+ 'formatDate' => array($this, 'formatDateHelper'),
+ 'formatDateDiff' => array($this, 'formatDateDiffHelper'),
+ 'cutString' => array($this, 'cutStringHelper'),
+ 'csrfTokenInput' => array($this, 'csrfTokenInputHelper'),
+ 'csrfTokenInUrl' => array($this, 'csrfTokenInUrlHelper'),
+ );
+ }
+}
diff --git a/src/mibew/libs/classes/Mibew/RequestProcessor/ThreadProcessor.php b/src/mibew/libs/classes/Mibew/RequestProcessor/ThreadProcessor.php
index afdd3962..3adeaba7 100644
--- a/src/mibew/libs/classes/Mibew/RequestProcessor/ThreadProcessor.php
+++ b/src/mibew/libs/classes/Mibew/RequestProcessor/ThreadProcessor.php
@@ -533,7 +533,7 @@ class ThreadProcessor extends ClientSideProcessor
if ($email) {
$thread->postMessage(
Thread::KIND_FOR_AGENT,
- getstring2('chat.visitor.email', array($email))
+ getstring2('chat.visitor.email', array($email), true)
);
}
@@ -647,19 +647,19 @@ class ThreadProcessor extends ClientSideProcessor
if ($referrer) {
$thread->postMessage(
Thread::KIND_FOR_AGENT,
- getstring2('chat.came.from', array($referrer))
+ getstring2('chat.came.from', array($referrer), true)
);
}
if ($email) {
$thread->postMessage(
Thread::KIND_FOR_AGENT,
- getstring2('chat.visitor.email', array($email))
+ getstring2('chat.visitor.email', array($email), true)
);
}
if ($info) {
$thread->postMessage(
Thread::KIND_FOR_AGENT,
- getstring2('chat.visitor.info', array($info))
+ getstring2('chat.visitor.info', array($info), true)
);
}
$thread->postMessage(Thread::KIND_USER, $message, array('name' => $name));
diff --git a/src/mibew/libs/classes/Mibew/Style/PageStyle.php b/src/mibew/libs/classes/Mibew/Style/PageStyle.php
index 32673528..42196964 100644
--- a/src/mibew/libs/classes/Mibew/Style/PageStyle.php
+++ b/src/mibew/libs/classes/Mibew/Style/PageStyle.php
@@ -19,12 +19,44 @@ namespace Mibew\Style;
// Import namespaces and classes of the core
use Mibew\Settings;
+use Mibew\Handlebars\HelpersSet;
/**
* Represents a style for operator pages
*/
class PageStyle extends AbstractStyle implements StyleInterface
{
+ /**
+ * Template engine for chat templates.
+ *
+ * @var \Handlebars\Handlebars
+ */
+ protected $templateEngine;
+
+ /**
+ * Object constructor
+ *
+ * @param string $style_name Name of the style
+ */
+ public function __construct($style_name)
+ {
+ parent::__construct($style_name);
+
+ $templates_loader = new \Handlebars\Loader\FilesystemLoader(
+ MIBEW_FS_ROOT . '/' . $this->filesPath() . '/templates_src/server_side/'
+ );
+
+ $this->templateEngine = new \Handlebars\Handlebars(array(
+ 'loader' => $templates_loader,
+ 'partials_loader' => $templates_loader,
+ 'helpers' => new \Handlebars\Helpers(HelpersSet::getHelpers())
+ ));
+
+ // Use custom function to escape strings
+ $this->templateEngine->setEscape('safe_htmlspecialchars');
+ $this->templateEngine->setEscapeArgs(array());
+ }
+
/**
* Builds base path for style files. This path is relative Mibew root and
* does not contain neither leading nor trailing slash.
@@ -49,20 +81,18 @@ class PageStyle extends AbstractStyle implements StyleInterface
// Prepare to output html
start_html_output();
- // Build full view name. Remove '\' and '/' characters form the
- // specified view name
- $full_view_name = MIBEW_FS_ROOT . '/' . $this->filesPath() . '/views/'
- . str_replace("/\\", '', $template_name) . '.php';
-
// $page variable is used in included views files, so we need to create
// it as an alias of $data argument.
$page = $data;
- // Add template root value to page variables
- $page['stylepath'] = MIBEW_WEB_ROOT . '/' . $this->filesPath();
+ // Pass additional variables to template
+ $page['mibewRoot'] = MIBEW_WEB_ROOT;
+ $page['mibewVersion'] = MIBEW_VERSION;
+ $page['currentLocale'] = CURRENT_LOCALE;
+ $page['rtl'] = (getlocal("localedirection") == 'rtl');
+ $page['stylePath'] = MIBEW_WEB_ROOT . '/' . $this->filesPath();
- // Load and execute the view
- require($full_view_name);
+ echo($this->templateEngine->render($template_name, $page));
}
/**
diff --git a/src/mibew/libs/classes/Mibew/Thread.php b/src/mibew/libs/classes/Mibew/Thread.php
index 6ccb5df7..e4057353 100644
--- a/src/mibew/libs/classes/Mibew/Thread.php
+++ b/src/mibew/libs/classes/Mibew/Thread.php
@@ -364,7 +364,7 @@ class Thread
// Send message
$thread->postMessage(
self::KIND_EVENTS,
- getstring_("chat.status.user.reopenedthread", $thread->locale)
+ getstring_("chat.status.user.reopenedthread", $thread->locale, true)
);
return $thread;
@@ -602,7 +602,8 @@ class Thread
// Send message to user
$message_to_post = getstring_(
"chat.status.operator.dead",
- $this->locale
+ $this->locale,
+ true
);
$this->postMessage(
self::KIND_CONN,
@@ -626,7 +627,8 @@ class Thread
// And send a message to operator
$message_to_post = getstring_(
"chat.status.user.dead",
- $this->locale
+ $this->locale,
+ true
);
$this->postMessage(
self::KIND_FOR_AGENT,
@@ -708,13 +710,15 @@ class Thread
$message_to_post = getstring2_(
"chat.status.operator.changed",
array($operator_name, $this->agentName),
- $this->locale
+ $this->locale,
+ true
);
} else {
$message_to_post = getstring2_(
"chat.status.operator.returned",
array($operator_name),
- $this->locale
+ $this->locale,
+ true
);
}
@@ -867,7 +871,8 @@ class Thread
getstring2_(
"chat.status.user.left",
array($this->userName),
- $this->locale
+ $this->locale,
+ true
)
);
} else {
@@ -876,7 +881,8 @@ class Thread
self::KIND_FOR_AGENT,
getstring_(
"chat.visitor.invitation.canceled",
- $this->locale
+ $this->locale,
+ true
)
);
} else {
@@ -885,7 +891,8 @@ class Thread
getstring2_(
"chat.status.operator.left",
array($this->agentName),
- $this->locale
+ $this->locale,
+ true
)
);
}
@@ -942,20 +949,23 @@ class Thread
$message = getstring2_(
"chat.status.operator.changed",
array($operator_name, $this->agentName),
- $this->locale
+ $this->locale,
+ true
);
} else {
$message = getstring2_(
"chat.status.operator.returned",
array($operator_name),
- $this->locale
+ $this->locale,
+ true
);
}
} else {
$message = getstring2_(
"chat.status.operator.joined",
array($operator_name),
- $this->locale
+ $this->locale,
+ true
);
}
} elseif ($this->state == self::STATE_CHATTING) {
@@ -965,7 +975,8 @@ class Thread
$message = getstring2_(
"chat.status.operator.changed",
array($operator_name, $this->agentName),
- $this->locale
+ $this->locale,
+ true
);
}
} else {
@@ -1015,7 +1026,8 @@ class Thread
$message = getstring2_(
"chat.status.user.changedname",
array($old_name, $new_name),
- $this->locale
+ $this->locale,
+ true
);
$this->postMessage(self::KIND_EVENTS, $message);
}
diff --git a/src/mibew/libs/common/csrf.php b/src/mibew/libs/common/csrf.php
index 50057a03..c51176a1 100644
--- a/src/mibew/libs/common/csrf.php
+++ b/src/mibew/libs/common/csrf.php
@@ -33,20 +33,18 @@ function csrf_check_token()
}
}
-/* print csrf token as a hidden field */
-function print_csrf_token_input()
+function get_csrf_token_input()
{
set_csrf_token();
- echo " ";
+ return ' ';
}
-/* print csrf token in url format */
-function print_csrf_token_in_url()
+function get_csrf_token_in_url()
{
set_csrf_token();
- echo "&csrf_token=" . $_SESSION['csrf_token'];
+ return "&csrf_token=" . $_SESSION['csrf_token'];
}
/* set csrf token */
diff --git a/src/mibew/libs/common/locale.php b/src/mibew/libs/common/locale.php
index ee3689eb..0adf3f4c 100644
--- a/src/mibew/libs/common/locale.php
+++ b/src/mibew/libs/common/locale.php
@@ -287,7 +287,7 @@ function getoutputenc()
: MIBEW_ENCODING;
}
-function getstring_($text, $locale)
+function getstring_($text, $locale, $raw = false)
{
global $messages;
if (!isset($messages[$locale])) {
@@ -296,53 +296,66 @@ function getstring_($text, $locale)
$localized = $messages[$locale];
if (isset($localized[$text])) {
- return $localized[$text];
+ return $raw
+ ? $localized[$text]
+ : sanitize_string($localized[$text], 'low', 'moderate');
}
if ($locale != 'en') {
- return getstring_($text, 'en');
+ return getstring_($text, 'en', $raw);
}
- return "!" . $text;
+ return "!" . ($raw ? $text : sanitize_string($text, 'low', 'moderate'));
}
-function getstring($text)
+function getstring($text, $raw = false)
{
- return getstring_($text, CURRENT_LOCALE);
+ return getstring_($text, CURRENT_LOCALE, $raw);
}
-function getlocal($text)
+function getlocal($text, $raw = false)
{
- return myiconv(MIBEW_ENCODING, getoutputenc(), getstring_($text, CURRENT_LOCALE));
+ return getlocal_($text, CURRENT_LOCALE, $raw);
}
-function getlocal_($text, $locale)
+function getlocal_($text, $locale, $raw = false)
{
- return myiconv(MIBEW_ENCODING, getoutputenc(), getstring_($text, $locale));
+ $string = myiconv(
+ MIBEW_ENCODING,
+ getoutputenc(),
+ getstring_($text, $locale, true)
+ );
+
+ return $raw ? $string : sanitize_string($string, 'low', 'moderate');
}
-function getstring2_($text, $params, $locale)
+function getstring2_($text, $params, $locale, $raw = false)
{
- $string = getstring_($text, $locale);
+ $string = getstring_($text, $locale, true);
for ($i = 0; $i < count($params); $i++) {
$string = str_replace("{" . $i . "}", $params[$i], $string);
}
- return $string;
+ return $raw ? $string : sanitize_string($string, 'low', 'moderate');
}
-function getstring2($text, $params)
+function getstring2($text, $params, $raw = false)
{
- return getstring2_($text, $params, CURRENT_LOCALE);
+ return getstring2_($text, $params, CURRENT_LOCALE, $raw);
}
-function getlocal2($text, $params)
+function getlocal2($text, $params, $raw = false)
{
- $string = myiconv(MIBEW_ENCODING, getoutputenc(), getstring_($text, CURRENT_LOCALE));
+ $string = myiconv(
+ MIBEW_ENCODING,
+ getoutputenc(),
+ getstring_($text, CURRENT_LOCALE, true)
+ );
+
for ($i = 0; $i < count($params); $i++) {
$string = str_replace("{" . $i . "}", $params[$i], $string);
}
- return $string;
+ return $raw ? $string : sanitize_string($string, 'low', 'moderate');
}
/* prepares for Javascript string */
@@ -354,7 +367,7 @@ function get_local_for_js($text, $params)
$string = str_replace("{" . $i . "}", $params[$i], $string);
}
- return $string;
+ return sanitize_string($string, 'low', 'moderate');
}
function locale_load_id_list($name)
diff --git a/src/mibew/libs/common/string.php b/src/mibew/libs/common/string.php
index db3feeab..490bd78d 100644
--- a/src/mibew/libs/common/string.php
+++ b/src/mibew/libs/common/string.php
@@ -54,3 +54,116 @@ function escape_with_cdata($text)
{
return "", "]]>]]>";
}
+
+/**
+ * Simple HTML sanitation.
+ *
+ * Includes some code from the PHP StripAttributes Class For XML and HTML.
+ *
+ * @param string $string Target string
+ * @param string $tags_level Sanitation level for tags. Available values are
+ * "high", "moderate" and "low".
+ * @param string $attr_level Sanitation level for attributes. Available values
+ * are "high", "moderate" and "low".
+ * @return string Sanitized string with stripped dangerous tags and attributes.
+ *
+ * @author David (semlabs.co.uk)
+ * @copyright (c) 2009, David (semlabs.co.uk)
+ * @license MIT
+ * @link http://semlabs.co.uk/journal/php-strip-attributes-class-for-xml-and-html
+ */
+function sanitize_string($string, $tags_level = 'high', $attr_level = 'high')
+{
+ $sanitize_tags = array(
+ 'high' => '',
+ 'moderate' => ' ',
+ 'low' => '