mirror of
https://github.com/Sygil-Dev/sygil-webui.git
synced 2024-12-18 17:11:50 +03:00
7252b1dde2
added tooltip support. Added Artist image tooltips.
329 lines
8.6 KiB
JavaScript
329 lines
8.6 KiB
JavaScript
// parent document
|
|
var parentDoc = window.parent.document;
|
|
// iframe element in parent document
|
|
var frame = window.frameElement;
|
|
// the area to put the suggestions in
|
|
var suggestionArea = document.getElementById('suggestion_area');
|
|
// button height is read when the first button gets created
|
|
var buttonHeight = -1;
|
|
// the maximum size of the iframe in buttons (3 x buttons height)
|
|
var maxHeightInButtons = 3;
|
|
// the prompt field connected to this iframe
|
|
var promptField = null;
|
|
// the category of suggestions
|
|
var activeCategory = [];
|
|
|
|
var conditionalButtons = null;
|
|
|
|
function currentFrameAbsolutePosition() {
|
|
let currentWindow = window;
|
|
let currentParentWindow;
|
|
let positions = [];
|
|
let rect;
|
|
|
|
while (currentWindow !== window.top) {
|
|
currentParentWindow = currentWindow.parent;
|
|
for (let idx = 0; idx < currentParentWindow.frames.length; idx++)
|
|
if (currentParentWindow.frames[idx] === currentWindow) {
|
|
for (let frameElement of currentParentWindow.document.getElementsByTagName('iframe')) {
|
|
if (frameElement.contentWindow === currentWindow) {
|
|
rect = frameElement.getBoundingClientRect();
|
|
positions.push({x: rect.x, y: rect.y});
|
|
}
|
|
}
|
|
currentWindow = currentParentWindow;
|
|
break;
|
|
}
|
|
}
|
|
return positions.reduce((accumulator, currentValue) => {
|
|
return {
|
|
x: accumulator.x + currentValue.x,
|
|
y: accumulator.y + currentValue.y
|
|
};
|
|
}, { x: 0, y: 0 });
|
|
}
|
|
|
|
// check if element is visible
|
|
function isVisible(e) {
|
|
return !!( e.offsetWidth || e.offsetHeight || e.getClientRects().length );
|
|
}
|
|
|
|
// remove everything from the suggestion area
|
|
function ClearSuggestionArea(text = "")
|
|
{
|
|
suggestionArea.innerHTML = text;
|
|
conditionalButtons = [];
|
|
}
|
|
|
|
// update iframe size depending on button rows
|
|
function UpdateSize()
|
|
{
|
|
// calculate maximum height
|
|
var maxHeight = buttonHeight * maxHeightInButtons;
|
|
// apply height to iframe
|
|
frame.style.height = Math.min(suggestionArea.offsetHeight,maxHeight)+"px";
|
|
}
|
|
|
|
// add a button to the suggestion area
|
|
function AddButton(label, action, dataTooltip="", tooltipImage="", pattern="", data="")
|
|
{
|
|
// create span
|
|
var button = document.createElement("span");
|
|
// label it
|
|
button.innerHTML = label;
|
|
if(data != "")
|
|
{
|
|
// add category attribute to button, will be read on click
|
|
button.setAttribute("data",data);
|
|
}
|
|
if(pattern != "")
|
|
{
|
|
// add category attribute to button, will be read on click
|
|
button.setAttribute("pattern",pattern);
|
|
}
|
|
if(dataTooltip != "")
|
|
{
|
|
// add category attribute to button, will be read on click
|
|
button.setAttribute("tooltip-text",dataTooltip);
|
|
}
|
|
if(tooltipImage != "")
|
|
{
|
|
// add category attribute to button, will be read on click
|
|
button.setAttribute("tooltip-image",tooltipImage);
|
|
}
|
|
// add button function
|
|
button.addEventListener('click', action, false);
|
|
button.addEventListener('mouseover', ButtonHoverEnter);
|
|
button.addEventListener('mouseout', ButtonHoverExit);
|
|
// add button to suggestion area
|
|
suggestionArea.appendChild(button);
|
|
// get buttonHeight if not set
|
|
if(buttonHeight < 0)
|
|
buttonHeight = button.offsetHeight;
|
|
return button;
|
|
}
|
|
|
|
// find visible prompt field to connect to this iframe
|
|
function GetPromptField()
|
|
{
|
|
// get all prompt fields, the %% placeholder %% is set in python
|
|
var all = parentDoc.querySelectorAll('textarea[placeholder="'+placeholder+'"]');
|
|
// filter visible
|
|
for(var i = 0; i < all.length; i++)
|
|
{
|
|
if(isVisible(all[i]))
|
|
{
|
|
promptField = all[i];
|
|
promptField.addEventListener('input', OnChange, false);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
function OnChange(e)
|
|
{
|
|
ButtonConditions();
|
|
}
|
|
|
|
// when pressing a button, give the focus back to the prompt field
|
|
function KeepFocus(e)
|
|
{
|
|
e.preventDefault();
|
|
promptField.focus();
|
|
}
|
|
|
|
function selectCategory(e)
|
|
{
|
|
KeepFocus(e);
|
|
// set category from attribute
|
|
activeCategory = e.target.getAttribute("data");
|
|
// rebuild menu
|
|
ShowMenu();
|
|
}
|
|
|
|
function leaveCategory(e)
|
|
{
|
|
KeepFocus(e);
|
|
activeCategory = "";
|
|
// rebuild menu
|
|
ShowMenu();
|
|
}
|
|
|
|
function SelectPhrase(e)
|
|
{
|
|
KeepFocus(e);
|
|
var pattern = e.target.getAttribute("pattern");
|
|
var entry = e.target.getAttribute("data");
|
|
|
|
// inserting via execCommand is required, this triggers all native browser functionality as if the user wrote into the prompt field.
|
|
parentDoc.execCommand('insertText', false /*no UI*/, pattern.replace('{}',entry));
|
|
}
|
|
|
|
function CheckButtonCondition(condition)
|
|
{
|
|
if(condition === "empty")
|
|
{
|
|
return promptField.value == "";
|
|
}
|
|
}
|
|
|
|
function ButtonConditions()
|
|
{
|
|
conditionalButtons.forEach(entry =>
|
|
{
|
|
if(CheckButtonCondition(entry.condition))
|
|
entry.element.style.display = "inline-block";
|
|
else
|
|
entry.element.style.display = "none";
|
|
});
|
|
}
|
|
|
|
function ButtonHoverEnter(e)
|
|
{
|
|
var text = e.target.getAttribute("tooltip-text");
|
|
var image = e.target.getAttribute("tooltip-image");
|
|
ShowTooltip(text, e.target, image)
|
|
}
|
|
|
|
function ButtonHoverExit(e)
|
|
{
|
|
HideTooltip();
|
|
}
|
|
|
|
function ShowTooltip(text, target, image = "")
|
|
{
|
|
if((text == "" || text == null) && (image == "" || image == null || thumbnails[image] === undefined))
|
|
return;
|
|
|
|
var currentFramePosition = currentFrameAbsolutePosition();
|
|
var rect = target.getBoundingClientRect();
|
|
var element = parentDoc["phraseTooltip"];
|
|
element.innerText = text;
|
|
if(image != "" && image != null && thumbnails[image] !== undefined)
|
|
{
|
|
|
|
var img = parentDoc.createElement('img');
|
|
console.log(image);
|
|
img.src = "data:image/webp;base64, "+thumbnails[image];
|
|
|
|
console.log(thumbnails[image]);
|
|
element.appendChild(img)
|
|
}
|
|
element.style.display = "flex";
|
|
element.style.top = (rect.bottom+currentFramePosition.y)+"px";
|
|
element.style.left = (rect.right+currentFramePosition.x)+"px";
|
|
element.style.width = "inherit";
|
|
element.style.height = "inherit";
|
|
}
|
|
|
|
function HideTooltip()
|
|
{
|
|
var element = parentDoc["phraseTooltip"];
|
|
element.style.display= "none";
|
|
element.innerHTML = "";
|
|
element.style.top = "0px";
|
|
element.style.left = "0px";
|
|
element.style.width = "0px";
|
|
element.style.height = "0px";
|
|
}
|
|
|
|
// generate menu in suggestion area
|
|
function ShowMenu()
|
|
{
|
|
// clear all buttons from menu
|
|
ClearSuggestionArea();
|
|
HideTooltip();
|
|
|
|
// if no chategory is selected
|
|
if(activeCategory == "")
|
|
{
|
|
for (var category in keyPhrases)
|
|
{
|
|
AddButton(category, selectCategory, keyPhrases[category]["description"], "", "", category);
|
|
}
|
|
// change iframe size after buttons have been added
|
|
UpdateSize();
|
|
}
|
|
// if a chategory is selected
|
|
else
|
|
{
|
|
// add a button to leave the chategory
|
|
var backbutton = AddButton("↑ back", leaveCategory);
|
|
var pattern = keyPhrases[activeCategory]["pattern"];
|
|
keyPhrases[activeCategory]["entries"].forEach(entry =>
|
|
{
|
|
var tempPattern = pattern;
|
|
if(entry["pattern_override"] != "")
|
|
{
|
|
tempPattern = entry["pattern_override"];
|
|
}
|
|
|
|
var button = AddButton(entry["phrase"], SelectPhrase, entry["description"], entry["phrase"],tempPattern, entry["phrase"]);
|
|
|
|
if(entry["show_if"] != "")
|
|
conditionalButtons.push({element:button,condition:entry["show_if"]});
|
|
});
|
|
// change iframe size after buttons have been added
|
|
UpdateSize();
|
|
ButtonConditions();
|
|
}
|
|
}
|
|
|
|
// listen for clicks on the prompt field
|
|
parentDoc.addEventListener("click", (e) =>
|
|
{
|
|
// skip if this frame is not visible
|
|
if(!isVisible(frame))
|
|
return;
|
|
|
|
// if the iframes prompt field is not set, get it and set it
|
|
if(promptField === null)
|
|
GetPromptField();
|
|
|
|
// get the field with focus
|
|
var target = parentDoc.activeElement;
|
|
|
|
// if the field with focus is a prompt field, the %% placeholder %% is set in python
|
|
if( target.placeholder === placeholder)
|
|
{
|
|
// generate menu
|
|
ShowMenu();
|
|
}
|
|
else
|
|
{
|
|
// else hide the iframe
|
|
frame.style.height = "0px";
|
|
}
|
|
});
|
|
|
|
// add custom style to iframe
|
|
frame.classList.add("suggestion-frame");
|
|
// clear suggestion area to remove the "javascript failed" message
|
|
ClearSuggestionArea();
|
|
// collapse the iframe by default
|
|
frame.style.height = "0px";
|
|
|
|
// only execute once (even though multiple iframes exist)
|
|
if(!parentDoc.hasOwnProperty('keyPhraseSuggestionsInitialized'))
|
|
{
|
|
// get parent document head
|
|
var head = parentDoc.getElementsByTagName('head')[0];
|
|
// add style tag
|
|
var s = parentDoc.createElement('style');
|
|
// set type attribute
|
|
s.setAttribute('type', 'text/css');
|
|
// add css forwarded from python
|
|
if (s.styleSheet) { // IE
|
|
s.styleSheet.cssText = parentCSS;
|
|
} else { // the world
|
|
s.appendChild(parentDoc.createTextNode(parentCSS));
|
|
}
|
|
var tooltip = parentDoc.createElement('div');
|
|
tooltip.id = "phrase-tooltip";
|
|
parentDoc.body.appendChild(tooltip);
|
|
parentDoc["phraseTooltip"] = tooltip;
|
|
// add style to head
|
|
head.appendChild(s);
|
|
// set flag so this only runs once
|
|
parentDoc["keyPhraseSuggestionsInitialized"] = true;
|
|
} |