« - »

Notification Service: NoticeTemplate edit

11 November 2008

In my first example of the notice template maintenance process, I introduced the template list page. In my second example, we add the first draft of the notice template edit page. I say “first draft” because, while this version is sufficient to start developing templates so that we can move on to other parts of the Notification Service, there are still a number of things that I would like add to the template edit page before I really consider it complete.

But, let’s not get too far ahead just yet. Before we start making changes, let’s look at the current version of the notice_template_edit_example.js file:

// notice_template_edit_example.js

var dataURIStart = '/notify/template/';
var queryParameter = {};
var userId = '';
var userURI = '';
var userName = '';
var newTemplate = true;
var inputErrors = '';
var context = '';
var name = '';

/**
 * Initialize the page
 */
function initPage() {
  loadQueryParameters();
  ajaxGet('/id/whoami', 'initPageCont','ajaxError');
}

/**
 * Loads in any parameters found in the current URL's query string
 */
function loadQueryParameters() {
  var thisURL = document.location.href;
  if (thisURL.indexOf('?') != -1) {
    var queryString = thisURL.substring(thisURL.indexOf('?') + 1);
    var parts = queryString.split('&');
    for (var i=0; i<parts.length; i++) {
      var moreParts = parts[i].split('=');
      if (moreParts != null && moreParts.length > 1) {
        queryParameter[moreParts[0]] = moreParts[1];
      }
    }
  }
}

/**
 * Initialize the page (continued)
 */
function initPageCont(xmlDoc) {
  var root = xmlDoc.documentElement;
  userId = root.getElementsByTagName('remoteUser')[0].attributes[0].value;
  userURI = root.getElementsByTagName('remoteUser')[0].attributes[1].value;
  userName = root.getElementsByTagName('remoteUser')[0].firstChild.data;
  var userLink = '<a class="action" href="javascript:popUpUserData(userURI);" title="' +
       userName + '">' + userName + '</a>';
  document.getElementById('userLink').innerHTML = userLink;
  if (queryParameter.context != null && queryParameter.name != null) {
    ajaxGet(dataURIStart + queryParameter.context + '/' + queryParameter.context,
         'populateInputFields','ajaxError');
  }
}

/**
 * Populates the input fields with data from the database
 */
function populateInputFields(xmlDoc) {
  var root = xmlDoc.documentElement;
  document.getElementById('context').value = root.attributes[1].value;
  document.getElementById('context').setAttribute('readonly', 'true');
  document.getElementById('name').value = root.attributes[2].value;
  document.getElementById('name').setAttribute('readonly', 'true');
  document.getElementById('description').value =
       root.getElementsByTagName('description')[0].firstChild.data;
  document.getElementById('description').focus();
  document.getElementById('contentType').value =
       root.getElementsByTagName('contentType')[0].firstChild.data;
  document.getElementById('defaultDeliveryMethod').value =
       root.getElementsByTagName('defaultDeliveryMethod')[0].firstChild.data;
  document.getElementById('titleSubject').value =
       root.getElementsByTagName('titleSubject')[0].firstChild.data;
  document.getElementById('body').innerHTML = root.getElementsByTagName('body')[0].firstChild.data;
  newTemplate = false;
}

/**
 * Opens up a new window to display the details of the current user
 */
function popUpUserData(uri) {
  var userWindow = window.open(uri, 'userWindow', 'toolbar=no,directories=no,status=no,
       scrollbars=yes,resizable=yes,resize=yes,menubar=no,height=400,width=500');
  if (window.focus) {
    userWindow.focus();
  }
}

/**
 * Saves the edited data
 */
function saveForm() {
  inputErrors = '';
  if (newTemplate) {
    validateTemplateContextAndName();
  } else {
    validateData();
  }
}

/**
 * Validates the table id on new entries
 */
function validateTemplateContextAndName() {
  context = document.getElementById('context').value;
  name = document.getElementById('name').value;
  if (validKeyFormat(context)) {
    if (validKeyFormat(name)) {
      // context and name are valid format; now make sure template is not already on file
      ajaxGet(dataURIStart + context + '/' + name, 'newTemplateAlreadyOnFile',
           'checkNewTemplateResponse');
    } else {
      addInputError('The format of the name is invalid.');
      sendInputErrors();
    }
  } else {
    addInputError('The format of the context is invalid.');
    sendInputErrors();
  }
}

/**
 * Reports a duplicate id error
 */
function newTemplateAlreadyOnFile(xmlDoc) {
  addInputError('The name specified ("' + name + '") is already on file in the context "' +
       context + '".');
  sendInputErrors();
}

/**
 * Checks the response code from the duplicate Template check
 */
function checkNewTemplateResponse(httpRequest) {
  if (httpRequest.status == 404) {
    // table id is not already on file ... validate the rest of the data
    validateData();
  } else {
    // must be some other error ... let the standard error handler take it
    ajaxError(httpRequest);
  }
}

/**
 * Validates the user input
 */
function validateData() {
  if (!(document.getElementById('context').value > '')) {
    addInputError('Context is required');
  }
  if (!(document.getElementById('name').value > '')) {
    addInputError('Name is required');
  }
  if (!(document.getElementById('description').value > '')) {
    addInputError('Description is required');
  }
  if (!(document.getElementById('contentType').value > '')) {
    addInputError('Content Type is required');
  }
  if (!(document.getElementById('defaultDeliveryMethod').value > '')) {
    addInputError('Default Delivery Method is required');
  }
  if (!(document.getElementById('titleSubject').value > '')) {
    addInputError('Title/Subject is required');
  }
  if (!(document.getElementById('body').innerHTML > '')) {
    addInputError('Message body is required');
  }
  if (inputErrors.length > 0) {
    sendInputErrors();
  } else {
    saveUserInput();
  }
}

/**
 * Validates the format for all key fields
 */
function validKeyFormat(id) {
  var testPattern=new RegExp('^[a-z]{1}[a-zA-Z0-9]{1,32}$');
  return testPattern.test(id);
}

/**
 * Adds one input error to the list of errors
 */
function addInputError(errorMessage) {
  if (inputErrors.length > 0) {
    inputErrors += '\n';
  }
  inputErrors += errorMessage;
}

/**
 * Send input errors
 */
function sendInputErrors() {
  var errorMessage = 'The following error(s) have been detected:\n\n';
  errorMessage += inputErrors;
  errorMessage += '\n\nPlease correct the error(s) and resubmit.';
  alert(errorMessage);
}

/**
 * Saves the user input
 */
function saveUserInput() {
  // field validation has passed; update database
  if (newTemplate) {
    createNewTemplate();
  } else {
    updateExistingTemplate();
  }
}

/**
 * Creates a new template
 */
function createNewTemplate() {
  context = document.getElementById('context').value;
  name = document.getElementById('name').value;
  var xml = '<?xml version="1.0" encoding="UTF-8"?>\n';
  xml += '<notify:template id="-1" context="';
  xml += context;
  xml += '" name="';
  xml += name;
  xml += '" xmlns:notify="http://www.restafarian.org/notify"
       xmlns:xlink="http://www.w3.org/1999/xlink">\n';
  xml += '  <description>';
  xml += document.getElementById('description').value;
  xml += '</description>\n';
  xml += '  <contentType>';
  xml += document.getElementById('contentType').value;
  xml += '</contentType>\n';
  xml += '  <defaultDeliveryMethod>';
  xml += document.getElementById('defaultDeliveryMethod').value;
  xml += '</defaultDeliveryMethod>\n';
  xml += '  <titleSubject>';
  xml += document.getElementById('titleSubject').value;
  xml += '</titleSubject>\n';
  xml += '  <body>';
  xml += document.getElementById('body').value;
  xml += '</body>\n';
  xml += '</name>\n';
  xml += '</notify:template>';
  ajaxPut(dataURIStart + context + '/' + name, xml, 'insertTemplateSuccessful','ajaxError');
}

/**
 * Notifies the user of a successful save operation
 */
function insertTemplateSuccessful() {
  alert('The notice template has been successfully added.');
  history.back();
}

/**
 * Updates an existing table
 */
function updateExistingTemplate() {
  context = document.getElementById('context').value;
  name = document.getElementById('name').value;
  var parameters = 'description=' + document.getElementById('description').value;
  parameters += '&contentType=' + document.getElementById('contentType').value;
  parameters += '&defaultDeliveryMethod=' + document.getElementById('defaultDeliveryMethod').value;
  parameters += '&titleSubject=' + document.getElementById('titleSubject').value;
  parameters += '&body=' + document.getElementById('body').innerHTML;
  ajaxPost(dataURIStart + context + '/' + name, parameters, 'updateTemplateSuccessful','ajaxError');
}

/**
 * Notifies the user of a successful save operation
 */
function updateTemplateSuccessful() {
  alert('The notice template has been successfully updated.');
  history.back();
}

As I say, this is good enough to start getting templates into the database, which I need to do in order to test the actual service itself, but at some point, I would like to come back and finish up a few things. For one, both the contentType and the defaultDeliveryMethod fields should be fed from a pick-list of specific options. This is the very kind of thing that I developed the Look-up Table service for, so I would like to define a couple of tables and then either feed the drop-downs from the table data or go all the way and just set up both fields as Smart Pick Lists. I don’t think the potential number of possible values for either of these fields will ever warrant going the Smart Pick-list route, but it would be a fun exercise, just the same.

The other thing that I would like to consider doing is replacing the HTML textarea with a Rich Text Editor like RTE, TinyMCE, or Xinha. I know — there are many others out there as well — but those are among the few that I have actually worked with before. This would have to be selective and based on the value of the contentType field. Another value in having the contentType backed by a look-up table is that I can define an additional field on the table for an indicator specifying whether or not the rich text editor is appropriate for each content type. That way, when a contentType is selected on the edit page, I can then decide whether to show the RTE or the plain textarea for the body.

Again, none of that is really necessary at this point, so I’ll be moving on to other things, but one day, just like with the DAO enhancements, I hope to circle back around and give things an upgrade.

But not today …


http://blog.restafarian.org/2008/11/notification-service-noticetemplate-edit/

Leave a reply

You must be logged in to post a comment.