Modal - slide from left possible?

(Edit: Solved by Eric - please be sure to read through to the end of the thread especially posts 7 and 8 for the full solution.)

Does anybody know if it is possible to adjust the behaviour of modals from the default ‘drop-down’?

I’d like to reproduce mobile phone or tablet app type behaviour where the modal would slide in from left, right or bottom of the screen.

Is it possible?

The CSS for modal “slide in” is hard-coded in: $:/core/modules/utils/dom/modal.js

To change this so modals slide in from the left and out to the right:

  1. Edit the $:/core/modules/utils/dom/modal.js shadow tiddler.
  2. Search for translateY and replace it with translateX.
  3. Search for self.srcWindow.innerHeight and replace it with self.srcWindow.innerWidth.
  4. Search for this.srcWindow.innerHeight and replace it with this.srcWindow.innerWidth.
  5. Press “done” to finish editing.
  6. Save-and-reload for the modified code to take effect.

Similarly, to change it so modals slide in from the bottom and out to the top:

  1. Edit the $:/core/modules/utils/dom/modal.js shadow tiddler.
  2. Search for self.srcWindow.innerHeight and replace it with (-self.srcWindow.innerHeight).
  3. Search for (-this.srcWindow.innerHeight) and replace it with this.srcWindow.innerHeight.
  4. Press “done” to finish editing.
  5. Save-and-reload for the modified code to take effect.

Lastly, to change it so modals slide in from the right and out to the left:

  1. Edit the $:/core/modules/utils/dom/modal.js shadow tiddler.
  2. Search for translateY and replace it with translateX.
  3. Search for self.srcWindow.innerHeight and replace it with (-self.srcWindow.innerWidth).
  4. Search for (-this.srcWindow.innerHeight) and replace it with this.srcWindow.innerWidth.
  5. Press “done” to finish editing.
  6. Save-and-reload for the modified code to take effect.

Rather than hard-coding one of the above changes, it should be possible to parameterize these different behaviors by adding a config tiddler (e.g., $:/config/modals) containing a value of “top”, “left”, “right” or “bottom” to control the “+/-” and “innerHeight” vs “innerWidth” references.

-e

3 Likes

Wow - thank you Eric! I’ll try the config option.

I don’t want to push it but is a modal that slides back out the way it came in doable with a tweak to the default modal? If not, forget I asked, I’ll slide out the way I came in.

Thanks for such a clear answer.

Yes. It’s pretty much like the other changes, except you only change one of the translateY functions.

For example, in the following, just skip step (3):

  1. Edit the $:/core/modules/utils/dom/modal.js shadow tiddler.
  2. Search for self.srcWindow.innerHeight and replace it with (-self.srcWindow.innerHeight).
  3. Search for (-this.srcWindow.innerHeight) and replace it with this.srcWindow.innerHeight.
  4. Press “done” to finish editing.
  5. Save-and-reload for the modified code to take effect.

This causes modals that slide down from the top, and slide back up when closed.

-e

2 Likes

Thank you Eric, you’re very kind. It seems like a feature that could be useful for others too. Maybe I’ll put in a PR request for an official modal config option if I can work out how that’s done.

If I get it going I’ll try to post a working example back here, in the meantime thanks very much, I’m marking it as a solution.

Here’s the TWO changes you need to make to $:/core/modules/utils/dom/modal.js in order to add parameters for “slidein” and “slideout”:

First, replace this:

$tw.utils.setStyle(modalWrapper,[
	{transform: "translateY(" + self.srcWindow.innerHeight + "px)"}
]);

with:

if (options.variables.slideout === "top") {
	$tw.utils.setStyle(modalWrapper,[
		{transform: "translateY(" + (-self.srcWindow.innerHeight) + "px)"}
	]);
} else if (options.variables.slideout === "left") {
	$tw.utils.setStyle(modalWrapper,[
		{transform: "translateX(" + (-self.srcWindow.innerWidth) + "px)"}
	]);
} else if (options.variables.slideout === "right") {
	$tw.utils.setStyle(modalWrapper,[
		{transform: "translateX(" + (self.srcWindow.innerWidth) + "px)"}
	]);
} else {
	$tw.utils.setStyle(modalWrapper,[
		{transform: "translateY(" + (self.srcWindow.innerHeight) + "px)"}
	]);
}

Next, replace this:

$tw.utils.setStyle(modalWrapper,[
	{transformOrigin: "0% 0%"},
	{transform: "translateY(" + (-this.srcWindow.innerHeight) + "px)"}
]);

with this:

if (options.variables.slidein === "bottom") {
	$tw.utils.setStyle(modalWrapper,[
		{transformOrigin: "0% 0%"},
		{transform: "translateY(" + (this.srcWindow.innerHeight) + "px)"}
	]);
} else if (options.variables.slidein === "left") {
	$tw.utils.setStyle(modalWrapper,[
		{transformOrigin: "0% 0%"},
		{transform: "translateX(" + (-this.srcWindow.innerWidth) + "px)"}
	]);
} else if (options.variables.slidein === "right") {
	$tw.utils.setStyle(modalWrapper,[
		{transformOrigin: "0% 0%"},
		{transform: "translateX(" + (this.srcWindow.innerWidth) + "px)"}
	]);
} else {
	$tw.utils.setStyle(modalWrapper,[
		{transformOrigin: "0% 0%"},
		{transform: "translateY(" + (-this.srcWindow.innerHeight) + "px)"}
	]);
}

Then, in your wikitext code for triggering the modal, where you write something like:

<$button> click me
   <$action-setfield $tiddler="$:/temp/mymodal" subtitle="..." text="..." footer=".."/>
   <$action-sendmessage $message="tm-modal" $param="$:/temp/mymodal"/>
</$button>

you would add slidein="..." and slideout="..." to the tm-modal message params, using any combination of "top", "bottom", "left" or "right", like this:

<$button> click me
   <$action-setfield $tiddler="$:/temp/mymodal" subtitle="..." text="..." footer=".."/>
   <$action-sendmessage $message="tm-modal" $param="$:/temp/mymodal"
      slidein="left" slideout="top"/>
</$button>

Note: If you omit the slidein="..." and slideout="..." params, it uses to the existing default behavior of slidein="top" and slideout="bottom"

That’s it. With these changes, you can now have control over the slidein/slideout directions for individual tm-modal dialogs.

Alternatively, you could enter global values into two tiddlers: $:/config/modals/slidein and $:/config/modals/slideout, and then write your $action-sendmessage widget like this:

<$action-sendmessage $message="tm-modal" $param="$:/temp/mymodal"
   slidein={{$:/config/modals/slidein}} slideout={{$:/config/modals/slideout}}/>

enjoy,
-e

2 Likes

Amazing Eric - you are a magician! Thank you so much, the clarity and full solution really help. Would this make a useful small plugin do you think?

As promised here is a working example if anybody needs it;

https://wattaged.github.io/popmap/#Popmap

The ‘dashboard’ buttons below the image now call up directional modals as per Eric’s suggestion above. I’ll try to adjust their ‘entry height’, width and style with css later.

Eric’s modal action can be seen on each of the buttons in this tiddler;

https://wattaged.github.io/popmap/#Menu%20buttons

I opted for the local parameters option as it seems to allow more flexibility.

This demo site also relies heavily on Eric and @DaveGifford s ‘showModal’ button so I’ll apologize now to them for the mangling of that. The site is a work in progress.

If any future readers are interested I changed this core tiddler as Eric instructed in post number 6:

$:/core/modules/utils/dom/modal.js

and then transcluded my content into the ‘text’ param of his $action-setfield call like this, I haven’t played with the other parameters yet;

<$action-setfield $tiddler="$:/temp/mymodal" text={{Select and ikon}}/>
<$action-sendmessage $message="tm-modal" $param="$:/temp/mymodal" slidein="left" slideout="left"/>

If you make a backup of your original $:/core/modules/utils/dom/modal.js (a good idea) and make Eric’s suggested changes to the original you might not see any changes in modal behaviour if the backup is still ‘active’. I deleted the module-type/utility field from the backup, reloaded and it worked (Or maybe I’m imagining this).

Big thanks again Eric.

1 Like

Update:

I’ve been happily using this adjustment to $:/core/modules/utils/dom/modal.js as per Eric’s excellent suggestion, with modals coming in from all directions but I think I’ve hit a ‘don’t mess with the shadow tiddlers’ snag.

I think it’s because the ‘get new plugins’ dialogue in Control panel uses a modal to open the TW plugin library. Clicking it throws a red javascript warning when it encounters the additional slidein/out alterations in the altered modal.js, preventing the installation of plugins via that route.

So - just a heads up/warning to anyone following this route to modal nirvana - it might not play well with the official plugin library.

Restoring the original $:/core/modules/utils/dom/modal.js is easily done, so keep a copy somewhere or if necessary it can be found in a fresh empty TW.

Maybe Eric has a magic solution but an enhancement to the modal magic in a future TW release might save him some work, so I’ll try requesting that in a pr.

Here’s the fix…

In the modified code for $:/core/modules/utils/dom/modal.js, change:
options.variables.slidein and options.variables.slideout
to
variables.slidein and variables.slideout

-e

Thanks Eric! I made the alterations and it now works perfectly and the plugin library is back in action. You’re a star.
Best
Watt