From 97aa353652257d0b4f4074c0f87bf6d08995d9c4 Mon Sep 17 00:00:00 2001
From: Hypolite Petovan <mrpetovan@gmail.com>
Date: Sat, 4 Aug 2018 15:59:04 +0200
Subject: [PATCH 1/3] [advancedcontentfilter] Move Vue template from DOM to
 compiled render functions

---
 .../advancedcontentfilter.php                 |   2 +-
 advancedcontentfilter/templates/settings.tpl  | 231 +++++++++++-------
 2 files changed, 142 insertions(+), 91 deletions(-)

diff --git a/advancedcontentfilter/advancedcontentfilter.php b/advancedcontentfilter/advancedcontentfilter.php
index 34d47425e..2d1308e7a 100644
--- a/advancedcontentfilter/advancedcontentfilter.php
+++ b/advancedcontentfilter/advancedcontentfilter.php
@@ -213,7 +213,7 @@ function advancedcontentfilter_content(App $a)
 			'$title' => L10n::t('Advanced Content Filter'),
 			'$add_a_rule' => L10n::t('Add a Rule'),
 			'$help' => L10n::t('Help'),
-			'$advanced_content_filter_intro' => L10n::t('Add and manage your personal content filter rules in this screen. Rules have a name and an arbitrary expression that will be matched against post data. For a complete reference of the available operations and variables, check the <a href="advancedcontentfilter/help">help page</a>.'),
+			'$advanced_content_filter_intro' => addslashes(L10n::t('Add and manage your personal content filter rules in this screen. Rules have a name and an arbitrary expression that will be matched against post data. For a complete reference of the available operations and variables, check the <a href="advancedcontentfilter/help">help page</a>.')),
 			'$your_rules' => L10n::t('Your rules'),
 			'$no_rules' => L10n::t('You have no rules yet! Start adding one by clicking on the button above next to the title.'),
 			'$disabled' => L10n::t('Disabled'),
diff --git a/advancedcontentfilter/templates/settings.tpl b/advancedcontentfilter/templates/settings.tpl
index 813dc9199..b12df73c2 100644
--- a/advancedcontentfilter/templates/settings.tpl
+++ b/advancedcontentfilter/templates/settings.tpl
@@ -1,98 +1,149 @@
 <div id="adminpage">
 	<style>[v-cloak] { display: none; }</style>
-	<div id="rules">
-		<p><a href="settings/addon">🔙 {{$backtosettings}}</a></p>
-		<h1>
-			{{$title}}
-
-			<a href="{{$baseurl}}/advancedcontentfilter/help" class="btn btn-default btn-sm" title="{{$help}}">
-				<i class="fa fa-question fa-2x" aria-hidden="true"></i>
-			</a>
-		</h1>
-		<div>{{$advanced_content_filter_intro}}</div>
-		<h2>
-			{{$your_rules}}
-			<button class="btn btn-primary btn-sm" title="{{$add_a_rule}}" @click="showModal = true">
-				<i class="fa fa-plus fa-2x" aria-hidden="true"></i>
-			</button>
-		</h2>
-		<div v-if="rules.length === 0" v-cloak>
-			{{$no_rules}}
-		</div>
-
-		<ul class="list-group" v-cloak>
-			<li class="list-group-item" v-for="rule in rules">
-				<p class="pull-right">
-					<button type="button" class="btn btn-xs btn-primary" v-on:click="toggleActive(rule)" aria-label="{{$disable_this_rule}}" title="{{$disable_this_rule}}" v-if="parseInt(rule.active)">
-						<i class="fa fa-toggle-on" aria-hidden="true"></i> {{$enabled}}
-					</button>
-					<button type="button" class="btn btn-xs btn-default" v-on:click="toggleActive(rule)" aria-label="{{$enable_this_rule}}" title="{{$enable_this_rule}}" v-else>
-						<i class="fa fa-toggle-off" aria-hidden="true"></i> {{$disabled}}
-					</button>
-
-					<button type="button" class="btn btn-xs btn-primary" v-on:click="editRule(rule)" aria-label="{{$edit_this_rule}}" title="{{$edit_this_rule}}">
-						<i class="fa fa-pencil" aria-hidden="true"></i>
-					</button>
-					<button type="button" class="btn btn-xs btn-default" v-on:click="deleteRule(rule)" aria-label="{{$delete_this_rule}}" title="{{$delete_this_rule}}">
-						<i class="fa fa-trash-o" aria-hidden="true"></i>
-					</button>
-				</p>
-				<h3 class="list-group-item-heading">
-					{{$rule}} #{{ rule.id }}: {{ rule.name }}
-				</h3>
-				<pre class="list-group-item-text" v-if="rule.expression">{{ rule.expression }}</pre>
-			</li>
-		</ul>
-
-		<div class="modal fade" ref="vuemodal" tabindex="-1" role="dialog" v-cloak>
-			<div class="modal-dialog" role="document">
-				<div class="modal-content">
-					<div class="modal-header">
-		{{if $current_theme == 'frio'}}
-						<button type="button" class="close" data-dismiss="modal" aria-label="{{$close}}" @click="showModal = false"><span aria-hidden="true">&times;</span></button>
-		{{/if}}
-						<h3 v-if="rule.id">{{$edit_the_rule}} "{{ rule.name }}"</h3>
-						<h3 v-if="!rule.id">{{$add_a_rule}}</h3>
-					</div>
-					<div class="modal-body">
-						<form>
-							<input type="hidden" name="form_security_token" id="csrf" value="{{$form_security_token}}" />
-							<div class="alert alert-danger" role="alert" v-if="errorMessage">{{ errorMessage }}</div>
-							<div class="form-group">
-								<input class="form-control" placeholder="{{$rule_name}}" v-model="rule.name">
-							</div>
-							<div class="form-group">
-								<input class="form-control" placeholder="{{$rule_expression}}" v-model="rule.expression">
-							</div>
-						</form>
-					</div>
-					<div class="modal-footer">
-						<button type="button" class="btn btn-default" data-dismiss="modal" aria-label="Close" @click="resetForm()">{{$cancel}}</button>
-						<button slot="button" class="btn btn-primary" type="button" v-if="rule.id" v-on:click="saveRule(rule)">{{$save_this_rule}}</button>
-						<button slot="button" class="btn btn-primary" type="button" v-if="!rule.id" v-on:click="addRule()">{{$add_a_rule}}</button>
-					</div>
-				</div><!-- /.modal-content -->
-			</div><!-- /.modal-dialog -->
-		</div><!-- /.modal -->
-
-		<form class="form-inline" v-on:submit.prevent="showVariables()">
-			<fieldset>
-				<legend>Show post variables</legend>
-				<div class="form-group" style="width: 50%">
-					<label for="itemUrl" class="sr-only">Post URL or item guid</label>
-					<input class="form-control" id="itemUrl" placeholder="Post URL or item guid" v-model="itemUrl" style="width: 100%">
-				</div>
-				<button type="submit" class="btn btn-primary">Show Variables</button>
-			</fieldset>
-		</form>
-		<pre v-cloak>
-{{ itemJson }}
-		</pre>
-	</div>
+	<div id="rules"></div>
 
 	<script> var existingRules = {{$rules}};</script>
 
 	<!-- JS -->
 	<script src="{{$baseurl}}/view/asset/vue/dist/vue.min.js"></script>
-	<script src="{{$baseurl}}/addon/advancedcontentfilter/advancedcontentfilter.js"></script>
+	<script>
+$.extend({
+	ajaxJSON: function(method, url, data) {
+		return $.ajax({
+			type: method.toUpperCase(),
+			url: url,
+			data: JSON.stringify(data),
+			contentType: 'application/json; charset=utf-8',
+			dataType: 'json'
+		});
+	}
+});
+
+new Vue({
+	el: '#rules',
+
+	data: {
+		showModal: false,
+		errorMessage: '',
+		editedIndex: null,
+		rule: {id: '', name: '', expression: '', created: ''},
+		rules: existingRules || [],
+		itemUrl: '',
+		itemJson: ''
+	},
+
+	watch: {
+		showModal: function () {
+			if (this.showModal) {
+				$(this.$refs.vuemodal).modal('show');
+			} else {
+				$(this.$refs.vuemodal).modal('hide');
+			}
+		}
+	},
+
+	mounted: function() {
+		$.ajaxSetup({headers: {'X-CSRF-Token': document.querySelector('#csrf').getAttribute('value')}});
+	},
+
+	methods: {
+		resetForm: function() {
+			this.rule = {id: '', name: '', expression: '', created: ''};
+			this.showModal = false;
+			this.editedIndex = null;
+		},
+
+		addRule: function () {
+			if (this.rule.name.trim()) {
+				this.errorMessage = '';
+
+				var self = this;
+				$.ajaxJSON('post', '/advancedcontentfilter/api/rules', this.rule)
+				.then(function (responseJSON) {
+					self.rules.push(responseJSON.rule);
+					self.resetForm();
+				}, function (response) {
+					self.errorMessage = response.responseJSON.message;
+				});
+			}
+		},
+
+		editRule: function (rule) {
+			this.editedIndex = this.rules.indexOf(rule);
+			this.rule = Object.assign({}, rule);
+			this.showModal = true;
+		},
+
+		saveRule: function (rule) {
+			this.errorMessage = '';
+
+			var self = this;
+			$.ajaxJSON('put', '/advancedcontentfilter/api/rules/' + rule.id, rule)
+			.then(function () {
+				self.rules[self.editedIndex] = rule;
+				self.resetForm();
+			}, function (response) {
+				self.errorMessage = response.responseJSON.message;
+			});
+		},
+
+		toggleActive: function (rule) {
+			var previousValue = this.rules[this.rules.indexOf(rule)].active;
+			var newValue = Math.abs(parseInt(rule.active) - 1);
+
+			this.rules[this.rules.indexOf(rule)].active = newValue;
+
+			var self = this;
+			$.ajaxJSON('put', '/advancedcontentfilter/api/rules/' + rule.id, {'active': newValue})
+			.fail(function (response) {
+				self.rules[self.rules.indexOf(rule)].active = previousValue;
+				console.log(response.responseJSON.message);
+			});
+		},
+
+		deleteRule: function (rule) {
+			if (confirm('Are you sure you want to delete this rule?')) {
+				var self = this;
+				$.ajaxJSON('delete', '/advancedcontentfilter/api/rules/' + rule.id)
+				.then(function () {
+					self.rules.splice(self.rules.indexOf(rule), 1);
+				}, function (response) {
+					console.log(response.responseJSON.message);
+				});
+			}
+		},
+
+		showVariables: function () {
+			var urlParts = this.itemUrl.split('/');
+			var guid = urlParts[urlParts.length - 1];
+
+			this.itemJson = '';
+
+			var self = this;
+			$.ajaxJSON('get', '/advancedcontentfilter/api/variables/' + guid)
+			.then(function (responseJSON) {
+				self.itemJson = responseJSON.variables;
+			}, function (response) {
+				self.itemJson = response.responseJSON.message;
+			});
+
+			return false;
+		}
+	},
+
+	// These render function have been compiled from templates/vue_dom.tpl, check this file out for instructions
+	render: function () {
+		with(this){return _c('div',{attrs:{"id":"rules"}},[_m(0),_m(1),_c('div',[_v("{{$advanced_content_filter_intro}}")]),_c('h2',[_v("{{$your_rules}}"),_c('button',{staticClass:"btn btn-primary btn-sm",attrs:{"title":"{{$add_a_rule}}"},on:{"click":function($event){showModal = true}}},[_c('i',{staticClass:"fa fa-plus fa-2x",attrs:{"aria-hidden":"true"}})])]),(rules.length === 0)?_c('div',{},[_v("{{$no_rules}}")]):_e(),_c('ul',{staticClass:"list-group"},_l((rules),function(rule){return _c('li',{staticClass:"list-group-item"},[_c('p',{staticClass:"pull-right"},[(parseInt(rule.active))?_c('button',{staticClass:"btn btn-xs btn-primary",attrs:{"type":"button","aria-label":"{{$disable_this_rule}}","title":"{{$disable_this_rule}}"},on:{"click":function($event){toggleActive(rule)}}},[_c('i',{staticClass:"fa fa-toggle-on",attrs:{"aria-hidden":"true"}}),_v(" {{$enabled}}")]):_c('button',{staticClass:"btn btn-xs btn-default",attrs:{"type":"button","aria-label":"{{$enable_this_rule}}","title":"{{$enable_this_rule}}"},on:{"click":function($event){toggleActive(rule)}}},[_c('i',{staticClass:"fa fa-toggle-off",attrs:{"aria-hidden":"true"}}),_v(" {{$disabled}}")]),_c('button',{staticClass:"btn btn-xs btn-primary",attrs:{"type":"button","aria-label":"{{$edit_this_rule}}","title":"{{$edit_this_rule}}"},on:{"click":function($event){editRule(rule)}}},[_c('i',{staticClass:"fa fa-pencil",attrs:{"aria-hidden":"true"}})]),_c('button',{staticClass:"btn btn-xs btn-default",attrs:{"type":"button","aria-label":"{{$delete_this_rule}}","title":"{{$delete_this_rule}}"},on:{"click":function($event){deleteRule(rule)}}},[_c('i',{staticClass:"fa fa-trash-o",attrs:{"aria-hidden":"true"}})])]),_c('h3',{staticClass:"list-group-item-heading"},[_v("{{$rule}} #"+_s(rule.id)+": "+_s(rule.name))]),(rule.expression)?_c('pre',{staticClass:"list-group-item-text"},[_v(_s(rule.expression))]):_e()])})),_c('div',{ref:"vuemodal",staticClass:"modal fade",attrs:{"tabindex":"-1","role":"dialog"}},[_c('div',{staticClass:"modal-dialog",attrs:{"role":"document"}},[_c('div',{staticClass:"modal-content"},[_c('div',{staticClass:"modal-header"},[_c('button',{staticClass:"close",attrs:{"type":"button","data-dismiss":"modal","aria-label":"{{$close}}"},on:{"click":function($event){showModal = false}}},[_c('span',{attrs:{"aria-hidden":"true"}},[_v("×")])]),(rule.id)?_c('h3',[_v("{{$edit_the_rule}} \""+_s(rule.name)+"\"")]):_e(),(!rule.id)?_c('h3',[_v("{{$add_a_rule}}")]):_e()]),_c('div',{staticClass:"modal-body"},[_c('form',[_c('input',{attrs:{"type":"hidden","name":"form_security_token","id":"csrf","value":"{{$form_security_token}}"}}),(errorMessage)?_c('div',{staticClass:"alert alert-danger",attrs:{"role":"alert"}},[_v(_s(errorMessage))]):_e(),_c('div',{staticClass:"form-group"},[_c('input',{directives:[{name:"model",rawName:"v-model",value:(rule.name),expression:"rule.name"}],staticClass:"form-control",attrs:{"placeholder":"{{$rule_name}}"},domProps:{"value":(rule.name)},on:{"input":function($event){if($event.target.composing)return;$set(rule, "name", $event.target.value)}}})]),_c('div',{staticClass:"form-group"},[_c('input',{directives:[{name:"model",rawName:"v-model",value:(rule.expression),expression:"rule.expression"}],staticClass:"form-control",attrs:{"placeholder":"{{$rule_expression}}"},domProps:{"value":(rule.expression)},on:{"input":function($event){if($event.target.composing)return;$set(rule, "expression", $event.target.value)}}})])])]),_c('div',{staticClass:"modal-footer"},[_c('button',{staticClass:"btn btn-default",attrs:{"type":"button","data-dismiss":"modal","aria-label":"Close"},on:{"click":function($event){resetForm()}}},[_v("{{$cancel}}")]),(rule.id)?_c('button',{staticClass:"btn btn-primary",attrs:{"slot":"button","type":"button"},on:{"click":function($event){saveRule(rule)}},slot:"button"},[_v("{{$save_this_rule}}")]):_e(),(!rule.id)?_c('button',{staticClass:"btn btn-primary",attrs:{"slot":"button","type":"button"},on:{"click":function($event){addRule()}},slot:"button"},[_v("{{$add_a_rule}}")]):_e()])])])]),_c('form',{staticClass:"form-inline",on:{"submit":function($event){$event.preventDefault();showVariables()}}},[_c('fieldset',[_c('legend',[_v("Show post variables")]),_c('div',{staticClass:"form-group",staticStyle:{"width":"50%"}},[_c('label',{staticClass:"sr-only",attrs:{"for":"itemUrl"}},[_v("Post URL or item guid")]),_c('input',{directives:[{name:"model",rawName:"v-model",value:(itemUrl),expression:"itemUrl"}],staticClass:"form-control",staticStyle:{"width":"100%"},attrs:{"id":"itemUrl","placeholder":"Post URL or item guid"},domProps:{"value":(itemUrl)},on:{"input":function($event){if($event.target.composing)return;itemUrl=$event.target.value}}})]),_c('button',{staticClass:"btn btn-primary",attrs:{"type":"submit"}},[_v("Show Variables")])])]),_c('pre',{},[_v(_s(itemJson))])])}
+	},
+
+	staticRenderFns: [
+		function () {
+			with(this){return _c('p',[_c('a',{attrs:{"href":"settings/addon"}},[_v("🔙 {{$backtosettings}}")])])}
+		},
+		function () {
+			with(this){return _c('h1',[_v("{{$title}}"),_c('a',{staticClass:"btn btn-default btn-sm",attrs:{"href":"{{$baseurl}}/advancedcontentfilter/help","title":"{{$help}}"}},[_c('i',{staticClass:"fa fa-question fa-2x",attrs:{"aria-hidden":"true"}})])])}
+		}
+	]
+});
+	</script>
 </div>

From ee8f151a232ef287d90553d49455da740c2c7a6c Mon Sep 17 00:00:00 2001
From: Hypolite Petovan <mrpetovan@gmail.com>
Date: Sat, 4 Aug 2018 16:00:03 +0200
Subject: [PATCH 2/3] [advancedcontentfilter] Remove obsolete external JS
 resource

---
 .../advancedcontentfilter.js                  | 122 ------------------
 1 file changed, 122 deletions(-)
 delete mode 100644 advancedcontentfilter/advancedcontentfilter.js

diff --git a/advancedcontentfilter/advancedcontentfilter.js b/advancedcontentfilter/advancedcontentfilter.js
deleted file mode 100644
index 67a2b8d24..000000000
--- a/advancedcontentfilter/advancedcontentfilter.js
+++ /dev/null
@@ -1,122 +0,0 @@
-$.ajaxSetup({headers: {'X-CSRF-Token': document.querySelector('#csrf').getAttribute('value')}});
-
-$.extend({
-	ajaxJSON: function(method, url, data) {
-		return $.ajax({
-			type: method.toUpperCase(),
-			url: url,
-			data: JSON.stringify(data),
-			contentType: 'application/json; charset=utf-8',
-			dataType: 'json'
-		});
-	}
-});
-
-new Vue({
-	el: '#rules',
-
-	data: {
-		showModal: false,
-		errorMessage: '',
-		editedIndex: null,
-		rule: {id: '', name: '', expression: '', created: ''},
-		rules: existingRules || [],
-		itemUrl: '',
-		itemJson: ''
-	},
-
-	watch: {
-		showModal: function () {
-			if (this.showModal) {
-				$(this.$refs.vuemodal).modal('show');
-			} else {
-				$(this.$refs.vuemodal).modal('hide');
-			}
-		}
-	},
-
-	methods: {
-		resetForm: function() {
-			this.rule = {id: '', name: '', expression: '', created: ''};
-			this.showModal = false;
-			this.editedIndex = null;
-		},
-
-		addRule: function () {
-			if (this.rule.name.trim()) {
-				this.errorMessage = '';
-
-				var self = this;
-				$.ajaxJSON('post', '/advancedcontentfilter/api/rules', this.rule)
-				.then(function (responseJSON) {
-					self.rules.push(responseJSON.rule);
-					self.resetForm();
-				}, function (response) {
-					self.errorMessage = response.responseJSON.message;
-				});
-			}
-		},
-
-		editRule: function (rule) {
-			this.editedIndex = this.rules.indexOf(rule);
-			this.rule = Object.assign({}, rule);
-			this.showModal = true;
-		},
-
-		saveRule: function (rule) {
-			this.errorMessage = '';
-
-			var self = this;
-			$.ajaxJSON('put', '/advancedcontentfilter/api/rules/' + rule.id, rule)
-			.then(function () {
-				self.rules[self.editedIndex] = rule;
-				self.resetForm();
-			}, function (response) {
-				self.errorMessage = response.responseJSON.message;
-			});
-		},
-
-		toggleActive: function (rule) {
-			var previousValue = this.rules[this.rules.indexOf(rule)].active;
-			var newValue = Math.abs(parseInt(rule.active) - 1);
-
-			this.rules[this.rules.indexOf(rule)].active = newValue;
-
-			var self = this;
-			$.ajaxJSON('put', '/advancedcontentfilter/api/rules/' + rule.id, {'active': newValue})
-			.fail(function (response) {
-				self.rules[self.rules.indexOf(rule)].active = previousValue;
-				console.log(response.responseJSON.message);
-			});
-		},
-
-		deleteRule: function (rule) {
-			if (confirm('Are you sure you want to delete this rule?')) {
-				var self = this;
-				$.ajaxJSON('delete', '/advancedcontentfilter/api/rules/' + rule.id)
-				.then(function () {
-					self.rules.splice(self.rules.indexOf(rule), 1);
-				}, function (response) {
-					console.log(response.responseJSON.message);
-				});
-			}
-		},
-
-		showVariables: function () {
-			var urlParts = this.itemUrl.split('/');
-			var guid = urlParts[urlParts.length - 1];
-
-			this.itemJson = '';
-
-			var self = this;
-			$.ajaxJSON('get', '/advancedcontentfilter/api/variables/' + guid)
-			.then(function (responseJSON) {
-				self.itemJson = responseJSON.variables;
-			}, function (response) {
-				self.itemJson = response.responseJSON.message;
-			});
-
-			return false;
-		}
-	}
-});
\ No newline at end of file

From 48d887dd21ea9cd9aaca5a843b564303680680d0 Mon Sep 17 00:00:00 2001
From: Hypolite Petovan <mrpetovan@gmail.com>
Date: Sat, 4 Aug 2018 16:00:41 +0200
Subject: [PATCH 3/3] [advancedcontentfilter] Add new support DOM file

---
 advancedcontentfilter/templates/vue_dom.tpl | 96 +++++++++++++++++++++
 1 file changed, 96 insertions(+)
 create mode 100644 advancedcontentfilter/templates/vue_dom.tpl

diff --git a/advancedcontentfilter/templates/vue_dom.tpl b/advancedcontentfilter/templates/vue_dom.tpl
new file mode 100644
index 000000000..24538b86d
--- /dev/null
+++ b/advancedcontentfilter/templates/vue_dom.tpl
@@ -0,0 +1,96 @@
+<!--
+	This the the source HTML for the render functions defined in settings.tpl
+	This file is only for reference only and editing it won't change the addon display.
+	Here's the workflow to change the actual display:
+	1. Edit this file
+	2. Run it through https://vuejs.org/v2/guide/render-function.html#Template-Compilation
+	3. In the results, replace ##$ by {{$ and ## by }} in order to restore smarty variable interpolation
+	4. Replace the render and staticRenderFns members in settings.tpl by the contents of the output anonymous() functions
+-->
+<div id="rules">
+	<p><a href="settings/addon">🔙 ##$backtosettings##</a></p>
+	<h1>
+		##$title##
+
+		<a href="##$baseurl##/advancedcontentfilter/help" class="btn btn-default btn-sm" title="##$help##">
+			<i class="fa fa-question fa-2x" aria-hidden="true"></i>
+		</a>
+	</h1>
+	<div>##$advanced_content_filter_intro##</div>
+	<h2>
+		##$your_rules##
+		<button class="btn btn-primary btn-sm" title="##$add_a_rule##" @click="showModal = true">
+			<i class="fa fa-plus fa-2x" aria-hidden="true"></i>
+		</button>
+	</h2>
+	<div v-if="rules.length === 0" v-cloak>
+		##$no_rules##
+	</div>
+
+	<ul class="list-group" v-cloak>
+		<li class="list-group-item" v-for="rule in rules">
+			<p class="pull-right">
+				<button type="button" class="btn btn-xs btn-primary" v-on:click="toggleActive(rule)" aria-label="##$disable_this_rule##" title="##$disable_this_rule##" v-if="parseInt(rule.active)">
+					<i class="fa fa-toggle-on" aria-hidden="true"></i> ##$enabled##
+				</button>
+				<button type="button" class="btn btn-xs btn-default" v-on:click="toggleActive(rule)" aria-label="##$enable_this_rule##" title="##$enable_this_rule##" v-else>
+					<i class="fa fa-toggle-off" aria-hidden="true"></i> ##$disabled##
+				</button>
+
+				<button type="button" class="btn btn-xs btn-primary" v-on:click="editRule(rule)" aria-label="##$edit_this_rule##" title="##$edit_this_rule##">
+					<i class="fa fa-pencil" aria-hidden="true"></i>
+				</button>
+				<button type="button" class="btn btn-xs btn-default" v-on:click="deleteRule(rule)" aria-label="##$delete_this_rule##" title="##$delete_this_rule##">
+					<i class="fa fa-trash-o" aria-hidden="true"></i>
+				</button>
+			</p>
+			<h3 class="list-group-item-heading">
+				##$rule## #{{ rule.id }}: {{ rule.name }}
+			</h3>
+			<pre class="list-group-item-text" v-if="rule.expression">{{ rule.expression }}</pre>
+		</li>
+	</ul>
+
+	<div class="modal fade" ref="vuemodal" tabindex="-1" role="dialog" v-cloak>
+		<div class="modal-dialog" role="document">
+			<div class="modal-content">
+				<div class="modal-header">
+					<button type="button" class="close" data-dismiss="modal" aria-label="##$close##" @click="showModal = false"><span aria-hidden="true">&times;</span></button>
+					<h3 v-if="rule.id">##$edit_the_rule## "{{ rule.name }}"</h3>
+					<h3 v-if="!rule.id">##$add_a_rule##</h3>
+				</div>
+				<div class="modal-body">
+					<form>
+						<input type="hidden" name="form_security_token" id="csrf" value="##$form_security_token##" />
+						<div class="alert alert-danger" role="alert" v-if="errorMessage">{{ errorMessage }}</div>
+						<div class="form-group">
+							<input class="form-control" placeholder="##$rule_name##" v-model="rule.name">
+						</div>
+						<div class="form-group">
+							<input class="form-control" placeholder="##$rule_expression##" v-model="rule.expression">
+						</div>
+					</form>
+				</div>
+				<div class="modal-footer">
+					<button type="button" class="btn btn-default" data-dismiss="modal" aria-label="Close" @click="resetForm()">##$cancel##</button>
+					<button slot="button" class="btn btn-primary" type="button" v-if="rule.id" v-on:click="saveRule(rule)">##$save_this_rule##</button>
+					<button slot="button" class="btn btn-primary" type="button" v-if="!rule.id" v-on:click="addRule()">##$add_a_rule##</button>
+				</div>
+			</div><!-- /.modal-content -->
+		</div><!-- /.modal-dialog -->
+	</div><!-- /.modal -->
+
+	<form class="form-inline" v-on:submit.prevent="showVariables()">
+		<fieldset>
+			<legend>Show post variables</legend>
+			<div class="form-group" style="width: 50%">
+				<label for="itemUrl" class="sr-only">Post URL or item guid</label>
+				<input class="form-control" id="itemUrl" placeholder="Post URL or item guid" v-model="itemUrl" style="width: 100%">
+			</div>
+			<button type="submit" class="btn btn-primary">Show Variables</button>
+		</fieldset>
+	</form>
+	<pre v-cloak>
+{{ itemJson }}
+	</pre>
+</div>