Add "zform" functionality to the web client.

A "zform" knows how to render data that follows our
schema for widget messages with form elements like
buttons and choices.

This code won't be triggered until a subsequent
server-side commit takes widget_content from
API callers such as the trivial chat bot and
creates submessages for us.
This commit is contained in:
Steve Howell 2018-02-23 09:37:19 -05:00 committed by Tim Abbott
parent 435719c65b
commit 1b57e568ff
7 changed files with 149 additions and 1 deletions

View File

@ -175,6 +175,7 @@
"user_events": false,
"voting_widget": false,
"tictactoe_widget": false,
"zform": false,
"widgetize": false,
"submessage": false,
"Plotly": false,

View File

@ -6,6 +6,7 @@ var widgets = {};
widgets.poll = voting_widget;
widgets.tictactoe = tictactoe_widget;
widgets.zform = zform;
exports.activate = function (in_opts) {
var widget_type = in_opts.widget_type;

115
static/js/zform.js Normal file
View File

@ -0,0 +1,115 @@
var zform = (function () {
var exports = {};
exports.validate_extra_data = function (data) {
function check(data) {
function check_choice_data(data) {
function check_choice_item(field_name, val) {
return schema.check_record(field_name, val, {
short_name: schema.check_string,
long_name: schema.check_string,
reply: schema.check_string,
});
}
function check_choices(field_name, val) {
return schema.check_array(
field_name,
val,
check_choice_item
);
}
return schema.check_record('zform data', data, {
heading: schema.check_string,
choices: check_choices,
});
}
if (data.type === 'choices') {
return check_choice_data(data);
}
return 'unknown zform type: ' + data.type;
}
var msg = check(data);
if (msg) {
blueslip.warn(msg);
return false;
}
return true;
};
exports.activate = function (opts) {
var self = {};
var outer_elem = opts.elem;
var data = opts.extra_data;
if (!exports.validate_extra_data(data)) {
// callee will log reason we fail
return;
}
function make_choices(data) {
// Assign idx values to each of our choices so that
// our template can create data-idx values for our
// JS code to use later.
_.each(data.choices, function (choice, idx) {
choice.idx = idx;
});
var html = templates.render('zform-choices', data);
var elem = $(html);
elem.find('button').on('click', function (e) {
e.stopPropagation();
// Grab our index from the markup.
var idx = $(e.target).attr('data-idx');
// Use the index from the markup to dereference our
// data structure.
var reply_content = data.choices[idx].reply;
transmit.reply_message({
message: opts.message,
content: reply_content,
});
});
return elem;
}
function render() {
var rendered_widget;
if (data.type === 'choices') {
rendered_widget = make_choices(data);
outer_elem.html(rendered_widget);
}
}
self.handle_events = function (events) {
if (events) {
blueslip.info('unexpected');
}
render();
};
render();
return self;
};
return exports;
}());
if (typeof module !== 'undefined') {
module.exports = zform;
}

View File

@ -0,0 +1,17 @@
.widget-choices ul {
padding: 3px;
}
.widget-choices li {
padding: 2px;
list-style: none;
}
.widget-choices button {
font-weight: 700;
color: blue;
}
.widget-choices-heading {
font-weight: 600;
}

View File

@ -0,0 +1,12 @@
<div class="widget-choices">
<div class="widget-choices-heading">{{ heading }}</div>
<ul>
{{#each choices}}
<li>
<button data-idx="{{ this.idx }}">{{ this.short_name }}</button>
&nbsp;
{{ this.long_name }}
</li>
{{/each}}
</ul>
</div>

View File

@ -79,7 +79,8 @@
"./static/styles/media.scss",
"./static/styles/typing_notifications.scss",
"./static/styles/hotspots.scss",
"./static/styles/night_mode.scss"
"./static/styles/night_mode.scss",
"./static/styles/widgets.scss"
],
"archive-styles": [
"./node_modules/katex/dist/katex.css",

View File

@ -964,6 +964,7 @@ JS_SPECS = {
'js/filter.js',
'js/voting_widget.js',
'js/tictactoe_widget.js',
'js/zform.js',
'js/widgetize.js',
'js/submessage.js',
'js/fetch_status.js',