Added autocomplete for template tags to the editor for email templates and landing pages.

This commit is contained in:
Jordan Wright 2018-12-30 00:02:41 -06:00
parent 60133b45e8
commit b4ff771b3a
10 changed files with 133 additions and 3 deletions

File diff suppressed because one or more lines are too long

8
static/css/main.css vendored
View file

@ -713,4 +713,12 @@ table.dataTable {
.cke_chrome {
border-top: 0 !important;
}
.cke_autocomplete_panel {
width: 400px !important;
}
.cke_autocomplete_panel>li {
padding: 10px 5px !important;
}

View file

@ -0,0 +1 @@
var TEMPLATE_TAGS=[{id:1,name:"RId",description:"The unique ID for the recipient."},{id:2,name:"FirstName",description:"The recipient's first name."},{id:3,name:"LastName",description:"The recipient's last name."},{id:4,name:"Position",description:"The recipient's position."},{id:5,name:"From",description:"The address emails are sent from."},{id:6,name:"TrackingURL",description:"The URL to track emails being opened."},{id:7,name:"Tracker",description:"An HTML tag that adds a hidden tracking image (recommended instead of TrackingURL)."},{id:8,name:"URL",description:"The URL to your Gophish listener."},{id:9,name:"BaseURL",description:"The base URL with the path and rid parameter stripped. Useful for making links to static files."}],textTestCallback=function(e){return e.collapsed?CKEDITOR.plugins.textMatch.match(e,matchCallback):null},matchCallback=function(e,t){var i=/\{{2}\.?([A-z]|\})*$/,a=e.slice(0,t).match(i);return a?{start:a.index,end:t}:null},dataCallback=function(e,t){t(TEMPLATE_TAGS.filter(function(t){return 0==("{{."+t.name.toLowerCase()+"}}").indexOf(e.query.toLowerCase())}))},setupAutocomplete=function(e){e.on("instanceReady",function(e){new CKEDITOR.plugins.autocomplete(e.editor,{textTestCallback:textTestCallback,dataCallback:dataCallback,itemTemplate:'<li data-id="{id}"><div><strong class="item-title">{name}</strong></div><div><i>{description}</i></div></li>',outputTemplate:"[[.{name}]]"}).getHtmlToInsert=function(e){var t=this.outputTemplate.output(e);return t=t.replace("[[","{{").replace("]]","}}")}})};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,115 @@
var TEMPLATE_TAGS = [{
id: 1,
name: 'RId',
description: 'The unique ID for the recipient.'
},
{
id: 2,
name: 'FirstName',
description: 'The recipient\'s first name.'
},
{
id: 3,
name: 'LastName',
description: 'The recipient\'s last name.'
},
{
id: 4,
name: 'Position',
description: 'The recipient\'s position.'
},
{
id: 5,
name: 'From',
description: 'The address emails are sent from.'
},
{
id: 6,
name: 'TrackingURL',
description: 'The URL to track emails being opened.'
},
{
id: 7,
name: 'Tracker',
description: 'An HTML tag that adds a hidden tracking image (recommended instead of TrackingURL).'
},
{
id: 8,
name: 'URL',
description: 'The URL to your Gophish listener.'
},
{
id: 9,
name: 'BaseURL',
description: 'The base URL with the path and rid parameter stripped. Useful for making links to static files.'
}
];
var textTestCallback = function (range) {
if (!range.collapsed) {
return null;
}
return CKEDITOR.plugins.textMatch.match(range, matchCallback);
}
var matchCallback = function (text, offset) {
var pattern = /\{{2}\.?([A-z]|\})*$/,
match = text.slice(0, offset)
.match(pattern);
if (!match) {
return null;
}
return {
start: match.index,
end: offset
};
}
/**
*
* @param {regex} matchInfo - The matched text object
* @param {function} callback - The callback to execute with the matched data
*/
var dataCallback = function (matchInfo, callback) {
var data = TEMPLATE_TAGS.filter(function (item) {
var itemName = '{{.' + item.name.toLowerCase() + '}}';
return itemName.indexOf(matchInfo.query.toLowerCase()) == 0;
});
callback(data);
}
/**
*
* @param {CKEditor} editor - The CKEditor instance.
*
* Installs the autocomplete plugin to the CKEditor.
*/
var setupAutocomplete = function (editor) {
editor.on('instanceReady', function (evt) {
var itemTemplate = '<li data-id="{id}">' +
'<div><strong class="item-title">{name}</strong></div>' +
'<div><i>{description}</i></div>' +
'</li>',
outputTemplate = '[[.{name}]]';
var autocomplete = new CKEDITOR.plugins.autocomplete(evt.editor, {
textTestCallback: textTestCallback,
dataCallback: dataCallback,
itemTemplate: itemTemplate,
outputTemplate: outputTemplate
});
// We have to use brackets for the output template tag and
// then manually replace them due to the way CKEditor's
// templating works.
autocomplete.getHtmlToInsert = function (item) {
var parsedTemplate = this.outputTemplate.output(item);
parsedTemplate = parsedTemplate.replace("[[", "{{").replace("]]", "}}")
return parsedTemplate
}
});
}

View file

@ -5,6 +5,7 @@
*/
var pages = []
// Save attempts to POST to /templates/
function save(idx) {
var page = {}
@ -107,6 +108,7 @@ function edit(idx) {
save(idx)
})
$("#html_editor").ckeditor()
setupAutocomplete(CKEDITOR.instances["html_editor"])
var page = {}
if (idx != -1) {
page = pages[idx]
@ -244,5 +246,6 @@ $(document).ready(function () {
infoTab.get('linkType').hidden = true;
}
});
load()
})

View file

@ -165,6 +165,7 @@ function edit(idx) {
this.value = null
})
$("#html_editor").ckeditor()
setupAutocomplete(CKEDITOR.instances["html_editor"])
$("#attachmentsTable").show()
attachmentsTable = $('#attachmentsTable').DataTable({
destroy: true,

View file

@ -148,5 +148,6 @@
{{define "scripts"}}
<script src="/js/src/vendor/ckeditor/ckeditor.js"></script>
<script src="/js/src/vendor/ckeditor/adapters/jquery.js"></script>
<script src="/js/dist/app/autocomplete.min.js"></script>
<script src="/js/dist/app/landing_pages.min.js"></script>
{{end}}

View file

@ -165,5 +165,6 @@
{{define "scripts"}}
<script src="/js/src/vendor/ckeditor/ckeditor.js"></script>
<script src="/js/src/vendor/ckeditor/adapters/jquery.js"></script>
<script src="/js/dist/app/autocomplete.min.js"></script>
<script src="/js/dist/app/templates.min.js"></script>
{{end}}