The Widget Tutorial
WebMacro manual:tutorials.widget.Page
Source
<div class="container" data-widget="tutorials.SyncWidget">
<div class="row">
<div class="col-xs-12">
<h1>Ikona Panther Widgets</h1>
<a href="/manual/content/tutorials.doc.WidgetTutorial" target="_blank">Widget Tutorial</a>
<hr>
</div>
</div>
<div class="row">
<div class="col-sm-6" data-widget="tutorials.FormWidget">
<h4>Register new email</h4>
<hr>
<div>
<input type="text" value="" class="form-control" data-form="EmailInput" placeholder="Enter email address">
</div>
<hr>
<button class="btn btn-success" data-form="SubmitEmailButton">Store Email</button>
</div>
<div class="col-sm-6" data-widget="tutorials.ListWidget" data-list-element-class="email-element">
<h4>Registered emails</h4>
<hr>
<p>
<span data-list="EmailsCountLabel"></span> registered emails</p>
<button class="btn btn-danger" data-list="EmptyEmailsButton">Empty emails</button>
<hr>
<ul class="nav nav-stacked nav-pills well" data-list="EmailsList"></ul>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<hr>
<div class="hidden alert alert-success" data-sync="StatusOk">
Update from server successful
</div>
<div class="hidden alert alert-danger" data-sync="StatusErrorEmailAlreadyExists">
The email was already in the list
</div>
<hr>
</div>
</div>
</div>
<script>
//this code should usually be included in the main css
//it is just here to show how to get panther widgets started
//after page load
$(function () {
//global debug options
var debug = true;
//global is window in clients
var global = window;
//set scope to panther
var scope = panther = global.panther = {};
/* include panther.ClientLib */
#{ panther.ClientLib }
//set scope to tutorials
scope = global.tutorials = {};
//create new widgets singleton for test page
var widgets = scope.widgets = new panther.widgets.Widgets();
/* include tutorials.widget.SyncWidget */
#{ tutorials.widget.SyncWidget }
/* include tutorials.widget.FormWidget */
#{ tutorials.widget.FormWidget }
/* include tutorials.widget.ListWidget */
#{ tutorials.widget.ListWidget }
//add global error handler
scope.widgets.on("Error", function handleErrors(type, error) {
if (console.error) {
console.error(error);
}
else {
console.log(error);
if (error.stack) {
console.log(error.stack);
}
}
});
//intialized the existing widgets on this page
widgets.init();
//print all widgets
console.log("There are " + widgets.size() + " widgets in this page", widgets.list());
});
</script>
WebMacro manual:tutorials.widget.FormWidget
Source
scope.FormWidget = (function (panther) {
panther.widgets.AbstractWidget.extend(FormWidget);
//load universal for validation
var scope = FormWidget;
#{ tutorials.widget.ValidateEmail }
function FormWidget() {
FormWidget.prototype.super.constructor.call(this);
}
FormWidget.prototype.init = function (element) {
FormWidget.prototype.super.init.call(this, element);
this.updateElements();
this.emailInput.focus();
};
FormWidget.prototype.initEmailInput = function (emailInput) {
this.emailInput = $(emailInput);
var self = this;
this.emailInput.on("keyup", function () {
self.updateElements();
});
this.emailInput.on("change", function () {
self.submitEmail();
});
};
FormWidget.prototype.initSubmitEmailButton = function (submitEmailButton) {
this.submitEmailButton = $(submitEmailButton);
var self = this;
this.submitEmailButton.on('click', function () {
self.submitEmail();
});
};
FormWidget.prototype.triggerAddEmail = function (email) { };
FormWidget.prototype.submitEmail = function () {
if (this.updateElements()) {
this.triggerAddEmail(this.emailInput.val());
this.emailInput.val("");
this.updateElements();
}
};
FormWidget.prototype.updateElements = function () {
//valid mail
if (FormWidget.validateEmail(this.emailInput.val())) {
this.emailInput.parent().removeClass("has-error");
this.submitEmailButton.removeClass("disabled");
return true;
}
//invalid mail
else {
this.emailInput.parent().addClass("has-error");
this.submitEmailButton.addClass("disabled");
return false;
}
};
return FormWidget;
})(panther);
WebMacro manual:tutorials.widget.ListWidget
Source
scope.ListWidget = (function (panther) {
panther.widgets.AbstractWidget.extend(ListWidget);
function ListWidget() {
ListWidget.prototype.super.constructor.call(this);
}
ListWidget.prototype.init = function (element) {
ListWidget.prototype.super.init.call(this, element);
this.emailListElementClass = this.element.data("listElementClass") || "";
this.updateElements([]);
};
ListWidget.prototype.initEmailsCountLabel = function (emailsCountLabel) {
this.emailsCountLabel = $(emailsCountLabel);
};
ListWidget.prototype.initEmptyEmailsButton = function (emptyEmailsButton) {
this.emptyEmailsButton = $(emptyEmailsButton);
var self = this;
//delete all item from list
this.emptyEmailsButton.on("click", function () {
self.triggerRemoveAllEmails();
});
};
ListWidget.prototype.initEmailsList = function (emailsList) {
this.emailsList = $(emailsList);
var self = this;
//delete one item from list
this.emailsList.on("click", "a[data-list='EmailListElement']", function (evt) {
evt.preventDefault();
self.triggerRemoveEmail($(this).text());
});
};
ListWidget.prototype.triggerRemoveAllEmails = function () { };
ListWidget.prototype.triggerRemoveEmail = function (email) { };
ListWidget.prototype.onUpdateEmails = function (emails) {
this.updateElements(emails);
};
ListWidget.prototype.updateElements = function (emails) {
//set label to email conunt
this.emailsCountLabel.text(emails.length);
//update list
this.emailsList.empty();
for (var i = 0; i < emails.length; i++) {
this.emailsList.append(
$("<li>")
.addClass(this.emailListElementClass)
.append(
$("<a>")
.attr("href", "#")
.attr("data-list", "EmailListElement")
.text(emails[i])
)
);
}
};
return ListWidget;
})(panther);
WebMacro manual:tutorials.widget.SyncWidget
Source
scope.SyncWidget = (function (panther) {
panther.widgets.AbstractWidget.extend(SyncWidget);
function SyncWidget() {
SyncWidget.prototype.super.constructor.call(this);
this.apiUrl = "#{content.home('tutorials.widget.Api')}";
}
SyncWidget.prototype.initStatusOk = function (statusOk) {
this.statusOk = $(statusOk);
};
SyncWidget.prototype.initStatusErrorEmailAlreadyExists = function (statusErrorEmailAlreadyExists) {
this.statusErrorEmailAlreadyExists = $(statusErrorEmailAlreadyExists);
};
SyncWidget.prototype.triggerUpdateEmails = function (emails) { };
SyncWidget.prototype.onAddEmail = function (email) {
updateEmailsWithServer.call(this, { ac: "add", email: email });
};
SyncWidget.prototype.onRemoveEmail = function (email) {
updateEmailsWithServer.call(this, { ac: "remove", email: email });
};
SyncWidget.prototype.onRemoveAllEmails = function () {
updateEmailsWithServer.call(this, { ac: "removeAll" });
};
SyncWidget.prototype.onWidgetsInitSuccess = function () {
updateEmailsWithServer.call(this, { ac: "list" });
};
SyncWidget.prototype.updateStatus = function (data) {
if (data.status === "OK") {
this.statusOk.removeClass("hidden");
this.statusErrorEmailAlreadyExists.addClass("hidden");
}
else if (data.status === "EMAIL_ALREADY_EXISTS") {
this.statusOk.addClass("hidden");
this.statusErrorEmailAlreadyExists.removeClass("hidden");
}
};
function updateEmailsWithServer(data) {
var self = this;
$.ajax(this.apiUrl, {
type: "post",
cache: false,
dataType: "json",
data: data,
success: function (data) {
self.updateStatus(data);
self.triggerUpdateEmails(data.emails);
},
error: function (data) {
self.updateStatus(data.responseJSON);
throw new Error("Invalid update from server " + JSON.stringify(data));
}
});
}
return SyncWidget;
})(panther);
WebMacro manual:tutorials.widget.Api
Source
require("request");
require("response");
require("session");
this.EmailApi = (function () {
var SESSION_KEY = "tutorials.widget.emails";
//load universal for validation
this.scope = EmailApi;
load("tutorials.widget.ValidateEmail");
function EmailApi() {}
EmailApi.prototype.handle = function (action) {
if (!action) {
throw new Error("ERROR_UNDEFINED_ACTION");
}
if (action.length > 50) {
throw new Error("ERROR_INVALID_ACTION");
}
var actionName = "do" + action[0].toUpperCase() + action.slice(1);
if (typeof (this[actionName]) === "function") {
return this[actionName]();
}
else {
throw new Error("ERROR_UNKNOWN_ACTION");
}
};
EmailApi.prototype.doList = function () {
var result = {};
result.status = "OK";
result.emails = getEmails();
return result;
};
EmailApi.prototype.doAdd = function () {
var result = {};
result.status = "OK";
var emails = getEmails();
var email = request.parameter("email");
//just allow to add valid emails
if (!EmailApi.validateEmail(email)) {
throw new Error("EMAIL_INVALID");
}
//dont alow to add the same email multiple times
var index = emails.indexOf(email);
if (index > -1) {
throw new Error("EMAIL_ALREADY_EXISTS");
}
emails.push(email);
setEmails(emails);
result.emails = emails;
return result;
};
EmailApi.prototype.doRemove = function () {
var result = {};
result.status = "OK";
var emails = getEmails();
var email = request.parameter("email");
var index = emails.indexOf(email);
if (index > -1) {
emails.splice(index, 1);
}
else {
throw new Error("EMAIL_DOES_NOT_EXIST");
}
setEmails(emails);
result.emails = emails;
return result;
};
EmailApi.prototype.doRemoveAll = function () {
var result = {};
result.status = "OK";
setEmails([]);
result.emails = [];
return result;
};
function getEmails() {
return JSON.parse(session.get(SESSION_KEY) || "[]");
}
function setEmails(emails) {
if (Array.isArray(emails)) {
session.set(SESSION_KEY, JSON.stringify(emails));
}
}
return EmailApi;
})();
function main() {
try {
var action = request.parameter("ac");
var emailApi = new EmailApi();
return JSON.stringify(emailApi.handle(action));
}
catch (ex) {
response.sendError(400, JSON.stringify({
status: ex.message
}));
}
}
WebMacro manual:tutorials.widget.ValidateEmail
Source
(function ValidateEmail(scope) {
scope.validateEmail = function (email) {
return /^[a-z0-9\-_]?[a-z0-9.\-_]+[a-z0-9\-_]?@[a-z.-]+\.[a-z]{2,3}$/i.test(email);
};
})(scope);
, multiple selections available,