1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-11-27 20:10:03 +00:00
TiddlyWiki5/core/modules/widgets/select.js
Jermolene 3c20f2396e Add support for assigning action widgets via the actions attribute
This is quite a big change: a new way to invoke action widgets.

The advantage is that it solves #2217 and #1564, a long running problem
that prevented us from adding action widgets to widgets that modify the
store.

This commit adds the new technique for the button and keyboard widgets,
but also extends the select widget to trigger action widgets for the
first time
2016-04-29 18:54:44 +01:00

188 lines
5.1 KiB
JavaScript

/*\
title: $:/core/modules/widgets/select.js
type: application/javascript
module-type: widget
Select widget:
```
<$select tiddler="MyTiddler" field="text">
<$list filter="[tag[chapter]]">
<option value=<<currentTiddler>>>
<$view field="description"/>
</option>
</$list>
</$select>
```
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var SelectWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
};
/*
Inherit from the base widget class
*/
SelectWidget.prototype = new Widget();
/*
Render this widget into the DOM
*/
SelectWidget.prototype.render = function(parent,nextSibling) {
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
this.renderChildren(parent,nextSibling);
this.setSelectValue();
$tw.utils.addEventListeners(this.getSelectDomNode(),[
{name: "change", handlerObject: this, handlerMethod: "handleChangeEvent"}
]);
};
/*
Handle a change event
*/
SelectWidget.prototype.handleChangeEvent = function(event) {
// Get the new value and assign it to the tiddler
if(this.selectMultiple == false) {
var value = this.getSelectDomNode().value;
} else {
var value = this.getSelectValues()
value = $tw.utils.stringifyList(value);
}
this.wiki.setText(this.selectTitle,this.selectField,this.selectIndex,value);
// Trigger actions
if(this.selectActions) {
this.invokeActionString(this.selectActions,this,event);
}
};
/*
If necessary, set the value of the select element to the current value
*/
SelectWidget.prototype.setSelectValue = function() {
var value = this.selectDefault;
// Get the value
if(this.selectIndex) {
value = this.wiki.extractTiddlerDataItem(this.selectTitle,this.selectIndex);
} else {
var tiddler = this.wiki.getTiddler(this.selectTitle);
if(tiddler) {
if(this.selectField === "text") {
// Calling getTiddlerText() triggers lazy loading of skinny tiddlers
value = this.wiki.getTiddlerText(this.selectTitle);
} else {
if($tw.utils.hop(tiddler.fields,this.selectField)) {
value = tiddler.getFieldString(this.selectField);
}
}
} else {
if(this.selectField === "title") {
value = this.selectTitle;
}
}
}
// Assign it to the select element if it's different than the current value
if (this.selectMultiple) {
value = value === undefined ? "" : value;
var select = this.getSelectDomNode();
var values = Array.isArray(value) ? value : $tw.utils.parseStringArray(value);
for(var i=0; i < select.children.length; i++){
if(values.indexOf(select.children[i].value) != -1) {
select.children[i].selected = true;
}
}
} else {
var domNode = this.getSelectDomNode();
if(domNode.value !== value) {
domNode.value = value;
}
}
};
/*
Get the DOM node of the select element
*/
SelectWidget.prototype.getSelectDomNode = function() {
return this.children[0].domNodes[0];
};
// Return an array of the selected opion values
// select is an HTML select element
SelectWidget.prototype.getSelectValues = function() {
var select, result, options, opt;
select = this.getSelectDomNode();
result = [];
options = select && select.options;
for (var i=0; i<options.length; i++) {
opt = options[i];
if (opt.selected) {
result.push(opt.value || opt.text);
}
}
return result;
}
/*
Compute the internal state of the widget
*/
SelectWidget.prototype.execute = function() {
// Get our parameters
this.selectActions = this.getAttribute("actions");
this.selectTitle = this.getAttribute("tiddler",this.getVariable("currentTiddler"));
this.selectField = this.getAttribute("field","text");
this.selectIndex = this.getAttribute("index");
this.selectClass = this.getAttribute("class");
this.selectDefault = this.getAttribute("default");
this.selectMultiple = this.getAttribute("multiple", false);
this.selectSize = this.getAttribute("size");
// Make the child widgets
var selectNode = {
type: "element",
tag: "select",
children: this.parseTreeNode.children
};
if(this.selectClass) {
$tw.utils.addAttributeToParseTreeNode(selectNode,"class",this.selectClass);
}
if(this.selectMultiple) {
$tw.utils.addAttributeToParseTreeNode(selectNode,"multiple","multiple");
}
if(this.selectSize) {
$tw.utils.addAttributeToParseTreeNode(selectNode,"size",this.selectSize);
}
this.makeChildWidgets([selectNode]);
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
SelectWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
// If we're using a different tiddler/field/index then completely refresh ourselves
if(changedAttributes.selectTitle || changedAttributes.selectField || changedAttributes.selectIndex) {
this.refreshSelf();
return true;
// If the target tiddler value has changed, just update setting and refresh the children
} else {
var childrenRefreshed = this.refreshChildren(changedTiddlers);
if(changedTiddlers[this.selectTitle] || childrenRefreshed) {
this.setSelectValue();
}
return childrenRefreshed;
}
};
exports.select = SelectWidget;
})();