mirror of https://github.com/zulip/zulip.git
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:
parent
435719c65b
commit
1b57e568ff
|
@ -175,6 +175,7 @@
|
|||
"user_events": false,
|
||||
"voting_widget": false,
|
||||
"tictactoe_widget": false,
|
||||
"zform": false,
|
||||
"widgetize": false,
|
||||
"submessage": false,
|
||||
"Plotly": false,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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>
|
||||
|
||||
{{ this.long_name }}
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
|
@ -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",
|
||||
|
|
|
@ -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',
|
||||
|
|
Loading…
Reference in New Issue