mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-30 01:36:24 +01:00 
			
		
		
		
	various widget refactorings
This commit is contained in:
		| @@ -35,7 +35,7 @@ import treeCache from './tree_cache.js'; | ||||
| import noteTooltipService from './note_tooltip.js'; | ||||
| import protectedSessionService from './protected_session.js'; | ||||
| import dateNotesService from './date_notes.js'; | ||||
| import StandardWidget from '../widgets/standard_widget.js'; | ||||
| import StandardWidget from '../widgets/collapsible_widget.js'; | ||||
| import ws from "./ws.js"; | ||||
| import hoistedNoteService from "./hoisted_note.js"; | ||||
| import appContext from "./app_context.js"; | ||||
|   | ||||
| @@ -24,26 +24,10 @@ | ||||
|  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||||
|  * OTHER DEALINGS IN THE SOFTWARE. | ||||
|  */ | ||||
| (function (root, factory) { | ||||
|     if (typeof define === 'function' && define.amd) { | ||||
|         // AMD. Register as an anonymous module. | ||||
|         define(function () { | ||||
|             return (root.returnExportsGlobal = factory()); | ||||
|         }); | ||||
|     } else if (typeof exports === 'object') { | ||||
|         // Node. Does not work with strict CommonJS, but | ||||
|         // only CommonJS-like enviroments that support module.exports, | ||||
|         // like Node. | ||||
|         module.exports = factory(); | ||||
|     } else { | ||||
|         // Browser globals | ||||
|         root.Springy = factory(); | ||||
|     } | ||||
| }(this, function() { | ||||
| window.Springy = function() { | ||||
| 	const Springy = {}; | ||||
|  | ||||
| 	var Springy = {}; | ||||
|  | ||||
| 	var Graph = Springy.Graph = function() { | ||||
| 	const Graph = Springy.Graph = function () { | ||||
| 		this.nodeSet = {}; | ||||
| 		this.nodes = []; | ||||
| 		this.edges = []; | ||||
| @@ -54,25 +38,25 @@ | ||||
| 		this.eventListeners = []; | ||||
| 	}; | ||||
|  | ||||
| 	var Node = Springy.Node = function(id, data) { | ||||
| 	const Node = Springy.Node = function (id, data) { | ||||
| 		this.id = id; | ||||
| 		this.data = (data !== undefined) ? data : {}; | ||||
|  | ||||
| 	// Data fields used by layout algorithm in this file: | ||||
| 	// this.data.mass | ||||
| 	// Data used by default renderer in springyui.js | ||||
| 	// this.data.label | ||||
| 		// Data fields used by layout algorithm in this file: | ||||
| 		// this.data.mass | ||||
| 		// Data used by default renderer in springyui.js | ||||
| 		// this.data.label | ||||
| 	}; | ||||
|  | ||||
| 	var Edge = Springy.Edge = function(id, source, target, data) { | ||||
| 	const Edge = Springy.Edge = function (id, source, target, data) { | ||||
| 		this.id = id; | ||||
| 		this.source = source; | ||||
| 		this.target = target; | ||||
| 		this.data = (data !== undefined) ? data : {}; | ||||
|  | ||||
| 	// Edge data field used by layout alorithm | ||||
| 	// this.data.length | ||||
| 	// this.data.type | ||||
| 		// Edge data field used by layout alorithm | ||||
| 		// this.data.length | ||||
| 		// this.data.type | ||||
| 	}; | ||||
|  | ||||
| 	Graph.prototype.addNode = function(node) { | ||||
| @@ -89,15 +73,15 @@ | ||||
| 	Graph.prototype.addNodes = function() { | ||||
| 		// accepts variable number of arguments, where each argument | ||||
| 		// is a string that becomes both node identifier and label | ||||
| 		for (var i = 0; i < arguments.length; i++) { | ||||
| 			var name = arguments[i]; | ||||
| 			var node = new Node(name, {label:name}); | ||||
| 		for (let i = 0; i < arguments.length; i++) { | ||||
| 			const name = arguments[i]; | ||||
| 			const node = new Node(name, {label: name}); | ||||
| 			this.addNode(node); | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	Graph.prototype.addEdge = function(edge) { | ||||
| 		var exists = false; | ||||
| 		let exists = false; | ||||
| 		this.edges.forEach(function(e) { | ||||
| 			if (edge.id === e.id) { exists = true; } | ||||
| 		}); | ||||
| @@ -129,30 +113,30 @@ | ||||
| 	Graph.prototype.addEdges = function() { | ||||
| 		// accepts variable number of arguments, where each argument | ||||
| 		// is a triple [nodeid1, nodeid2, attributes] | ||||
| 		for (var i = 0; i < arguments.length; i++) { | ||||
| 			var e = arguments[i]; | ||||
| 			var node1 = this.nodeSet[e[0]]; | ||||
| 		for (let i = 0; i < arguments.length; i++) { | ||||
| 			const e = arguments[i]; | ||||
| 			const node1 = this.nodeSet[e[0]]; | ||||
| 			if (node1 == undefined) { | ||||
| 				throw new TypeError("invalid node name: " + e[0]); | ||||
| 			} | ||||
| 			var node2 = this.nodeSet[e[1]]; | ||||
| 			const node2 = this.nodeSet[e[1]]; | ||||
| 			if (node2 == undefined) { | ||||
| 				throw new TypeError("invalid node name: " + e[1]); | ||||
| 			} | ||||
| 			var attr = e[2]; | ||||
| 			const attr = e[2]; | ||||
|  | ||||
| 			this.newEdge(node1, node2, attr); | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	Graph.prototype.newNode = function(data) { | ||||
| 		var node = new Node(this.nextNodeId++, data); | ||||
| 		const node = new Node(this.nextNodeId++, data); | ||||
| 		this.addNode(node); | ||||
| 		return node; | ||||
| 	}; | ||||
|  | ||||
| 	Graph.prototype.newEdge = function(source, target, data) { | ||||
| 		var edge = new Edge(this.nextEdgeId++, source, target, data); | ||||
| 		const edge = new Edge(this.nextEdgeId++, source, target, data); | ||||
| 		this.addEdge(edge); | ||||
| 		return edge; | ||||
| 	}; | ||||
| @@ -210,7 +194,7 @@ | ||||
| 			delete this.nodeSet[node.id]; | ||||
| 		} | ||||
|  | ||||
| 		for (var i = this.nodes.length - 1; i >= 0; i--) { | ||||
| 		for (let i = this.nodes.length - 1; i >= 0; i--) { | ||||
| 			if (this.nodes[i].id === node.id) { | ||||
| 				this.nodes.splice(i, 1); | ||||
| 			} | ||||
| @@ -221,7 +205,7 @@ | ||||
|  | ||||
| 	// removes edges associated with a given node | ||||
| 	Graph.prototype.detachNode = function(node) { | ||||
| 		var tmpEdges = this.edges.slice(); | ||||
| 		const tmpEdges = this.edges.slice(); | ||||
| 		tmpEdges.forEach(function(e) { | ||||
| 			if (e.source.id === node.id || e.target.id === node.id) { | ||||
| 				this.removeEdge(e); | ||||
| @@ -233,17 +217,17 @@ | ||||
|  | ||||
| 	// remove a node and it's associated edges from the graph | ||||
| 	Graph.prototype.removeEdge = function(edge) { | ||||
| 		for (var i = this.edges.length - 1; i >= 0; i--) { | ||||
| 		for (let i = this.edges.length - 1; i >= 0; i--) { | ||||
| 			if (this.edges[i].id === edge.id) { | ||||
| 				this.edges.splice(i, 1); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		for (var x in this.adjacency) { | ||||
| 			for (var y in this.adjacency[x]) { | ||||
| 				var edges = this.adjacency[x][y]; | ||||
| 		for (const x in this.adjacency) { | ||||
| 			for (const y in this.adjacency[x]) { | ||||
| 				const edges = this.adjacency[x][y]; | ||||
|  | ||||
| 				for (var j=edges.length - 1; j>=0; j--) { | ||||
| 				for (let j = edges.length - 1; j >= 0; j--) { | ||||
| 					if (this.adjacency[x][y][j].id === edge.id) { | ||||
| 						this.adjacency[x][y].splice(j, 1); | ||||
| 					} | ||||
| @@ -276,28 +260,28 @@ | ||||
| 	} | ||||
| 	*/ | ||||
| 	Graph.prototype.merge = function(data) { | ||||
| 		var nodes = []; | ||||
| 		const nodes = []; | ||||
| 		data.nodes.forEach(function(n) { | ||||
| 			nodes.push(this.addNode(new Node(n.id, n.data))); | ||||
| 		}, this); | ||||
|  | ||||
| 		data.edges.forEach(function(e) { | ||||
| 			var from = nodes[e.from]; | ||||
| 			var to = nodes[e.to]; | ||||
| 			const from = nodes[e.from]; | ||||
| 			const to = nodes[e.to]; | ||||
|  | ||||
| 			var id = (e.directed) | ||||
| 				? (id = e.type + "-" + from.id + "-" + to.id) | ||||
| 			let id = (e.directed) | ||||
| 				? (e.type + "-" + from.id + "-" + to.id) | ||||
| 				: (from.id < to.id) // normalise id for non-directed edges | ||||
| 					? e.type + "-" + from.id + "-" + to.id | ||||
| 					: e.type + "-" + to.id + "-" + from.id; | ||||
|  | ||||
| 			var edge = this.addEdge(new Edge(id, from, to, e.data)); | ||||
| 			const edge = this.addEdge(new Edge(id, from, to, e.data)); | ||||
| 			edge.data.type = e.type; | ||||
| 		}, this); | ||||
| 	}; | ||||
|  | ||||
| 	Graph.prototype.filterNodes = function(fn) { | ||||
| 		var tmpNodes = this.nodes.slice(); | ||||
| 		const tmpNodes = this.nodes.slice(); | ||||
| 		tmpNodes.forEach(function(n) { | ||||
| 			if (!fn(n)) { | ||||
| 				this.removeNode(n); | ||||
| @@ -306,7 +290,7 @@ | ||||
| 	}; | ||||
|  | ||||
| 	Graph.prototype.filterEdges = function(fn) { | ||||
| 		var tmpEdges = this.edges.slice(); | ||||
| 		const tmpEdges = this.edges.slice(); | ||||
| 		tmpEdges.forEach(function(e) { | ||||
| 			if (!fn(e)) { | ||||
| 				this.removeEdge(e); | ||||
| @@ -326,9 +310,10 @@ | ||||
| 	}; | ||||
|  | ||||
| 	// ----------- | ||||
| 	var Layout = Springy.Layout = {}; | ||||
| 	Layout.ForceDirected = function(graph, stiffness, repulsion, damping, minEnergyThreshold, maxSpeed) { | ||||
| 	const Layout = Springy.Layout = {}; | ||||
| 	Layout.ForceDirected = function(graph, stopCheckerCallback, stiffness, repulsion, damping, minEnergyThreshold, maxSpeed) { | ||||
| 		this.graph = graph; | ||||
| 		this.stopCheckerCallback = stopCheckerCallback || (() => false); | ||||
| 		this.stiffness = stiffness; // spring stiffness constant | ||||
| 		this.repulsion = repulsion; // repulsion constant | ||||
| 		this.damping = damping; // velocity damping factor | ||||
| @@ -341,7 +326,7 @@ | ||||
|  | ||||
| 	Layout.ForceDirected.prototype.point = function(node) { | ||||
| 		if (!(node.id in this.nodePoints)) { | ||||
| 			var mass = (node.data.mass !== undefined) ? node.data.mass : 1.0; | ||||
| 			const mass = (node.data.mass !== undefined) ? node.data.mass : 1.0; | ||||
| 			this.nodePoints[node.id] = new Layout.ForceDirected.Point(Vector.random(), mass); | ||||
| 		} | ||||
|  | ||||
| @@ -350,11 +335,11 @@ | ||||
|  | ||||
| 	Layout.ForceDirected.prototype.spring = function(edge) { | ||||
| 		if (!(edge.id in this.edgeSprings)) { | ||||
| 			var length = (edge.data.length !== undefined) ? edge.data.length : 1.0; | ||||
| 			const length = (edge.data.length !== undefined) ? edge.data.length : 1.0; | ||||
|  | ||||
| 			var existingSpring = false; | ||||
| 			let existingSpring = false; | ||||
|  | ||||
| 			var from = this.graph.getEdges(edge.source, edge.target); | ||||
| 			const from = this.graph.getEdges(edge.source, edge.target); | ||||
| 			from.forEach(function(e) { | ||||
| 				if (existingSpring === false && e.id in this.edgeSprings) { | ||||
| 					existingSpring = this.edgeSprings[e.id]; | ||||
| @@ -365,8 +350,8 @@ | ||||
| 				return new Layout.ForceDirected.Spring(existingSpring.point1, existingSpring.point2, 0.0, 0.0); | ||||
| 			} | ||||
|  | ||||
| 			var to = this.graph.getEdges(edge.target, edge.source); | ||||
| 			from.forEach(function(e){ | ||||
| 			const to = this.graph.getEdges(edge.target, edge.source); | ||||
| 			to.forEach(function(e){ | ||||
| 				if (existingSpring === false && e.id in this.edgeSprings) { | ||||
| 					existingSpring = this.edgeSprings[e.id]; | ||||
| 				} | ||||
| @@ -386,7 +371,7 @@ | ||||
|  | ||||
| 	// callback should accept two arguments: Node, Point | ||||
| 	Layout.ForceDirected.prototype.eachNode = function(callback) { | ||||
| 		var t = this; | ||||
| 		const t = this; | ||||
| 		this.graph.nodes.forEach(function(n){ | ||||
| 			callback.call(t, n, t.point(n)); | ||||
| 		}); | ||||
| @@ -394,7 +379,7 @@ | ||||
|  | ||||
| 	// callback should accept two arguments: Edge, Spring | ||||
| 	Layout.ForceDirected.prototype.eachEdge = function(callback) { | ||||
| 		var t = this; | ||||
| 		const t = this; | ||||
| 		this.graph.edges.forEach(function(e){ | ||||
| 			callback.call(t, e, t.spring(e)); | ||||
| 		}); | ||||
| @@ -402,7 +387,7 @@ | ||||
|  | ||||
| 	// callback should accept one argument: Spring | ||||
| 	Layout.ForceDirected.prototype.eachSpring = function(callback) { | ||||
| 		var t = this; | ||||
| 		const t = this; | ||||
| 		this.graph.edges.forEach(function(e){ | ||||
| 			callback.call(t, t.spring(e)); | ||||
| 		}); | ||||
| @@ -413,12 +398,11 @@ | ||||
| 	Layout.ForceDirected.prototype.applyCoulombsLaw = function() { | ||||
| 		this.eachNode(function(n1, point1) { | ||||
| 			this.eachNode(function(n2, point2) { | ||||
| 				if (point1 !== point2) | ||||
| 				{ | ||||
| 					var d = point1.p.subtract(point2.p); | ||||
| 					var distance = d.magnitude() + 0.1; // avoid massive forces at small distances (and divide by zero) | ||||
| 				if (point1 !== point2) { | ||||
| 					const d = point1.p.subtract(point2.p); | ||||
| 					const distance = d.magnitude() + 0.1; // avoid massive forces at small distances (and divide by zero) | ||||
|  | ||||
| 					var direction = d.normalise(); | ||||
| 					const direction = d.normalise(); | ||||
|  | ||||
| 					// apply force to each end point | ||||
| 					point1.applyForce(direction.multiply(this.repulsion).divide(distance * distance * distance * 0.5)); | ||||
| @@ -430,9 +414,9 @@ | ||||
|  | ||||
| 	Layout.ForceDirected.prototype.applyHookesLaw = function() { | ||||
| 		this.eachSpring(function(spring){ | ||||
| 			var d = spring.point2.p.subtract(spring.point1.p); // the direction of the spring | ||||
| 			var displacement = spring.length - d.magnitude(); | ||||
| 			var direction = d.normalise(); | ||||
| 			const d = spring.point2.p.subtract(spring.point1.p); // the direction of the spring | ||||
| 			const displacement = spring.length - d.magnitude(); | ||||
| 			const direction = d.normalise(); | ||||
|  | ||||
| 			// apply force to each end point | ||||
| 			spring.point1.applyForce(direction.multiply(spring.k * displacement * -0.5)); | ||||
| @@ -442,7 +426,7 @@ | ||||
|  | ||||
| 	Layout.ForceDirected.prototype.attractToCentre = function() { | ||||
| 		this.eachNode(function(node, point) { | ||||
| 			var direction = point.p.multiply(-1.0); | ||||
| 			const direction = point.p.multiply(-1.0); | ||||
| 			point.applyForce(direction.multiply(this.repulsion / 50.0)); | ||||
| 		}); | ||||
| 	}; | ||||
| @@ -470,9 +454,9 @@ | ||||
|  | ||||
| 	// Calculate the total kinetic energy of the system | ||||
| 	Layout.ForceDirected.prototype.totalEnergy = function(timestep) { | ||||
| 		var energy = 0.0; | ||||
| 		let energy = 0.0; | ||||
| 		this.eachNode(function(node, point) { | ||||
| 			var speed = point.v.magnitude(); | ||||
| 			const speed = point.v.magnitude(); | ||||
| 			energy += 0.5 * point.m * speed * speed; | ||||
| 		}); | ||||
|  | ||||
| @@ -484,7 +468,7 @@ | ||||
| 	 * In case it's running then the call is ignored, and none of the callbacks passed is ever executed. | ||||
| 	 */ | ||||
| 	Layout.ForceDirected.prototype.start = function(onRenderStop) { | ||||
| 		var t = this; | ||||
| 		const t = this; | ||||
|  | ||||
| 		if (this._started) return; | ||||
| 		this._started = true; | ||||
| @@ -493,6 +477,10 @@ | ||||
| 		function step() { | ||||
| 			t.tick(0.03); | ||||
|  | ||||
| 			if (t.stopCheckerCallback()) { | ||||
| 				onRenderStop(); | ||||
| 			} | ||||
|  | ||||
| 			// stop simulation when energy of the system goes below a threshold | ||||
| 			if (t._stop || t.totalEnergy() < t.minEnergyThreshold) { | ||||
| 				t._started = false; | ||||
| @@ -519,11 +507,11 @@ | ||||
|  | ||||
| 	// Find the nearest point to a particular position | ||||
| 	Layout.ForceDirected.prototype.nearest = function(pos) { | ||||
| 		var min = {node: null, point: null, distance: null}; | ||||
| 		var t = this; | ||||
| 		let min = {node: null, point: null, distance: null}; | ||||
| 		const t = this; | ||||
| 		this.graph.nodes.forEach(function(n){ | ||||
| 			var point = t.point(n); | ||||
| 			var distance = point.p.subtract(pos).magnitude(); | ||||
| 			const point = t.point(n); | ||||
| 			const distance = point.p.subtract(pos).magnitude(); | ||||
|  | ||||
| 			if (min.distance === null || distance < min.distance) { | ||||
| 				min = {node: n, point: point, distance: distance}; | ||||
| @@ -535,8 +523,8 @@ | ||||
|  | ||||
| 	// returns [bottomleft, topright] | ||||
| 	Layout.ForceDirected.prototype.getBoundingBox = function() { | ||||
| 		var bottomleft = new Vector(-2,-2); | ||||
| 		var topright = new Vector(2,2); | ||||
| 		const bottomleft = new Vector(-2, -2); | ||||
| 		const topright = new Vector(2, 2); | ||||
|  | ||||
| 		this.eachNode(function(n, point) { | ||||
| 			if (point.p.x < bottomleft.x) { | ||||
| @@ -553,14 +541,14 @@ | ||||
| 			} | ||||
| 		}); | ||||
|  | ||||
| 		var padding = topright.subtract(bottomleft).multiply(0.07); // ~5% padding | ||||
| 		const padding = topright.subtract(bottomleft).multiply(0.07); // ~5% padding | ||||
|  | ||||
| 		return {bottomleft: bottomleft.subtract(padding), topright: topright.add(padding)}; | ||||
| 	}; | ||||
|  | ||||
|  | ||||
| 	// Vector | ||||
| 	var Vector = Springy.Vector = function(x, y) { | ||||
| 	const Vector = Springy.Vector = function(x, y) { | ||||
| 		this.x = x; | ||||
| 		this.y = y; | ||||
| 	}; | ||||
| @@ -629,10 +617,8 @@ | ||||
| 	/** | ||||
| 	 * Renderer handles the layout rendering loop | ||||
| 	 */ | ||||
| 	var Renderer = Springy.Renderer = function(layout, onRenderStop) { | ||||
| 	const Renderer = Springy.Renderer = function (layout) { | ||||
| 		this.layout = layout; | ||||
| 		this.onRenderStop = onRenderStop; | ||||
|  | ||||
| 		this.layout.graph.addGraphListener(this); | ||||
| 	}; | ||||
|  | ||||
| @@ -657,8 +643,8 @@ | ||||
| 		this.layout.stop(); | ||||
| 	}; | ||||
|  | ||||
| 	var isEmpty = function(obj) { | ||||
| 		for (var k in obj) { | ||||
| 	const isEmpty = function(obj) { | ||||
| 		for (const k in obj) { | ||||
| 			if (obj.hasOwnProperty(k)) { | ||||
| 				return false; | ||||
| 			} | ||||
| @@ -667,4 +653,4 @@ | ||||
| 	}; | ||||
|  | ||||
|   return Springy; | ||||
| })); | ||||
| }(); | ||||
|   | ||||
| @@ -29,6 +29,7 @@ import protectedSessionHolder from "./protected_session_holder.js"; | ||||
| import bundleService from "./bundle.js"; | ||||
| import DialogEventComponent from "./dialog_events.js"; | ||||
| import Entrypoints from "./entrypoints.js"; | ||||
| import CalendarWidget from "../widgets/calendar.js"; | ||||
|  | ||||
| class AppContext { | ||||
|     constructor() { | ||||
| @@ -98,6 +99,7 @@ class AppContext { | ||||
|  | ||||
|         const rightPaneWidgets = [ | ||||
|             new NoteInfoWidget(this), | ||||
|             new TabCachingWidget(this, () => new CalendarWidget(this)), | ||||
|             new TabCachingWidget(this, () => new AttributesWidget(this)), | ||||
|             new TabCachingWidget(this, () => new LinkMapWidget(this)), | ||||
|             new TabCachingWidget(this, () => new NoteRevisionsWidget(this)), | ||||
|   | ||||
| @@ -7,7 +7,7 @@ import treeCache from './tree_cache.js'; | ||||
| import noteTooltipService from './note_tooltip.js'; | ||||
| import protectedSessionService from './protected_session.js'; | ||||
| import dateNotesService from './date_notes.js'; | ||||
| import CollapsibleWidget from '../widgets/standard_widget.js'; | ||||
| import CollapsibleWidget from '../widgets/collapsible_widget.js'; | ||||
| import ws from "./ws.js"; | ||||
| import hoistedNoteService from "./hoisted_note.js"; | ||||
| import appContext from "./app_context.js"; | ||||
|   | ||||
| @@ -19,7 +19,8 @@ export default class LinkMap { | ||||
|         this.options = Object.assign({ | ||||
|             maxDepth: 10, | ||||
|             maxNotes: 30, | ||||
|             zoom: 1.0 | ||||
|             zoom: 1.0, | ||||
|             stopCheckerCallback: () => false | ||||
|         }, options); | ||||
|  | ||||
|         this.$linkMapContainer = $linkMapContainer; | ||||
| @@ -30,6 +31,10 @@ export default class LinkMap { | ||||
|         await libraryLoader.requireLibrary(libraryLoader.LINK_MAP); | ||||
|  | ||||
|         jsPlumb.ready(() => { | ||||
|             if (this.options.stopCheckerCallback()) { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             this.initJsPlumbInstance(); | ||||
|  | ||||
|             this.initPanZoom(); | ||||
| @@ -43,6 +48,10 @@ export default class LinkMap { | ||||
|  | ||||
|         this.cleanup(); | ||||
|  | ||||
|         if (this.options.stopCheckerCallback()) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         const links = await server.post(`notes/${this.note.noteId}/link-map`, { | ||||
|             maxNotes: this.options.maxNotes, | ||||
|             maxDepth: this.options.maxDepth | ||||
| @@ -63,6 +72,7 @@ export default class LinkMap { | ||||
|  | ||||
|         const layout = new Springy.Layout.ForceDirected( | ||||
|             graph, | ||||
|             this.options.stopCheckerCallback, | ||||
|             // param explanation here: https://github.com/dhotson/springy/issues/58 | ||||
|             400.0, // Spring stiffness | ||||
|             600.0, // Node repulsion | ||||
| @@ -122,6 +132,10 @@ export default class LinkMap { | ||||
|             return $noteBox; | ||||
|         }; | ||||
|  | ||||
|         if (this.options.stopCheckerCallback()) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         this.renderer = new Springy.Renderer(layout); | ||||
|         await this.renderer.start(500); | ||||
|  | ||||
|   | ||||
| @@ -461,7 +461,7 @@ async function duplicateNote(noteId, parentNoteId) { | ||||
|  | ||||
|     await ws.waitForMaxKnownSyncId(); | ||||
|  | ||||
|     await activateNote(note.noteId); | ||||
|     await appContext.activateOrOpenNote(note.noteId); | ||||
|  | ||||
|     const origNote = await treeCache.getNote(noteId); | ||||
|     toastService.showMessage(`Note "${origNote.title}" has been duplicated`); | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import utils from "../services/utils.js"; | ||||
| import linkService from "../services/link.js"; | ||||
| import ws from "../services/ws.js"; | ||||
| import CollapsibleWidget from "./standard_widget.js"; | ||||
| import CollapsibleWidget from "./collapsible_widget.js"; | ||||
|  | ||||
| class AttributesWidget extends CollapsibleWidget { | ||||
|     getWidgetTitle() { return "Attributes"; } | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import CollapsibleWidget from "./standard_widget.js"; | ||||
| import CollapsibleWidget from "./collapsible_widget.js"; | ||||
| import libraryLoader from "../services/library_loader.js"; | ||||
| import utils from "../services/utils.js"; | ||||
| import dateNoteService from "../services/date_notes.js"; | ||||
| @@ -10,7 +10,7 @@ const TPL = ` | ||||
|   <div class="calendar-header"> | ||||
|     <button class="calendar-btn bx bx-left-arrow-alt" data-calendar-toggle="previous"></button> | ||||
|  | ||||
|     <div class="calendar-header__label" data-calendar-label="month"> | ||||
|     <div class="calendar-header-label" data-calendar-label="month"> | ||||
|       March 2017 | ||||
|     </div> | ||||
|  | ||||
| @@ -29,45 +29,29 @@ class CalendarWidget extends CollapsibleWidget { | ||||
|  | ||||
|     async isEnabled() { | ||||
|         return await super.isEnabled() | ||||
|             && await this.tabContext.note.hasLabel("dateNote"); | ||||
|             && this.tabContext.note.hasOwnedLabel("dateNote"); | ||||
|     } | ||||
|  | ||||
|     async doRenderBody() { | ||||
|         await libraryLoader.requireLibrary(libraryLoader.CALENDAR_WIDGET); | ||||
|  | ||||
|         this.$body.html(TPL); | ||||
|     } | ||||
|  | ||||
|     async refreshWithNote() { | ||||
|         this.init(this.$body, await this.tabContext.note.getLabelValue("dateNote")); | ||||
|     } | ||||
|  | ||||
|     init($el, activeDate) { | ||||
|         this.activeDate = new Date(activeDate + "T12:00:00"); // attaching time fixes local timezone handling | ||||
|         this.todaysDate = new Date(); | ||||
|         this.date = new Date(this.activeDate.getTime()); | ||||
|  | ||||
|         this.$month = $el.find('[data-calendar-area="month"]'); | ||||
|         this.$next = $el.find('[data-calendar-toggle="next"]'); | ||||
|         this.$previous = $el.find('[data-calendar-toggle="previous"]'); | ||||
|         this.$month = this.$body.find('[data-calendar-area="month"]'); | ||||
|         this.$next = this.$body.find('[data-calendar-toggle="next"]'); | ||||
|         this.$previous = this.$body.find('[data-calendar-toggle="previous"]'); | ||||
|         this.$label = this.$body.find('[data-calendar-label="month"]'); | ||||
|  | ||||
|         this.$next.on('click', () => { | ||||
|             this.clearCalendar(); | ||||
|             this.date.setMonth(this.date.getMonth() + 1); | ||||
|             this.createMonth(); | ||||
|         }); | ||||
|  | ||||
|         this.$previous.on('click', () => { | ||||
|             this.clearCalendar(); | ||||
|             this.date.setMonth(this.date.getMonth() - 1); | ||||
|             this.createMonth(); | ||||
|         }); | ||||
|  | ||||
|         this.$label = $el.find('[data-calendar-label="month"]'); | ||||
|  | ||||
|         this.date.setDate(1); | ||||
|         this.createMonth(); | ||||
|  | ||||
|         this.$body.on('click', '.calendar-date', async ev => { | ||||
|             const date = $(ev.target).closest('.calendar-date').attr('data-calendar-date'); | ||||
|  | ||||
| @@ -82,6 +66,19 @@ class CalendarWidget extends CollapsibleWidget { | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     async refreshWithNote(note) { | ||||
|         this.init(this.$body, note.getOwnedLabelValue("dateNote")); | ||||
|     } | ||||
|  | ||||
|     init($el, activeDate) { | ||||
|         this.activeDate = new Date(activeDate + "T12:00:00"); // attaching time fixes local timezone handling | ||||
|         this.todaysDate = new Date(); | ||||
|         this.date = new Date(this.activeDate.getTime()); | ||||
|         this.date.setDate(1); | ||||
|  | ||||
|         this.createMonth(); | ||||
|     } | ||||
|  | ||||
|     createDay(dateNotesForMonth, num, day) { | ||||
|         const $newDay = $('<a>') | ||||
|             .addClass("calendar-date") | ||||
| @@ -113,7 +110,7 @@ class CalendarWidget extends CollapsibleWidget { | ||||
|         } | ||||
|  | ||||
|         $newDay.append($date); | ||||
|         this.$month.append($newDay); | ||||
|         return $newDay; | ||||
|     } | ||||
|  | ||||
|     isEqual(a, b) { | ||||
| @@ -126,14 +123,19 @@ class CalendarWidget extends CollapsibleWidget { | ||||
|         const month = utils.formatDateISO(this.date).substr(0, 7); | ||||
|         const dateNotesForMonth = await server.get('date-notes/notes-for-month/' + month); | ||||
|  | ||||
|         this.$month.empty(); | ||||
|  | ||||
|         const currentMonth = this.date.getMonth(); | ||||
|         while (this.date.getMonth() === currentMonth) { | ||||
|             this.createDay( | ||||
|             const $day = this.createDay( | ||||
|                 dateNotesForMonth, | ||||
|                 this.date.getDate(), | ||||
|                 this.date.getDay(), | ||||
|                 this.date.getFullYear() | ||||
|             ); | ||||
|  | ||||
|             this.$month.append($day); | ||||
|  | ||||
|             this.date.setDate(this.date.getDate() + 1); | ||||
|         } | ||||
|         // while loop trips over and day is at 30/31, bring it back | ||||
| @@ -159,10 +161,6 @@ class CalendarWidget extends CollapsibleWidget { | ||||
|             'December' | ||||
|         ][monthIndex]; | ||||
|     } | ||||
|  | ||||
|     clearCalendar() { | ||||
|         this.$month.html(''); | ||||
|     } | ||||
| } | ||||
|  | ||||
| export default CalendarWidget; | ||||
| @@ -1,4 +1,3 @@ | ||||
| import utils from "../services/utils.js"; | ||||
| import TabAwareWidget from "./tab_aware_widget.js"; | ||||
|  | ||||
| const WIDGET_TPL = ` | ||||
| @@ -21,7 +20,7 @@ const WIDGET_TPL = ` | ||||
| </div> | ||||
| `; | ||||
|  | ||||
| class CollapsibleWidget extends TabAwareWidget { | ||||
| export default class CollapsibleWidget extends TabAwareWidget { | ||||
|     getWidgetTitle() { return "Untitled widget"; } | ||||
|  | ||||
|     getHeaderActions() { return []; } | ||||
| @@ -30,7 +29,7 @@ class CollapsibleWidget extends TabAwareWidget { | ||||
|  | ||||
|     getMaxHeight() { return null; } | ||||
|  | ||||
|     render() { | ||||
|     doRender() { | ||||
|         this.$widget = $(WIDGET_TPL); | ||||
|         this.$widget.find('[data-target]').attr('data-target', "#" + this.componentId); | ||||
|  | ||||
| @@ -69,23 +68,15 @@ class CollapsibleWidget extends TabAwareWidget { | ||||
|         this.$headerActions = this.$widget.find('.widget-header-actions'); | ||||
|         this.$headerActions.append(...this.getHeaderActions()); | ||||
|  | ||||
|         this.initialized = this.renderBody(); | ||||
|         this.initialized = this.doRenderBody(); | ||||
|  | ||||
|         return this.$widget; | ||||
|     } | ||||
|  | ||||
|     async renderBody() { | ||||
|         await this.doRenderBody(); | ||||
|     } | ||||
|  | ||||
|     /** for overriding */ | ||||
|     async doRenderBody() {} | ||||
|  | ||||
|     isExpanded() { | ||||
|         return this.$bodyWrapper.hasClass("show"); | ||||
|     } | ||||
|  | ||||
|     cleanup() {} | ||||
| } | ||||
|  | ||||
| export default CollapsibleWidget; | ||||
| @@ -1,9 +1,9 @@ | ||||
| import CollapsibleWidget from "./standard_widget.js"; | ||||
| import CollapsibleWidget from "./collapsible_widget.js"; | ||||
| import linkService from "../services/link.js"; | ||||
| import server from "../services/server.js"; | ||||
| import treeCache from "../services/tree_cache.js"; | ||||
|  | ||||
| class EditedNotesWidget extends CollapsibleWidget { | ||||
| export default class EditedNotesWidget extends CollapsibleWidget { | ||||
|     getWidgetTitle() { return "Edited notes on this day"; } | ||||
|  | ||||
|     getHelp() { | ||||
| @@ -19,8 +19,7 @@ class EditedNotesWidget extends CollapsibleWidget { | ||||
|             && await this.tabContext.note.hasLabel("dateNote"); | ||||
|     } | ||||
|  | ||||
|     async refreshWithNote() { | ||||
|         const note = this.tabContext.note; | ||||
|     async refreshWithNote(note) { | ||||
|         // remember which title was when we found the similar notes | ||||
|         this.title = note.title; | ||||
|         let editedNotes = await server.get('edited-notes/' + await note.getLabelValue("dateNote")); | ||||
| @@ -54,5 +53,3 @@ class EditedNotesWidget extends CollapsibleWidget { | ||||
|         this.$body.empty().append($list); | ||||
|     } | ||||
| } | ||||
|  | ||||
| export default EditedNotesWidget; | ||||
| @@ -1,4 +1,4 @@ | ||||
| import CollapsibleWidget from "./standard_widget.js"; | ||||
| import CollapsibleWidget from "./collapsible_widget.js"; | ||||
|  | ||||
| let linkMapContainerIdCtr = 1; | ||||
|  | ||||
| @@ -28,7 +28,7 @@ class LinkMapWidget extends CollapsibleWidget { | ||||
|         return [$showFullButton]; | ||||
|     } | ||||
|  | ||||
|     async refreshWithNote() { | ||||
|     async refreshWithNote(note) { | ||||
|         this.$body.css('opacity', 0); | ||||
|         this.$body.html(TPL); | ||||
|  | ||||
| @@ -38,9 +38,10 @@ class LinkMapWidget extends CollapsibleWidget { | ||||
|  | ||||
|         const LinkMapServiceClass = (await import('../services/link_map.js')).default; | ||||
|  | ||||
|         this.linkMapService = new LinkMapServiceClass(this.tabContext.note, $linkMapContainer, { | ||||
|         this.linkMapService = new LinkMapServiceClass(note, $linkMapContainer, { | ||||
|             maxDepth: 1, | ||||
|             zoom: 0.6 | ||||
|             zoom: 0.6, | ||||
|             stopCheckerCallback: () => this.noteId !== note.noteId // stop when current note is not what was originally requested | ||||
|         }); | ||||
|  | ||||
|         await this.linkMapService.render(); | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import CollapsibleWidget from "./standard_widget.js"; | ||||
| import CollapsibleWidget from "./collapsible_widget.js"; | ||||
|  | ||||
| const TPL = ` | ||||
| <table class="note-info-widget-table"> | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import server from "../services/server.js"; | ||||
| import CollapsibleWidget from "./standard_widget.js"; | ||||
| import CollapsibleWidget from "./collapsible_widget.js"; | ||||
|  | ||||
| const TPL = ` | ||||
| <ul class="note-revision-list" style="max-height: 150px; overflow: auto;"> | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import CollapsibleWidget from "./standard_widget.js"; | ||||
| import CollapsibleWidget from "./collapsible_widget.js"; | ||||
| import linkService from "../services/link.js"; | ||||
| import server from "../services/server.js"; | ||||
| import treeCache from "../services/tree_cache.js"; | ||||
|   | ||||
| @@ -43,10 +43,22 @@ export default class TabAwareWidget extends BasicWidget { | ||||
|         this.refresh(); | ||||
|     } | ||||
|  | ||||
|     refresh() { | ||||
|         if (this.note) { | ||||
|     async isEnabled() { | ||||
|         return !!this.note; | ||||
|     } | ||||
|  | ||||
|     async refresh() { | ||||
|         if (await this.isEnabled()) { | ||||
|             const start = Date.now(); | ||||
|  | ||||
|             this.toggle(true); | ||||
|             this.refreshWithNote(this.note, this.notePath); | ||||
|             await this.refreshWithNote(this.note, this.notePath); | ||||
|  | ||||
|             const end = Date.now(); | ||||
|  | ||||
|             if (end - start > 10) { | ||||
|                 console.log(`Refresh of ${this.componentId} took ${end-start}ms`); | ||||
|             } | ||||
|         } | ||||
|         else { | ||||
|             this.toggle(false); | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import CollapsibleWidget from "./standard_widget.js"; | ||||
| import CollapsibleWidget from "./collapsible_widget.js"; | ||||
| import linkService from "../services/link.js"; | ||||
|  | ||||
| class WhatLinksHereWidget extends CollapsibleWidget { | ||||
|   | ||||
| @@ -31,7 +31,7 @@ | ||||
|   padding: 0 0.5rem 0.5rem 0.5rem; | ||||
| } | ||||
|  | ||||
| .calendar-widget .calendar-header__label { | ||||
| .calendar-widget .calendar-header-label { | ||||
|   font-weight: bold; | ||||
|   text-align: center; | ||||
|   width: 100%; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user