mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2025-01-28 18:04:44 +00:00
Fixes to make nested popups work
Thus making the export button a lot more useful
This commit is contained in:
parent
27c9e7269e
commit
b882a0dff1
@ -19,40 +19,7 @@ Creates a Popup object with these options:
|
|||||||
var Popup = function(options) {
|
var Popup = function(options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
this.rootElement = options.rootElement || document.body;
|
this.rootElement = options.rootElement || document.body;
|
||||||
};
|
this.popups = []; // Array of {title:,wiki:,domNode:} objects
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -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
|
title: title of the tiddler where the popup details are stored
|
||||||
domNode: dom node to which the popup will be positioned
|
domNode: dom node to which the popup will be positioned
|
||||||
wiki: wiki
|
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) {
|
Popup.prototype.triggerPopup = function(options) {
|
||||||
// Get the current popup state tiddler
|
console.log("triggerPopup",options)
|
||||||
var value = options.wiki.getTextReference(options.title,"");
|
// Check if this popup is already active
|
||||||
// Check if the popup is open by checking whether it matches "(<x>,<y>)"
|
var index = -1;
|
||||||
var state = !this.readPopupState(options.title,value);
|
for(var t=0; t<this.popups.length; t++) {
|
||||||
if("force" in options) {
|
if(this.popups[t].title === options.title) {
|
||||||
|
index = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Compute the new state
|
||||||
|
var state = index === -1;
|
||||||
|
if(options.force !== undefined) {
|
||||||
state = options.force;
|
state = options.force;
|
||||||
}
|
}
|
||||||
|
// Show or cancel the popup according to the new state
|
||||||
if(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);
|
this.show(options);
|
||||||
} else {
|
} 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
|
Returns true if the specified title and text identifies an active popup
|
||||||
*/
|
*/
|
||||||
Popup.prototype.readPopupState = function(title,text) {
|
Popup.prototype.readPopupState = function(text) {
|
||||||
var popupLocationRegExp = /^\((-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+)\)$/,
|
console.log("readPopupState",text)
|
||||||
result = false;
|
var popupLocationRegExp = /^\((-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+)\)$/;
|
||||||
if(this.title === title) {
|
return popupLocationRegExp.test(text);
|
||||||
result = popupLocationRegExp.test(text);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.Popup = Popup;
|
exports.Popup = Popup;
|
||||||
|
@ -462,20 +462,24 @@ Returns an object with the following fields, all optional:
|
|||||||
exports.parseTextReference = function(textRef) {
|
exports.parseTextReference = function(textRef) {
|
||||||
// Separate out the title, field name and/or JSON indices
|
// Separate out the title, field name and/or JSON indices
|
||||||
var reTextRef = /^\s*([^!#]+)?(?:(?:!!([^\s]+))|(?:##(.+)))?\s*/mg,
|
var reTextRef = /^\s*([^!#]+)?(?:(?:!!([^\s]+))|(?:##(.+)))?\s*/mg,
|
||||||
match = reTextRef.exec(textRef);
|
match = reTextRef.exec(textRef),
|
||||||
|
result = {};
|
||||||
if(match && reTextRef.lastIndex === textRef.length) {
|
if(match && reTextRef.lastIndex === textRef.length) {
|
||||||
// Return the parts
|
// Return the parts
|
||||||
return {
|
if(match[1]) {
|
||||||
title: match[1],
|
result.title = match[1];
|
||||||
field: match[2],
|
}
|
||||||
index: match[3]
|
if(match[2]) {
|
||||||
};
|
result.field = match[2];
|
||||||
|
}
|
||||||
|
if(match[3]) {
|
||||||
|
result.index = match[3];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// If we couldn't parse it (eg it started with a)
|
// If we couldn't parse it
|
||||||
return {
|
result.title = textRef
|
||||||
title: textRef
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -36,15 +36,19 @@ ButtonWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
// Create element
|
// Create element
|
||||||
var domNode = this.document.createElement("button");
|
var domNode = this.document.createElement("button");
|
||||||
// Assign classes
|
// Assign classes
|
||||||
var classes = this["class"].split(" ") || [];
|
var classes = this["class"].split(" ") || [],
|
||||||
|
isPoppedUp = this.popup && this.isPoppedUp();
|
||||||
if(this.selectedClass) {
|
if(this.selectedClass) {
|
||||||
if(this.set && this.setTo && this.isSelected()) {
|
if(this.set && this.setTo && this.isSelected()) {
|
||||||
$tw.utils.pushTop(classes,this.selectedClass.split(" "));
|
$tw.utils.pushTop(classes,this.selectedClass.split(" "));
|
||||||
}
|
}
|
||||||
if(this.popup && this.isPoppedUp()) {
|
if(isPoppedUp) {
|
||||||
$tw.utils.pushTop(classes,this.selectedClass.split(" "));
|
$tw.utils.pushTop(classes,this.selectedClass.split(" "));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(isPoppedUp) {
|
||||||
|
$tw.utils.pushTop(classes,"tc-popup-handle");
|
||||||
|
}
|
||||||
domNode.className = classes.join(" ");
|
domNode.className = classes.join(" ");
|
||||||
// Assign other attributes
|
// Assign other attributes
|
||||||
if(this.style) {
|
if(this.style) {
|
||||||
@ -101,7 +105,7 @@ ButtonWidget.prototype.isSelected = function() {
|
|||||||
|
|
||||||
ButtonWidget.prototype.isPoppedUp = function() {
|
ButtonWidget.prototype.isPoppedUp = function() {
|
||||||
var tiddler = this.wiki.getTiddler(this.popup);
|
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;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ description: {{$:/language/Buttons/Language/Hint}}
|
|||||||
\define flag-title()
|
\define flag-title()
|
||||||
$(languagePluginTitle)$/icon
|
$(languagePluginTitle)$/icon
|
||||||
\end
|
\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">
|
<$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]]">
|
<$list filter="[<tv-config-toolbar-icons>prefix[yes]]">
|
||||||
<span class="tc-image-button">
|
<span class="tc-image-button">
|
||||||
@ -18,6 +19,7 @@ $(languagePluginTitle)$/icon
|
|||||||
<span class="tc-btn-text"><$text text={{$:/language/Buttons/Language/Caption}}/></span>
|
<span class="tc-btn-text"><$text text={{$:/language/Buttons/Language/Caption}}/></span>
|
||||||
</$list>
|
</$list>
|
||||||
</$button>
|
</$button>
|
||||||
|
</span>
|
||||||
<$reveal state=<<qualify "$:/state/popup/language">> type="popup" position="below" animate="yes">
|
<$reveal state=<<qualify "$:/state/popup/language">> type="popup" position="below" animate="yes">
|
||||||
<div class="tc-drop-down tc-drop-down-language-chooser">
|
<div class="tc-drop-down tc-drop-down-language-chooser">
|
||||||
<$linkcatcher to="$:/language">
|
<$linkcatcher to="$:/language">
|
||||||
|
@ -6,6 +6,7 @@ description: {{$:/language/Buttons/StoryView/Hint}}
|
|||||||
\define icon()
|
\define icon()
|
||||||
$:/core/images/storyview-$(storyview)$
|
$:/core/images/storyview-$(storyview)$
|
||||||
\end
|
\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">
|
<$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]]">
|
<$list filter="[<tv-config-toolbar-icons>prefix[yes]]">
|
||||||
<$set name="storyview" value={{$:/view}}>
|
<$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>
|
<span class="tc-btn-text"><$text text={{$:/language/Buttons/StoryView/Caption}}/></span>
|
||||||
</$list>
|
</$list>
|
||||||
</$button>
|
</$button>
|
||||||
|
</span>
|
||||||
<$reveal state=<<qualify "$:/state/popup/storyview">> type="popup" position="below" animate="yes">
|
<$reveal state=<<qualify "$:/state/popup/storyview">> type="popup" position="below" animate="yes">
|
||||||
<div class="tc-drop-down">
|
<div class="tc-drop-down">
|
||||||
<$linkcatcher to="$:/view">
|
<$linkcatcher to="$:/view">
|
||||||
|
@ -3,6 +3,7 @@ tags: $:/tags/PageControls
|
|||||||
caption: {{$:/core/images/theme-button}} {{$:/language/Buttons/Theme/Caption}}
|
caption: {{$:/core/images/theme-button}} {{$:/language/Buttons/Theme/Caption}}
|
||||||
description: {{$:/language/Buttons/Theme/Hint}}
|
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">
|
<$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]]">
|
<$list filter="[<tv-config-toolbar-icons>prefix[yes]]">
|
||||||
{{$:/core/images/theme-button}}
|
{{$:/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>
|
<span class="tc-btn-text"><$text text={{$:/language/Buttons/Theme/Caption}}/></span>
|
||||||
</$list>
|
</$list>
|
||||||
</$button>
|
</$button>
|
||||||
|
</span>
|
||||||
<$reveal state=<<qualify "$:/state/popup/theme">> type="popup" position="below" animate="yes">
|
<$reveal state=<<qualify "$:/state/popup/theme">> type="popup" position="below" animate="yes">
|
||||||
<div class="tc-drop-down">
|
<div class="tc-drop-down">
|
||||||
<$linkcatcher to="$:/theme">
|
<$linkcatcher to="$:/theme">
|
||||||
|
@ -29,7 +29,7 @@ $:/config/ViewToolbarButtons/Visibility/$(listItem)$
|
|||||||
</$list>
|
</$list>
|
||||||
</div>
|
</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"/>
|
<$transclude tiddler="$:/core/ui/TiddlerInfo"/>
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ title: $:/core/macros/export
|
|||||||
tags: $:/tags/Macro
|
tags: $:/tags/Macro
|
||||||
|
|
||||||
\define exportButton(exportFilter:"[!is[system]sort[title]]",lingoBase)
|
\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">
|
<$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]]">
|
<$list filter="[<tv-config-toolbar-icons>prefix[yes]]">
|
||||||
{{$:/core/images/export-button}}
|
{{$:/core/images/export-button}}
|
||||||
@ -10,6 +11,7 @@ tags: $:/tags/Macro
|
|||||||
<span class="tc-btn-text"><$text text={{$lingoBase$Caption}}/></span>
|
<span class="tc-btn-text"><$text text={{$lingoBase$Caption}}/></span>
|
||||||
</$list>
|
</$list>
|
||||||
</$button>
|
</$button>
|
||||||
|
</span>
|
||||||
<$reveal state=<<qualify "$:/state/popup/export">> type="popup" position="below" animate="yes">
|
<$reveal state=<<qualify "$:/state/popup/export">> type="popup" position="below" animate="yes">
|
||||||
<div class="tc-drop-down">
|
<div class="tc-drop-down">
|
||||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/Exporter]]">
|
<$list filter="[all[shadows+tiddlers]tag[$:/tags/Exporter]]">
|
||||||
|
@ -651,6 +651,10 @@ button.tc-untagged-label {
|
|||||||
font-size: 0.6em;
|
font-size: 0.6em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tc-tiddler-controls .tc-drop-down .tc-drop-down {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
.tc-tiddler-controls button {
|
.tc-tiddler-controls button {
|
||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
}
|
}
|
||||||
@ -917,6 +921,10 @@ canvas.tc-edit-bitmapeditor {
|
|||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tc-drop-down .tc-drop-down {
|
||||||
|
margin-left: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
.tc-drop-down button svg, .tc-drop-down a svg {
|
.tc-drop-down button svg, .tc-drop-down a svg {
|
||||||
fill: <<colour foreground>>;
|
fill: <<colour foreground>>;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user