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);