1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-11-27 20:10:03 +00:00
TiddlyWiki5/core/modules/utils/dom/modal.js
saqimtiaz ca6dd93214
Add support for a custom class to modal wrapper (#4490)
* Add support for a custom class to modal wrapper

As per https://github.com/Jermolene/TiddlyWiki5/issues/4485 add support for a custom class to modal wrapper, by means of a field in the modal tiddler. The class is added to the modal wrapper in addition to the default class, allowing for custom styling via css of any part of the modal.

* Remove redundant check for tiddler.
2020-03-12 16:58:14 +00:00

219 lines
6.9 KiB
JavaScript

/*\
title: $:/core/modules/utils/dom/modal.js
type: application/javascript
module-type: utils
Modal message mechanism
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var widget = require("$:/core/modules/widgets/widget.js");
var Modal = function(wiki) {
this.wiki = wiki;
this.modalCount = 0;
};
/*
Display a modal dialogue
title: Title of tiddler to display
options: see below
Options include:
downloadLink: Text of a big download link to include
*/
Modal.prototype.display = function(title,options) {
options = options || {};
this.srcDocument = options.variables && (options.variables.rootwindow === "true" ||
options.variables.rootwindow === "yes") ? document :
(options.event.event && options.event.event.target ? options.event.event.target.ownerDocument : document);
this.srcWindow = this.srcDocument.defaultView;
var self = this,
refreshHandler,
duration = $tw.utils.getAnimationDuration(),
tiddler = this.wiki.getTiddler(title);
// Don't do anything if the tiddler doesn't exist
if(!tiddler) {
return;
}
// Create the variables
var variables = $tw.utils.extend({currentTiddler: title},options.variables);
// Create the wrapper divs
var wrapper = this.srcDocument.createElement("div"),
modalBackdrop = this.srcDocument.createElement("div"),
modalWrapper = this.srcDocument.createElement("div"),
modalHeader = this.srcDocument.createElement("div"),
headerTitle = this.srcDocument.createElement("h3"),
modalBody = this.srcDocument.createElement("div"),
modalLink = this.srcDocument.createElement("a"),
modalFooter = this.srcDocument.createElement("div"),
modalFooterHelp = this.srcDocument.createElement("span"),
modalFooterButtons = this.srcDocument.createElement("span");
// Up the modal count and adjust the body class
this.modalCount++;
this.adjustPageClass();
// Add classes
$tw.utils.addClass(wrapper,"tc-modal-wrapper");
if(tiddler.fields && tiddler.fields.class) {
$tw.utils.addClass(wrapper,tiddler.fields.class);
}
$tw.utils.addClass(modalBackdrop,"tc-modal-backdrop");
$tw.utils.addClass(modalWrapper,"tc-modal");
$tw.utils.addClass(modalHeader,"tc-modal-header");
$tw.utils.addClass(modalBody,"tc-modal-body");
$tw.utils.addClass(modalFooter,"tc-modal-footer");
// Join them together
wrapper.appendChild(modalBackdrop);
wrapper.appendChild(modalWrapper);
modalHeader.appendChild(headerTitle);
modalWrapper.appendChild(modalHeader);
modalWrapper.appendChild(modalBody);
modalFooter.appendChild(modalFooterHelp);
modalFooter.appendChild(modalFooterButtons);
modalWrapper.appendChild(modalFooter);
// Render the title of the message
var headerWidgetNode = this.wiki.makeTranscludeWidget(title,{
field: "subtitle",
mode: "inline",
children: [{
type: "text",
attributes: {
text: {
type: "string",
value: title
}}}],
parentWidget: $tw.rootWidget,
document: this.srcDocument,
variables: variables,
importPageMacros: true
});
headerWidgetNode.render(headerTitle,null);
// Render the body of the message
var bodyWidgetNode = this.wiki.makeTranscludeWidget(title,{
parentWidget: $tw.rootWidget,
document: this.srcDocument,
variables: variables,
importPageMacros: true
});
bodyWidgetNode.render(modalBody,null);
// Setup the link if present
if(options.downloadLink) {
modalLink.href = options.downloadLink;
modalLink.appendChild(this.srcDocument.createTextNode("Right-click to save changes"));
modalBody.appendChild(modalLink);
}
// Render the footer of the message
if(tiddler.fields && tiddler.fields.help) {
var link = this.srcDocument.createElement("a");
link.setAttribute("href",tiddler.fields.help);
link.setAttribute("target","_blank");
link.setAttribute("rel","noopener noreferrer");
link.appendChild(this.srcDocument.createTextNode("Help"));
modalFooterHelp.appendChild(link);
modalFooterHelp.style.float = "left";
}
var footerWidgetNode = this.wiki.makeTranscludeWidget(title,{
field: "footer",
mode: "inline",
children: [{
type: "button",
attributes: {
message: {
type: "string",
value: "tm-close-tiddler"
}
},
children: [{
type: "text",
attributes: {
text: {
type: "string",
value: $tw.language.getString("Buttons/Close/Caption")
}}}
]}],
parentWidget: $tw.rootWidget,
document: this.srcDocument,
variables: variables,
importPageMacros: true
});
footerWidgetNode.render(modalFooterButtons,null);
// Set up the refresh handler
refreshHandler = function(changes) {
headerWidgetNode.refresh(changes,modalHeader,null);
bodyWidgetNode.refresh(changes,modalBody,null);
footerWidgetNode.refresh(changes,modalFooterButtons,null);
};
this.wiki.addEventListener("change",refreshHandler);
// Add the close event handler
var closeHandler = function(event) {
// Remove our refresh handler
self.wiki.removeEventListener("change",refreshHandler);
// Decrease the modal count and adjust the body class
self.modalCount--;
self.adjustPageClass();
// Force layout and animate the modal message away
$tw.utils.forceLayout(modalBackdrop);
$tw.utils.forceLayout(modalWrapper);
$tw.utils.setStyle(modalBackdrop,[
{opacity: "0"}
]);
$tw.utils.setStyle(modalWrapper,[
{transform: "translateY(" + self.srcWindow.innerHeight + "px)"}
]);
// Set up an event for the transition end
self.srcWindow.setTimeout(function() {
if(wrapper.parentNode) {
// Remove the modal message from the DOM
self.srcDocument.body.removeChild(wrapper);
}
},duration);
// Don't let anyone else handle the tm-close-tiddler message
return false;
};
headerWidgetNode.addEventListener("tm-close-tiddler",closeHandler,false);
bodyWidgetNode.addEventListener("tm-close-tiddler",closeHandler,false);
footerWidgetNode.addEventListener("tm-close-tiddler",closeHandler,false);
// Set the initial styles for the message
$tw.utils.setStyle(modalBackdrop,[
{opacity: "0"}
]);
$tw.utils.setStyle(modalWrapper,[
{transformOrigin: "0% 0%"},
{transform: "translateY(" + (-this.srcWindow.innerHeight) + "px)"}
]);
// Put the message into the document
this.srcDocument.body.appendChild(wrapper);
// Set up animation for the styles
$tw.utils.setStyle(modalBackdrop,[
{transition: "opacity " + duration + "ms ease-out"}
]);
$tw.utils.setStyle(modalWrapper,[
{transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms ease-in-out"}
]);
// Force layout
$tw.utils.forceLayout(modalBackdrop);
$tw.utils.forceLayout(modalWrapper);
// Set final animated styles
$tw.utils.setStyle(modalBackdrop,[
{opacity: "0.7"}
]);
$tw.utils.setStyle(modalWrapper,[
{transform: "translateY(0px)"}
]);
};
Modal.prototype.adjustPageClass = function() {
var windowContainer = $tw.pageContainer ? ($tw.pageContainer === this.srcDocument.body.firstChild ? $tw.pageContainer : this.srcDocument.body.firstChild) : null;
if(windowContainer) {
$tw.utils.toggleClass(windowContainer,"tc-modal-displayed",this.modalCount > 0);
}
};
exports.Modal = Modal;
})();