diff --git a/assets/css/bootstrap-wizard-lib/LICENSE b/assets/css/bootstrap-wizard-lib/LICENSE
new file mode 100644
index 0000000..6aee4f8
--- /dev/null
+++ b/assets/css/bootstrap-wizard-lib/LICENSE
@@ -0,0 +1,19 @@
+Copyright (C) 2013 Panopta, Andrew Moffat
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/assets/css/bootstrap-wizard-lib/bootstrap-wizard.css b/assets/css/bootstrap-wizard-lib/bootstrap-wizard.css
new file mode 100644
index 0000000..4713675
--- /dev/null
+++ b/assets/css/bootstrap-wizard-lib/bootstrap-wizard.css
@@ -0,0 +1,182 @@
+/* WIZARD GENERAL */
+.wizard {
+ display:none;
+}
+
+.wizard-dialog {}
+.wizard-content {}
+
+.wizard-body {
+ padding: 0;
+ margin: 0;
+}
+
+/* WIZARD HEADER */
+.wizard-header {
+ padding: 9px 15px;
+ border-bottom: 0;
+}
+
+.wizard-header h3 {
+ margin: 0;
+ line-height: 35px;
+ display: inline;
+ font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ font-family: inherit;
+ font-weight: bold;
+ text-rendering: optimizelegibility;
+ color: rgb(51, 51, 51);
+}
+
+.wizard-subtitle {
+ font-weight:bold;
+ color:#AFAFAF;
+ padding-left:20px;
+}
+
+
+/* WIZARD NAVIGATION */
+.wizard-steps {
+ width: 28%;
+ background-color: #f5f5f5;
+ border-bottom-left-radius: 6px;
+ position: relative;
+}
+
+.wizard-nav-container {
+ padding-bottom: 30px;
+}
+
+.wizard-nav-list {
+ margin-bottom: 0;
+}
+
+.wizard-nav-link .glyphicon-chevron-right {
+ float:right;
+ margin-top:12px;
+ margin-right:-6px;
+ opacity:.25;
+}
+
+li.wizard-nav-item.active .glyphicon-chevron-right {
+ opacity:1;
+}
+
+li.wizard-nav-item {
+ line-height:40px;
+}
+
+.wizard-nav-list > li > a {
+ background-color:#f5f5f5;
+ padding:3px 15px 3px 20px;
+ cursor:default;
+ color:#B4B4B4;
+}
+
+.wizard-nav-list > li > a:hover {
+ background-color: transparent;
+}
+
+.wizard-nav-list > li.already-visited > a.wizard-nav-link {
+ color:#08C;
+ cursor:pointer;
+}
+
+.wizard-nav-list > li.active > a.wizard-nav-link {
+ color:white;
+}
+
+.wizard-nav-item .already-visited .active {
+ background-color:#08C;
+}
+
+.wizard-nav-list li.active > a {
+ background-color:#08C;
+}
+
+
+/* WIZARD CONTENT */
+.wizard-body form {
+ padding: 0;
+ margin: 0;
+}
+
+/* WIZARD PROGRESS BAR */
+.wizard-progress-container {
+ margin-top: 20px;
+ padding: 15px;
+ width: 100%;
+ position: absolute;
+ bottom: 0;
+}
+
+.wizard-card-container {
+ margin-left: 28%;
+}
+
+/* WIZARD CARDS */
+.wizard-error,
+.wizard-failure,
+.wizard-success,
+.wizard-loading,
+.wizard-card {
+ border-top: 1px solid #EEE;
+ display:none;
+ padding:35px;
+ padding-top:20px;
+ overflow-y:auto;
+
+ /*
+ position:relative;
+ height:300px;
+ margin-right: 5px;
+ */
+}
+
+.wizard-card-overlay {
+ overflow-y: initial;
+}
+
+.wizard-card > h3 {
+ margin-top:0;
+ margin-bottom:20px;
+ font-size:21px;
+ line-height:40px;
+ font-weight:normal;
+}
+
+/* WIZARD FOOTER */
+.wizard-footer {
+ padding:0;
+}
+
+.wizard-buttons-container {
+ padding:20px;
+}
+
+.wizard-cancel {
+ margin-left: 12px;
+}
+
+/* Inner Card */
+.wizard-input-section {
+ margin-bottom:20px;
+}
+
+.wizard-dialog .popover.error-popover {
+ background-color:#F2DEDE;
+ color:#B94A48;
+ border-color:#953B39;
+}
+
+.wizard-dialog .popover.error-popover .arrow::after {
+ border-right-color:#F2DEDE;
+}
+
+.wizard-dialog .popover.error-popover .popover-title {
+ display:none;
+}
+
+.wizard-dialog .popover.error-popover .arrow {
+ border-right-color:#953B39;
+}
\ No newline at end of file
diff --git a/assets/fonts/FontAwesome.otf b/assets/fonts/FontAwesome.otf
new file mode 100644
index 0000000..81c9ad9
Binary files /dev/null and b/assets/fonts/FontAwesome.otf differ
diff --git a/assets/fonts/fontawesome-webfont.eot b/assets/fonts/fontawesome-webfont.eot
new file mode 100644
index 0000000..84677bc
Binary files /dev/null and b/assets/fonts/fontawesome-webfont.eot differ
diff --git a/assets/fonts/fontawesome-webfont.ttf b/assets/fonts/fontawesome-webfont.ttf
new file mode 100644
index 0000000..96a3639
Binary files /dev/null and b/assets/fonts/fontawesome-webfont.ttf differ
diff --git a/assets/fonts/fontawesome-webfont.woff b/assets/fonts/fontawesome-webfont.woff
new file mode 100644
index 0000000..628b6a5
Binary files /dev/null and b/assets/fonts/fontawesome-webfont.woff differ
diff --git a/assets/fonts/glyphicons-halflings-regular.eot b/assets/fonts/glyphicons-halflings-regular.eot
new file mode 100644
index 0000000..4a4ca86
Binary files /dev/null and b/assets/fonts/glyphicons-halflings-regular.eot differ
diff --git a/assets/fonts/glyphicons-halflings-regular.svg b/assets/fonts/glyphicons-halflings-regular.svg
new file mode 100644
index 0000000..e3e2dc7
--- /dev/null
+++ b/assets/fonts/glyphicons-halflings-regular.svg
@@ -0,0 +1,229 @@
+
+
+
\ No newline at end of file
diff --git a/assets/fonts/glyphicons-halflings-regular.ttf b/assets/fonts/glyphicons-halflings-regular.ttf
new file mode 100644
index 0000000..67fa00b
Binary files /dev/null and b/assets/fonts/glyphicons-halflings-regular.ttf differ
diff --git a/assets/fonts/glyphicons-halflings-regular.woff b/assets/fonts/glyphicons-halflings-regular.woff
new file mode 100644
index 0000000..8c54182
Binary files /dev/null and b/assets/fonts/glyphicons-halflings-regular.woff differ
diff --git a/assets/js/bootstrap-wizard-lib/LICENSE b/assets/js/bootstrap-wizard-lib/LICENSE
new file mode 100644
index 0000000..6aee4f8
--- /dev/null
+++ b/assets/js/bootstrap-wizard-lib/LICENSE
@@ -0,0 +1,19 @@
+Copyright (C) 2013 Panopta, Andrew Moffat
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/assets/js/bootstrap-wizard-lib/bootstrap-wizard.js b/assets/js/bootstrap-wizard-lib/bootstrap-wizard.js
new file mode 100644
index 0000000..b0bc7f7
--- /dev/null
+++ b/assets/js/bootstrap-wizard-lib/bootstrap-wizard.js
@@ -0,0 +1,1171 @@
+/*
+ * Copyright (C) 2013 Panopta, Andrew Moffat
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+(function ($) {
+ $.fn.wizard = function(args) {
+ return new Wizard(this, args);
+ };
+
+ $.fn.wizard.logging = false;
+
+ var WizardCard = function(wizard, card, index, prev, next) {
+ this.wizard = wizard;
+ this.index = index;
+ this.prev = prev;
+ this.next = next;
+ this.el = card;
+ this.title = card.find("h3").first().text();
+ this.name = card.data("cardname") || this.title;
+
+ this.nav = this._createNavElement(this.title, index);
+
+ this._disabled = false;
+ this._loaded = false;
+ this._events = {};
+ };
+
+ WizardCard.prototype = {
+ select: function() {
+ this.log("selecting");
+ if (!this.isSelected()) {
+ this.nav.addClass("active");
+ this.el.show();
+
+ if (!this._loaded) {
+ this.trigger("loaded");
+ this.reload();
+ }
+
+ this.trigger("selected");
+ }
+
+
+ /*
+ * this is ugly, but we're handling the changing of the wizard's
+ * buttons here, in the WizardCard select. so when a card is
+ * selected, we're figuring out if we're the first card or the
+ * last card and changing the wizard's buttons via the guts of
+ * the wizard
+ *
+ * ideally this logic should be encapsulated by some wizard methods
+ * that we can call from here, instead of messing with the guts
+ */
+ var w = this.wizard;
+
+ // The back button is only disabled on this first card...
+ w.backButton.toggleClass("disabled", this.index == 0);
+
+ if (this.index >= w._cards.length-1) {
+ this.log("on last card, changing next button to submit");
+
+ w.changeNextButton(w.args.buttons.submitText, "btn-success");
+ w._readyToSubmit = true;
+ w.trigger("readySubmit");
+ }
+ else {
+ w._readyToSubmit = false;
+ w.changeNextButton(w.args.buttons.nextText, "btn-primary");
+ }
+
+ return this;
+ },
+
+ _createNavElement: function(name, i) {
+ var li = $('
');
+ var a = $('');
+ a.data("navindex", i);
+ li.append(a);
+ a.append(' ');
+ a.append(name);
+ return li;
+ },
+
+ markVisited: function() {
+ this.log("marking as visited");
+ this.nav.addClass("already-visited");
+ this.trigger("markVisited");
+ return this;
+ },
+
+ unmarkVisited: function() {
+ this.log("unmarking as visited");
+ this.nav.removeClass("already-visited");
+ this.trigger("unmarkVisited");
+ return this;
+ },
+
+ deselect: function() {
+ this.nav.removeClass("active");
+ this.el.hide();
+ this.trigger("deselect");
+ return this;
+ },
+
+ enable: function() {
+ this.log("enabling");
+
+ // Issue #38 Hiding navigation link when hide card
+ // Awaiting approval
+ //
+ // this.nav.removeClass('hide');
+
+ this.nav.addClass("active");
+ this._disabled = false;
+ this.trigger("enabled");
+ return this;
+ },
+
+ disable: function(hideCard) {
+ this.log("disabling");
+ this._disabled = true;
+ this.nav.removeClass("active already-visited");
+ if (hideCard) {
+ this.el.hide();
+ // Issue #38 Hiding navigation link when hide card
+ // Awaiting approval
+ //
+ // this.nav.addClass('hide');
+ }
+ this.trigger("disabled");
+ return this;
+ },
+
+ isDisabled: function() {
+ return this._disabled;
+ },
+
+ alreadyVisited: function() {
+ return this.nav.hasClass("already-visited");
+ },
+
+ isSelected: function() {
+ return this.nav.hasClass("active");
+ },
+
+ reload: function() {
+ this._loaded = true;
+ this.trigger("reload");
+ return this;
+ },
+
+ on: function() {
+ return this.wizard.on.apply(this, arguments);
+ },
+
+ trigger: function() {
+ this.callListener("on"+arguments[0]);
+ return this.wizard.trigger.apply(this, arguments);
+ },
+
+ /*
+ * displays an alert box on the current card
+ */
+ toggleAlert: function(msg, toggle) {
+ this.log("toggling alert to: " + toggle);
+
+ toggle = typeof(toggle) == "undefined" ? true : toggle;
+
+ if (toggle) {this.trigger("showAlert");}
+ else {this.trigger("hideAlert");}
+
+ var div;
+ var alert = this.el.children("h3").first().next("div.alert");
+
+ if (alert.length == 0) {
+ /*
+ * we're hiding anyways, so no need to create anything.
+ * we'll do that if we ever are actually showing the alert
+ */
+ if (!toggle) {return this;}
+
+ this.log("couldn't find existing alert div, creating one");
+ div = $("");
+ div.addClass("alert");
+ div.addClass("hide");
+ div.insertAfter(this.el.find("h3").first());
+ }
+ else {
+ this.log("found existing alert div");
+ div = alert.first();
+ }
+
+ if (toggle) {
+ if (msg != null) {
+ this.log("setting alert msg to", msg);
+ div.html(msg);
+ }
+ div.show();
+ }
+ else {
+ div.hide();
+ }
+ return this;
+ },
+
+ /*
+ * this looks for event handlers embedded into the html of the
+ * wizard card itself, in the form of a data- attribute
+ */
+ callListener: function(name) {
+ // a bug(?) in jquery..can't access data- if name is camelCase
+ name = name.toLowerCase();
+
+ this.log("looking for listener " + name);
+ var listener = window[this.el.data(name)];
+ if (listener) {
+ this.log("calling listener " + name);
+ var wizard = this.wizard;
+
+ try {
+ var vret = listener(this);
+ }
+ catch (e) {
+ this.log("exception calling listener " + name + ": ", e);
+ }
+ }
+ else {
+ this.log("didn't find listener " + name);
+ }
+ },
+
+ problem: function(toggle) {
+ this.nav.find("a").toggleClass("wizard-step-error", toggle);
+ },
+
+ validate: function() {
+ var failures = false;
+ var self = this;
+
+ /*
+ * run all the validators embedded on the inputs themselves
+ */
+ this.el.find("[data-validate]").each(function(i, el) {
+ self.log("validating individiual inputs");
+ el = $(el);
+
+ var v = el.data("validate");
+ if (!v) {return;}
+
+ var ret = {
+ status: true,
+ title: "Error",
+ msg: ""
+ };
+
+ var vret = window[v](el);
+ $.extend(ret, vret);
+
+ // Add-On
+ // This allows the use of a INPUT+BTN used as one according to boostrap layout
+ // for the wizard it is required to add an id with btn-(ID of Input)
+ // this will make sure the popover is drawn on the correct element
+ if ( $('#btn-' + el.attr('id')).length === 1 ) {
+ el = $('#btn-' + el.attr('id'));
+ }
+
+ if (!ret.status) {
+ failures = true;
+
+ // Updated to show error on correct form-group
+ el.parents("div.form-group").toggleClass("has-error", true);
+
+ // This allows the use of a INPUT+BTN used as one according to boostrap layout
+ // for the wizard it is required to add an id with btn-(ID of Input)
+ // this will make sure the popover is drawn on the correct element
+ if ( $('#btn-' + el.attr('id')).length === 1 ) {
+ el = $('#btn-' + el.attr('id'));
+ }
+
+ self.wizard.errorPopover(el, ret.msg);
+ } else {
+ el.parents("div.form-group").toggleClass("has-error", false);
+
+ // This allows the use of a INPUT+BTN used as one according to boostrap layout
+ // for the wizard it is required to add an id with btn-(ID of Input)
+ // this will make sure the popover is drawn on the correct element
+ if ( $('#btn-' + el.attr('id')).length === 1 ) {
+ el = $('#btn-' + el.attr('id'));
+ }
+
+ try {
+ el.popover("destroy");
+ }
+ /*
+ * older versions of bootstrap don't have a destroy call
+ * for popovers
+ */
+ catch (e) {
+ el.popover("hide");
+ }
+ }
+ });
+ this.log("after validating inputs, failures is", failures);
+
+ /*
+ * run the validator embedded in the card
+ */
+ var cardValidator = window[this.el.data("validate")];
+ if (cardValidator) {
+ this.log("running html-embedded card validator");
+ var cardValidated = cardValidator(this);
+ if (typeof(cardValidated) == "undefined" || cardValidated == null) {
+ cardValidated = true;
+ }
+ if (!cardValidated) failures = true;
+ this.log("after running html-embedded card validator, failures is", failures);
+ }
+
+ /*
+ * run the validate listener
+ */
+ this.log("running listener validator");
+ var listenerValidated = this.trigger("validate");
+ if (typeof(listenerValidated) == "undefined" || listenerValidated == null) {
+ listenerValidated = true;
+ }
+ if (!listenerValidated) failures = true;
+ this.log("after running listener validator, failures is", failures);
+
+ var validated = !failures;
+ if (validated) {
+ this.log("validated, calling listeners");
+ this.trigger("validated");
+ }
+ else {
+ this.log("invalid");
+ this.trigger("invalid");
+ }
+ return validated;
+ },
+
+ log: function() {
+ if (!window.console || !$.fn.wizard.logging) {return;}
+ var prepend = "card '"+this.name+"': ";
+ var args = [prepend];
+ args.push.apply(args, arguments);
+
+ console.log.apply(console, args);
+ },
+
+ isActive: function() {
+ return this.nav.hasClass("active");
+ }
+ };
+
+ Wizard = function(markup, args) {
+
+ /* TEMPLATE */
+ this.wizard_template = [
+ '
',
+ '
',
+ '
',
+ '
',
+ '',
+ '',
+ '',
+ '
',
+ '
',
+ '
',
+ '
',
+ '
',
+ '
',
+ '
',
+ '
',
+ '
',
+ '',
+ '
',
+ '
',
+ '
',
+ '',
+ '
',
+
+ '
',
+ '
',
+ '
'
+ ];
+
+ this.args = {
+ keyboard: true,
+ backdrop: true,
+ show: false,
+ submitUrl: "",
+ showCancel: false,
+ showClose: true,
+ progressBarCurrent: false,
+ increaseHeight: 0,
+ contentHeight: 400,
+ contentWidth: '50%',
+ buttons: {
+ cancelText: "Cancel",
+ nextText: "Next",
+ backText: "Back",
+ submitText: "Submit",
+ submittingText: "Submitting...",
+ },
+ formClass: "form-horizontal"
+ };
+
+ $.extend(this.args, args || {});
+
+ this._create(markup);
+ };
+
+ Wizard.prototype = {
+ log: function() {
+ if (!window.console || !$.fn.wizard.logging) {return;}
+ var prepend = "wizard "+this.el.id+": ";
+ var args = [prepend];
+ args.push.apply(args, arguments);
+ console.log.apply(console, args);
+ },
+
+ _create: function(markup) {
+ this.markup = $(markup);
+ this.title = this.markup.data('title');
+ this.submitCards = this.markup.find(".wizard-error,.wizard-failure,.wizard-success,.wizard-loading");
+ this.el = $(this.wizard_template.join('\n'));
+ $('body').append(this.el);
+
+ this.modal = this.el.modal({
+ keyboard: this.args.keyboard,
+ show: this.args.show,
+ backdrop: this.args.backdrop
+ });
+
+ this.dimensions = {
+ contentHeight: this.args.contentHeight,
+ contentWidth: this.args.contentWidth
+ };
+ this.dialog = this.modal.find('.wizard-dialog');
+ this.content = this.modal.find('.wizard-content');
+ this.header = this.modal.find('.wizard-header');
+ this.body = this.modal.find('.wizard-body');
+ this.wizardSteps = this.modal.find('.wizard-steps');
+ this.wizardCards = this.modal.find('.wizard-cards');
+ this.wizardCardContainer = this.modal.find('.wizard-card-container');
+ this.wizardCardContainer
+ .append(this.markup.find('.wizard-card'))
+ .append(this.submitCards);
+ this.navContainer = this.modal.find('.wizard-nav-container');
+ this.navList = this.modal.find('.wizard-nav-list');
+ this.progressContainer = this.modal.find('.wizard-progress-container');
+ this.progress = this.progressContainer.find('.progress-bar');
+ this.closeButton = this.modal.find('button.wizard-close.close');
+ this.cardsContainer = this.modal.find('wizard-cards-container');
+ this.form = this.modal.find('form');
+ this.footer = this.modal.find(".wizard-footer");
+ this.cancelButton = this.footer.find(".wizard-cancel");
+ this.backButton = this.footer.find(".wizard-back");
+ this.nextButton = this.footer.find(".wizard-next");
+
+ this._cards = [];
+ this.cards = {};
+ this._readyToSubmit = false;
+ this.percentComplete = 0;
+ this._submitting = false;
+ this._events = {};
+ this._firstShow = true;
+
+ this._createCards();
+
+ this.nextButton.click(this, this._handleNextClick);
+ this.backButton.click(this, this._handleBackClick);
+
+ this.cancelButton.text(this.args.buttons.cancelText);
+ this.backButton.text(this.args.buttons.backText);
+ this.nextButton.text(this.args.buttons.nextText);
+
+ // Apply Form Class(es)
+ this.form.addClass(this.args.formClass);
+
+ // Register Array Holder for popovers
+ this.popovers = [];
+
+ var self = this;
+ var _close = function() {
+ self.reset();
+ self.close();
+ self.trigger("closed");
+ };
+
+ // Register Close Button
+ this.closeButton.click(_close);
+ this.cancelButton.click(_close);
+
+ this.wizardSteps.on("click", "li.already-visited a.wizard-nav-link", this,
+ function(event) {
+ var index = parseInt($(event.target).data("navindex"));
+ event.data.setCard(index);
+ });
+
+ if ( this.title.length != 0 ) {
+ this.setTitle(this.title);
+ }
+
+ this.on("submit", this._defaultSubmit);
+
+ // Set Modal Dimensions
+ this.autoDimensions();
+ },
+
+ autoDimensions: function() {
+ // DO NOT REMOVE DISPLAY ; Temporary display is required for calculation
+ this.modal.css('display', 'block');
+
+ this.dimensions.header = this.header.outerHeight(true);
+
+ // Navigation Pane is dyanmic build on card content
+ // Navigation Pane === BASE Inner Content Height
+ this.dimensions.navigation = this.wizardSteps.outerHeight(true);
+ if ( this.dimensions.navigation < this.dimensions.contentHeight ) {
+ this.dimensions.navigation = this.dimensions.contentHeight;
+ this.navContainer.height( (this.dimensions.contentHeight-30) - this.progressContainer.outerHeight(true));
+ }
+
+ // Dimension Alias ( Body Height === (Navigation Height) )
+ this.dimensions.body = this.dimensions.navigation;
+
+ // Apply OuterHeight of navigation to it's parent wizardSteps
+ this.wizardSteps.height(this.dimensions.body);
+
+ // Modal Height === (Header + Content)
+ this.dimensions.modal = (this.dimensions.header + this.dimensions.navigation);
+ this.content.height(this.dimensions.modal + 'px');
+ this.dialog.width(this.dimensions.contentWidth);
+
+ this.body.height(this.dimensions.body + 'px');
+ this.wizardCards.height(this.dimensions.body + 'px');
+
+ // Footer Height
+ this.dimensions.footer = this.footer.outerHeight(true);
+
+ // Card Container === (Body - Footer)
+ this.dimensions.cardContainer = (this.dimensions.body - this.dimensions.footer);
+ this.wizardCardContainer.height(this.dimensions.cardContainer);
+
+ // Reposition
+ this.dimensions.offset = ($(window).height() - this.dialog.height()) / 2;
+ this.dialog.css({
+ 'margin-top': this.dimensions.offset + 'px',
+ 'padding-top': 0
+ });
+
+ // DO NOT REMOVE NEXT LINE
+ this.modal.css('display', '');
+ },
+
+ setTitle: function(title) {
+ this.log("setting title to", title);
+ this.modal.find(".wizard-title").first().text(title);
+ return this;
+ },
+
+ setSubtitle: function(title) {
+ this.log("setting subtitle to", title);
+ this.modal.find(".wizard-subtitle").first().text(title);
+ return this;
+ },
+
+ errorPopover: function(el, msg, allowHtml) {
+ this.log("launching popover on", el);
+ allowHtml = typeof allowHtml !== "undefined" ? allowHtml : false;
+ var popover = el.popover({
+ content: msg,
+ trigger: "manual",
+ html: allowHtml,
+ container: el.parents('.form-group')
+ }).addClass("error-popover").popover("show").next(".popover");
+
+ el.parents('.form-group').find('.popover').addClass("error-popover");
+
+ this.popovers.push(el);
+
+ return popover;
+ },
+
+ destroyPopover: function(pop) {
+ pop = $(pop);
+
+ /*
+ * this is the element that the popover was created for
+ */
+ try {
+ pop.popover("destroy");
+ }
+ /*
+ * older versions of bootstrap don't have a destroy call
+ * for popovers
+ */
+ catch (e) {
+ pop.popover("hide");
+ }
+ },
+
+ hidePopovers: function(el) {
+ this.log("hiding all popovers");
+ var self = this;
+
+ $.each(this.popovers, function(i, p) {
+ self.destroyPopover(p);
+ });
+
+ this.modal.find('.has-error').removeClass('has-error');
+ this.popovers = [];
+ },
+
+ eachCard: function(fn) {
+ $.each(this._cards, fn);
+ return this;
+ },
+
+ getActiveCard: function() {
+ this.log("getting active card");
+ var currentCard = null;
+
+ $.each(this._cards, function(i, card) {
+ if (card.isActive()) {
+ currentCard = card;
+ return false;
+ }
+ });
+ if (currentCard) {this.log("found active card", currentCard);}
+ else {this.log("couldn't find an active card");}
+ return currentCard;
+ },
+
+ changeNextButton: function(text, cls) {
+ this.log("changing next button, text: " + text, "class: " + cls);
+ if (typeof(cls) != "undefined") {
+ this.nextButton.removeClass("btn-success btn-primary");
+ }
+
+ if (cls) {
+ this.nextButton.addClass(cls);
+ }
+ this.nextButton.text(text);
+ return this;
+ },
+
+ hide: function() {
+ this.log("hiding");
+ this.modal.modal("hide");
+ return this;
+ },
+
+ close: function() {
+ this.log("closing");
+ this.modal.modal("hide");
+ return this;
+ },
+
+
+ show: function(modalOptions) {
+ this.log("showing");
+ if (this._firstShow) {
+ this.setCard(0);
+ this._firstShow = false;
+ }
+ if (this.args.showCancel) {
+ this.cancelButton.show();
+ } else {
+ this.cancelButton.hide();
+ }
+ if (this.args.showClose) { this.closeButton.show(); }
+ this.modal.modal('show');
+
+ return this;
+ },
+
+ on: function(name, fn) {
+ this.log("adding listener to event " + name);
+ this._events[name] = fn;
+ return this;
+ },
+
+ trigger: function() {
+ var name = arguments[0];
+ var args = Array.prototype.slice.call(arguments);
+ args.shift();
+ args.unshift(this);
+
+ this.log("firing event " + name);
+ var handler = this._events[name];
+ if (handler === undefined && this.wizard !== undefined) {
+ handler = this.wizard._events[name];
+ }
+ var ret = null;
+
+ if (typeof(handler) == "function") {
+ this.log("found event handler, calling " + name);
+ try {
+ ret = handler.apply(this, args);
+ }
+ catch (e) {
+ this.log("event handler " + name + " had an exception");
+ }
+ }
+ else {
+ this.log("couldn't find an event handler for " + name);
+ }
+ return ret;
+ },
+
+
+ reset: function() {
+ this.log("resetting");
+
+ this.updateProgressBar(0);
+ this.hideSubmitCards();
+
+ this.setCard(0);
+ this.lockCards();
+
+ this.enableNextButton();
+ this.showButtons();
+
+ this.hidePopovers();
+
+ this.trigger("reset");
+ return this;
+ },
+
+ /*
+ * this handles switching to the next card or previous card, taking
+ * care to skip over disabled cards
+ */
+ _abstractIncrementStep: function(direction, getNext) {
+ var current = this.getActiveCard();
+ var next;
+
+ if (current) {
+ /*
+ * loop until we find a card that isn't disabled
+ */
+ this.log("searching for valid next card");
+ while (true) {
+ next = getNext(current);
+ if (next) {
+ this.log("looking at card", next.index);
+ if (next.isDisabled()) {
+ this.log("card " + next.index + " is disabled/locked, continuing");
+ current = next;
+ continue;
+ }
+ else {
+ return this.setCard(current.index+direction);
+ }
+ }
+ else {
+ this.log("next card is not defined, breaking");
+ break;
+ }
+ }
+ }
+ else {
+ this.log("current card is undefined");
+ }
+ },
+
+
+ incrementCard: function() {
+ this.log("incrementing card");
+ var card = this._abstractIncrementStep(1, function(current){return current.next;});
+ this.trigger("incrementCard");
+ return card;
+ },
+
+ decrementCard: function() {
+ this.log("decrementing card");
+ var card = this._abstractIncrementStep(-1, function(current){return current.prev;});
+ this.trigger("decrementCard");
+ return card;
+ },
+
+ setCard: function(i) {
+ this.log("setting card to " + i);
+ this.hideSubmitCards();
+ var currentCard = this.getActiveCard();
+
+ if (this._submitting) {
+ this.log("we're submitting the wizard already, can't change cards");
+ return currentCard;
+ }
+
+ var newCard = this._cards[i];
+ if (newCard) {
+ if (newCard.isDisabled()) {
+ this.log("new card is currently disabled, returning");
+ return currentCard;
+ }
+
+ if (currentCard) {
+
+ /*
+ * here, we're only validating if we're going forward,
+ * not if we're going backwards in a step
+ */
+ if (i > currentCard.index) {
+ var cardToValidate = currentCard;
+ var ok = false;
+
+ /*
+ * we need to loop over every card between our current
+ * card and the card that we clicked, and re-validate
+ * them. if there's an error, we need to select the
+ * first card to have an error
+ */
+ while (cardToValidate.index != newCard.index) {
+ /*
+ * unless we're validating the card that we're
+ * leaving, we need to select the card, so that
+ * any validators that trigger errorPopovers can
+ * display correctly
+ */
+ if (cardToValidate.index != currentCard.index) {
+ cardToValidate.prev.deselect();
+ cardToValidate.prev.markVisited();
+ cardToValidate.select();
+ }
+ ok = cardToValidate.validate();
+ if (!ok) {
+ return cardToValidate;
+ }
+ cardToValidate = cardToValidate.next;
+ }
+
+ cardToValidate.prev.deselect();
+ cardToValidate.prev.markVisited();
+ }
+
+ currentCard.deselect();
+ currentCard.markVisited();
+ }
+
+ newCard.select();
+
+ if (this.args.progressBarCurrent) {
+ this.percentComplete = i * 100.0 / this._cards.length;
+ this.updateProgressBar(this.percentComplete);
+ }
+ else {
+ var lastPercent = this.percentComplete;
+ this.percentComplete = i * 100.0 / this._cards.length;
+ this.percentComplete = Math.max(lastPercent, this.percentComplete);
+ this.updateProgressBar(this.percentComplete);
+ }
+
+ return newCard;
+ }
+ else {
+ this.log("couldn't find card " + i);
+ }
+ },
+
+ updateProgressBar: function(percent) {
+ this.log("updating progress to " + percent + "%");
+ this.progress.css({width: percent + "%"});
+ this.percentComplete = percent;
+
+ this.trigger("progressBar", percent);
+
+ if (percent == 100) {
+ this.log("progress is 100, animating progress bar");
+ this.progressContainer.find('.progress').addClass("active");
+ }
+ else if (percent == 0) {
+ this.log("progress is 0, disabling animation");
+ this.progressContainer.find('.progress').removeClass("active");
+ }
+ },
+
+ getNextCard: function() {
+ var currentCard = this.getActiveCard();
+ if (currentCard) return currentCard.next;
+ },
+
+ lockCards: function() {
+ this.log("locking nav cards");
+ this.eachCard(function(i,card){card.unmarkVisited();});
+ return this;
+ },
+
+ disableCards: function() {
+ this.log("disabling all nav cards");
+ this.eachCard(function(i,card){card.disable();});
+ return this;
+ },
+
+ enableCards: function() {
+ this.log("enabling all nav cards");
+ this.eachCard(function(i,card){card.enable();});
+ return this;
+ },
+
+ hideCards: function() {
+ this.log("hiding cards");
+ this.eachCard(function(i,card){card.deselect();});
+ this.hideSubmitCards();
+ return this;
+ },
+
+ hideButtons: function() {
+ this.log("hiding buttons");
+ this.cancelButton.hide();
+ this.closeButton.hide();
+ this.nextButton.hide();
+ this.backButton.hide();
+ return this;
+ },
+
+ showButtons: function() {
+ this.log("showing buttons");
+ if (this.args.showCancel) {
+ this.cancelButton.show();
+ } else {
+ this.cancelButton.hide();
+ }
+ if (this.args.showClose) { this.closeButton.show(); };
+ this.nextButton.show();
+ this.backButton.show();
+ return this;
+ },
+
+ getCard: function(el) {
+ var cardDOMEl = $(el).parents(".wizard-card").first()[0];
+ if (cardDOMEl) {
+ var foundCard = null;
+ this.eachCard(function(i, card) {
+ if (cardDOMEl == card.el[0]) {
+ foundCard = card;
+ return false;
+ }
+ return true;
+ });
+ return foundCard;
+ }
+ else {
+ return null;
+ }
+ },
+
+ _createCards: function() {
+ var prev = null;
+ var next = null;
+ var currentCard = null;
+ var wizard = this;
+ var self = this;
+
+ self.log("Creating Cards");
+
+ var cards = this.modal.find(".wizard-cards .wizard-card");
+ $.each(cards, function(i, card) {
+ card = $(card);
+
+ prev = currentCard;
+ currentCard = new WizardCard(wizard, card, i, prev, next);
+ self._cards.push(currentCard);
+ if (currentCard.name) {
+ self.cards[currentCard.name] = currentCard;
+ }
+ if (prev) {prev.next = currentCard;}
+
+ self.modal.find(".wizard-steps .wizard-nav-list").append(currentCard.nav);
+ });
+ },
+
+ showSubmitCard: function(name) {
+ this.log("showing "+name+" submit card");
+
+ var card = this.el.find(".wizard-"+name);
+ if (card.length) {
+ this.hideCards();
+ this.el.find(".wizard-"+name).show();
+ }
+ else {
+ this.log("couldn't find submit card "+name);
+ }
+ },
+
+ hideSubmitCard: function(name) {
+ this.log("hiding "+name+" submit card");
+ this.el.find(".wizard-"+name).hide();
+ },
+
+ hideSubmitCards: function() {
+ var wizard = this;
+ $.each(["success", "error", "failure", "loading"], function(i, name) {
+ wizard.hideSubmitCard(name);
+ });
+ },
+
+ enableNextButton: function() {
+ this.log("enabling next button");
+ this.nextButton.removeAttr("disabled");
+ return this;
+ },
+
+ disableNextButton: function() {
+ this.log("disabling next button");
+ this.nextButton.attr("disabled", "disabled");
+ return this;
+ },
+
+ serializeArray: function() {
+ var form = this.form.serializeArray();
+ this.form.find('input[disabled][data-serialize="1"]').each(function() {
+ formObj = {
+ name: $(this).attr('name'),
+ value: $(this).val()
+ };
+
+ form.push(formObj);
+ });
+
+ return form;
+ },
+
+ serialize: function() {
+ var form = this.form.serialize();
+ this.form.find('input[disabled][data-serialize="1"]').each(function() {
+ form = form + '&' + $(this).attr('name') + '=' + $(this).val();
+ });
+
+ return form;
+ },
+
+ find: function(selector) {
+ return this.modal.find(selector);
+ },
+
+
+ /*
+ * the next 3 functions are to be called by the custom submit event
+ * handler. the idea is that after you make an ajax call to submit
+ * your wizard data (or whatever it is you want to do at the end of
+ * the wizard), you call one of these 3 handlers to display a specific
+ * card for either success, failure, or error
+ */
+ submitSuccess: function() {
+ this.log("submit success");
+ this._submitting = false;
+ this.showSubmitCard("success");
+ this.trigger("submitSuccess");
+ },
+
+ submitFailure: function() {
+ this.log("submit failure");
+ this._submitting = false;
+ this.showSubmitCard("failure");
+ this.trigger("submitFailure");
+ },
+
+ submitError: function() {
+ this.log("submit error");
+ this._submitting = false;
+ this.showSubmitCard("error");
+ this.trigger("submitError");
+ },
+
+
+ _submit: function() {
+ this.log("submitting wizard");
+ this._submitting = true;
+
+ this.lockCards();
+ this.cancelButton.hide();
+ this.closeButton.hide();
+ this.backButton.hide();
+
+ this.showSubmitCard("loading");
+ this.updateProgressBar(100);
+
+ this.changeNextButton(this.args.buttons.submittingText, false);
+ this.disableNextButton();
+
+ var ret = this.trigger("submit");
+ this.trigger("loading");
+ },
+
+ _onNextClick: function() {
+ this.log("handling 'next' button click");
+ var currentCard = this.getActiveCard();
+ if (this._readyToSubmit && currentCard.validate()) {
+ this._submit();
+ }
+ else {
+ currentCard = this.incrementCard();
+ }
+ },
+
+ _onBackClick: function() {
+ this.log("handling 'back' button click");
+ var currentCard = this.decrementCard();
+ },
+
+ _handleNextClick: function(event) {
+ var wizard = event.data;
+ wizard._onNextClick.call(wizard);
+ },
+
+ _handleBackClick: function(event) {
+ var wizard = event.data;
+ wizard._onBackClick.call(wizard);
+ },
+
+
+ /*
+ * this function is attached by default to the wizard's "submit" event.
+ * if you choose to implement your own custom submit logic, you should
+ * copy how this function works
+ */
+ _defaultSubmit: function(wizard) {
+ $.ajax({
+ type: "POST",
+ url: wizard.args.submitUrl,
+ data: wizard.serialize(),
+ dataType: "json"
+ }).done(function(response) {
+ wizard.submitSuccess();
+ wizard.hideButtons();
+ wizard.updateProgressBar(0);
+ }).fail(function() {
+ wizard.submitFailure();
+ wizard.hideButtons();
+ });
+ }
+ };
+
+
+}(window.jQuery));
diff --git a/assets/js/bootstrap-wizard-lib/bootstrap-wizard.min.js b/assets/js/bootstrap-wizard-lib/bootstrap-wizard.min.js
new file mode 100644
index 0000000..898bb73
--- /dev/null
+++ b/assets/js/bootstrap-wizard-lib/bootstrap-wizard.min.js
@@ -0,0 +1 @@
+(function(e){e.fn.wizard=function(e){return new Wizard(this,e)};e.fn.wizard.logging=false;var t=function(e,t,n,r,i){this.wizard=e;this.index=n;this.prev=r;this.next=i;this.el=t;this.title=t.find("h3").first().text();this.name=t.data("cardname")||this.title;this.nav=this._createNavElement(this.title,n);this._disabled=false;this._loaded=false;this._events={}};t.prototype={select:function(){this.log("selecting");if(!this.isSelected()){this.nav.addClass("active");this.el.show();if(!this._loaded){this.trigger("loaded");this.reload()}this.trigger("selected")}var e=this.wizard;e.backButton.toggleClass("disabled",this.index==0);if(this.index>=e._cards.length-1){this.log("on last card, changing next button to submit");e.changeNextButton(e.args.buttons.submitText,"btn-success");e._readyToSubmit=true;e.trigger("readySubmit")}else{e._readyToSubmit=false;e.changeNextButton(e.args.buttons.nextText,"btn-primary")}return this},_createNavElement:function(t,n){var r=e('');var i=e('');i.data("navindex",n);r.append(i);i.append(' ');i.append(t);return r},markVisited:function(){this.log("marking as visited");this.nav.addClass("already-visited");this.trigger("markVisited");return this},unmarkVisited:function(){this.log("unmarking as visited");this.nav.removeClass("already-visited");this.trigger("unmarkVisited");return this},deselect:function(){this.nav.removeClass("active");this.el.hide();this.trigger("deselect");return this},enable:function(){this.log("enabling");this.nav.addClass("active");this._disabled=false;this.trigger("enabled");return this},disable:function(e){this.log("disabling");this._disabled=true;this.nav.removeClass("active already-visited");if(e){this.el.hide()}this.trigger("disabled");return this},isDisabled:function(){return this._disabled},alreadyVisited:function(){return this.nav.hasClass("already-visited")},isSelected:function(){return this.nav.hasClass("active")},reload:function(){this._loaded=true;this.trigger("reload");return this},on:function(){return this.wizard.on.apply(this,arguments)},trigger:function(){this.callListener("on"+arguments[0]);return this.wizard.trigger.apply(this,arguments)},toggleAlert:function(t,n){this.log("toggling alert to: "+n);n=typeof n=="undefined"?true:n;if(n){this.trigger("showAlert")}else{this.trigger("hideAlert")}var r;var i=this.el.children("h3").first().next("div.alert");if(i.length==0){if(!n){return this}this.log("couldn't find existing alert div, creating one");r=e("");r.addClass("alert");r.addClass("hide");r.insertAfter(this.el.find("h3").first())}else{this.log("found existing alert div");r=i.first()}if(n){if(t!=null){this.log("setting alert msg to",t);r.html(t)}r.show()}else{r.hide()}return this},callListener:function(e){e=e.toLowerCase();this.log("looking for listener "+e);var t=window[this.el.data(e)];if(t){this.log("calling listener "+e);var n=this.wizard;try{var r=t(this)}catch(i){this.log("exception calling listener "+e+": ",i)}}else{this.log("didn't find listener "+e)}},problem:function(e){this.nav.find("a").toggleClass("wizard-step-error",e)},validate:function(){var t=false;var n=this;this.el.find("[data-validate]").each(function(r,i){n.log("validating individiual inputs");i=e(i);var s=i.data("validate");if(!s){return}var o={status:true,title:"Error",msg:""};var u=window[s](i);e.extend(o,u);if(e("#btn-"+i.attr("id")).length===1){i=e("#btn-"+i.attr("id"))}if(!o.status){t=true;i.parents("div.form-group").toggleClass("has-error",true);if(e("#btn-"+i.attr("id")).length===1){i=e("#btn-"+i.attr("id"))}n.wizard.errorPopover(i,o.msg)}else{i.parents("div.form-group").toggleClass("has-error",false);if(e("#btn-"+i.attr("id")).length===1){i=e("#btn-"+i.attr("id"))}try{i.popover("destroy")}catch(a){i.popover("hide")}}});this.log("after validating inputs, failures is",t);var r=window[this.el.data("validate")];if(r){this.log("running html-embedded card validator");var i=r(this);if(typeof i=="undefined"||i==null){i=true}if(!i)t=true;this.log("after running html-embedded card validator, failures is",t)}this.log("running listener validator");var s=this.trigger("validate");if(typeof s=="undefined"||s==null){s=true}if(!s)t=true;this.log("after running listener validator, failures is",t);var o=!t;if(o){this.log("validated, calling listeners");this.trigger("validated")}else{this.log("invalid");this.trigger("invalid")}return o},log:function(){if(!window.console||!e.fn.wizard.logging){return}var t="card '"+this.name+"': ";var n=[t];n.push.apply(n,arguments);console.log.apply(console,n)},isActive:function(){return this.nav.hasClass("active")}};Wizard=function(t,n){this.wizard_template=['
','
','
','
','','','',"
",'
','
','
','
',"
","
",'
','
','',"
","
","
","","
","
","
","
"];this.args={keyboard:true,backdrop:true,show:false,submitUrl:"",showCancel:false,showClose:true,progressBarCurrent:false,increaseHeight:0,contentHeight:300,contentWidth:'50%',buttons:{cancelText:"Cancel",nextText:"Next",backText:"Back",submitText:"Submit",submittingText:"Submitting..."},formClass:"form-horizontal"};e.extend(this.args,n||{});this._create(t)};Wizard.prototype={log:function(){if(!window.console||!e.fn.wizard.logging){return}var t="wizard "+this.el.id+": ";var n=[t];n.push.apply(n,arguments);console.log.apply(console,n)},_create:function(t){this.markup=e(t);this.title=this.markup.data("title");this.submitCards=this.markup.find(".wizard-error,.wizard-failure,.wizard-success,.wizard-loading");this.el=e(this.wizard_template.join("\n"));e("body").append(this.el);this.modal=this.el.modal({keyboard:this.args.keyboard,show:this.args.show,backdrop:this.args.backdrop});this.dimensions={contentHeight:this.args.contentHeight,contentWidth:this.args.contentWidth};this.dialog=this.modal.find(".wizard-dialog");this.content=this.modal.find(".wizard-content");this.header=this.modal.find(".wizard-header");this.body=this.modal.find(".wizard-body");this.wizardSteps=this.modal.find(".wizard-steps");this.wizardCards=this.modal.find(".wizard-cards");this.wizardCardContainer=this.modal.find(".wizard-card-container");this.wizardCardContainer.append(this.markup.find(".wizard-card")).append(this.submitCards);this.navContainer=this.modal.find(".wizard-nav-container");this.navList=this.modal.find(".wizard-nav-list");this.progressContainer=this.modal.find(".wizard-progress-container");this.progress=this.progressContainer.find(".progress-bar");this.closeButton=this.modal.find("button.wizard-close.close");this.cardsContainer=this.modal.find("wizard-cards-container");this.form=this.modal.find("form");this.footer=this.modal.find(".wizard-footer");this.cancelButton=this.footer.find(".wizard-cancel");this.backButton=this.footer.find(".wizard-back");this.nextButton=this.footer.find(".wizard-next");this._cards=[];this.cards={};this._readyToSubmit=false;this.percentComplete=0;this._submitting=false;this._events={};this._firstShow=true;this._createCards();this.nextButton.click(this,this._handleNextClick);this.backButton.click(this,this._handleBackClick);this.cancelButton.text(this.args.buttons.cancelText);this.backButton.text(this.args.buttons.backText);this.nextButton.text(this.args.buttons.nextText);this.form.addClass(this.args.formClass);this.popovers=[];var n=this;var r=function(){n.reset();n.close();n.trigger("closed")};this.closeButton.click(r);this.cancelButton.click(r);this.wizardSteps.on("click","li.already-visited a.wizard-nav-link",this,function(t){var n=parseInt(e(t.target).data("navindex"));t.data.setCard(n)});if(this.title.length!=0){this.setTitle(this.title)}this.on("submit",this._defaultSubmit);this.autoDimensions()},autoDimensions:function(){this.modal.css("display","block");this.dimensions.header=this.header.outerHeight(true);this.dimensions.navigation=this.wizardSteps.outerHeight(true);if(this.dimensions.navigationt.index){var r=t;var i=false;while(r.index!=n.index){if(r.index!=t.index){r.prev.deselect();r.prev.markVisited();r.select()}i=r.validate();if(!i){return r}r=r.next}r.prev.deselect();r.prev.markVisited()}t.deselect();t.markVisited()}n.select();if(this.args.progressBarCurrent){this.percentComplete=e*100/this._cards.length;this.updateProgressBar(this.percentComplete)}else{var s=this.percentComplete;this.percentComplete=e*100/this._cards.length;this.percentComplete=Math.max(s,this.percentComplete);this.updateProgressBar(this.percentComplete)}return n}else{this.log("couldn't find card "+e)}},updateProgressBar:function(e){this.log("updating progress to "+e+"%");this.progress.css({width:e+"%"});this.percentComplete=e;this.trigger("progressBar",e);if(e==100){this.log("progress is 100, animating progress bar");this.progressContainer.find(".progress").addClass("active")}else if(e==0){this.log("progress is 0, disabling animation");this.progressContainer.find(".progress").removeClass("active")}},getNextCard:function(){var e=this.getActiveCard();if(e)return e.next},lockCards:function(){this.log("locking nav cards");this.eachCard(function(e,t){t.unmarkVisited()});return this},disableCards:function(){this.log("disabling all nav cards");this.eachCard(function(e,t){t.disable()});return this},enableCards:function(){this.log("enabling all nav cards");this.eachCard(function(e,t){t.enable()});return this},hideCards:function(){this.log("hiding cards");this.eachCard(function(e,t){t.deselect()});this.hideSubmitCards();return this},hideButtons:function(){this.log("hiding buttons");this.cancelButton.hide();this.closeButton.hide();this.nextButton.hide();this.backButton.hide();return this},showButtons:function(){this.log("showing buttons");if(this.args.showCancel){this.cancelButton.show()}else{this.cancelButton.hide()}if(this.args.showClose){this.closeButton.show()}this.nextButton.show();this.backButton.show();return this},getCard:function(t){var n=e(t).parents(".wizard-card").first()[0];if(n){var r=null;this.eachCard(function(e,t){if(n==t.el[0]){r=t;return false}return true});return r}else{return null}},_createCards:function(){var n=null;var r=null;var i=null;var s=this;var o=this;o.log("Creating Cards");var u=this.modal.find(".wizard-cards .wizard-card");e.each(u,function(u,a){a=e(a);n=i;i=new t(s,a,u,n,r);o._cards.push(i);if(i.name){o.cards[i.name]=i}if(n){n.next=i}o.modal.find(".wizard-steps .wizard-nav-list").append(i.nav)})},showSubmitCard:function(e){this.log("showing "+e+" submit card");var t=this.el.find(".wizard-"+e);if(t.length){this.hideCards();this.el.find(".wizard-"+e).show()}else{this.log("couldn't find submit card "+e)}},hideSubmitCard:function(e){this.log("hiding "+e+" submit card");this.el.find(".wizard-"+e).hide()},hideSubmitCards:function(){var t=this;e.each(["success","error","failure","loading"],function(e,n){t.hideSubmitCard(n)})},enableNextButton:function(){this.log("enabling next button");this.nextButton.removeAttr("disabled");return this},disableNextButton:function(){this.log("disabling next button");this.nextButton.attr("disabled","disabled");return this},serializeArray:function(){var t=this.form.serializeArray();this.form.find('input[disabled][data-serialize="1"]').each(function(){formObj={name:e(this).attr("name"),value:e(this).val()};t.push(formObj)});return t},serialize:function(){var t=this.form.serialize();this.form.find('input[disabled][data-serialize="1"]').each(function(){t=t+"&"+e(this).attr("name")+"="+e(this).val()});return t},find:function(e){return this.modal.find(e)},submitSuccess:function(){this.log("submit success");this._submitting=false;this.showSubmitCard("success");this.trigger("submitSuccess")},submitFailure:function(){this.log("submit failure");this._submitting=false;this.showSubmitCard("failure");this.trigger("submitFailure")},submitError:function(){this.log("submit error");this._submitting=false;this.showSubmitCard("error");this.trigger("submitError")},_submit:function(){this.log("submitting wizard");this._submitting=true;this.lockCards();this.cancelButton.hide();this.closeButton.hide();this.backButton.hide();this.showSubmitCard("loading");this.updateProgressBar(100);this.changeNextButton(this.args.buttons.submittingText,false);this.disableNextButton();var e=this.trigger("submit");this.trigger("loading")},_onNextClick:function(){this.log("handling 'next' button click");var e=this.getActiveCard();if(this._readyToSubmit&&e.validate()){this._submit()}else{e=this.incrementCard()}},_onBackClick:function(){this.log("handling 'back' button click");var e=this.decrementCard()},_handleNextClick:function(e){var t=e.data;t._onNextClick.call(t)},_handleBackClick:function(e){var t=e.data;t._onBackClick.call(t)},_defaultSubmit:function(t){e.ajax({type:"POST",url:t.args.submitUrl,data:t.serialize(),dataType:"json"}).done(function(e){t.submitSuccess();t.hideButtons();t.updateProgressBar(0)}).fail(function(){t.submitFailure();t.hideButtons()})}}})(window.jQuery)
diff --git a/conf/setup_dashboard/cep-config/config-xmls.zip b/conf/setup_dashboard/cep-config/config-xmls.zip
new file mode 100644
index 0000000..1aecb4a
Binary files /dev/null and b/conf/setup_dashboard/cep-config/config-xmls.zip differ
diff --git a/conf/setup_dashboard/cep-config/eventbuilders/TrackerJsonBuilder.xml b/conf/setup_dashboard/cep-config/eventbuilders/TrackerJsonBuilder.xml
new file mode 100755
index 0000000..f317088
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/eventbuilders/TrackerJsonBuilder.xml
@@ -0,0 +1,34 @@
+
+
+
+ trackingstream
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/setup_dashboard/cep-config/eventbuilders/geoJsonBuilder.xml b/conf/setup_dashboard/cep-config/eventbuilders/geoJsonBuilder.xml
new file mode 100755
index 0000000..2982073
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/eventbuilders/geoJsonBuilder.xml
@@ -0,0 +1,33 @@
+
+
+
+ geoJson
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/setup_dashboard/cep-config/eventformatters/geoJsonFormatter.xml b/conf/setup_dashboard/cep-config/eventformatters/geoJsonFormatter.xml
new file mode 100755
index 0000000..935944c
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/eventformatters/geoJsonFormatter.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+ {
+ "type": "Feature",
+ "id": "{{id}}",
+ "properties": {
+ "speed": {{speed}},
+ "heading": {{heading}},
+ "state": "{{state}}",
+ "information": "{{information}}",
+ "notify": {{notify}}
+ },
+ "geometry": {
+ "type": "Point",
+ "coordinates": [{{longitude}},{{latitude}}]
+ }
+}
+
+
+
+ geoDataEndPoint
+
+
diff --git a/conf/setup_dashboard/cep-config/eventformatters/mysqlFormatter.xml b/conf/setup_dashboard/cep-config/eventformatters/mysqlFormatter.xml
new file mode 100755
index 0000000..381ffc5
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/eventformatters/mysqlFormatter.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ alerts_history
+
+ insert
+
+
diff --git a/conf/setup_dashboard/cep-config/executionplans/eventsFunionGenerateNotofications.xml b/conf/setup_dashboard/cep-config/executionplans/eventsFunionGenerateNotofications.xml
new file mode 100755
index 0000000..0e8d1a7
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/executionplans/eventsFunionGenerateNotofications.xml
@@ -0,0 +1,27 @@
+
+
+ Fuse multiple events into one event and notify to user if a state has change from the previous value
+
+ 0
+ false
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/setup_dashboard/cep-config/executionplans/geo_speed_alert.xml b/conf/setup_dashboard/cep-config/executionplans/geo_speed_alert.xml
new file mode 100755
index 0000000..389199c
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/executionplans/geo_speed_alert.xml
@@ -0,0 +1,20 @@
+
+
+ When an object reatch to a pre-defined aleart speed, CEP change the state of that event to ALEARTED and overwrite the information.
+
+ 0
+ false
+
+
+
+
+ = 34]#transform.geo:subscribeExecutionPlan()
+select id , latitude, longitude,timeStamp, speed, heading ,eventId , "ALERTED" as state, "This vehicle is going over speed!!" as information
+insert into dataOut;
+from dataIn[speed < 34]
+select id , latitude, longitude,timeStamp, speed, heading ,eventId , "NORMAL" as state, "Normal driving pattern" as information
+insert into dataOut;]]>
+
+
+
+
diff --git a/conf/setup_dashboard/cep-config/executionplans/geo_testing2_proxymity_alert.xml b/conf/setup_dashboard/cep-config/executionplans/geo_testing2_proxymity_alert.xml
new file mode 100755
index 0000000..620eabb
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/executionplans/geo_testing2_proxymity_alert.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ 0
+ false
+
+
+
+
+
+
+
+
+
diff --git a/conf/setup_dashboard/cep-config/executionplans/geo_within_Akuregoda_alert.xml b/conf/setup_dashboard/cep-config/executionplans/geo_within_Akuregoda_alert.xml
new file mode 100755
index 0000000..5894e7b
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/executionplans/geo_within_Akuregoda_alert.xml
@@ -0,0 +1,21 @@
+
+
+
+
+ 0
+ false
+
+
+
+
+ from dataIn[geo:iswithin(longitude,latitude,"{'type':'Polygon','coordinates':[[[79.9320602416992,6.878369189928266],[79.9148941040039,6.894729791048567],[79.92382049560545,6.911430655357409],[79.95574951171875,6.912793965187959],[79.96261596679686,6.89984236311519],[79.96330261230467,6.879391744022743],[79.9320602416992,6.878369189928266]]]}")==true]#transform.geo:subscribeExecutionPlan()
+select id , latitude, longitude,timeStamp, speed, heading ,eventId , "ALERTED" as state, "This vehicle is in Akuregoda1 restricted area!!!" as information
+insert into dataOut;
+from dataIn[geo:iswithin(longitude,latitude,"{'type':'Polygon','coordinates':[[[79.9320602416992,6.878369189928266],[79.9148941040039,6.894729791048567],[79.92382049560545,6.911430655357409],[79.95574951171875,6.912793965187959],[79.96261596679686,6.89984236311519],[79.96330261230467,6.879391744022743],[79.9320602416992,6.878369189928266]]]}")!=true]
+select id , latitude, longitude,timeStamp, speed, heading ,eventId , "NORMAL" as state, "" as information
+insert into dataOut;
+
+
+
+
diff --git a/conf/setup_dashboard/cep-config/executionplans/geo_within_Colombo_alert.xml b/conf/setup_dashboard/cep-config/executionplans/geo_within_Colombo_alert.xml
new file mode 100755
index 0000000..02f1bc4
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/executionplans/geo_within_Colombo_alert.xml
@@ -0,0 +1,21 @@
+
+
+
+
+ 0
+ false
+
+
+
+
+ from dataIn[geo:iswithin(longitude,latitude,"{'type':'Polygon','coordinates':[[[79.85206604003906,6.928982968564734],[79.85584259033203,6.943467395179309],[79.86974716186523,6.941592965070489],[79.88245010375977,6.92506357659203],[79.87335205078125,6.919440044277738],[79.85206604003906,6.928982968564734]]]}")==true]#transform.geo:subscribeExecutionPlan()
+select id , latitude, longitude,timeStamp, speed, heading ,eventId , "ALERTED" as state, "This vehicle is in Fence1 restricted area!!!" as information
+insert into dataOut;
+from dataIn[geo:iswithin(longitude,latitude,"{'type':'Polygon','coordinates':[[[79.85206604003906,6.928982968564734],[79.85584259033203,6.943467395179309],[79.86974716186523,6.941592965070489],[79.88245010375977,6.92506357659203],[79.87335205078125,6.919440044277738],[79.85206604003906,6.928982968564734]]]}")!=true]
+select id , latitude, longitude,timeStamp, speed, heading ,eventId , "NORMAL" as state, "" as information
+insert into dataOut;
+
+
+
+
diff --git a/conf/setup_dashboard/cep-config/executionplans/geo_within_Havlock_town_alert.xml b/conf/setup_dashboard/cep-config/executionplans/geo_within_Havlock_town_alert.xml
new file mode 100755
index 0000000..4ceefc0
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/executionplans/geo_within_Havlock_town_alert.xml
@@ -0,0 +1,21 @@
+
+
+
+
+ 0
+ false
+
+
+
+
+ from dataIn[geo:iswithin(longitude,latitude,"{'type':'Polygon','coordinates':[[[79.8676872253418,6.889276320041728],[79.85858917236328,6.899671944935481],[79.86236572265625,6.909556097920147],[79.87661361694336,6.909896927097974],[79.88004684448242,6.902057793869],[79.88056182861328,6.894218530807201],[79.87232208251953,6.891150957776738],[79.8676872253418,6.889276320041728]]]}")==true]#transform.geo:subscribeExecutionPlan()
+select id , latitude, longitude,timeStamp, speed, heading ,eventId , "ALERTED" as state, "This vehicle is in Havlock_town1 restricted area!!!" as information
+insert into dataOut;
+from dataIn[geo:iswithin(longitude,latitude,"{'type':'Polygon','coordinates':[[[79.8676872253418,6.889276320041728],[79.85858917236328,6.899671944935481],[79.86236572265625,6.909556097920147],[79.87661361694336,6.909896927097974],[79.88004684448242,6.902057793869],[79.88056182861328,6.894218530807201],[79.87232208251953,6.891150957776738],[79.8676872253418,6.889276320041728]]]}")!=true]
+select id , latitude, longitude,timeStamp, speed, heading ,eventId , "NORMAL" as state, "" as information
+insert into dataOut;
+
+
+
+
diff --git a/conf/setup_dashboard/cep-config/executionplans/geo_within_marine_drive_alert.xml b/conf/setup_dashboard/cep-config/executionplans/geo_within_marine_drive_alert.xml
new file mode 100755
index 0000000..b26bcf2
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/executionplans/geo_within_marine_drive_alert.xml
@@ -0,0 +1,21 @@
+
+
+
+
+ 0
+ false
+
+
+
+
+ from dataIn[geo:iswithin(longitude,latitude,"{'type':'Polygon','coordinates':[[[79.85635757446289,6.878880467250712],[79.84176635742188,6.931027855791152],[79.84502792358398,6.931879889517218],[79.86202239990233,6.875471941373295],[79.86425399780273,6.868313957458993],[79.85893249511719,6.867973098394459],[79.85635757446289,6.878880467250712]]]}")==true]#transform.geo:subscribeExecutionPlan()
+select id , latitude, longitude,timeStamp, speed, heading ,eventId , "ALERTED" as state, "This vehicle is in marine_drive1 restricted area!!!" as information
+insert into dataOut;
+from dataIn[geo:iswithin(longitude,latitude,"{'type':'Polygon','coordinates':[[[79.85635757446289,6.878880467250712],[79.84176635742188,6.931027855791152],[79.84502792358398,6.931879889517218],[79.86202239990233,6.875471941373295],[79.86425399780273,6.868313957458993],[79.85893249511719,6.867973098394459],[79.85635757446289,6.878880467250712]]]}")!=true]
+select id , latitude, longitude,timeStamp, speed, heading ,eventId , "NORMAL" as state, "" as information
+insert into dataOut;
+
+
+
+
diff --git a/conf/setup_dashboard/cep-config/executionplans/geo_within_town_hall_alert.xml b/conf/setup_dashboard/cep-config/executionplans/geo_within_town_hall_alert.xml
new file mode 100755
index 0000000..3162e47
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/executionplans/geo_within_town_hall_alert.xml
@@ -0,0 +1,21 @@
+
+
+
+
+ 0
+ false
+
+
+
+
+ from dataIn[geo:iswithin(longitude,latitude,"{'type':'Polygon','coordinates':[[[79.86013412475586,6.910578584716491],[79.8544692993164,6.916543046940773],[79.86391067504883,6.923018663504],[79.87112045288086,6.918417576658827],[79.87112045288086,6.915179747927456],[79.86682891845703,6.909896927097974],[79.86013412475586,6.910578584716491]]]}")==true]#transform.geo:subscribeExecutionPlan()
+select id , latitude, longitude,timeStamp, speed, heading ,eventId , "ALERTED" as state, "This vehicle is in town_hall1 restricted area!!!" as information
+insert into dataOut;
+from dataIn[geo:iswithin(longitude,latitude,"{'type':'Polygon','coordinates':[[[79.86013412475586,6.910578584716491],[79.8544692993164,6.916543046940773],[79.86391067504883,6.923018663504],[79.87112045288086,6.918417576658827],[79.87112045288086,6.915179747927456],[79.86682891845703,6.909896927097974],[79.86013412475586,6.910578584716491]]]}")!=true]
+select id , latitude, longitude,timeStamp, speed, heading ,eventId , "NORMAL" as state, "" as information
+insert into dataOut;
+
+
+
+
diff --git a/conf/setup_dashboard/cep-config/executionplans/inputStandardizer.xml b/conf/setup_dashboard/cep-config/executionplans/inputStandardizer.xml
new file mode 100755
index 0000000..976c723
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/executionplans/inputStandardizer.xml
@@ -0,0 +1,18 @@
+
+
+
+
+ 0
+ false
+
+
+
+
+
+
+
+
+
diff --git a/conf/setup_dashboard/cep-config/inputeventadaptors/GPSStreamAdaptor.xml b/conf/setup_dashboard/cep-config/inputeventadaptors/GPSStreamAdaptor.xml
new file mode 100755
index 0000000..fdc5a5d
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/inputeventadaptors/GPSStreamAdaptor.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/conf/setup_dashboard/cep-config/outputeventadaptors/DefaultMysqlOutputAdaptor.xml b/conf/setup_dashboard/cep-config/outputeventadaptors/DefaultMysqlOutputAdaptor.xml
new file mode 100755
index 0000000..19bfa96
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/outputeventadaptors/DefaultMysqlOutputAdaptor.xml
@@ -0,0 +1,5 @@
+
+
+ mysql_db
+
diff --git a/conf/setup_dashboard/cep-config/outputeventadaptors/DefaultWebsocketOutputAdaptor.xml b/conf/setup_dashboard/cep-config/outputeventadaptors/DefaultWebsocketOutputAdaptor.xml
new file mode 100755
index 0000000..c8f5574
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/outputeventadaptors/DefaultWebsocketOutputAdaptor.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/conf/setup_dashboard/cep-config/streamdefinitions.zip b/conf/setup_dashboard/cep-config/streamdefinitions.zip
new file mode 100644
index 0000000..8907359
Binary files /dev/null and b/conf/setup_dashboard/cep-config/streamdefinitions.zip differ
diff --git a/conf/setup_dashboard/cep-config/streamdefinitions/AlertsNotifications:1.0.0.json b/conf/setup_dashboard/cep-config/streamdefinitions/AlertsNotifications:1.0.0.json
new file mode 100644
index 0000000..d6ebc5f
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/streamdefinitions/AlertsNotifications:1.0.0.json
@@ -0,0 +1,33 @@
+{
+ "streamId": "AlertsNotifications:1.0.0",
+ "name": "AlertsNotifications",
+ "version": "1.0.0",
+ "nickName": "",
+ "description": "Alerts which need to be notified to the user, output only when the alert information is changed.",
+ "payloadData": [
+ {
+ "name": "id",
+ "type": "STRING"
+ },
+ {
+ "name": "state",
+ "type": "STRING"
+ },
+ {
+ "name": "information",
+ "type": "STRING"
+ },
+ {
+ "name": "timeStamp",
+ "type": "STRING"
+ },
+ {
+ "name": "latitude",
+ "type": "DOUBLE"
+ },
+ {
+ "name": "longitude",
+ "type": "DOUBLE"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/conf/setup_dashboard/cep-config/streamdefinitions/fusedSpatialEvent:1.0.0.json b/conf/setup_dashboard/cep-config/streamdefinitions/fusedSpatialEvent:1.0.0.json
new file mode 100644
index 0000000..b751367
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/streamdefinitions/fusedSpatialEvent:1.0.0.json
@@ -0,0 +1,45 @@
+{
+ "streamId": "fusedSpatialEvent:1.0.0",
+ "name": "fusedSpatialEvent",
+ "version": "1.0.0",
+ "nickName": "",
+ "description": "",
+ "payloadData": [
+ {
+ "name": "id",
+ "type": "STRING"
+ },
+ {
+ "name": "latitude",
+ "type": "DOUBLE"
+ },
+ {
+ "name": "longitude",
+ "type": "DOUBLE"
+ },
+ {
+ "name": "timeStamp",
+ "type": "STRING"
+ },
+ {
+ "name": "speed",
+ "type": "FLOAT"
+ },
+ {
+ "name": "heading",
+ "type": "FLOAT"
+ },
+ {
+ "name": "state",
+ "type": "STRING"
+ },
+ {
+ "name": "information",
+ "type": "STRING"
+ },
+ {
+ "name": "notify",
+ "type": "BOOL"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/conf/setup_dashboard/cep-config/streamdefinitions/processedSpatialEvents:1.0.0.json b/conf/setup_dashboard/cep-config/streamdefinitions/processedSpatialEvents:1.0.0.json
new file mode 100644
index 0000000..6533374
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/streamdefinitions/processedSpatialEvents:1.0.0.json
@@ -0,0 +1,45 @@
+{
+ "streamId": "processedSpatialEvents:1.0.0",
+ "name": "processedSpatialEvents",
+ "version": "1.0.0",
+ "nickName": "",
+ "description": "",
+ "payloadData": [
+ {
+ "name": "id",
+ "type": "STRING"
+ },
+ {
+ "name": "latitude",
+ "type": "DOUBLE"
+ },
+ {
+ "name": "longitude",
+ "type": "DOUBLE"
+ },
+ {
+ "name": "timeStamp",
+ "type": "STRING"
+ },
+ {
+ "name": "speed",
+ "type": "FLOAT"
+ },
+ {
+ "name": "heading",
+ "type": "FLOAT"
+ },
+ {
+ "name": "eventId",
+ "type": "STRING"
+ },
+ {
+ "name": "state",
+ "type": "STRING"
+ },
+ {
+ "name": "information",
+ "type": "STRING"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/conf/setup_dashboard/cep-config/streamdefinitions/rawInputStream:1.0.0.json b/conf/setup_dashboard/cep-config/streamdefinitions/rawInputStream:1.0.0.json
new file mode 100644
index 0000000..032ad56
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/streamdefinitions/rawInputStream:1.0.0.json
@@ -0,0 +1,33 @@
+{
+ "streamId": "rawInputStream:1.0.0",
+ "name": "rawInputStream",
+ "version": "1.0.0",
+ "nickName": "",
+ "description": "Any raw data send from external users to CEP, this stream will be used by inputStandardizer to transform raw events to standard spatial event(with spatial standards ).",
+ "payloadData": [
+ {
+ "name": "id",
+ "type": "STRING"
+ },
+ {
+ "name": "timeStamp",
+ "type": "STRING"
+ },
+ {
+ "name": "latitude",
+ "type": "DOUBLE"
+ },
+ {
+ "name": "longitude",
+ "type": "DOUBLE"
+ },
+ {
+ "name": "speed",
+ "type": "FLOAT"
+ },
+ {
+ "name": "heading",
+ "type": "FLOAT"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/conf/setup_dashboard/cep-config/streamdefinitions/standardSpatialEvents:1.0.0.json b/conf/setup_dashboard/cep-config/streamdefinitions/standardSpatialEvents:1.0.0.json
new file mode 100644
index 0000000..a719e0c
--- /dev/null
+++ b/conf/setup_dashboard/cep-config/streamdefinitions/standardSpatialEvents:1.0.0.json
@@ -0,0 +1,37 @@
+{
+ "streamId": "standardSpatialEvents:1.0.0",
+ "name": "standardSpatialEvents",
+ "version": "1.0.0",
+ "nickName": "",
+ "description": "Standardized event by spatial InputStandardizer execution plan",
+ "payloadData": [
+ {
+ "name": "id",
+ "type": "STRING"
+ },
+ {
+ "name": "latitude",
+ "type": "DOUBLE"
+ },
+ {
+ "name": "longitude",
+ "type": "DOUBLE"
+ },
+ {
+ "name": "timeStamp",
+ "type": "STRING"
+ },
+ {
+ "name": "speed",
+ "type": "FLOAT"
+ },
+ {
+ "name": "heading",
+ "type": "FLOAT"
+ },
+ {
+ "name": "eventId",
+ "type": "STRING"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/conf/setup_dashboard/mysql-config/geo_dashboard_db_struct.sql b/conf/setup_dashboard/mysql-config/geo_dashboard_db_struct.sql
new file mode 100755
index 0000000..14241ab
--- /dev/null
+++ b/conf/setup_dashboard/mysql-config/geo_dashboard_db_struct.sql
@@ -0,0 +1,36 @@
+-- DROP DATABASE IF EXISTS wso2_geo;
+-- CREATE DATABASE wso2_geo DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
+-- USE wso2_geo;
+
+-- Create syntax for TABLE 'alerts_history'
+CREATE TABLE `alerts_history` (
+ `id` varchar (255) not null ,
+ `state` varchar (100),
+ `timeStamp` varchar (255),
+ `information` text,
+ `longitude` float,
+ `latitude` float,
+ primary key (`id`,`timeStamp`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
+
+-- Create syntax for TABLE 'webMapService'
+CREATE TABLE `webMapService` (
+ `id` INT NOT NULL AUTO_INCREMENT ,
+ `serviceUrl` MEDIUMTEXT NOT NULL,
+ `name` VARCHAR (255),
+ `layers` VARCHAR (255),
+ `version` VARCHAR (255),
+ `format` VARCHAR (255),
+ KEY `id` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
+
+-- Create syntax for TABLE 'tileServers'
+CREATE TABLE `tileServers` (
+ `id` INT NOT NULL AUTO_INCREMENT ,
+ `url` MEDIUMTEXT NOT NULL,
+ `name` VARCHAR (255),
+ `subdomains` VARCHAR (255),
+ `attribution` MEDIUMTEXT ,
+ `maxzoom` INT ,
+ PRIMARY KEY (`id`)
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
diff --git a/conf/setup_dashboard/mysql-config/geo_db_setup.sh b/conf/setup_dashboard/mysql-config/geo_db_setup.sh
new file mode 100755
index 0000000..613c3b6
--- /dev/null
+++ b/conf/setup_dashboard/mysql-config/geo_db_setup.sh
@@ -0,0 +1,79 @@
+#!/usr/bin/env bash
+
+# Default values for database variables.
+dbhost="localhost"
+dbport=3306
+dbname="wso2_geo"
+dir=$( cd "$( dirname "$0" )" && pwd )
+
+logo() {
+ echo "================================================================================================"
+ echo " W S O 2 G E O D A T A S E T U P "
+ echo "================================================================================================"
+}
+
+usage() {
+ logo
+ echo " Parameters indicates the following information:"
+ echo " -u User name to access database server."
+ echo " -p User password to access database server."
+ echo " -h Data Base Server address (default: localhost)."
+ echo " -r Data Base Server Port (default: 3306)"
+ echo " -n Data Base Name for the geonames.org data (default: wso2_geo)"
+ echo "================================================================================================"
+ exit -1
+}
+
+if [ $# -lt 1 ]; then
+ usage
+ exit 1
+fi
+
+logo
+
+# Parses command line parameters.
+while getopts "u:p:h:r:n:" opt;
+do
+ case $opt in
+ u) dbusername=$OPTARG ;;
+ p) dbpassword=$OPTARG ;;
+ h) dbhost=$OPTARG ;;
+ r) dbport=$OPTARG ;;
+ n) dbname=$OPTARG ;;
+ esac
+done
+
+if [ -z $dbusername ]; then
+ echo "No user name provided for accessing the database. Please write some value in parameter -u..."
+ exit 1
+fi
+
+if [ -z $dbpassword ]; then
+ echo "No user password provided for accessing the database. Please write some value in parameter -p..."
+ exit 1
+fi
+
+echo "Database parameters being used..."
+echo "UserName: " $dbusername
+echo "Password: " $dbpassword
+echo "DB Host: " $dbhost
+echo "DB Port: " $dbport
+echo "DB Name: " $dbname
+
+
+echo "Creating database $dbname..."
+mysql -h $dbhost -P $dbport -u $dbusername -p$dbpassword -Bse "DROP DATABASE IF EXISTS $dbname;"
+mysql -h $dbhost -P $dbport -u $dbusername -p$dbpassword -Bse "CREATE DATABASE $dbname DEFAULT CHARACTER SET utf8;"
+
+echo "Creating tables for database $dbname..."
+mysql -h $dbhost -P $dbport -u $dbusername -p$dbpassword -Bse "USE $dbname;"
+mysql -h $dbhost -P $dbport -u $dbusername -p$dbpassword $dbname < $dir/geo_dashboard_db_struct.sql
+
+
+if [ $? == 0 ]; then
+ echo "[OK]"
+else
+ echo "[FAILED]"
+fi
+
+exit 0
diff --git a/conf/setup_dashboard/mysql-config/mysql-config.zip b/conf/setup_dashboard/mysql-config/mysql-config.zip
new file mode 100644
index 0000000..ef7dca7
Binary files /dev/null and b/conf/setup_dashboard/mysql-config/mysql-config.zip differ
diff --git a/controllers/modals/setup_dashboard.jag b/controllers/modals/setup_dashboard.jag
new file mode 100644
index 0000000..35b0fba
--- /dev/null
+++ b/controllers/modals/setup_dashboard.jag
@@ -0,0 +1,122 @@
+
Setup Geo-Dashboard
+
+
+
*CEP info
+
+
+
+
+
+
Mysql conf
+
+
+
+
+
+
+
CEP queries
+
+
+
+ Download CEP configuration files
+ (eventbuilders,eventformatters,executionplans,inputeventadaptors,outputeventadaptors) and
+ copy into {path_to_cep}/repository/deployment/server/ directory.
+
+
+
+
+
+ Download CEP stream definitions and
+ append to {path_to_cep}/repository/conf/data-bridge/stream-definitions.xml file.
+
+
+
+
+
+
+
CEP Ext's
+
+
+ Get (Clone) a copy of siddhi geo extensions from github and build the necessary extensions and put .jar(s)> into
+ {path_to_cep}/repository/components/lib/ directory.
+
+
+
+
+
+
+ Add the following fully-qualified class name(s) to
+ {path_to_cep}/repository/conf/siddhi/siddhi.extension file.
+
+ org.wso2.cep.geo.notify.NotifyAlert
+ org.wso2.cep.geo.functions.EventIdGenerator
+ org.wso2.cep.geo.libs.FuseEvents
+ org.wso2.cep.geo.libs.executionPlanSubscriber
+ org.wso2.cep.geo.proximity.GeoProximity
+ org.wso2.cep.geo.GeoIsWithin
+
+
+
+
+
+
+
+
Update jaggery
+ If you get the following error when trying to login, Most probably it is cause by using outdated jaggery server.
+
+ HTTP Status 500 - org.mozzila,javascript.EcmaError: TypeErrorL Cannot find tenantUser in object [object Object].(/geo_dashboard/controllers/authentication.jag#13)
+
+ Copy this directory to your local {path_to_cep}/modules/carbon/scripts/server/ directory in Jaggery server.
+
\ No newline at end of file
diff --git a/controllers/setup_dashboard.jag b/controllers/setup_dashboard.jag
new file mode 100644
index 0000000..9d888a4
--- /dev/null
+++ b/controllers/setup_dashboard.jag
@@ -0,0 +1,9 @@
+<%
+
+var log = new Log();
+log.info(request.getAllParameters("UTF-8"));
+response.contentType = 'application/json';
+response.characterEncoding = 'UTF-8';
+response.content = true;
+
+%>
\ No newline at end of file
diff --git a/index.jag b/index.jag
index 062fabb..b50dc0a 100755
--- a/index.jag
+++ b/index.jag
@@ -15,11 +15,27 @@
+
+
+
+
+
+
+
+
@@ -73,7 +89,7 @@
-
+
@@ -87,9 +103,144 @@
+
+
+
+
+
+
+
+
Setup Geo-Dashboard
+
+
+
*CEP info
+
+
+
+
+
+
Mysql conf
+
+
+
+
+
+
+
CEP queries
+
+
+
+ Download CEP configuration files
+ (eventbuilders,eventformatters,executionplans,inputeventadaptors,outputeventadaptors) and
+ copy into {path_to_cep}/repository/deployment/server/ directory.
+
+
+
+
+
+ Download CEP stream definitions and
+ append to {path_to_cep}/repository/conf/data-bridge/stream-definitions.xml file.
+
+
+
+
+
+
+
CEP Ext's
+
+
+ Get (Clone) a copy of siddhi geo extensions from github and build the necessary extensions and put .jar(s)> into
+ {path_to_cep}/repository/components/lib/ directory.
+
+
+
+
+
+
+ Add the following fully-qualified class name(s) to
+ {path_to_cep}/repository/conf/siddhi/siddhi.extension file.
+
+ org.wso2.cep.geo.notify.NotifyAlert
+ org.wso2.cep.geo.functions.EventIdGenerator
+ org.wso2.cep.geo.libs.FuseEvents
+ org.wso2.cep.geo.libs.executionPlanSubscriber
+ org.wso2.cep.geo.proximity.GeoProximity
+ org.wso2.cep.geo.GeoIsWithin
+
+
+
+
+
+
+
+
Update jaggery
+ If you get the following error when trying to login, Most probably it is cause by using outdated jaggery server.
+
+ HTTP Status 500 - org.mozzila,javascript.EcmaError: TypeErrorL Cannot find tenantUser in object [object Object].(/geo_dashboard/controllers/authentication.jag#13)
+
+ Copy this directory to your local {path_to_cep}/modules/carbon/scripts/server/ directory in Jaggery server.
+