Skip to content

csrail/top_todo

Repository files navigation

A node js environment using the webpack bundler.

Exploration

Try out this app! A simple todo application starting from a root projectSet which has many projects and each project many tasks. This application demonstrates the combination of multiple programming principles.

Exposition

This application architecture observes separating logic and GUI apart. Ideally data should also be abstracted into a separate layer but the localStorage for this project has not been implemented.

The entry point into the application is index.js. It contains code that glue the modules, object instantiation and method calls together.

A model represents each type of object we are creating, the projectSetModel, projectModel, taskModel. A projectSetModel object is composed with a list of projectModel objects, the projectModel object is composed with a list of taskModel objects.

Each model is rendered as its own 'deployable' for viewing, composed with the webModel module and the webView module.

The deployables feature dependency injection, association through aggregation (passing each related object as an argument) over association through composition. The dependency injection naturally leads to an "object destructuring" where values from known object keys are assigned to a variable. When the object key is not found in the obj passed, then the value assigned to the variable is undefined. This use case enables a form to function differently depending on whether the _project is undefined or not. This pattern is probably useful when an object only has two states, "undefined", and already "defined", that is, "to be created", and "to be edited" respectively. Otherwise it's probably better to use an inheritance type pattern, where a new class is subclassed from a parent class to avoid multiple if statements.

// "Object destructuring"
const projectFormDeployable = function (obj) {
    const _projectSet = obj.projectSetObject;
    const _project = obj.projectObject;

    const constructor = () => {
        if (_project == undefined)
            webObject.setElementText(heading)(CREATE_TITLE);
        if (_project !== undefined)
            webObject.setElementText(heading)(EDIT_TITLE);
    };
    //
    // ...code
    //
};

Excavation

The webModel module works as a module mixin to help manage HTML and CSS operations with javascript. It is instanced by importing the webModel module and initialising a webObject. Anything related to HTML and CSS operations are then invoked through webObject such as webObject.createElement, webObject.setElementText, webObject.setElementAttribute.

The functons defined in the webModel module use closures which take in one argument at a time and return a function. The first argument is always the HTML element to be created or modified, while the remaining arguments are for the property of interest.

// Regarding the webObject.createElement function:
// the function expects a string to match an existing html element name.
// - the first partial application returns a function expecting a string
// which implies the id of the html element
// - the second partial application of the function returns a function
// expecting a list of strings which implies the classes of the html element
// - the third partial application of the function returns a html element
// of the given type in the first partial application, assigned with the id
// of the second partial application, assigned with the classes of the
// third partial application.
const = todoNameInput = webObject.createElement("input")(NAME_ID)([
    "size_16",
    "height_input_text",
    "color_tone_400",
    "padding_4",
])

The webView module features polymorphism, it has a contract with objects that are "deployable". So long as the deployable passed into webView has a constructor function, the webView module will render it.

const webView = (function (deployables = []) {
    const _deployables = deployables;

    const applyViewTo = (target) => {
        for (const d of _deployables) {
            target.appendChild(d.constructor());
        }
        return target;
    };

    //
    // ...code
    //
})();

The CSS is arranged into discrete units so that each class has a single responsibility, and a collection of classes that are related to each other operate as a single equivalence class (reflexive, symmetric, transitive) and are all listed in a single file. Therefore ideas surrounding the box layout (height, width, border, padding, margins) are in a distinct file to flexbox (display, flex-direction, justify-content) which is distinct to font layout (font-size, font-weight, font-color). This modular CSS supports the closure pattern seen above and the assignment of classes in the third partial application of the function webObject.createElement.

base.css
box_layout.css
flexbox.css
font_layout.css
interactions.css
minimum.css

Exhaustives

Implemented the models with primary keys and a pseduo database in todoSchemaModel.js. For this small application, equality checking on the object's memory location would be a better way of finding which project or task to delete.

Setting up localStorage seemed strange since these objects are normally stored in a database and not in the browser. Key lessons from JSON formatting is that JSON.stringify() strips away all functions, so key-value pairs need to contain literals. So there would need to be a function within each model responsible for creating a suitable object to stringify, i.e. a stringify constructor of sorts. Then the inverse function will also need to happen for JSON.parse(), a parse constructor needs to be created to populate models correctly.

Bug: editing a task and confirming the edit should return the user to the selected task, but instead it returns the user back to the parent project.

Eggs

The user interface and user experience was crafted on a digital artboard. All icons were digitally drawn.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published