kopia lustrzana https://github.com/miklobit/TiddlyWiki5
Fixes to make nested popups work
Thus making the export button a lot more usefulprint-window-tiddler
rodzic
27c9e7269e
commit
b882a0dff1
|
@ -19,40 +19,7 @@ Creates a Popup object with these options:
|
|||
var Popup = function(options) {
|
||||
options = options || {};
|
||||
this.rootElement = options.rootElement || document.body;
|
||||
};
|
||||
|
||||
Popup.prototype.show = function(options) {
|
||||
this.cancel();
|
||||
this.title = options.title;
|
||||
this.wiki = options.wiki;
|
||||
this.anchorDomNode = options.domNode;
|
||||
$tw.utils.addClass(this.anchorDomNode,"tc-popup");
|
||||
this.rootElement.addEventListener("click",this,false);
|
||||
};
|
||||
|
||||
Popup.prototype.handleEvent = function(event) {
|
||||
// Dismiss the popup if we get a click on an element that doesn't have .tc-popup class
|
||||
if(event.type === "click") {
|
||||
var node = event.target;
|
||||
while(node && !$tw.utils.hasClass(node,"tc-popup")) {
|
||||
node = node.parentNode;
|
||||
}
|
||||
if(!node) {
|
||||
this.cancel();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Popup.prototype.cancel = function() {
|
||||
if(this.anchorDomNode) {
|
||||
$tw.utils.removeClass(this.anchorDomNode,"tc-popup");
|
||||
this.anchorDomNode = null;
|
||||
}
|
||||
this.rootElement.removeEventListener("click",this,false);
|
||||
if(this.title) {
|
||||
this.wiki.deleteTiddler(this.title);
|
||||
this.title = null;
|
||||
}
|
||||
this.popups = []; // Array of {title:,wiki:,domNode:} objects
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -60,38 +27,134 @@ Trigger a popup open or closed. Parameters are in a hashmap:
|
|||
title: title of the tiddler where the popup details are stored
|
||||
domNode: dom node to which the popup will be positioned
|
||||
wiki: wiki
|
||||
force: if specified, forces the popup state to true or false
|
||||
force: if specified, forces the popup state to true or false (instead of toggling it)
|
||||
*/
|
||||
Popup.prototype.triggerPopup = function(options) {
|
||||
// Get the current popup state tiddler
|
||||
var value = options.wiki.getTextReference(options.title,"");
|
||||
// Check if the popup is open by checking whether it matches "(<x>,<y>)"
|
||||
var state = !this.readPopupState(options.title,value);
|
||||
if("force" in options) {
|
||||
console.log("triggerPopup",options)
|
||||
// Check if this popup is already active
|
||||
var index = -1;
|
||||
for(var t=0; t<this.popups.length; t++) {
|
||||
if(this.popups[t].title === options.title) {
|
||||
index = t;
|
||||
}
|
||||
}
|
||||
// Compute the new state
|
||||
var state = index === -1;
|
||||
if(options.force !== undefined) {
|
||||
state = options.force;
|
||||
}
|
||||
// Show or cancel the popup according to the new state
|
||||
if(state) {
|
||||
// Set the position if we're opening it
|
||||
this.cancel();
|
||||
options.wiki.setTextReference(options.title,
|
||||
"(" + options.domNode.offsetLeft + "," + options.domNode.offsetTop + "," +
|
||||
options.domNode.offsetWidth + "," + options.domNode.offsetHeight + ")");
|
||||
this.show(options);
|
||||
} else {
|
||||
this.cancel();
|
||||
this.cancel(index);
|
||||
}
|
||||
};
|
||||
|
||||
Popup.prototype.handleEvent = function(event) {
|
||||
console.log("handleEvent",event)
|
||||
if(event.type === "click") {
|
||||
// Find out what was clicked on
|
||||
var info = this.popupInfo(event.target),
|
||||
cancelLevel = info.popupLevel - 1;
|
||||
// Don't remove the level that was clicked on if we clicked on a handle
|
||||
if(info.isHandle) {
|
||||
cancelLevel++;
|
||||
}
|
||||
// Cancel
|
||||
this.cancel(cancelLevel);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Find the popup level containing a DOM node. Returns:
|
||||
popupLevel: count of the number of nested popups containing the specified element
|
||||
isHandle: true if the specified element is within a popup handle
|
||||
*/
|
||||
Popup.prototype.popupInfo = function(domNode) {
|
||||
var isHandle = false,
|
||||
popupCount = 0,
|
||||
node = domNode;
|
||||
// First check ancestors to see if we're within a popup handle
|
||||
while(node) {
|
||||
if($tw.utils.hasClass(node,"tc-popup-handle")) {
|
||||
isHandle = true;
|
||||
popupCount++;
|
||||
}
|
||||
if($tw.utils.hasClass(node,"tc-popup-keep")) {
|
||||
isHandle = true;
|
||||
}
|
||||
node = node.parentNode;
|
||||
}
|
||||
// Then count the number of ancestor popups
|
||||
node = domNode;
|
||||
while(node) {
|
||||
if($tw.utils.hasClass(node,"tc-popup")) {
|
||||
popupCount++;
|
||||
}
|
||||
node = node.parentNode;
|
||||
}
|
||||
var info = {
|
||||
popupLevel: popupCount,
|
||||
isHandle: isHandle
|
||||
};
|
||||
console.log("Returning popupInfo",info)
|
||||
return info;
|
||||
};
|
||||
|
||||
/*
|
||||
Display a popup by adding it to the stack
|
||||
*/
|
||||
Popup.prototype.show = function(options) {
|
||||
console.log("show",options)
|
||||
// Find out what was clicked on
|
||||
var info = this.popupInfo(options.domNode);
|
||||
// Cancel any higher level popups
|
||||
this.cancel(info.popupLevel);
|
||||
// Store the popup details
|
||||
this.popups.push({
|
||||
title: options.title,
|
||||
wiki: options.wiki,
|
||||
domNode: options.domNode
|
||||
});
|
||||
// Set the state tiddler
|
||||
options.wiki.setTextReference(options.title,
|
||||
"(" + options.domNode.offsetLeft + "," + options.domNode.offsetTop + "," +
|
||||
options.domNode.offsetWidth + "," + options.domNode.offsetHeight + ")");
|
||||
// Add the click handler if we have any popups
|
||||
if(this.popups.length > 0) {
|
||||
console.log("Adding click handler")
|
||||
this.rootElement.addEventListener("click",this,true);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Cancel all popups at or above a specified level or DOM node
|
||||
level: popup level to cancel (0 cancels all popups)
|
||||
*/
|
||||
Popup.prototype.cancel = function(level) {
|
||||
console.log("cancel",level)
|
||||
var numPopups = this.popups.length;
|
||||
level = Math.max(0,Math.min(level,numPopups));
|
||||
for(var t=level; t<numPopups; t++) {
|
||||
var popup = this.popups.pop();
|
||||
if(popup.title) {
|
||||
popup.wiki.deleteTiddler(popup.title);
|
||||
}
|
||||
}
|
||||
if(this.popups.length === 0) {
|
||||
console.log("Removing click handler")
|
||||
this.rootElement.removeEventListener("click",this,false);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Returns true if the specified title and text identifies an active popup
|
||||
*/
|
||||
Popup.prototype.readPopupState = function(title,text) {
|
||||
var popupLocationRegExp = /^\((-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+)\)$/,
|
||||
result = false;
|
||||
if(this.title === title) {
|
||||
result = popupLocationRegExp.test(text);
|
||||
}
|
||||
return result;
|
||||
Popup.prototype.readPopupState = function(text) {
|
||||
console.log("readPopupState",text)
|
||||
var popupLocationRegExp = /^\((-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+)\)$/;
|
||||
return popupLocationRegExp.test(text);
|
||||
};
|
||||
|
||||
exports.Popup = Popup;
|
||||
|
|
|
@ -462,20 +462,24 @@ Returns an object with the following fields, all optional:
|
|||
exports.parseTextReference = function(textRef) {
|
||||
// Separate out the title, field name and/or JSON indices
|
||||
var reTextRef = /^\s*([^!#]+)?(?:(?:!!([^\s]+))|(?:##(.+)))?\s*/mg,
|
||||
match = reTextRef.exec(textRef);
|
||||
match = reTextRef.exec(textRef),
|
||||
result = {};
|
||||
if(match && reTextRef.lastIndex === textRef.length) {
|
||||
// Return the parts
|
||||
return {
|
||||
title: match[1],
|
||||
field: match[2],
|
||||
index: match[3]
|
||||
};
|
||||
if(match[1]) {
|
||||
result.title = match[1];
|
||||
}
|
||||
if(match[2]) {
|
||||
result.field = match[2];
|
||||
}
|
||||
if(match[3]) {
|
||||
result.index = match[3];
|
||||
}
|
||||
} else {
|
||||
// If we couldn't parse it (eg it started with a)
|
||||
return {
|
||||
title: textRef
|
||||
};
|
||||
// If we couldn't parse it
|
||||
result.title = textRef
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -36,15 +36,19 @@ ButtonWidget.prototype.render = function(parent,nextSibling) {
|
|||
// Create element
|
||||
var domNode = this.document.createElement("button");
|
||||
// Assign classes
|
||||
var classes = this["class"].split(" ") || [];
|
||||
var classes = this["class"].split(" ") || [],
|
||||
isPoppedUp = this.popup && this.isPoppedUp();
|
||||
if(this.selectedClass) {
|
||||
if(this.set && this.setTo && this.isSelected()) {
|
||||
$tw.utils.pushTop(classes,this.selectedClass.split(" "));
|
||||
}
|
||||
if(this.popup && this.isPoppedUp()) {
|
||||
if(isPoppedUp) {
|
||||
$tw.utils.pushTop(classes,this.selectedClass.split(" "));
|
||||
}
|
||||
}
|
||||
if(isPoppedUp) {
|
||||
$tw.utils.pushTop(classes,"tc-popup-handle");
|
||||
}
|
||||
domNode.className = classes.join(" ");
|
||||
// Assign other attributes
|
||||
if(this.style) {
|
||||
|
@ -101,7 +105,7 @@ ButtonWidget.prototype.isSelected = function() {
|
|||
|
||||
ButtonWidget.prototype.isPoppedUp = function() {
|
||||
var tiddler = this.wiki.getTiddler(this.popup);
|
||||
var result = tiddler && tiddler.fields.text ? $tw.popup.readPopupState(this.popup,tiddler.fields.text) : false;
|
||||
var result = tiddler && tiddler.fields.text ? $tw.popup.readPopupState(tiddler.fields.text) : false;
|
||||
return result;
|
||||
};
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ description: {{$:/language/Buttons/Language/Hint}}
|
|||
\define flag-title()
|
||||
$(languagePluginTitle)$/icon
|
||||
\end
|
||||
<span class="tc-popup-keep">
|
||||
<$button popup=<<qualify "$:/state/popup/language">> tooltip={{$:/language/Buttons/Language/Hint}} aria-label={{$:/language/Buttons/Language/Caption}} class=<<tv-config-toolbar-class>> selectedClass="tc-selected">
|
||||
<$list filter="[<tv-config-toolbar-icons>prefix[yes]]">
|
||||
<span class="tc-image-button">
|
||||
|
@ -18,6 +19,7 @@ $(languagePluginTitle)$/icon
|
|||
<span class="tc-btn-text"><$text text={{$:/language/Buttons/Language/Caption}}/></span>
|
||||
</$list>
|
||||
</$button>
|
||||
</span>
|
||||
<$reveal state=<<qualify "$:/state/popup/language">> type="popup" position="below" animate="yes">
|
||||
<div class="tc-drop-down tc-drop-down-language-chooser">
|
||||
<$linkcatcher to="$:/language">
|
||||
|
|
|
@ -6,6 +6,7 @@ description: {{$:/language/Buttons/StoryView/Hint}}
|
|||
\define icon()
|
||||
$:/core/images/storyview-$(storyview)$
|
||||
\end
|
||||
<span class="tc-popup-keep">
|
||||
<$button popup=<<qualify "$:/state/popup/storyview">> tooltip={{$:/language/Buttons/StoryView/Hint}} aria-label={{$:/language/Buttons/StoryView/Caption}} class=<<tv-config-toolbar-class>> selectedClass="tc-selected">
|
||||
<$list filter="[<tv-config-toolbar-icons>prefix[yes]]">
|
||||
<$set name="storyview" value={{$:/view}}>
|
||||
|
@ -16,6 +17,7 @@ $:/core/images/storyview-$(storyview)$
|
|||
<span class="tc-btn-text"><$text text={{$:/language/Buttons/StoryView/Caption}}/></span>
|
||||
</$list>
|
||||
</$button>
|
||||
</span>
|
||||
<$reveal state=<<qualify "$:/state/popup/storyview">> type="popup" position="below" animate="yes">
|
||||
<div class="tc-drop-down">
|
||||
<$linkcatcher to="$:/view">
|
||||
|
|
|
@ -3,6 +3,7 @@ tags: $:/tags/PageControls
|
|||
caption: {{$:/core/images/theme-button}} {{$:/language/Buttons/Theme/Caption}}
|
||||
description: {{$:/language/Buttons/Theme/Hint}}
|
||||
|
||||
<span class="tc-popup-keep">
|
||||
<$button popup=<<qualify "$:/state/popup/theme">> tooltip={{$:/language/Buttons/Theme/Hint}} aria-label={{$:/language/Buttons/Theme/Caption}} class=<<tv-config-toolbar-class>> selectedClass="tc-selected">
|
||||
<$list filter="[<tv-config-toolbar-icons>prefix[yes]]">
|
||||
{{$:/core/images/theme-button}}
|
||||
|
@ -11,6 +12,7 @@ description: {{$:/language/Buttons/Theme/Hint}}
|
|||
<span class="tc-btn-text"><$text text={{$:/language/Buttons/Theme/Caption}}/></span>
|
||||
</$list>
|
||||
</$button>
|
||||
</span>
|
||||
<$reveal state=<<qualify "$:/state/popup/theme">> type="popup" position="below" animate="yes">
|
||||
<div class="tc-drop-down">
|
||||
<$linkcatcher to="$:/theme">
|
||||
|
|
|
@ -29,7 +29,7 @@ $:/config/ViewToolbarButtons/Visibility/$(listItem)$
|
|||
</$list>
|
||||
</div>
|
||||
|
||||
<$reveal type="nomatch" text="" default="" state=<<tiddlerInfoState>> class="tc-tiddler-info tc-popup" animate="yes" retain="yes">
|
||||
<$reveal type="nomatch" text="" default="" state=<<tiddlerInfoState>> class="tc-tiddler-info tc-popup-keep" animate="yes" retain="yes">
|
||||
|
||||
<$transclude tiddler="$:/core/ui/TiddlerInfo"/>
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ title: $:/core/macros/export
|
|||
tags: $:/tags/Macro
|
||||
|
||||
\define exportButton(exportFilter:"[!is[system]sort[title]]",lingoBase)
|
||||
<span class="tc-popup-keep">
|
||||
<$button popup=<<qualify "$:/state/popup/export">> tooltip={{$lingoBase$Hint}} aria-label={{$lingoBase$Caption}} class=<<tv-config-toolbar-class>> selectedClass="tc-selected">
|
||||
<$list filter="[<tv-config-toolbar-icons>prefix[yes]]">
|
||||
{{$:/core/images/export-button}}
|
||||
|
@ -10,6 +11,7 @@ tags: $:/tags/Macro
|
|||
<span class="tc-btn-text"><$text text={{$lingoBase$Caption}}/></span>
|
||||
</$list>
|
||||
</$button>
|
||||
</span>
|
||||
<$reveal state=<<qualify "$:/state/popup/export">> type="popup" position="below" animate="yes">
|
||||
<div class="tc-drop-down">
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/Exporter]]">
|
||||
|
|
|
@ -651,6 +651,10 @@ button.tc-untagged-label {
|
|||
font-size: 0.6em;
|
||||
}
|
||||
|
||||
.tc-tiddler-controls .tc-drop-down .tc-drop-down {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.tc-tiddler-controls button {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
@ -917,6 +921,10 @@ canvas.tc-edit-bitmapeditor {
|
|||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.tc-drop-down .tc-drop-down {
|
||||
margin-left: 14px;
|
||||
}
|
||||
|
||||
.tc-drop-down button svg, .tc-drop-down a svg {
|
||||
fill: <<colour foreground>>;
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue