The existing web page content repeats the html
for buttons which invoke popup modal dialogs.
To add new popups the same html
is copy-and-pasted resulting in very hard to maintain content.
Additionally, if the identifiers for the modal dialog is accidentally duplicated then the incorrect dialog would be brought up with no error feedback. This occurred quite often resulting a fair amount of time spent tracking down issues.
To address this issue, the proposal was to componentize the popup and button to:
Separate the user interfaces (UI) from the content. This allowed for common parts of the UI and interaction to be defined once in a component. This included any header and footer content, the main scrollable content area, and any common dialog buttons.
Allow the UI to be built dynamically for different content. This is done as a utility script with each invocation handling a given web page.
One instance of the original UI for the button and modal dialog was extracted.
$TOKEN_NAME$
syntax
was used with TOKEN_NAME
be replaced as needed to provide unique DOM
identifiers. template file
.A new utility was added to read the template file as well as parameters indicating where content resides, as well identifiers for button icon and label, dialog title, and DOM identifier. Basic string replacement per token is performed by the utility. The final content is returned by the utility.
The original content was replaced by new DOM
elements which identified where to insert a modal as well as the parameters for the modal. Using DOM
elements is easy to understand and parse providing a quick way to add modals to any document. An arbitrary number of declarations can be made with one for each button/popup pair.
Content for help is written in one or more Markdown
files and then run through a utility to produce two HTML
versions for each Markdown
file.
One is for a non-popup page and includes the insertion of the content into a templated HTML
document which get's header and footer and additional wrapper information inserted in to.
The other is the content without any additional wrappers.
The help pages used the first version and the utilities page popups use the second version. Popups can reference one or more of these content files as a "wrapper" file. It is this wrapper file that is used in the described implementation.
Thus all content is only written once and reused. Note that the Markdown
content is suitable for sites which can directly display this content -- such in a Github
repository.
The following figure provides a summary of the overall logic implemented.
- Cylinders
represent data which is either content or reusable template components
- Boxes
represent logic / processing which is performed.
Breakdown
At the far left is the Markdown
files containing the content. Larger content such as videos are stored externally and referenced in. For example videos are stored on YouTube.
The same "build" script is used generate the two version of this content as HTML
files: One for usage in a popup and one as a stand-alone page. For the latter additional reusable components such as header, footer, styling and navigation merged in.
The standalone page is referenced in to the main help and published to it's final location.
For the popup page:
The follow shows the original content, the reusable template file created, and the separated content file and the reference which replaces the original content.
The button which triggers the pop-up is shown below as used on the help page. All corresponding help and video buttons shown follow the same usage pattern resulting in four references and four content files all using the sample template file.
<!-- Video Button trigger modal -->
<div data-bs-toggle="tooltip" data-bs-title="Open Videos">
<button type="button" class="btn btn-sm btn-outline-primary"
data-bs-toggle="modal" data-bs-target="#nodeEditorModal">
<img src="../documents/icons/clapper.svg" width="16" height="16">
</button>
</div>
<!-- Help Video Modal -->
<div class="modal fade" id="nodeEditorModal" tabindex="-1"
aria-labelledby="nodeEditorModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-scrollable modal-xl-custom">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="nodeEditorModalLabel">Node Editor
</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
<div class="modal-body p-2">
<details open>
<summary>Creating Your First Material</summary>
<iframe src="https://www.youtube.com/embed/G2Z2U8AmArc?rel=0&vq=hd1080"
title="Creating Your First Material" width="100%"
height="600px" frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen>
</iframe>
</details>
<details open>
<summary>Using NodeGraphs</summary>
<iframe src="https://www.youtube.com/embed/ztDuVeyUwZU?rel=0&vq=hd1080"
title="Creating a Simple Shader" width="100%" height="600px"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen>
</iframe>
</details>
<details open>
<summary>Property Editor</summary>
<iframe src="https://www.youtube.com/embed/j_6vux9dPxU?rel=0&vq=hd1080"
title="Creating a Simple Shader" width="100%" height="600px"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen>
</iframe>
</details>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary"
data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
Note that tokens such as $HELP_MODAL$
are reused for different places to
provide: comments and unique identifiers for the button, the modal and modal label.
<!-- $HELP_MODAL$ Modal Button -->
<div data-bs-toggle="tooltip" data-bs-title="$HELP_BUTTON_TITLE$">
<button type="button" class="btn btn-sm btn-outline-primary"
data-bs-toggle="modal" data-bs-target="#$HELP_MODAL$">
<img src="$HELP_BUTTON_ICON$" width="16" height="16">
</button>
</div>
<!-- $HELP_MODAL$ Modal -->
<div class="modal fade" id="$HELP_MODAL$" tabindex="-1"
aria-labelledby="$HELP_MODAL$_Label" aria-hidden="true">
<div class="modal-dialog modal-dialog-scrollable modal-xl-custom">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="$HELP_MODAL$_Label">$HELP_CONTENT_TITLE$
</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
<div class="modal-body p-2">
$HELP_MODAL_CONTENT$
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary"
data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<details open>
<summary>Creating Your First Material</summary>
<iframe src="https://www.youtube.com/embed/G2Z2U8AmArc?rel=0&vq=hd1080"
title="Creating Your First Material" width="100%"
height="600px" frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen>
</iframe>
</details>
<details open>
<summary>Using NodeGraphs</summary>
<iframe src="https://www.youtube.com/embed/ztDuVeyUwZU?rel=0&vq=hd1080"
title="Creating a Simple Shader" width="100%" height="600px"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen>
</iframe>
</details>
<details open>
<summary>Property Editor</summary>
<iframe src="https://www.youtube.com/embed/j_6vux9dPxU?rel=0&vq=hd1080"
title="Creating a Simple Shader" width="100%" height="600px"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen>
</iframe>
</details>
<div class="help_modal" content_file="node_editor_videos_content.html" ,
title="Node Editor Videos" , button_title="Open Videos" id="node_editor_videos_popup"
button_icon="../documents/icons/clapper.svg"></div>