Formatting Javascript using js-beautifier

pull/75/head
Jordan Wright 2016-01-16 22:59:40 -06:00
parent e78ec27ef2
commit 2dda83814c
8 changed files with 924 additions and 875 deletions

View File

@ -2,254 +2,267 @@ var map = null
// statuses is a helper map to point result statuses to ui classes // statuses is a helper map to point result statuses to ui classes
var statuses = { var statuses = {
"Email Sent" : { "Email Sent": {
slice: "ct-slice-donut-sent", slice: "ct-slice-donut-sent",
legend: "ct-legend-sent", legend: "ct-legend-sent",
label: "label-success" label: "label-success"
}, },
"Email Opened" : { "Email Opened": {
slice: "ct-slice-donut-opened", slice: "ct-slice-donut-opened",
legend: "ct-legend-opened", legend: "ct-legend-opened",
label: "label-warning" label: "label-warning"
}, },
"Clicked Link" : { "Clicked Link": {
slice: "ct-slice-donut-clicked", slice: "ct-slice-donut-clicked",
legend: "ct-legend-clicked", legend: "ct-legend-clicked",
label: "label-danger" label: "label-danger"
}, },
"Success" : { "Success": {
slice: "ct-slice-donut-clicked", slice: "ct-slice-donut-clicked",
legend: "ct-legend-clicked", legend: "ct-legend-clicked",
label: "label-danger" label: "label-danger"
}, },
"Error" : { "Error": {
slice: "ct-slice-donut-error", slice: "ct-slice-donut-error",
legend: "ct-legend-error", legend: "ct-legend-error",
label: "label-default" label: "label-default"
}, },
"Unknown" : { "Unknown": {
slice: "ct-slice-donut-error", slice: "ct-slice-donut-error",
legend: "ct-legend-error", legend: "ct-legend-error",
label: "label-default" label: "label-default"
} }
} }
var campaign = {} var campaign = {}
function dismiss(){ function dismiss() {
$("#modal\\.flashes").empty() $("#modal\\.flashes").empty()
$("#modal").modal('hide') $("#modal").modal('hide')
$("#resultsTable").dataTable().DataTable().clear().draw() $("#resultsTable").dataTable().DataTable().clear().draw()
} }
// Deletes a campaign after prompting the user // Deletes a campaign after prompting the user
function deleteCampaign(){ function deleteCampaign() {
if (confirm("Are you sure you want to delete: " + campaign.name + "?")){ if (confirm("Are you sure you want to delete: " + campaign.name + "?")) {
api.campaignId.delete(campaign.id) api.campaignId.delete(campaign.id)
.success(function(msg){ .success(function(msg) {
console.log(msg) console.log(msg)
}) })
.error(function(e){ .error(function(e) {
$("#modal\\.flashes").empty().append("<div style=\"text-align:center\" class=\"alert alert-danger\">\ $("#modal\\.flashes").empty().append("<div style=\"text-align:center\" class=\"alert alert-danger\">\
<i class=\"fa fa-exclamation-circle\"></i> " + data.responseJSON.message + "</div>") <i class=\"fa fa-exclamation-circle\"></i> " + data.responseJSON.message + "</div>")
}) })
} }
} }
$(document).ready(function(){ $(document).ready(function() {
campaign.id = window.location.pathname.split('/').slice(-1)[0] campaign.id = window.location.pathname.split('/').slice(-1)[0]
api.campaignId.get(campaign.id) api.campaignId.get(campaign.id)
.success(function(c){ .success(function(c) {
campaign = c campaign = c
if (campaign){ if (campaign) {
// Set the title // Set the title
$("#page-title").text("Results for " + c.name) $("#page-title").text("Results for " + c.name)
// Setup tooltips // Setup tooltips
$('[data-toggle="tooltip"]').tooltip() $('[data-toggle="tooltip"]').tooltip()
// Setup our graphs // Setup our graphs
var timeline_data = {series:[{ var timeline_data = {
name: "Events", series: [{
data: [] name: "Events",
}]} data: []
var email_data = {series:[]} }]
var email_legend = {}
var email_series_data = {}
var timeline_opts = {
axisX: {
showGrid: false,
type: Chartist.FixedScaleAxis,
divisor: 5,
labelInterpolationFnc: function(value){
return moment(value).format('MMMM Do YYYY h:mm')
}
},
axisY: {
type: Chartist.FixedScaleAxis,
ticks: [0, 1, 2],
low: 0,
showLabel: false
},
showArea: false,
plugins: []
}
var email_opts = {
donut : true,
donutWidth: 40,
chartPadding: 0,
showLabel: false
}
// Setup the results table
resultsTable = $("#resultsTable").DataTable();
$.each(campaign.results, function(i, result){
label = statuses[result.status].label || "label-default";
resultsTable.row.add([
result.first_name || "",
result.last_name || "",
result.email || "",
result.position || "",
"<span class=\"label " + label + "\">" + result.status + "</span>"
]).draw()
if (!email_series_data[result.status]){
email_series_data[result.status] = 1
} else {
email_series_data[result.status]++;
} }
}) var email_data = {
// Setup the graphs series: []
$.each(campaign.timeline, function(i, event){
timeline_data.series[0].data.push({meta : i, x: new Date(event.time), y:1})
})
$.each(email_series_data, function(status, count){
email_data.series.push({meta: status, value: count})
})
var timeline_chart = new Chartist.Line('#timeline_chart', timeline_data, timeline_opts)
// Setup the overview chart listeners
$chart = $("#timeline_chart")
var $toolTip = $chart
.append('<div class="chartist-tooltip"></div>')
.find('.chartist-tooltip')
.hide();
$chart.on('mouseenter', '.ct-point', function() {
var $point = $(this)
value = $point.attr('ct:value')
cidx = $point.attr('ct:meta')
html = "Event: " + campaign.timeline[cidx].message
if (campaign.timeline[cidx].email) {
html += '<br>' + "Email: " + campaign.timeline[cidx].email
} }
$toolTip.html(html).show() var email_legend = {}
}); var email_series_data = {}
$chart.on('mouseleave', '.ct-point', function() { var timeline_opts = {
$toolTip.hide(); axisX: {
}); showGrid: false,
$chart.on('mousemove', function(event) { type: Chartist.FixedScaleAxis,
$toolTip.css({ divisor: 5,
left: (event.offsetX || event.originalEvent.layerX) - $toolTip.width() / 2 - 10, labelInterpolationFnc: function(value) {
top: (event.offsetY + 70 || event.originalEvent.layerY) - $toolTip.height() - 40 return moment(value).format('MMMM Do YYYY h:mm')
});
});
var email_chart = new Chartist.Pie("#email_chart", email_data, email_opts)
email_chart.on('draw', function(data){
// We don't want to create the legend twice
if (!email_legend[data.meta]) {
console.log(data.meta)
$("#email_chart_legend").append('<li><span class="' + statuses[data.meta].legend + '"></span>' + data.meta + '</li>')
email_legend[data.meta] = true
}
data.element.addClass(statuses[data.meta].slice)
})
// Setup the average chart listeners
$piechart = $("#email_chart")
var $pietoolTip = $piechart
.append('<div class="chartist-tooltip"></div>')
.find('.chartist-tooltip')
.hide();
$piechart.on('mouseenter', '.ct-slice-donut', function() {
var $point = $(this)
value = $point.attr('ct:value')
label = $point.attr('ct:meta')
$pietoolTip.html(label + ': ' + value.toString()).show();
});
$piechart.on('mouseleave', '.ct-slice-donut', function() {
$pietoolTip.hide();
});
$piechart.on('mousemove', function(event) {
$pietoolTip.css({
left: (event.offsetX || event.originalEvent.layerX) - $pietoolTip.width() / 2 - 10,
top: (event.offsetY + 40 || event.originalEvent.layerY) - $pietoolTip.height() - 80
});
});
$("#loading").hide()
$("#campaignResults").show()
map = new Datamap({
element: document.getElementById("resultsMap"),
responsive: true,
fills: {
defaultFill: "#ffffff",
point: "#283F50"
},
geographyConfig: {
highlightFillColor : "#1abc9c",
borderColor:"#283F50"
},
bubblesConfig: {
borderColor: "#283F50"
}
});
bubbles = []
$.each(campaign.results, function(i, result){
// Check that it wasn't an internal IP
if (result.latitude == 0 && result.longitude == 0) { return true; }
newIP = true
$.each(bubbles, function(i, bubble){
if (bubble.ip == result.ip){
bubbles[i].radius += 1
newIP = false
return false
}
})
if (newIP){
console.log("Adding bubble at: ")
console.log({
latitude : result.latitude,
longitude: result.longitude,
name : result.ip,
fillKey: "point"
})
bubbles.push({
latitude : result.latitude,
longitude: result.longitude,
name : result.ip,
fillKey: "point",
radius: 2
})
}
})
map.bubbles(bubbles)
}
// Load up the map data (only once!)
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
if ($(e.target).attr('href') == "#overview"){
if (!map){
map = new Datamap({
element: document.getElementById("resultsMap"),
responsive: true,
fills: {
defaultFill: "#ffffff"
},
geographyConfig: {
highlightFillColor : "#1abc9c",
borderColor:"#283F50"
} }
}); },
axisY: {
type: Chartist.FixedScaleAxis,
ticks: [0, 1, 2],
low: 0,
showLabel: false
},
showArea: false,
plugins: []
} }
var email_opts = {
donut: true,
donutWidth: 40,
chartPadding: 0,
showLabel: false
}
// Setup the results table
resultsTable = $("#resultsTable").DataTable();
$.each(campaign.results, function(i, result) {
label = statuses[result.status].label || "label-default";
resultsTable.row.add([
result.first_name || "",
result.last_name || "",
result.email || "",
result.position || "",
"<span class=\"label " + label + "\">" + result.status + "</span>"
]).draw()
if (!email_series_data[result.status]) {
email_series_data[result.status] = 1
} else {
email_series_data[result.status]++;
}
})
// Setup the graphs
$.each(campaign.timeline, function(i, event) {
timeline_data.series[0].data.push({
meta: i,
x: new Date(event.time),
y: 1
})
})
$.each(email_series_data, function(status, count) {
email_data.series.push({
meta: status,
value: count
})
})
var timeline_chart = new Chartist.Line('#timeline_chart', timeline_data, timeline_opts)
// Setup the overview chart listeners
$chart = $("#timeline_chart")
var $toolTip = $chart
.append('<div class="chartist-tooltip"></div>')
.find('.chartist-tooltip')
.hide();
$chart.on('mouseenter', '.ct-point', function() {
var $point = $(this)
value = $point.attr('ct:value')
cidx = $point.attr('ct:meta')
html = "Event: " + campaign.timeline[cidx].message
if (campaign.timeline[cidx].email) {
html += '<br>' + "Email: " + campaign.timeline[cidx].email
}
$toolTip.html(html).show()
});
$chart.on('mouseleave', '.ct-point', function() {
$toolTip.hide();
});
$chart.on('mousemove', function(event) {
$toolTip.css({
left: (event.offsetX || event.originalEvent.layerX) - $toolTip.width() / 2 - 10,
top: (event.offsetY + 70 || event.originalEvent.layerY) - $toolTip.height() - 40
});
});
var email_chart = new Chartist.Pie("#email_chart", email_data, email_opts)
email_chart.on('draw', function(data) {
// We don't want to create the legend twice
if (!email_legend[data.meta]) {
console.log(data.meta)
$("#email_chart_legend").append('<li><span class="' + statuses[data.meta].legend + '"></span>' + data.meta + '</li>')
email_legend[data.meta] = true
}
data.element.addClass(statuses[data.meta].slice)
})
// Setup the average chart listeners
$piechart = $("#email_chart")
var $pietoolTip = $piechart
.append('<div class="chartist-tooltip"></div>')
.find('.chartist-tooltip')
.hide();
$piechart.on('mouseenter', '.ct-slice-donut', function() {
var $point = $(this)
value = $point.attr('ct:value')
label = $point.attr('ct:meta')
$pietoolTip.html(label + ': ' + value.toString()).show();
});
$piechart.on('mouseleave', '.ct-slice-donut', function() {
$pietoolTip.hide();
});
$piechart.on('mousemove', function(event) {
$pietoolTip.css({
left: (event.offsetX || event.originalEvent.layerX) - $pietoolTip.width() / 2 - 10,
top: (event.offsetY + 40 || event.originalEvent.layerY) - $pietoolTip.height() - 80
});
});
$("#loading").hide()
$("#campaignResults").show()
map = new Datamap({
element: document.getElementById("resultsMap"),
responsive: true,
fills: {
defaultFill: "#ffffff",
point: "#283F50"
},
geographyConfig: {
highlightFillColor: "#1abc9c",
borderColor: "#283F50"
},
bubblesConfig: {
borderColor: "#283F50"
}
});
bubbles = []
$.each(campaign.results, function(i, result) {
// Check that it wasn't an internal IP
if (result.latitude == 0 && result.longitude == 0) {
return true;
}
newIP = true
$.each(bubbles, function(i, bubble) {
if (bubble.ip == result.ip) {
bubbles[i].radius += 1
newIP = false
return false
}
})
if (newIP) {
console.log("Adding bubble at: ")
console.log({
latitude: result.latitude,
longitude: result.longitude,
name: result.ip,
fillKey: "point"
})
bubbles.push({
latitude: result.latitude,
longitude: result.longitude,
name: result.ip,
fillKey: "point",
radius: 2
})
}
})
map.bubbles(bubbles)
} }
// Load up the map data (only once!)
$('a[data-toggle="tab"]').on('shown.bs.tab', function(e) {
if ($(e.target).attr('href') == "#overview") {
if (!map) {
map = new Datamap({
element: document.getElementById("resultsMap"),
responsive: true,
fills: {
defaultFill: "#ffffff"
},
geographyConfig: {
highlightFillColor: "#1abc9c",
borderColor: "#283F50"
}
});
}
}
})
})
.error(function() {
$("#loading").hide()
errorFlash(" Campaign not found!")
}) })
})
.error(function(){
$("#loading").hide()
errorFlash(" Campaign not found!")
})
}) })

View File

@ -1,212 +1,226 @@
// labels is a map of campaign statuses to // labels is a map of campaign statuses to
// CSS classes // CSS classes
var labels = { var labels = {
"In progress" : "label-primary", "In progress": "label-primary",
"Queued" : "label-info", "Queued": "label-info",
"Completed" : "label-success", "Completed": "label-success",
"Emails Sent" : "label-success", "Emails Sent": "label-success",
"Error" : "label-danger" "Error": "label-danger"
} }
// Save attempts to POST to /campaigns/ // Save attempts to POST to /campaigns/
function save(){ function save() {
groups = [] groups = []
$.each($("#groupTable").DataTable().rows().data(), function(i, group){ $.each($("#groupTable").DataTable().rows().data(), function(i, group) {
groups.push({name: group[0]}) groups.push({
name: group[0]
})
}) })
console.log(groups) console.log(groups)
var campaign = { var campaign = {
name: $("#name").val(), name: $("#name").val(),
template:{ template: {
name: $("#template").val() name: $("#template").val()
}, },
url: $("#url").val(), url: $("#url").val(),
page: { page: {
name: $("#page").val() name: $("#page").val()
}, },
smtp: { smtp: {
from_address: $("input[name=from]").val(), from_address: $("input[name=from]").val(),
host: $("input[name=host]").val(), host: $("input[name=host]").val(),
username: $("input[name=username]").val(), username: $("input[name=username]").val(),
password: $("input[name=password]").val(), password: $("input[name=password]").val(),
}, },
groups: groups groups: groups
} }
// Submit the campaign // Submit the campaign
api.campaigns.post(campaign) api.campaigns.post(campaign)
.success(function(data){ .success(function(data) {
successFlash("Campaign successfully launched!") successFlash("Campaign successfully launched!")
window.location = "/campaigns/" + campaign.id.toString() window.location = "/campaigns/" + campaign.id.toString()
}) })
.error(function(data){ .error(function(data) {
$("#modal\\.flashes").empty().append("<div style=\"text-align:center\" class=\"alert alert-danger\">\ $("#modal\\.flashes").empty().append("<div style=\"text-align:center\" class=\"alert alert-danger\">\
<i class=\"fa fa-exclamation-circle\"></i> " + data.responseJSON.message + "</div>") <i class=\"fa fa-exclamation-circle\"></i> " + data.responseJSON.message + "</div>")
}) })
} }
function dismiss(){ function dismiss() {
$("#modal\\.flashes").empty() $("#modal\\.flashes").empty()
$("#modal").modal('hide') $("#modal").modal('hide')
$("#groupTable").dataTable().DataTable().clear().draw() $("#groupTable").dataTable().DataTable().clear().draw()
} }
function edit(campaign){ function edit(campaign) {
// Clear the bloodhound instance // Clear the bloodhound instance
group_bh.clear(); group_bh.clear();
template_bh.clear(); template_bh.clear();
page_bh.clear(); page_bh.clear();
if (campaign == "new") { if (campaign == "new") {
api.groups.get() api.groups.get()
.success(function(groups){ .success(function(groups) {
if (groups.length == 0){ if (groups.length == 0) {
modalError("No groups found!") modalError("No groups found!")
return false; return false;
} } else {
else { group_bh.add(groups)
group_bh.add(groups) }
} })
}) api.templates.get()
api.templates.get() .success(function(templates) {
.success(function(templates){ if (templates.length == 0) {
if (templates.length == 0){ modalError("No templates found!")
modalError("No templates found!") return false
return false } else {
} template_bh.add(templates)
else { }
template_bh.add(templates) })
} api.pages.get()
}) .success(function(pages) {
api.pages.get() if (pages.length == 0) {
.success(function(pages){ modalError("No pages found!")
if (pages.length == 0){ return false
modalError("No pages found!") } else {
return false page_bh.add(pages)
} }
else { })
page_bh.add(pages)
}
})
} }
} }
$(document).ready(function(){ $(document).ready(function() {
api.campaigns.get() api.campaigns.get()
.success(function(campaigns){ .success(function(campaigns) {
$("#loading").hide() $("#loading").hide()
if (campaigns.length > 0){ if (campaigns.length > 0) {
$("#campaignTable").show() $("#campaignTable").show()
campaignTable = $("#campaignTable").DataTable(); campaignTable = $("#campaignTable").DataTable();
$.each(campaigns, function(i, campaign){ $.each(campaigns, function(i, campaign) {
label = labels[campaign.status] || "label-default"; label = labels[campaign.status] || "label-default";
campaignTable.row.add([ campaignTable.row.add([
campaign.name, campaign.name,
moment(campaign.created_date).format('MMMM Do YYYY, h:mm:ss a'), moment(campaign.created_date).format('MMMM Do YYYY, h:mm:ss a'),
"<span class=\"label " + label + "\">" + campaign.status + "</span>", "<span class=\"label " + label + "\">" + campaign.status + "</span>",
"<div class='pull-right'><a class='btn btn-primary' href='/campaigns/" + campaign.id + "'>\ "<div class='pull-right'><a class='btn btn-primary' href='/campaigns/" + campaign.id + "'>\
<i class='fa fa-bar-chart'></i>\ <i class='fa fa-bar-chart'></i>\
</a>\ </a>\
<button class='btn btn-danger' onclick='alert(\"test\")'>\ <button class='btn btn-danger' onclick='alert(\"test\")'>\
<i class='fa fa-trash-o'></i>\ <i class='fa fa-trash-o'></i>\
</button></div>" </button></div>"
]).draw() ]).draw()
}) })
} else { } else {
$("#emptyMessage").show() $("#emptyMessage").show()
} }
})
.error(function(){
$("#loading").hide()
errorFlash("Error fetching campaigns")
})
$("#groupForm").submit(function(){
groupTable.row.add([
$("#groupSelect").val(),
'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>'
]).draw()
$("#groupTable").on("click", "span>i.fa-trash-o", function(){
groupTable.row( $(this).parents('tr') )
.remove()
.draw();
}) })
return false; .error(function() {
}) $("#loading").hide()
// Create the group typeahead objects errorFlash("Error fetching campaigns")
})
$("#groupForm").submit(function() {
groupTable.row.add([
$("#groupSelect").val(),
'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>'
]).draw()
$("#groupTable").on("click", "span>i.fa-trash-o", function() {
groupTable.row($(this).parents('tr'))
.remove()
.draw();
})
return false;
})
// Create the group typeahead objects
groupTable = $("#groupTable").DataTable() groupTable = $("#groupTable").DataTable()
group_bh = new Bloodhound({ group_bh = new Bloodhound({
datumTokenizer: function(g) { return Bloodhound.tokenizers.whitespace(g.name) }, datumTokenizer: function(g) {
return Bloodhound.tokenizers.whitespace(g.name)
},
queryTokenizer: Bloodhound.tokenizers.whitespace, queryTokenizer: Bloodhound.tokenizers.whitespace,
local: [] local: []
}) })
group_bh.initialize() group_bh.initialize()
$("#groupSelect.typeahead.form-control").typeahead({ $("#groupSelect.typeahead.form-control").typeahead({
hint: true, hint: true,
highlight: true, highlight: true,
minLength: 1 minLength: 1
}, }, {
{ name: "groups",
name: "groups", source: group_bh,
source: group_bh, templates: {
templates: { empty: function(data) {
empty: function(data) {return '<div class="tt-suggestion">No groups matched that query</div>' }, return '<div class="tt-suggestion">No groups matched that query</div>'
suggestion: function(data){ return '<div>' + data.name + '</div>' } },
} suggestion: function(data) {
}) return '<div>' + data.name + '</div>'
.bind('typeahead:select', function(ev, group){ }
$("#groupSelect").typeahead('val', group.name) }
}) })
.bind('typeahead:autocomplete', function(ev, group){ .bind('typeahead:select', function(ev, group) {
$("#groupSelect").typeahead('val', group.name) $("#groupSelect").typeahead('val', group.name)
}); })
.bind('typeahead:autocomplete', function(ev, group) {
$("#groupSelect").typeahead('val', group.name)
});
// Create the template typeahead objects // Create the template typeahead objects
template_bh = new Bloodhound({ template_bh = new Bloodhound({
datumTokenizer: function(t) { return Bloodhound.tokenizers.whitespace(t.name) }, datumTokenizer: function(t) {
return Bloodhound.tokenizers.whitespace(t.name)
},
queryTokenizer: Bloodhound.tokenizers.whitespace, queryTokenizer: Bloodhound.tokenizers.whitespace,
local: [] local: []
}) })
template_bh.initialize() template_bh.initialize()
$("#template.typeahead.form-control").typeahead({ $("#template.typeahead.form-control").typeahead({
hint: true, hint: true,
highlight: true, highlight: true,
minLength: 1 minLength: 1
}, }, {
{ name: "templates",
name: "templates", source: template_bh,
source: template_bh, templates: {
templates: { empty: function(data) {
empty: function(data) {return '<div class="tt-suggestion">No templates matched that query</div>' }, return '<div class="tt-suggestion">No templates matched that query</div>'
suggestion: function(data){ return '<div>' + data.name + '</div>' } },
} suggestion: function(data) {
}) return '<div>' + data.name + '</div>'
.bind('typeahead:select', function(ev, template){ }
$("#template").typeahead('val', template.name) }
}) })
.bind('typeahead:autocomplete', function(ev, template){ .bind('typeahead:select', function(ev, template) {
$("#template").typeahead('val', template.name) $("#template").typeahead('val', template.name)
}); })
.bind('typeahead:autocomplete', function(ev, template) {
$("#template").typeahead('val', template.name)
});
// Create the landing page typeahead objects // Create the landing page typeahead objects
page_bh = new Bloodhound({ page_bh = new Bloodhound({
datumTokenizer: function(p) { return Bloodhound.tokenizers.whitespace(p.name) }, datumTokenizer: function(p) {
return Bloodhound.tokenizers.whitespace(p.name)
},
queryTokenizer: Bloodhound.tokenizers.whitespace, queryTokenizer: Bloodhound.tokenizers.whitespace,
local: [] local: []
}) })
page_bh.initialize() page_bh.initialize()
$("#page.typeahead.form-control").typeahead({ $("#page.typeahead.form-control").typeahead({
hint: true, hint: true,
highlight: true, highlight: true,
minLength: 1 minLength: 1
}, }, {
{ name: "pages",
name: "pages", source: page_bh,
source: page_bh, templates: {
templates: { empty: function(data) {
empty: function(data) {return '<div class="tt-suggestion">No pages matched that query</div>' }, return '<div class="tt-suggestion">No pages matched that query</div>'
suggestion: function(data){ return '<div>' + data.name + '</div>' } },
} suggestion: function(data) {
}) return '<div>' + data.name + '</div>'
.bind('typeahead:select', function(ev, page){ }
$("#page").typeahead('val', page.name) }
}) })
.bind('typeahead:autocomplete', function(ev, page){ .bind('typeahead:select', function(ev, page) {
$("#page").typeahead('val', page.name) $("#page").typeahead('val', page.name)
}); })
.bind('typeahead:autocomplete', function(ev, page) {
$("#page").typeahead('val', page.name)
});
}) })

View File

@ -1,129 +1,145 @@
var campaigns = [] var campaigns = []
// labels is a map of campaign statuses to // labels is a map of campaign statuses to
// CSS classes // CSS classes
var labels = { var labels = {
"In progress" : "label-primary", "In progress": "label-primary",
"Queued" : "label-info", "Queued": "label-info",
"Completed" : "label-success", "Completed": "label-success",
"Emails Sent" : "label-success", "Emails Sent": "label-success",
"Error" : "label-danger" "Error": "label-danger"
} }
$(document).ready(function(){ $(document).ready(function() {
api.campaigns.get() api.campaigns.get()
.success(function(cs){ .success(function(cs) {
$("#loading").hide() $("#loading").hide()
campaigns = cs campaigns = cs
if (campaigns.length > 0){ if (campaigns.length > 0) {
$("#dashboard").show() $("#dashboard").show()
// Create the overview chart data // Create the overview chart data
var overview_data = {labels:[],series:[[]]} var overview_data = {
var average_data = {series:[]} labels: [],
var overview_opts = { series: [
axisX: { []
showGrid: false ]
}, }
showArea: true, var average_data = {
plugins: [] series: []
} }
var average_opts = { var overview_opts = {
donut : true, axisX: {
donutWidth: 40, showGrid: false
chartPadding: 0, },
showLabel: false showArea: true,
} plugins: []
var average = 0 }
campaignTable = $("#campaignTable").DataTable(); var average_opts = {
$.each(campaigns, function(i, campaign){ donut: true,
var campaign_date = moment(campaign.created_date).format('MMMM Do YYYY h:mm:ss a') donutWidth: 40,
var label = labels[campaign.status] || "label-default"; chartPadding: 0,
// Add it to the table showLabel: false
campaignTable.row.add([ }
campaign.name, var average = 0
campaign_date, campaignTable = $("#campaignTable").DataTable();
"<span class=\"label " + label + "\">" + campaign.status + "</span>", $.each(campaigns, function(i, campaign) {
"<div class='pull-right'><a class='btn btn-primary' href='/campaigns/" + campaign.id + "'>\ var campaign_date = moment(campaign.created_date).format('MMMM Do YYYY h:mm:ss a')
var label = labels[campaign.status] || "label-default";
// Add it to the table
campaignTable.row.add([
campaign.name,
campaign_date,
"<span class=\"label " + label + "\">" + campaign.status + "</span>",
"<div class='pull-right'><a class='btn btn-primary' href='/campaigns/" + campaign.id + "'>\
<i class='fa fa-bar-chart'></i>\ <i class='fa fa-bar-chart'></i>\
</a>\ </a>\
<button class='btn btn-danger' onclick='deleteCampaign(" + i + ")'>\ <button class='btn btn-danger' onclick='deleteCampaign(" + i + ")'>\
<i class='fa fa-trash-o'></i>\ <i class='fa fa-trash-o'></i>\
</button></div>" </button></div>"
]).draw() ]).draw()
// Add it to the chart data // Add it to the chart data
campaign.y = 0 campaign.y = 0
$.each(campaign.results, function(j, result){ $.each(campaign.results, function(j, result) {
if (result.status == "Success"){ if (result.status == "Success") {
campaign.y++; campaign.y++;
} }
})
campaign.y = Math.floor((campaign.y / campaign.results.length) * 100)
average += campaign.y
// Add the data to the overview chart
overview_data.labels.push(campaign_date)
overview_data.series[0].push({
meta: i,
value: campaign.y
})
}) })
campaign.y = Math.floor((campaign.y / campaign.results.length) * 100) average = Math.floor(average / campaigns.length);
average += campaign.y average_data.series.push({
// Add the data to the overview chart meta: "Unsuccessful Phishes",
overview_data.labels.push(campaign_date) value: 100 - average
overview_data.series[0].push({meta : i, value: campaign.y}) })
}) average_data.series.push({
average = Math.floor(average / campaigns.length); meta: "Successful Phishes",
average_data.series.push({meta: "Unsuccessful Phishes", value: 100 - average}) value: average
average_data.series.push({meta: "Successful Phishes", value: average}) })
// Build the charts // Build the charts
var average_chart = new Chartist.Pie("#average_chart", average_data, average_opts) var average_chart = new Chartist.Pie("#average_chart", average_data, average_opts)
var overview_chart = new Chartist.Line('#overview_chart', overview_data, overview_opts) var overview_chart = new Chartist.Line('#overview_chart', overview_data, overview_opts)
// Setup the average chart listeners // Setup the average chart listeners
$piechart = $("#average_chart") $piechart = $("#average_chart")
var $pietoolTip = $piechart var $pietoolTip = $piechart
.append('<div class="chartist-tooltip"></div>') .append('<div class="chartist-tooltip"></div>')
.find('.chartist-tooltip') .find('.chartist-tooltip')
.hide(); .hide();
$piechart.on('mouseenter', '.ct-slice-donut', function() { $piechart.on('mouseenter', '.ct-slice-donut', function() {
var $point = $(this) var $point = $(this)
value = $point.attr('ct:value') value = $point.attr('ct:value')
label = $point.attr('ct:meta') label = $point.attr('ct:meta')
$pietoolTip.html(label + ': ' + value.toString() + "%").show(); $pietoolTip.html(label + ': ' + value.toString() + "%").show();
});
$piechart.on('mouseleave', '.ct-slice-donut', function() {
$pietoolTip.hide();
});
$piechart.on('mousemove', function(event) {
$pietoolTip.css({
left: (event.offsetX || event.originalEvent.layerX) - $pietoolTip.width() / 2 - 10,
top: (event.offsetY + 40 || event.originalEvent.layerY) - $pietoolTip.height() - 80
}); });
});
// Setup the overview chart listeners $piechart.on('mouseleave', '.ct-slice-donut', function() {
$chart = $("#overview_chart") $pietoolTip.hide();
var $toolTip = $chart
.append('<div class="chartist-tooltip"></div>')
.find('.chartist-tooltip')
.hide();
$chart.on('mouseenter', '.ct-point', function() {
var $point = $(this)
value = $point.attr('ct:value') || 0
cidx = $point.attr('ct:meta')
$toolTip.html(campaigns[cidx].name + '<br>' + "Successes: " + value.toString() + "%").show();
});
$chart.on('mouseleave', '.ct-point', function() {
$toolTip.hide();
});
$chart.on('mousemove', function(event) {
$toolTip.css({
left: (event.offsetX || event.originalEvent.layerX) - $toolTip.width() / 2 - 10,
top: (event.offsetY + 40 || event.originalEvent.layerY) - $toolTip.height() - 40
}); });
}); $piechart.on('mousemove', function(event) {
$("#overview_chart").on("click", ".ct-point", function(e) { $pietoolTip.css({
var $cidx = $(this).attr('ct:meta'); left: (event.offsetX || event.originalEvent.layerX) - $pietoolTip.width() / 2 - 10,
window.location.href = "/campaigns/" + campaigns[cidx].id top: (event.offsetY + 40 || event.originalEvent.layerY) - $pietoolTip.height() - 80
}); });
} else { });
$("#emptyMessage").show()
} // Setup the overview chart listeners
}) $chart = $("#overview_chart")
.error(function(){ var $toolTip = $chart
errorFlash("Error fetching campaigns") .append('<div class="chartist-tooltip"></div>')
}) .find('.chartist-tooltip')
.hide();
$chart.on('mouseenter', '.ct-point', function() {
var $point = $(this)
value = $point.attr('ct:value') || 0
cidx = $point.attr('ct:meta')
$toolTip.html(campaigns[cidx].name + '<br>' + "Successes: " + value.toString() + "%").show();
});
$chart.on('mouseleave', '.ct-point', function() {
$toolTip.hide();
});
$chart.on('mousemove', function(event) {
$toolTip.css({
left: (event.offsetX || event.originalEvent.layerX) - $toolTip.width() / 2 - 10,
top: (event.offsetY + 40 || event.originalEvent.layerY) - $toolTip.height() - 40
});
});
$("#overview_chart").on("click", ".ct-point", function(e) {
var $cidx = $(this).attr('ct:meta');
window.location.href = "/campaigns/" + campaigns[cidx].id
});
} else {
$("#emptyMessage").show()
}
})
.error(function() {
errorFlash("Error fetching campaigns")
})
}) })

View File

@ -4,72 +4,75 @@
Author: Jordan Wright <github.com/jordan-wright> Author: Jordan Wright <github.com/jordan-wright>
*/ */
var pages = [] var pages = []
// Save attempts to POST to /templates/ // Save attempts to POST to /templates/
function save(idx){ function save(idx) {
var page = {} var page = {}
page.name = $("#name").val() page.name = $("#name").val()
page.html = CKEDITOR.instances["html_editor"].getData(); page.html = CKEDITOR.instances["html_editor"].getData();
if (idx != -1){ if (idx != -1) {
page.id = pages[idx].id page.id = pages[idx].id
api.pageId.put(page) api.pageId.put(page)
.success(function(data){ .success(function(data) {
successFlash("Page edited successfully!") successFlash("Page edited successfully!")
load() load()
dismiss() dismiss()
}) })
} else { } else {
// Submit the page // Submit the page
api.pages.post(page) api.pages.post(page)
.success(function(data){ .success(function(data) {
successFlash("Page added successfully!") successFlash("Page added successfully!")
load() load()
dismiss() dismiss()
}) })
.error(function(data){ .error(function(data) {
modalError(data.responseJSON.message) modalError(data.responseJSON.message)
}) })
} }
} }
function dismiss(){ function dismiss() {
$("#modal\\.flashes").empty() $("#modal\\.flashes").empty()
$("#name").val("") $("#name").val("")
$("#html_editor").val("") $("#html_editor").val("")
$("#newLandingPageModal").modal('hide') $("#newLandingPageModal").modal('hide')
} }
function deletePage(idx){ function deletePage(idx) {
if (confirm("Delete " + pages[idx].name + "?")){ if (confirm("Delete " + pages[idx].name + "?")) {
api.pageId.delete(pages[idx].id) api.pageId.delete(pages[idx].id)
.success(function(data){ .success(function(data) {
successFlash(data.message) successFlash(data.message)
load() load()
}) })
} }
} }
function importSite(){ function importSite() {
url = $("#url").val() url = $("#url").val()
if (!url){ if (!url) {
modalError("No URL Specified!") modalError("No URL Specified!")
} else { } else {
api.clone_site({ api.clone_site({
url: url, url: url,
include_resources: false include_resources: false
}) })
.success(function(data){ .success(function(data) {
console.log($("#html_editor")) console.log($("#html_editor"))
$("#html_editor").val(data.html) $("#html_editor").val(data.html)
$("#importSiteModal").modal("hide") $("#importSiteModal").modal("hide")
}) })
.error(function(data){ .error(function(data) {
modalError(data.responseJSON.message) modalError(data.responseJSON.message)
}) })
} }
} }
function edit(idx){ function edit(idx) {
$("#modalSubmit").unbind('click').click(function(){save(idx)}) $("#modalSubmit").unbind('click').click(function() {
save(idx)
})
$("#html_editor").ckeditor() $("#html_editor").ckeditor()
var page = {} var page = {}
if (idx != -1) { if (idx != -1) {
@ -79,82 +82,80 @@ function edit(idx){
} }
} }
function load(){ function load() {
/* /*
load() - Loads the current pages using the API load() - Loads the current pages using the API
*/ */
$("#pagesTable").hide() $("#pagesTable").hide()
$("#emptyMessage").hide() $("#emptyMessage").hide()
$("#loading").show() $("#loading").show()
api.pages.get() api.pages.get()
.success(function(ps){ .success(function(ps) {
pages = ps pages = ps
$("#loading").hide() $("#loading").hide()
if (pages.length > 0){ if (pages.length > 0) {
$("#pagesTable").show() $("#pagesTable").show()
pagesTable = $("#pagesTable").DataTable(); pagesTable = $("#pagesTable").DataTable();
pagesTable.clear() pagesTable.clear()
$.each(pages, function(i, page){ $.each(pages, function(i, page) {
pagesTable.row.add([ pagesTable.row.add([
page.name, page.name,
moment(page.modified_date).format('MMMM Do YYYY, h:mm:ss a'), moment(page.modified_date).format('MMMM Do YYYY, h:mm:ss a'),
"<div class='pull-right'><button class='btn btn-primary' data-toggle='modal' data-target='#newLandingPageModal' onclick='edit(" + i + ")'>\ "<div class='pull-right'><button class='btn btn-primary' data-toggle='modal' data-target='#newLandingPageModal' onclick='edit(" + i + ")'>\
<i class='fa fa-pencil'></i>\ <i class='fa fa-pencil'></i>\
</button>\ </button>\
<button class='btn btn-danger' onclick='deletePage(" + i + ")'>\ <button class='btn btn-danger' onclick='deletePage(" + i + ")'>\
<i class='fa fa-trash-o'></i>\ <i class='fa fa-trash-o'></i>\
</button></div>" </button></div>"
]).draw() ]).draw()
}) })
} else { } else {
$("#emptyMessage").show() $("#emptyMessage").show()
} }
}) })
.error(function(){ .error(function() {
$("#loading").hide() $("#loading").hide()
errorFlash("Error fetching pages") errorFlash("Error fetching pages")
}) })
} }
$(document).ready(function(){ $(document).ready(function() {
// Setup multiple modals // Setup multiple modals
// Code based on http://miles-by-motorcycle.com/static/bootstrap-modal/index.html // Code based on http://miles-by-motorcycle.com/static/bootstrap-modal/index.html
$('.modal').on('hidden.bs.modal', function( event ) { $('.modal').on('hidden.bs.modal', function(event) {
$(this).removeClass( 'fv-modal-stack' ); $(this).removeClass('fv-modal-stack');
$('body').data( 'fv_open_modals', $('body').data( 'fv_open_modals' ) - 1 ); $('body').data('fv_open_modals', $('body').data('fv_open_modals') - 1);
}); });
$( '.modal' ).on( 'shown.bs.modal', function ( event ) { $('.modal').on('shown.bs.modal', function(event) {
// Keep track of the number of open modals // Keep track of the number of open modals
if ( typeof( $('body').data( 'fv_open_modals' ) ) == 'undefined' ) if (typeof($('body').data('fv_open_modals')) == 'undefined') {
{ $('body').data('fv_open_modals', 0);
$('body').data( 'fv_open_modals', 0 );
} }
// if the z-index of this modal has been set, ignore. // if the z-index of this modal has been set, ignore.
if ( $(this).hasClass( 'fv-modal-stack' ) ) if ($(this).hasClass('fv-modal-stack')) {
{
return; return;
} }
$(this).addClass( 'fv-modal-stack' ); $(this).addClass('fv-modal-stack');
// Increment the number of open modals // Increment the number of open modals
$('body').data( 'fv_open_modals', $('body').data( 'fv_open_modals' ) + 1 ); $('body').data('fv_open_modals', $('body').data('fv_open_modals') + 1);
// Setup the appropriate z-index // Setup the appropriate z-index
$(this).css('z-index', 1040 + (10 * $('body').data( 'fv_open_modals' ))); $(this).css('z-index', 1040 + (10 * $('body').data('fv_open_modals')));
$( '.modal-backdrop' ).not( '.fv-modal-stack' ).css( 'z-index', 1039 + (10 * $('body').data( 'fv_open_modals' ))); $('.modal-backdrop').not('.fv-modal-stack').css('z-index', 1039 + (10 * $('body').data('fv_open_modals')));
$( '.modal-backdrop' ).not( 'fv-modal-stack' ).addClass( 'fv-modal-stack' ); $('.modal-backdrop').not('fv-modal-stack').addClass('fv-modal-stack');
}); });
$.fn.modal.Constructor.prototype.enforceFocus = function() { $.fn.modal.Constructor.prototype.enforceFocus = function() {
$( document ) $(document)
.off( 'focusin.bs.modal' ) // guard against infinite focus loop .off('focusin.bs.modal') // guard against infinite focus loop
.on( 'focusin.bs.modal', $.proxy( function( e ) { .on('focusin.bs.modal', $.proxy(function(e) {
if ( if (
this.$element[ 0 ] !== e.target && !this.$element.has( e.target ).length this.$element[0] !== e.target && !this.$element.has(e.target).length
// CKEditor compatibility fix start. // CKEditor compatibility fix start.
&& !$( e.target ).closest( '.cke_dialog, .cke' ).length && !$(e.target).closest('.cke_dialog, .cke').length
// CKEditor compatibility fix end. // CKEditor compatibility fix end.
) { ) {
this.$element.trigger( 'focus' ); this.$element.trigger('focus');
} }
}, this ) ); }, this));
}; };
load() load()
}) })

View File

@ -1,24 +1,24 @@
$(document).ready(function(){ $(document).ready(function() {
$("#apiResetForm").submit(function(e){ $("#apiResetForm").submit(function(e) {
$.post("/api/reset", $(this).serialize()) $.post("/api/reset", $(this).serialize())
.done(function(data){ .done(function(data) {
api_key = data.data api_key = data.data
successFlash(data.message) successFlash(data.message)
$("#api_key").val(api_key) $("#api_key").val(api_key)
}) })
.fail(function(data){ .fail(function(data) {
errorFlash(data.message) errorFlash(data.message)
}) })
return false return false
}) })
$("#settingsForm").submit(function(e){ $("#settingsForm").submit(function(e) {
$.post("/settings", $(this).serialize()) $.post("/settings", $(this).serialize())
.done(function(data){ .done(function(data) {
successFlash(data.message) successFlash(data.message)
}) })
.fail(function(data){ .fail(function(data) {
errorFlash(data.responseJSON.message) errorFlash(data.responseJSON.message)
}) })
return false return false
}) })
}) })

View File

@ -1,64 +1,66 @@
var templates = [] var templates = []
var icons = { var icons = {
"application/vnd.ms-excel" : "fa-file-excel-o", "application/vnd.ms-excel": "fa-file-excel-o",
"text/plain" : "fa-file-text-o", "text/plain": "fa-file-text-o",
"image/gif" : "fa-file-image-o", "image/gif": "fa-file-image-o",
"image/png" : "fa-file-image-o", "image/png": "fa-file-image-o",
"application/pdf" : "fa-file-pdf-o", "application/pdf": "fa-file-pdf-o",
"application/x-zip-compressed" : "fa-file-archive-o", "application/x-zip-compressed": "fa-file-archive-o",
"application/x-gzip" : "fa-file-archive-o", "application/x-gzip": "fa-file-archive-o",
"application/vnd.openxmlformats-officedocument.presentationml.presentation" : "fa-file-powerpoint-o", "application/vnd.openxmlformats-officedocument.presentationml.presentation": "fa-file-powerpoint-o",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document" : "fa-file-word-o", "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "fa-file-word-o",
"application/octet-stream" : "fa-file-o", "application/octet-stream": "fa-file-o",
"application/x-msdownload" : "fa-file-o" "application/x-msdownload": "fa-file-o"
} }
// Save attempts to POST to /templates/ // Save attempts to POST to /templates/
function save(idx){ function save(idx) {
var template = {attachments:[]} var template = {
attachments: []
}
template.name = $("#name").val() template.name = $("#name").val()
template.subject = $("#subject").val() template.subject = $("#subject").val()
template.html = CKEDITOR.instances["html_editor"].getData(); template.html = CKEDITOR.instances["html_editor"].getData();
// Fix the URL Scheme added by CKEditor (until we can remove it from the plugin) // Fix the URL Scheme added by CKEditor (until we can remove it from the plugin)
template.html = template.html.replace(/https?:\/\/{{\.URL}}/gi, "{{.URL}}") template.html = template.html.replace(/https?:\/\/{{\.URL}}/gi, "{{.URL}}")
// If the "Add Tracker Image" checkbox is checked, add the tracker // If the "Add Tracker Image" checkbox is checked, add the tracker
if ($("#use_tracker_checkbox").prop("checked") && if ($("#use_tracker_checkbox").prop("checked") &&
template.html.indexOf("{{.Tracker}}") == -1 && template.html.indexOf("{{.Tracker}}") == -1 &&
template.html.indexOf("{{.TrackingUrl}}") == -1){ template.html.indexOf("{{.TrackingUrl}}") == -1) {
template.html = template.html.replace("</body>", "{{.Tracker}}</body>") template.html = template.html.replace("</body>", "{{.Tracker}}</body>")
} }
template.text = $("#text_editor").val() template.text = $("#text_editor").val()
// Add the attachments // Add the attachments
$.each($("#attachmentsTable").DataTable().rows().data(), function(i, target){ $.each($("#attachmentsTable").DataTable().rows().data(), function(i, target) {
template.attachments.push({ template.attachments.push({
name : target[1], name: target[1],
content: target[3], content: target[3],
type: target[4], type: target[4],
}) })
}) })
if (idx != -1){ if (idx != -1) {
template.id = templates[idx].id template.id = templates[idx].id
api.templateId.put(template) api.templateId.put(template)
.success(function(data){ .success(function(data) {
successFlash("Template edited successfully!") successFlash("Template edited successfully!")
load() load()
dismiss() dismiss()
}) })
} else { } else {
// Submit the template // Submit the template
api.templates.post(template) api.templates.post(template)
.success(function(data){ .success(function(data) {
successFlash("Template added successfully!") successFlash("Template added successfully!")
load() load()
dismiss() dismiss()
}) })
.error(function(data){ .error(function(data) {
modalError(data.responseJSON.message) modalError(data.responseJSON.message)
}) })
} }
} }
function dismiss(){ function dismiss() {
$("#modal\\.flashes").empty() $("#modal\\.flashes").empty()
$("#attachmentsTable").dataTable().DataTable().clear().draw() $("#attachmentsTable").dataTable().DataTable().clear().draw()
$("#name").val("") $("#name").val("")
@ -67,24 +69,24 @@ function dismiss(){
$("#modal").modal('hide') $("#modal").modal('hide')
} }
function deleteTemplate(idx){ function deleteTemplate(idx) {
if (confirm("Delete " + templates[idx].name + "?")){ if (confirm("Delete " + templates[idx].name + "?")) {
api.templateId.delete(templates[idx].id) api.templateId.delete(templates[idx].id)
.success(function(data){ .success(function(data) {
successFlash(data.message) successFlash(data.message)
load() load()
}) })
} }
} }
function attach(files){ function attach(files) {
attachmentsTable = $("#attachmentsTable").DataTable(); attachmentsTable = $("#attachmentsTable").DataTable();
$.each(files, function(i, file){ $.each(files, function(i, file) {
var reader = new FileReader(); var reader = new FileReader();
/* Make this a datatable */ /* Make this a datatable */
reader.onload = function(e){ reader.onload = function(e) {
var icon = icons[file.type] || "fa-file-o" var icon = icons[file.type] || "fa-file-o"
// Add the record to the modal // Add the record to the modal
attachmentsTable.row.add([ attachmentsTable.row.add([
'<i class="fa ' + icon + '"></i>', '<i class="fa ' + icon + '"></i>',
file.name, file.name,
@ -100,33 +102,38 @@ function attach(files){
}) })
} }
function edit(idx){ function edit(idx) {
$("#modalSubmit").unbind('click').click(function(){save(idx)}) $("#modalSubmit").unbind('click').click(function() {
$("#attachmentUpload").unbind('click').click(function(){this.value=null}) save(idx)
})
$("#attachmentUpload").unbind('click').click(function() {
this.value = null
})
$("#html_editor").ckeditor() $("#html_editor").ckeditor()
$("#attachmentsTable").show() $("#attachmentsTable").show()
attachmentsTable = null attachmentsTable = null
if ( $.fn.dataTable.isDataTable('#attachmentsTable') ) { if ($.fn.dataTable.isDataTable('#attachmentsTable')) {
attachmentsTable = $('#attachmentsTable').DataTable(); attachmentsTable = $('#attachmentsTable').DataTable();
} } else {
else {
attachmentsTable = $("#attachmentsTable").DataTable({ attachmentsTable = $("#attachmentsTable").DataTable({
"aoColumnDefs" : [{ "aoColumnDefs": [{
"targets" : [3,4], "targets": [3, 4],
"sClass" : "datatable_hidden" "sClass": "datatable_hidden"
}] }]
}); });
} }
var template = {attachments:[]} var template = {
attachments: []
}
if (idx != -1) { if (idx != -1) {
template = templates[idx] template = templates[idx]
$("#name").val(template.name) $("#name").val(template.name)
$("#subject").val(template.subject) $("#subject").val(template.subject)
$("#html_editor").val(template.html) $("#html_editor").val(template.html)
$("#text_editor").val(template.text) $("#text_editor").val(template.text)
$.each(template.attachments, function(i, file){ $.each(template.attachments, function(i, file) {
var icon = icons[file.type] || "fa-file-o" var icon = icons[file.type] || "fa-file-o"
// Add the record to the modal // Add the record to the modal
attachmentsTable.row.add([ attachmentsTable.row.add([
'<i class="fa ' + icon + '"></i>', '<i class="fa ' + icon + '"></i>',
file.name, file.name,
@ -137,110 +144,108 @@ function edit(idx){
}) })
} }
// Handle Deletion // Handle Deletion
$("#attachmentsTable").unbind('click').on("click", "span>i.fa-trash-o", function(){ $("#attachmentsTable").unbind('click').on("click", "span>i.fa-trash-o", function() {
attachmentsTable.row( $(this).parents('tr') ) attachmentsTable.row($(this).parents('tr'))
.remove() .remove()
.draw(); .draw();
}) })
} }
function importEmail(){ function importEmail() {
raw = $("#email_content").val() raw = $("#email_content").val()
if (!raw){ if (!raw) {
modalError("No Content Specified!") modalError("No Content Specified!")
} else { } else {
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: "/api/import/email", url: "/api/import/email",
data: raw, data: raw,
dataType: "json", dataType: "json",
contentType: "text/plain" contentType: "text/plain"
}) })
.success(function(data){ .success(function(data) {
$("#text_editor").val(data.text) $("#text_editor").val(data.text)
$("#html_editor").val(data.html) $("#html_editor").val(data.html)
$("#subject").val(data.subject) $("#subject").val(data.subject)
$("#importEmailModal").modal("hide") $("#importEmailModal").modal("hide")
}) })
.error(function(data){ .error(function(data) {
modalError(data.responseJSON.message) modalError(data.responseJSON.message)
}) })
} }
} }
function load(){ function load() {
$("#templateTable").hide() $("#templateTable").hide()
$("#emptyMessage").hide() $("#emptyMessage").hide()
$("#loading").show() $("#loading").show()
api.templates.get() api.templates.get()
.success(function(ts){ .success(function(ts) {
templates = ts templates = ts
$("#loading").hide() $("#loading").hide()
if (templates.length > 0){ if (templates.length > 0) {
$("#templateTable").show() $("#templateTable").show()
templateTable = $("#templateTable").DataTable(); templateTable = $("#templateTable").DataTable();
templateTable.clear() templateTable.clear()
$.each(templates, function(i, template){ $.each(templates, function(i, template) {
templateTable.row.add([ templateTable.row.add([
template.name, template.name,
moment(template.modified_date).format('MMMM Do YYYY, h:mm:ss a'), moment(template.modified_date).format('MMMM Do YYYY, h:mm:ss a'),
"<div class='pull-right'><button class='btn btn-primary' data-toggle='modal' data-target='#modal' onclick='edit(" + i + ")'>\ "<div class='pull-right'><button class='btn btn-primary' data-toggle='modal' data-target='#modal' onclick='edit(" + i + ")'>\
<i class='fa fa-pencil'></i>\ <i class='fa fa-pencil'></i>\
</button>\ </button>\
<button class='btn btn-danger' onclick='deleteTemplate(" + i + ")'>\ <button class='btn btn-danger' onclick='deleteTemplate(" + i + ")'>\
<i class='fa fa-trash-o'></i>\ <i class='fa fa-trash-o'></i>\
</button></div>" </button></div>"
]).draw() ]).draw()
}) })
} else { } else {
$("#emptyMessage").show() $("#emptyMessage").show()
} }
}) })
.error(function(){ .error(function() {
$("#loading").hide() $("#loading").hide()
errorFlash("Error fetching templates") errorFlash("Error fetching templates")
}) })
} }
$(document).ready(function(){ $(document).ready(function() {
// Setup multiple modals // Setup multiple modals
// Code based on http://miles-by-motorcycle.com/static/bootstrap-modal/index.html // Code based on http://miles-by-motorcycle.com/static/bootstrap-modal/index.html
$('.modal').on('hidden.bs.modal', function( event ) { $('.modal').on('hidden.bs.modal', function(event) {
$(this).removeClass( 'fv-modal-stack' ); $(this).removeClass('fv-modal-stack');
$('body').data( 'fv_open_modals', $('body').data( 'fv_open_modals' ) - 1 ); $('body').data('fv_open_modals', $('body').data('fv_open_modals') - 1);
}); });
$( '.modal' ).on( 'shown.bs.modal', function ( event ) { $('.modal').on('shown.bs.modal', function(event) {
// Keep track of the number of open modals // Keep track of the number of open modals
if ( typeof( $('body').data( 'fv_open_modals' ) ) == 'undefined' ) if (typeof($('body').data('fv_open_modals')) == 'undefined') {
{ $('body').data('fv_open_modals', 0);
$('body').data( 'fv_open_modals', 0 );
} }
// if the z-index of this modal has been set, ignore. // if the z-index of this modal has been set, ignore.
if ( $(this).hasClass( 'fv-modal-stack' ) ) if ($(this).hasClass('fv-modal-stack')) {
{
return; return;
} }
$(this).addClass( 'fv-modal-stack' ); $(this).addClass('fv-modal-stack');
// Increment the number of open modals // Increment the number of open modals
$('body').data( 'fv_open_modals', $('body').data( 'fv_open_modals' ) + 1 ); $('body').data('fv_open_modals', $('body').data('fv_open_modals') + 1);
// Setup the appropriate z-index // Setup the appropriate z-index
$(this).css('z-index', 1040 + (10 * $('body').data( 'fv_open_modals' ))); $(this).css('z-index', 1040 + (10 * $('body').data('fv_open_modals')));
$( '.modal-backdrop' ).not( '.fv-modal-stack' ).css( 'z-index', 1039 + (10 * $('body').data( 'fv_open_modals' ))); $('.modal-backdrop').not('.fv-modal-stack').css('z-index', 1039 + (10 * $('body').data('fv_open_modals')));
$( '.modal-backdrop' ).not( 'fv-modal-stack' ).addClass( 'fv-modal-stack' ); $('.modal-backdrop').not('fv-modal-stack').addClass('fv-modal-stack');
}); });
$.fn.modal.Constructor.prototype.enforceFocus = function() { $.fn.modal.Constructor.prototype.enforceFocus = function() {
$( document ) $(document)
.off( 'focusin.bs.modal' ) // guard against infinite focus loop .off('focusin.bs.modal') // guard against infinite focus loop
.on( 'focusin.bs.modal', $.proxy( function( e ) { .on('focusin.bs.modal', $.proxy(function(e) {
if ( if (
this.$element[ 0 ] !== e.target && !this.$element.has( e.target ).length this.$element[0] !== e.target && !this.$element.has(e.target).length
// CKEditor compatibility fix start. // CKEditor compatibility fix start.
&& !$( e.target ).closest( '.cke_dialog, .cke' ).length && !$(e.target).closest('.cke_dialog, .cke').length
// CKEditor compatibility fix end. // CKEditor compatibility fix end.
) { ) {
this.$element.trigger( 'focus' ); this.$element.trigger('focus');
} }
}, this ) ); }, this));
}; };
load() load()
}) })

View File

@ -1,60 +1,62 @@
var groups = [] var groups = []
// Save attempts to POST or PUT to /groups/ // Save attempts to POST or PUT to /groups/
function save(idx){ function save(idx) {
var targets = [] var targets = []
$.each($("#targetsTable").DataTable().rows().data(), function(i, target){ $.each($("#targetsTable").DataTable().rows().data(), function(i, target) {
targets.push({ targets.push({
first_name : target[0], first_name: target[0],
last_name: target[1], last_name: target[1],
email: target[2], email: target[2],
position: target[3] position: target[3]
}) })
}) })
var group = { var group = {
name: $("#name").val(), name: $("#name").val(),
targets: targets targets: targets
} }
// Submit the group // Submit the group
if (idx != -1) { if (idx != -1) {
// If we're just editing an existing group, // If we're just editing an existing group,
// we need to PUT /groups/:id // we need to PUT /groups/:id
group.id = groups[idx].id group.id = groups[idx].id
api.groupId.put(group) api.groupId.put(group)
.success(function(data){ .success(function(data) {
successFlash("Group updated successfully!") successFlash("Group updated successfully!")
load() load()
dismiss() dismiss()
$("#modal").modal('hide') $("#modal").modal('hide')
}) })
.error(function(data){ .error(function(data) {
modalError(data.responseJSON.message) modalError(data.responseJSON.message)
}) })
} else { } else {
// Else, if this is a new group, POST it // Else, if this is a new group, POST it
// to /groups // to /groups
api.groups.post(group) api.groups.post(group)
.success(function(data){ .success(function(data) {
successFlash("Group added successfully!") successFlash("Group added successfully!")
load() load()
dismiss() dismiss()
$("#modal").modal('hide') $("#modal").modal('hide')
}) })
.error(function(data){ .error(function(data) {
modalError(data.responseJSON.message) modalError(data.responseJSON.message)
}) })
} }
} }
function dismiss(){ function dismiss() {
$("#targetsTable").dataTable().DataTable().clear().draw() $("#targetsTable").dataTable().DataTable().clear().draw()
$("#name").val("") $("#name").val("")
$("#modal\\.flashes").empty() $("#modal\\.flashes").empty()
} }
function edit(idx){ function edit(idx) {
targets = $("#targetsTable").dataTable() targets = $("#targetsTable").dataTable()
$("#modalSubmit").unbind('click').click(function(){save(idx)}) $("#modalSubmit").unbind('click').click(function() {
save(idx)
})
if (idx == -1) { if (idx == -1) {
group = {} group = {}
} else { } else {
@ -62,31 +64,6 @@ function edit(idx){
$("#name").val(group.name) $("#name").val(group.name)
$.each(group.targets, function(i, record) { $.each(group.targets, function(i, record) {
targets.DataTable() targets.DataTable()
.row.add([
record.first_name,
record.last_name,
record.email,
record.position,
'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>'
]).draw()
});
}
// Handle file uploads
$("#csvupload").fileupload({
dataType:"json",
add: function(e, data){
$("#modal\\.flashes").empty()
var acceptFileTypes= /(csv|txt)$/i;
var filename = data.originalFiles[0]['name']
if (filename && !acceptFileTypes.test(filename.split(".").pop())) {
modalError("Unsupported file extension (use .csv or .txt)")
return false;
}
data.submit();
},
done: function(e, data){
$.each(data.result, function(i, record) {
targets.DataTable()
.row.add([ .row.add([
record.first_name, record.first_name,
record.last_name, record.last_name,
@ -94,90 +71,115 @@ function edit(idx){
record.position, record.position,
'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>' '<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>'
]).draw() ]).draw()
});
}
// Handle file uploads
$("#csvupload").fileupload({
dataType: "json",
add: function(e, data) {
$("#modal\\.flashes").empty()
var acceptFileTypes = /(csv|txt)$/i;
var filename = data.originalFiles[0]['name']
if (filename && !acceptFileTypes.test(filename.split(".").pop())) {
modalError("Unsupported file extension (use .csv or .txt)")
return false;
}
data.submit();
},
done: function(e, data) {
$.each(data.result, function(i, record) {
targets.DataTable()
.row.add([
record.first_name,
record.last_name,
record.email,
record.position,
'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>'
]).draw()
}); });
} }
}) })
} }
function deleteGroup(idx){ function deleteGroup(idx) {
if (confirm("Delete " + groups[idx].name + "?")){ if (confirm("Delete " + groups[idx].name + "?")) {
api.groupId.delete(groups[idx].id) api.groupId.delete(groups[idx].id)
.success(function(data){ .success(function(data) {
successFlash(data.message) successFlash(data.message)
load() load()
}) })
} }
} }
function load(){ function load() {
$("#groupTable").hide() $("#groupTable").hide()
$("#emptyMessage").hide() $("#emptyMessage").hide()
$("#loading").show() $("#loading").show()
api.groups.get() api.groups.get()
.success(function(gs){ .success(function(gs) {
$("#loading").hide() $("#loading").hide()
if (gs.length > 0){ if (gs.length > 0) {
groups = gs groups = gs
$("#emptyMessage").hide() $("#emptyMessage").hide()
$("#groupTable").show() $("#groupTable").show()
groupTable = $("#groupTable").DataTable(); groupTable = $("#groupTable").DataTable();
groupTable.clear(); groupTable.clear();
$.each(groups, function(i, group){ $.each(groups, function(i, group) {
var targets = "" var targets = ""
$.each(group.targets, function(i, target){ $.each(group.targets, function(i, target) {
targets += target.email + ", " targets += target.email + ", "
if (targets.length > 50) { if (targets.length > 50) {
targets = targets.slice(0,-3) + "..." targets = targets.slice(0, -3) + "..."
return false; return false;
} }
}) })
groupTable.row.add([ groupTable.row.add([
group.name, group.name,
targets, targets,
moment(group.modified_date).format('MMMM Do YYYY, h:mm:ss a'), moment(group.modified_date).format('MMMM Do YYYY, h:mm:ss a'),
"<div class='pull-right'><button class='btn btn-primary' data-toggle='modal' data-target='#modal' onclick='edit(" + i + ")'>\ "<div class='pull-right'><button class='btn btn-primary' data-toggle='modal' data-target='#modal' onclick='edit(" + i + ")'>\
<i class='fa fa-pencil'></i>\ <i class='fa fa-pencil'></i>\
</button>\ </button>\
<button class='btn btn-danger' onclick='deleteGroup(" + i + ")'>\ <button class='btn btn-danger' onclick='deleteGroup(" + i + ")'>\
<i class='fa fa-trash-o'></i>\ <i class='fa fa-trash-o'></i>\
</button></div>" </button></div>"
]).draw() ]).draw()
}) })
} else { } else {
$("#emptyMessage").show() $("#emptyMessage").show()
} }
}) })
.error(function(){ .error(function() {
errorFlash("Error fetching groups") errorFlash("Error fetching groups")
}) })
} }
$(document).ready(function(){ $(document).ready(function() {
load() load()
// Setup the event listeners // Setup the event listeners
// Handle manual additions // Handle manual additions
$("#targetForm").submit(function(){ $("#targetForm").submit(function() {
targets.DataTable()
.row.add([
$("#firstName").val(),
$("#lastName").val(),
$("#email").val(),
$("#position").val(),
'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>'
])
.draw()
$("#targetForm>div>input").val('')
$("#firstName").focus()
return false
})
// Handle Deletion
$("#targetsTable").on("click", "span>i.fa-trash-o", function() {
targets.DataTable() targets.DataTable()
.row.add([ .row($(this).parents('tr'))
$("#firstName").val(), .remove()
$("#lastName").val(), .draw();
$("#email").val(),
$("#position").val(),
'<span style="cursor:pointer;"><i class="fa fa-trash-o"></i></span>'
])
.draw()
$("#targetForm>div>input").val('')
$("#firstName").focus()
return false
}) })
// Handle Deletion $("#modal").on("hide.bs.modal", function() {
$("#targetsTable").on("click", "span>i.fa-trash-o", function(){ dismiss()
targets.DataTable()
.row( $(this).parents('tr') )
.remove()
.draw();
})
$("#modal").on("hide.bs.modal", function(){
dismiss()
}) })
}) })

View File

@ -1,18 +1,16 @@
function errorFlash(message) { function errorFlash(message) {
$("#flashes").empty() $("#flashes").empty()
$("#flashes").append("<div style=\"text-align:center\" class=\"alert alert-danger\">\ $("#flashes").append("<div style=\"text-align:center\" class=\"alert alert-danger\">\
<i class=\"fa fa-exclamation-circle\"></i> " + message + "</div>" <i class=\"fa fa-exclamation-circle\"></i> " + message + "</div>")
)
} }
function successFlash(message) { function successFlash(message) {
$("#flashes").empty() $("#flashes").empty()
$("#flashes").append("<div style=\"text-align:center\" class=\"alert alert-success\">\ $("#flashes").append("<div style=\"text-align:center\" class=\"alert alert-success\">\
<i class=\"fa fa-check-circle\"></i> " + message + "</div>" <i class=\"fa fa-check-circle\"></i> " + message + "</div>")
)
} }
function modalError(message){ function modalError(message) {
$("#modal\\.flashes").empty().append("<div style=\"text-align:center\" class=\"alert alert-danger\">\ $("#modal\\.flashes").empty().append("<div style=\"text-align:center\" class=\"alert alert-danger\">\
<i class=\"fa fa-exclamation-circle\"></i> " + message + "</div>") <i class=\"fa fa-exclamation-circle\"></i> " + message + "</div>")
} }
@ -23,7 +21,7 @@ function query(endpoint, method, data) {
async: false, async: false,
method: method, method: method,
data: JSON.stringify(data), data: JSON.stringify(data),
dataType:"json", dataType: "json",
contentType: "application/json" contentType: "application/json"
}) })
} }
@ -33,117 +31,117 @@ Define our API Endpoints
*/ */
var api = { var api = {
// campaigns contains the endpoints for /campaigns // campaigns contains the endpoints for /campaigns
campaigns : { campaigns: {
// get() - Queries the API for GET /campaigns // get() - Queries the API for GET /campaigns
get: function(){ get: function() {
return query("/campaigns/", "GET", {}) return query("/campaigns/", "GET", {})
}, },
// post() - Posts a campaign to POST /campaigns // post() - Posts a campaign to POST /campaigns
post: function(data){ post: function(data) {
return query("/campaigns/", "POST", data) return query("/campaigns/", "POST", data)
} }
}, },
// campaignId contains the endpoints for /campaigns/:id // campaignId contains the endpoints for /campaigns/:id
campaignId : { campaignId: {
// get() - Queries the API for GET /campaigns/:id // get() - Queries the API for GET /campaigns/:id
get: function(id){ get: function(id) {
return query("/campaigns/" + id, "GET", {}) return query("/campaigns/" + id, "GET", {})
}, },
// delete() - Deletes a campaign at DELETE /campaigns/:id // delete() - Deletes a campaign at DELETE /campaigns/:id
delete: function(id){ delete: function(id) {
return query("/campaigns/" + id, "DELETE", data) return query("/campaigns/" + id, "DELETE", data)
} }
}, },
// groups contains the endpoints for /groups // groups contains the endpoints for /groups
groups : { groups: {
// get() - Queries the API for GET /groups // get() - Queries the API for GET /groups
get: function(){ get: function() {
return query("/groups/", "GET", {}) return query("/groups/", "GET", {})
}, },
// post() - Posts a campaign to POST /groups // post() - Posts a campaign to POST /groups
post: function(group){ post: function(group) {
return query("/groups/", "POST", group) return query("/groups/", "POST", group)
} }
}, },
// groupId contains the endpoints for /groups/:id // groupId contains the endpoints for /groups/:id
groupId : { groupId: {
// get() - Queries the API for GET /groups/:id // get() - Queries the API for GET /groups/:id
get: function(id){ get: function(id) {
return query("/groups/" + id, "GET", {}) return query("/groups/" + id, "GET", {})
}, },
// put() - Puts a campaign to PUT /groups/:id // put() - Puts a campaign to PUT /groups/:id
put: function (group){ put: function(group) {
return query("/groups/" + group.id, "PUT", group) return query("/groups/" + group.id, "PUT", group)
}, },
// delete() - Deletes a campaign at DELETE /groups/:id // delete() - Deletes a campaign at DELETE /groups/:id
delete: function(id){ delete: function(id) {
return query("/groups/" + id, "DELETE", {}) return query("/groups/" + id, "DELETE", {})
} }
}, },
// templates contains the endpoints for /templates // templates contains the endpoints for /templates
templates : { templates: {
// get() - Queries the API for GET /templates // get() - Queries the API for GET /templates
get: function(){ get: function() {
return query("/templates/", "GET", {}) return query("/templates/", "GET", {})
}, },
// post() - Posts a campaign to POST /templates // post() - Posts a campaign to POST /templates
post: function(template){ post: function(template) {
return query("/templates/", "POST", template) return query("/templates/", "POST", template)
} }
}, },
// templateId contains the endpoints for /templates/:id // templateId contains the endpoints for /templates/:id
templateId : { templateId: {
// get() - Queries the API for GET /templates/:id // get() - Queries the API for GET /templates/:id
get: function(id){ get: function(id) {
return query("/templates/" + id, "GET", {}) return query("/templates/" + id, "GET", {})
}, },
// put() - Puts a campaign to PUT /templates/:id // put() - Puts a campaign to PUT /templates/:id
put: function (template){ put: function(template) {
return query("/templates/" + template.id, "PUT", template) return query("/templates/" + template.id, "PUT", template)
}, },
// delete() - Deletes a campaign at DELETE /templates/:id // delete() - Deletes a campaign at DELETE /templates/:id
delete: function(id){ delete: function(id) {
return query("/templates/" + id, "DELETE", {}) return query("/templates/" + id, "DELETE", {})
} }
}, },
// pages contains the endpoints for /pages // pages contains the endpoints for /pages
pages : { pages: {
// get() - Queries the API for GET /pages // get() - Queries the API for GET /pages
get: function(){ get: function() {
return query("/pages/", "GET", {}) return query("/pages/", "GET", {})
}, },
// post() - Posts a campaign to POST /pages // post() - Posts a campaign to POST /pages
post: function(page){ post: function(page) {
return query("/pages/", "POST", page) return query("/pages/", "POST", page)
} }
}, },
// templateId contains the endpoints for /templates/:id // templateId contains the endpoints for /templates/:id
pageId : { pageId: {
// get() - Queries the API for GET /templates/:id // get() - Queries the API for GET /templates/:id
get: function(id){ get: function(id) {
return query("/pages/" + id, "GET", {}) return query("/pages/" + id, "GET", {})
}, },
// put() - Puts a campaign to PUT /templates/:id // put() - Puts a campaign to PUT /templates/:id
put: function (page){ put: function(page) {
return query("/pages/" + page.id, "PUT", page) return query("/pages/" + page.id, "PUT", page)
}, },
// delete() - Deletes a campaign at DELETE /templates/:id // delete() - Deletes a campaign at DELETE /templates/:id
delete: function(id){ delete: function(id) {
return query("/pages/" + id, "DELETE", {}) return query("/pages/" + id, "DELETE", {})
} }
}, },
// import handles all of the "import" functions in the api // import handles all of the "import" functions in the api
import_email : function(raw) { import_email: function(raw) {
return query("/import/email", "POST", {}) return query("/import/email", "POST", {})
}, },
clone_site : function(req){ clone_site: function(req) {
return query("/import/site", "POST", req) return query("/import/site", "POST", req)
} }
} }
// Register our moment.js datatables listeners // Register our moment.js datatables listeners
$(document).ready(function(){ $(document).ready(function() {
$.fn.dataTable.moment('MMMM Do YYYY, h:mm:ss a'); $.fn.dataTable.moment('MMMM Do YYYY, h:mm:ss a');
// Setup tooltips // Setup tooltips
$('[data-toggle="tooltip"]').tooltip() $('[data-toggle="tooltip"]').tooltip()
}); });