mirror of
https://gitlab.com/octtspacc/OcttKB
synced 2025-04-18 01:07:19 +02:00
163 lines
4.3 KiB
JavaScript
163 lines
4.3 KiB
JavaScript
/*\
|
|
title: $:/plugins/ebalster/condition/widgets/condition.js
|
|
type: application/javascript
|
|
module-type: widget
|
|
|
|
Base class for condition widgets.
|
|
|
|
\*/
|
|
(function(){
|
|
|
|
/*jslint node: true, browser: true */
|
|
/*global $tw: false */
|
|
"use strict";
|
|
|
|
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
|
|
|
var ConditionWidget = function(parseTreeNode,options) {
|
|
if(arguments.length > 0) {
|
|
this.initialise(parseTreeNode,options);
|
|
}
|
|
};
|
|
|
|
/*
|
|
Inherit from the base widget class
|
|
*/
|
|
ConditionWidget.prototype = new Widget();
|
|
|
|
/*
|
|
Render this widget into the DOM
|
|
*/
|
|
ConditionWidget.prototype.render = function(parent,nextSibling) {
|
|
this.parentDomNode = parent;
|
|
this.computeAttributes();
|
|
this.execute();
|
|
this.rerender(parent,nextSibling);
|
|
};
|
|
|
|
ConditionWidget.prototype.rerender = function(parent,nextSibling) {
|
|
this.removeChildDomNodes();
|
|
if (this.conditionError) {
|
|
// Show an error.
|
|
var parseTreeNodes = [{type: "element", tag: "span", attributes: {
|
|
"class": {type: "string", value: "tc-error"}
|
|
}, children: [
|
|
{type: "text", text: this.conditionError}
|
|
]}];
|
|
this.makeChildWidgets(parseTreeNodes);
|
|
}
|
|
else if (this.isOpen) {
|
|
// Construct and render the child widgets.
|
|
this.makeChildWidgets(this.parseTreeNode.children);
|
|
}
|
|
else {
|
|
// Destroy the child widgets.
|
|
this.children = [];
|
|
}
|
|
this.renderChildren(parent,nextSibling);
|
|
};
|
|
|
|
/*
|
|
Compute the internal state of the widget (default behavior)
|
|
*/
|
|
ConditionWidget.prototype.execute = function() {
|
|
this.executeIf("$condition");
|
|
};
|
|
|
|
/*
|
|
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
|
*/
|
|
ConditionWidget.prototype.refresh = function(changedTiddlers) {
|
|
var currentlyOpen = this.isOpen;
|
|
var changedAttributes = this.computeAttributes();
|
|
this.execute();
|
|
if(this.isOpen !== currentlyOpen) {
|
|
var nextSibling = this.findNextSiblingDomNode();
|
|
this.rerender(this.parentDomNode,nextSibling);
|
|
return true;
|
|
}
|
|
return this.refreshChildren(changedTiddlers);
|
|
};
|
|
|
|
/*
|
|
Utility: Is a value "truthy"?
|
|
*/
|
|
ConditionWidget.prototype.valueIsTruthy = function(value) {
|
|
// It's truthy if it's not falsy, ie, undefined, false, blank or zero.
|
|
return !(/^\s*(undefined|false|null|0+|0*\.0+|0+\.0*|)\s*$/i.test(value));
|
|
};
|
|
|
|
/*
|
|
Utility: Find a preceding non-text widget for an "else" widget.
|
|
*/
|
|
ConditionWidget.prototype.findPrecedingConditionWidget = function() {
|
|
var siblings = (this.parentWidget ? this.parentWidget.children : null);
|
|
var sibling;
|
|
if (siblings) {
|
|
for (var i = siblings.indexOf(this)-1; i >= 0; --i) {
|
|
sibling = siblings[i];
|
|
if (sibling.parseTreeNode.type == "text") continue;
|
|
if (sibling.isOpen != null || sibling.list != null) return sibling;
|
|
return null;
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
|
|
/*
|
|
Utility: Test if another widget triggers an "else"; ie, false conditions, closed reveals, empty lists.
|
|
*/
|
|
ConditionWidget.prototype.widgetTriggersElse = function(widget) {
|
|
// Condition widgets
|
|
if (widget.triggerElse != null) return widget.triggerElse;
|
|
// Reveal widget
|
|
if (widget.isOpen != null) return !widget.isOpen;
|
|
// List widget
|
|
if (widget.list != null) return (widget.list instanceof Array) && widget.list.length == 0;
|
|
};
|
|
|
|
/*
|
|
Utility: Execute as an "else" condition, computing isOpen and conditionError accordingly.
|
|
*/
|
|
ConditionWidget.prototype.executeElse = function(widgetName) {
|
|
this.isOpen = false;
|
|
this.conditionError = null;
|
|
this.triggerElse = false;
|
|
var predicate = this.findPrecedingConditionWidget();
|
|
if (!predicate) {
|
|
this.conditionError = (widgetName||"$else") + " widget must follow $if, $else-if, $reveal or $list.";
|
|
return;
|
|
}
|
|
this.isOpen = this.widgetTriggersElse(predicate);
|
|
};
|
|
|
|
/*
|
|
Utility: Execute as an "if" condition, computing isOpen and conditionError accordingly.
|
|
*/
|
|
ConditionWidget.prototype.executeIf = function(widgetName) {
|
|
this.isOpen = false;
|
|
this.conditionError = null;
|
|
this.triggerElse = false;
|
|
// Re-check our "if" condition.
|
|
var value = this.getAttribute("value");
|
|
var match = this.getAttribute("match");
|
|
if (value == null) {
|
|
this.conditionError = (widgetName||"$condition") + " widget requires a 'value' attribute.";
|
|
return;
|
|
}
|
|
else if (match == null) {
|
|
// Open if the value is truthy.
|
|
this.isOpen = this.valueIsTruthy(value);
|
|
}
|
|
else {
|
|
this.isOpen = (value == match);
|
|
}
|
|
if (this.getAttribute("not")) {
|
|
this.isOpen = !this.isOpen;
|
|
}
|
|
this.triggerElse = !this.isOpen;
|
|
};
|
|
|
|
exports.condition = ConditionWidget;
|
|
|
|
})(); |