Skip to content

Window Framework

Valentin Rigolle edited this page May 8, 2019 · 4 revisions

Custom Window Framework

In order to simplify the creation and management of windows, we provide the generic class Window. It reprensents the basic component with a simple HTML structure in which you can put your own nodes, along with default CSS.

Demo

Window example

You can try a Demo of the Window framework in examples/DemoWindow/Demo.html. A custom window has already been implemented in the CustomWindow.js file to see how it works. The Demo allows the user to test the 4 common interactions with a window : creation / deletion and hiding / showing.

Implementing a window

In this section, we will explain how to use the Window module to create a custom window.

Imports

In order to use the Window class, you must import it from the src/Shared/js/Window module. You must allow import the stylesheet associated with it, located in src/Shared/css/window.css. The first lines of your module file should look like something similar to this :

// Relative path. The module is located in a directory similar to 'src/Extensions/CustomModule/' and the current
// module is called 'view/CustomWindow.js'
import { Window } from '../../../Shared/js/Window';view
import '../../../Shared/css/window.css';

If you do not use a system that allows you to import CSS, you can just insert it as a link node in the HTML file :

<link rel="stylesheet" href="../../../src/Shared/css/window.css">

Extend the Window class

The custom window should extend the Window class and call the superclass' constructor :

export class CustomWindow extends Window {
    constructor() {
        super('customModule', 'My Window');
    }
}

Here, we pass two arguments to the super constructor : the first should be a unique name among all the windows in the website. It will be used to generate unique IDs in the HTML elements of the window. The second argument is the title of the window, which will be shown in the header bar.

Inserting a custom content

As is, the window will not contain anything. You can put your custom content by overriding the innerContentHtml getter, which will be called during the window creation :

get innerContentHtml () {
    return `
        <p>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
        </p>
    `;
}

For this example, we just insert a mock paragraph. By running this example, you can see

Instanciating the module and inserting it into the document

In the main script of the web page, we can instantiate our custom window :

import { CustomWindow } from './CustomWindow';

//your code

let customWindow = new CustomWindow();

We must now insert it into our HTML. For example, if we have a <div id="main-content"> node in the DOM, we can do it that way :

const content = document.getElementById('main-content');
customWindow.appendTo(content);

The our custom Window now appears in our web page. You can drag it around and resize it. You'll see that the paragraph shrinks in width to stay inside the windows' borders, and a scrool bar appear if the height of the window is not sufficient to contain paragraph. If we check the HTML generated by this code, it looks similar to this :

<div class="window" id="_window_custom">
   <div class="window-header" id="_window_header_custom">
      <h1 class="window-title" id="_window_header_title_custom">My window</h1>
      <button class="window-close-button" id="_window_header_close_button_custom">CLOSE</button>
   </div>
   <div class="window-content" id="_window_content_custom">
      <div class="window-inner-content" id="_window_inner_content_custom">
         <p>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
         </p>
      </div>
   </div>
</div>

We can see that the basic structure was generated along with custom IDs and CSS classes. If you want to modify the style, you can use these as CSS accessors.

Specification

Methods and getters

The following are the most common methods and getters. The 'Type' column can be either 'method', 'getter' or constructor'. The column 'Override' specifies if the method or getter can be overriden by the extending classes (note that overriding these methods is never mandatory).

Name Type Parameters Override Returns Description
constructor constructor uniqueName, title, hideOnClose=true Instantiate the Window. uniqueName will be used to generate unique IDs in the HTML nodes. title will be put into the header bar. hideOnClose defines the behavior of the close button. If set to true, it will hide the window (call the hide method). Else, it will destroy it (call the dispose method).
innerContentHtml getter ✔️ The html content put into the window content This method is called during the window creation to fill the content div.
windowCreated method ✔️ This method is called when the window is created, but before the EVENT_CREATED event is sent. See the "Lifecycle hooks" section.
windowDestroyed method ✔️ This method is called when the window is destroyed, but before the EVENT_DESTROYED event is sent. See the "Lifecycle hooks" section.
appendTo method htmlElement If the window has not been created, creates the DOM element and fill it with the innerContentHtml. Adds it as a child to htmlElement. Binds the close button click event depending on the hideOnClose parameter. Calls the lifecycle hook windowCreated, then triggers the events EVENT_CREATED and EVENT_SHOWN.
dispose method If the window has been created, removes the DOM element corresponding to it. Call the lifecycle hook windowDestroyed, then triggers the event EVENT_DESTROYED
show method If the window has been created and is hidden, sets the display property to grid, then triggers the event EVENT_SHOWN
hide method If the window has been created and is shown, sets the display property to none, then triggers the event EVENT_DESTROYED
html getter The html content of the main <div> of the window. Computes and returns the HTML content of the main <div>
isCreated getter true if the window exists, else otherwise. Checks if the window property of the object is defined.
isVisible getter true if the window is shown, else otherwise. Checks if the display CSS property of the window is not set to none.
addListener method listener Adds listener to the current listeners.
notifyListeners method event Calls every listener with the event paremeter

The following methods are getters that allows you to access specific DOM elements of the window, along with their IDs. If you want to change the style or the content of one of these elements, you can access them this way.

Getter name DOM Element Window part it reffers
window, windowId <div> The main div that contains the window.
header, headerId <div> The div containing the title and the close button.
headerTitle, headerTitleId <h1> The title of the window.
headerCloseButton, headerCloseButtonId <button> The close button.
content, contentId <div> The div representing the lower part of the window.
innerContent, innerContentId <div> A div that fills the previous the content element. After the creation of the window, it contains the HTML that the getter innerContentHtml returns.

Fields

The window uses some fields to store data. The subclasses have access to them but should not modify them directly, as this could create unexpected behavior.

Field name Type Description
name String The unique name used to generate unique IDs
title String The title of the window
hideOnClose Boolean Specify the behavior of the close button.
parentElement DOM element The DOM element that was passed as parameter in the appendTo method.
listeners Array List of listeners (see the "Listening to events" section)

Lifecycle

The lifecycle of a window goes as it follows :

  1. The window is instanciated. This is generally done at the beginning of the program.
  2. The window is created through the appendTo method. From this moment, the getter isCreated returns true. By default, after creation the window is also visible, so the getter isVisible returns true too.
  3. The window can be hidden with the hide method. After that, isVisible returns false although isCreated still returns true. The window can be rendered visible again by calling the show method.
  4. The window is destroyed by the dispose method. The methods isCreated and isVisible both return false. Note that the object instanciated at the beginning is still perfectly valid and the window can be created again with appendTo.

Here is a scheme to understand the process :

Scheme

You can react to events by two means : by overriding the lifecycle hook methods or by listening to events. Lifecycle hooks are methods called when the window is created or destroyed and is fired before the corresponding events. Overriding them can be useful if you want to do particular actions at these moments. For example, if your window contains buttons, you can bind them to javascript functions during the windowCreated hook :

windowCreated() {
    document.getElementById('myButton').onclick = () => {
        //custom actions...
    };
}

Listening to events

The other way of reacting to window events is by listening to them. This is done by calling the addListener method which takes a function as parameter. It will pass a string as argument, whose value can be one of the static fields of the Window class :

  • EVENT_CREATED
  • EVENT_DESTROYED
  • EVENT_SHOWN
  • EVENT_HIDDEN

By adding listeners, external components can access events of you custom window.

let myWindow = new CustomWindow();

myWindow.addListener((event) => {
    if (event === Window.EVENT_CREATED) {
        console.log('My window was created !');
    }
});

myWindow.appendTo(htmlElement);
//Prints in the console 'My window was created !'

Setting position, size and other CSS properties

By default, the window has an initial position in the parent element, along with a default width. The initial height depends of the children contained by innerContent. The window is resizable and has a minimum width and height. If the height of the content is greater than the window, a scroll bar will appear to access the whole content. All these behavior are defined by CSS properties that can be overriden, either in CSS files or directly in the class that inherits Window. The later is a quick way to change the behavior of a window to your preferences, and is recommended for setting initial values such as position and size. You can do that in the windowCreated lifecycle hook for example :

windowCreated() {
    this.window.style.setProperty('width', '500px'); //window is a square of 500 by 500
    this.window.style.setProperty('height', '500px');
    this.window.style.setProperty('left', '1100px'); //it is positioned at the top right of the screen
    this.window.style.setProperty('top', '80px');
    this.window.style.setProperty('resize', 'none'); //it cannot be resized
}