TiddlyWiki5/core/modules/macros/list/listviews/cecily.js

136 lines
4.1 KiB
JavaScript

/*\
title: $:/core/modules/macros/list/listviews/cecily.js
type: application/javascript
module-type: listview
Views the list through a 2D map
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
function CecilyListView(listMacro) {
// The list macro we're attached to
this.listMacro = listMacro;
// Prepare the list frame
var listFrame = this.listMacro.listFrame,
listFrameDomNode = listFrame.domNode;
// Position the initial list entries on the map
this.loadMap();
for(var t=0; t<listFrame.children.length; t++) {
if(listFrame.children[t].listElementInfo) {
var domNode = listFrame.children[t].domNode,
title = listFrame.children[t].listElementInfo.title;
domNode.style.position = "absolute";
this.positionTiddler(title,domNode);
}
}
}
CecilyListView.prototype.getMapTiddlerTitle = function() {
return this.listMacro.params.map || "$:/TiddlerMap";
};
CecilyListView.prototype.loadMap = function() {
this.map = this.listMacro.wiki.getTiddlerData(this.getMapTiddlerTitle(),{
positions: {},
newTiddlerPosition: {x: 0, y: 0}
});
};
CecilyListView.prototype.saveMap = function() {
this.listMacro.wiki.setTiddlerData(this.getMapTiddlerTitle(),this.map);
};
// Get the position of a particular tiddler
CecilyListView.prototype.lookupTiddlerInMap = function(title,domNode) {
// First try looking it up in the map
if(this.map.positions[title]) {
return this.map.positions[title];
}
// If the tiddler wasn't in the map we'll have to compute it
var newPosition;
switch(this.map.positionNew) {
default: // "right"
newPosition = {
x: this.map.newTiddlerPosition.x,
y: this.map.newTiddlerPosition.y,
w: 100,
h: 100
};
this.map.newTiddlerPosition.x += newPosition.w * 1.2;
break;
}
// A default position
newPosition = newPosition || {x: 0,y: 0,w: 100,h: 100};
// Save the position back to the map
this.map.positions[title] = newPosition;
this.saveMap();
return newPosition;
};
CecilyListView.prototype.positionTiddler = function(title,domNode) {
var pos = this.lookupTiddlerInMap(title,domNode),
scale = pos.w/domNode.offsetWidth;
domNode.setAttribute("data-tw-zoom",JSON.stringify(pos));
$tw.utils.setStyle(domNode,[
{transformOrigin: "0% 0%"},
{transform: "translateX(" + pos.x + "px) translateY(" + pos.y + "px) scale(" + scale + ")"}
]);
};
CecilyListView.prototype.navigateTo = function(historyInfo) {
var listElementIndex = this.listMacro.findListElementByTitle(0,historyInfo.title),
listElementNode = this.listMacro.listFrame.children[listElementIndex],
targetElement = listElementNode.domNode;
// Scroll the node into view
var scrollEvent = document.createEvent("Event");
scrollEvent.initEvent("tw-scroll",true,true);
targetElement.dispatchEvent(scrollEvent);
};
CecilyListView.prototype.insert = function(index) {
var listElementNode = this.listMacro.listFrame.children[index],
targetElement = listElementNode.domNode;
targetElement.style.position = "absolute";
$tw.utils.setStyle(targetElement,[
{transition: ""},
{opacity: "0.0"}
]);
this.positionTiddler(listElementNode.listElementInfo.title,targetElement);
$tw.utils.forceLayout(targetElement);
$tw.utils.setStyle(targetElement,[
{transition: "opacity " + $tw.config.preferences.animationDurationMs + " ease-out"},
{opacity: "1.0"}
]);
};
CecilyListView.prototype.remove = function(index) {
var listElementNode = this.listMacro.listFrame.children[index],
targetElement = listElementNode.domNode;
// Attach an event handler for the end of the transition
targetElement.addEventListener($tw.utils.convertEventName("transitionEnd"),function(event) {
if(targetElement.parentNode) {
targetElement.parentNode.removeChild(targetElement);
}
},false);
// Animate the closure
$tw.utils.setStyle(targetElement,[
{transition: "opacity " + $tw.config.preferences.animationDurationMs + " ease-out"},
{opacity: "1.0"}
]);
$tw.utils.forceLayout(targetElement);
$tw.utils.setStyle(targetElement,[
{opacity: "0.0"}
]);
// Returning true causes the DOM node not to be deleted
return true;
};
exports.cecily = CecilyListView;
})();