Task List Project – Sprint One

Sprint 1: Simple HTML

This stage begins with the simple HTML page with minimal CSS and JavaScript. The HTML provides placeholders for all on-screen components and includes some example data (tasks).

<!DOCTYPE html>
 <html lang="en">
  <head>
    <meta charset="utf-8">

    <title>To Do Project</title>
    <meta name="description" content="">
    <meta name="author" content="">
  </head>

  <body>
    <header>
      <h1>To Do List Project</h1>
    </header>

    <main>
      <section>
        <ol>
          <li id="li_1">Prepare basic HTML</li>
          <li id="li_2">Add visibility CSS</li>
          <li id="li_3">Add event handlers</li>
        </ol>
      </section>

      <section>
        <article>
          <button>Delete</button>
          <button>Edit</button>
          <button>Add</button>
        </article>

        <article>
          <textarea placeholder="Add text here"></textarea>
          <button>Save</button>
          <button>Cancel</button>
        </article>
      </section>
    </main>

    <footer>
      <p>&copy; Copyright by ___</p>
    </footer>
  </body>
</html>

The basic HTML was constructed as little more than a wireframe, as might be expected from a UI designer. This showed three panels; the task list, basic operation/view buttons (Delete, Edit and Add), and the Task details panel (TextArea for data entry along with Save and Cancel buttons). When rendered it is far from pretty but all the components are visible.

Screen 1

The CSS is used only to control visibility of on-screen components to support usability of the application, it is not concerned (at this stage) with the styling or theme of the application; that is addressed much later.

.function_Container article {
  display: none;
}

.show_list_Functions .list_Functions,
.show_listItems_Functions .listItems_Functions {
  display: block;
}

CSS classes were prepared to orchestrate the visibility of the Button panel and Task details panel so only one was visible as any one time, dependent of the class of the panel container. The first rule hides all the Articles that contain the button and Task detail panels. The combined second and third rules make one panel visible depending on a class of the containing Section.

.highlighted { 
  color: red; 
}

.lowLight { 
  cursor: pointer; 
}

The fourth rules highlights the selected task and the final rule resets the de-selected task and shows a pointer cursor to illustrate that it is clickable. More on the last two rules later but, the first three rules require the HTML to be enhanced as follows.

 <section class="function_Container show_list_Functions">
   <article class="list_Functions">
     <button>Delete</button>
     <button>Edit</button>
     <button>Add</button>
   </article>

   <article class="listItems_Functions">
     <textarea placeholder="Add text here"></textarea></br>
     <button>Save</button>
     <button>Cancel</button>
   </article>
 </section>

As above, the rendering changes to show only the Article with the class of “list_Functions”; the button panel.

Screen 2a

With the class of the Section changed to class=”function_Container show_listItems_Functions”, the button panel is hidden and the Task Details panel is shown. Also notice, the inclusion of a <br/> break tag that neaten’s up the screen a little.

Screen 2b

The switch, itself, is performed through a piece of JavaScript (showFunctions function) with a parameter of the Article to show.

function showFunctions(pstrArticle) {
  var objSection = document.querySelector('.function_Container');
 
  if (!!objSection) {
    objSection.className = 
      objSection.className.replace(/show_[^\s]*/, 
        "show_" + pstrArticle + "_Functions");
  }
}

The JavaScript function locates the Section containing the Articles and which we set the class attribute to effect the panel switching. If found, the value of the className attribute is changed to replace the current selection with the given selection, using a Regular Expression. This function will be called under the following circumstances:

  • When a task in the list is selected and the Edit button clicked, in which case the Task Details panel is shown.
  • When either Save or Cancel buttons, of the Task Details panel, are clicked the Button panel is re-shown.
  • When the Add button is clicked the Task Details panel is shown.

JavaScript functions are also used to manipulate and present the Task list, which are usually triggered by the user clicking one of the buttons (Save, Delete or Edit). All the button on-click events are statically linked, as follows, and we provide Id’s for the target controls (OL list and Task details TextArea):

<section>
  <ol class="mainList" id="list_1">
    <li id="{{ID}}" class="lowLight">{{TITLE}}</li>
  </ol>
</section>
 
<section class="function_Container show_list_Functions">
  <article class="list_Functions">
    <button onclick="deleteListItem()">Delete</button>
    <button onclick="editListItem()">Edit</button>
    <button onclick="addListItem()">Add</button>
  </article>
 
  <article class="listItems_Functions">
    <textarea id="listItemTextArea" placeholder="Add text here"></textarea>
    <button onclick="saveListItem()">Save</button>
    <button onclick="cancelListItemChange()">Cancel</button>
  </article>
</section>

An onClick event is attached to “list_1” once it is populated during application start-up using the following code:

var gnumMaxListItems;

document.onreadystatechange = function () {
  if (document.readyState == 'complete') {
    var objList_1 = document.getElementById('list_1');

    gnumMaxListItems = objList_1.children.length; 
    objList_1.addEventListener('click', function(e) { 
      if (e.target && e.target.nodeName == 'LI') {
        selectedItem(e.target.id);
      }
    });
  }
};

“gnumMaxListItems” is a global variable (not ideal) used as a temporary base for the index of the next Task to be added. It is initialised when the list is first populated and incremented with each new Task. It is not decremented when Tasks are deleted, the index is just lost. The index is only used when presenting the Tasks in the list and are not stored.

The “document.onreadystatechange” function is fired as the web page is loaded and rendered. When “complete”, the Task list (target) component is located and gnumMaxListItems is set, based on the population of the Task list. The onClick event handler is then attached to the Task list to pick-up and process whenever the user selects a Task (LI), upon which the selectedItem function is called with a reference to the selected Task.

Functions (JavaScript)

In addition to the selectedItem function there are five functions to handle button clicks (follow the link for details of each function):

  • editListItem: Edit button – Enables the Task details panel and populates the text area with the value of the selected item in the list.
  • deleteListItem: Delete button – confirms the user action before removing the selected item from the list.
  • addListItem: Add button – Clears the text area and shows the Task details panel ready for a new Task to be created.
  • cancelListItemChange: Cancel button – Abandons the current change/create operation, de-selects any selected item and hides the Task details panel.
  • saveListItem: Save button – Stores the updated or created Task in the list, hides the panel and refreshes the Task list.

Refactoring

In the new Agile method of software development, a process of “refactoring” is often undertaken towards the end of each sprint. This ensures the next sprint commences with the best possible code and attempts to full integrate new changes in to the codebase.

In our example, four of the functions discussed above clear the selected Task from the list using the same fragment of code.

var objHighlightedItem = document.querySelector('.highlighted');

if (!!objHighlightedItem) {
  objHighlightedItem.className = 
    objHighlightedItem.className.replace(/highlighted/, "lowLight");
}

We can improve the code by creating a clearSelectedTask function, as follows, and calling it from each of the four functions.

function clearSelectedTask() {
  var objHighlightedItem = document.querySelector('.highlighted');

  if (!!objHighlightedItem) {
    objHighlightedItem.className = 
      objHighlightedItem.className.replace(/highlighted/, "lowLight");
  }
}

This improves matter sightly by establishing a single piece of code for this purpose rather than having it duplicated through-out the code base. Should we want to change this mechanism in future we only have one place to go, and all four functions we receive the benefit.

However, this change introduces another instance of code used to local the selected Task in the list.

var objHighlightedItem = document.querySelector('.highlighted');

The above fragment of code should be replaced with a function for the same reasons as before (code reuse and improved maintenance); never mind the fact we are creating a 3-line function for a single line of code, which is called 4 or 5 times. If the mechanism changes, its one place to address.

function getSelectedTask() {
  return document.querySelector('.highlighted');
}

This means all the places that used the original method should now make the following, much simpler, call.

var objHighlightedItem = getSelectedTask();

Return to main section of this article.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s