Add sorted list, textarea and typed input
parent
04b35c05ad
commit
8eb5c3e6db
|
@ -436,3 +436,4 @@
|
|||
@cp_form-poll-yes: @cryptpad_color_light_green;
|
||||
@cp_form-poll-maybe: @cryptpad_color_light_yellow;
|
||||
@cp_form_poll-yes-color: @cryptpad_color_green;
|
||||
@cp_form-invalid: @cryptpad_color_red;
|
||||
|
|
|
@ -435,4 +435,5 @@
|
|||
@cp_form-poll-no: @cryptpad_color_light_red;
|
||||
@cp_form-poll-yes: @cryptpad_color_light_green;
|
||||
@cp_form-poll-maybe: @cryptpad_color_light_yellow;
|
||||
@cp_form_poll-yes-color: @cryptpad_color_green;
|
||||
@cp_form-poll-yes-color: @cryptpad_color_green;
|
||||
@cp_form-invalid: @cryptpad_color_red;
|
||||
|
|
|
@ -203,6 +203,9 @@
|
|||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
input:invalid {
|
||||
border: 1px solid @cp_form-invalid;
|
||||
}
|
||||
}
|
||||
.cp-form-input-block {
|
||||
//width: @form_input-width;
|
||||
|
@ -328,6 +331,12 @@
|
|||
&:not(:last-child) { margin-bottom: 1px; }
|
||||
}
|
||||
}
|
||||
.cp-form-results-type-textarea-data {
|
||||
white-space: pre-wrap;
|
||||
font-size: 14px;
|
||||
border: 1px solid @cp_profile-hint;
|
||||
padding: 0 5px;
|
||||
}
|
||||
.cp-form-results-type-radio {
|
||||
display: table;
|
||||
.cp-form-results-type-multiradio-data {
|
||||
|
@ -390,6 +399,18 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.cp-form-type-sort {
|
||||
cursor: grab;
|
||||
padding: 2px;
|
||||
.cp-form-handle {
|
||||
margin-right: 5px;
|
||||
}
|
||||
.cp-form-sort-order {
|
||||
border: 1px solid @cp_profile-hint;
|
||||
padding: 0 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.cp-form-type-poll {
|
||||
display: inline-flex;
|
||||
|
@ -461,7 +482,7 @@
|
|||
border: 5px double @cp_form-bg1;
|
||||
}
|
||||
div.cp-form-poll-answer {
|
||||
color: @cp_form_poll-yes-color;
|
||||
color: @cp_form-poll-yes-color;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,14 +80,23 @@ define([
|
|||
Messages.form_invalid = "Invalid form";
|
||||
Messages.form_editBlock = "Edit";
|
||||
Messages.form_editMax = "Max selectable options";
|
||||
Messages.form_editMaxLength = "Maximum characters";
|
||||
Messages.form_editType = "Options type";
|
||||
|
||||
Messages.form_poll_text = "Text";
|
||||
Messages.form_poll_day = "Day";
|
||||
Messages.form_poll_time = "Time";
|
||||
|
||||
|
||||
Messages.form_textType = "Text type";
|
||||
Messages.form_text_text = "Text";
|
||||
Messages.form_text_url = "URL";
|
||||
Messages.form_text_email = "Email";
|
||||
Messages.form_text_number = "Number";
|
||||
|
||||
Messages.form_default = "Your question here?";
|
||||
Messages.form_type_input = "Text"; // XXX
|
||||
Messages.form_type_textarea = "Textarea"; // XXX
|
||||
Messages.form_type_radio = "Radio"; // XXX
|
||||
Messages.form_type_multiradio = "Multiline Radio"; // XXX
|
||||
Messages.form_type_checkbox = "Checkbox"; // XXX
|
||||
|
@ -161,6 +170,109 @@ define([
|
|||
var MAX_OPTIONS = 15; // XXX
|
||||
var MAX_ITEMS = 10; // XXX
|
||||
|
||||
var saveAndCancelOptions = function (getRes, cb) {
|
||||
// Cancel changes
|
||||
var cancelBlock = h('button.btn.btn-secondary', Messages.cancel);
|
||||
$(cancelBlock).click(function () { cb(); });
|
||||
|
||||
// Save changes
|
||||
var saveBlock = h('button.btn.btn-primary', [
|
||||
h('i.fa.fa-floppy-o'),
|
||||
h('span', Messages.settings_save)
|
||||
]);
|
||||
|
||||
$(saveBlock).click(function () {
|
||||
$(saveBlock).attr('disabled', 'disabled');
|
||||
cb(getRes());
|
||||
});
|
||||
|
||||
return h('div', [cancelBlock, saveBlock]);
|
||||
};
|
||||
var editTextOptions = function (opts, setCursorGetter, cb, tmp) {
|
||||
if (tmp && tmp.content && Sortify(opts) === Sortify(tmp.old)) {
|
||||
opts = tmp.content;
|
||||
}
|
||||
|
||||
var maxLength, getLengthVal;
|
||||
if (opts.maxLength) {
|
||||
var lengthInput = h('input', {
|
||||
type:"number",
|
||||
value: opts.maxLength,
|
||||
min: 100,
|
||||
max: 5000
|
||||
});
|
||||
maxLength = h('div.cp-form-edit-max-options', [
|
||||
h('span', Messages.form_editMaxLength),
|
||||
lengthInput
|
||||
]);
|
||||
getLengthVal = function () {
|
||||
var val = Number($(lengthInput).val()) || 1000;
|
||||
if (val < 100) { val = 1; }
|
||||
if (val > 5000) { val = 5000; }
|
||||
return val;
|
||||
};
|
||||
|
||||
var $l = $(lengthInput).on('input', Util.throttle(function () {
|
||||
$l.val(getLengthVal());
|
||||
}, 500));
|
||||
|
||||
}
|
||||
|
||||
var type, typeSelect;
|
||||
if (opts.type) {
|
||||
var options = ['text', 'number', 'url', 'email'].map(function (t) {
|
||||
return {
|
||||
tag: 'a',
|
||||
attributes: {
|
||||
'class': 'cp-form-type-value',
|
||||
'data-value': t,
|
||||
'href': '#',
|
||||
},
|
||||
content: Messages['form_text_'+t]
|
||||
};
|
||||
});
|
||||
var dropdownConfig = {
|
||||
text: '', // Button initial text
|
||||
options: options, // Entries displayed in the menu
|
||||
//left: true, // Open to the left of the button
|
||||
//container: $(type),
|
||||
isSelect: true,
|
||||
caretDown: true,
|
||||
buttonCls: 'btn btn-secondary'
|
||||
};
|
||||
typeSelect = UIElements.createDropdown(dropdownConfig);
|
||||
typeSelect.setValue(opts.type);
|
||||
|
||||
type = h('div.cp-form-edit-type', [
|
||||
h('span', Messages.form_textType),
|
||||
typeSelect[0]
|
||||
]);
|
||||
}
|
||||
|
||||
setCursorGetter(function () {
|
||||
return {
|
||||
old: (tmp && tmp.old) || opts,
|
||||
content: {
|
||||
maxLength: getLengthVal ? getLengthVal() : undefined,
|
||||
type: typeSelect ? typeSelect.getValue() : undefined
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var getSaveRes = function () {
|
||||
return {
|
||||
maxLength: getLengthVal ? getLengthVal() : undefined,
|
||||
type: typeSelect ? typeSelect.getValue() : undefined
|
||||
};
|
||||
};
|
||||
var saveAndCancel = saveAndCancelOptions(getSaveRes, cb);
|
||||
|
||||
return [
|
||||
maxLength,
|
||||
type,
|
||||
saveAndCancel
|
||||
];
|
||||
};
|
||||
var editOptions = function (v, setCursorGetter, cb, tmp) {
|
||||
var add = h('button.btn.btn-secondary', [
|
||||
h('i.fa.fa-plus'),
|
||||
|
@ -415,10 +527,6 @@ define([
|
|||
if ($container.find('input').length >= MAX_OPTIONS) { $add.hide(); }
|
||||
if ($(containerItems).find('input').length >= MAX_ITEMS) { $addItem.hide(); }
|
||||
|
||||
// Cancel changes
|
||||
var cancelBlock = h('button.btn.btn-secondary', Messages.cancel);
|
||||
$(cancelBlock).click(function () { cb(); });
|
||||
|
||||
// Set cursor getter (to handle remote changes to the form)
|
||||
setCursorGetter(function () {
|
||||
var values = [];
|
||||
|
@ -471,14 +579,7 @@ define([
|
|||
};
|
||||
});
|
||||
|
||||
// Save changes
|
||||
var saveBlock = h('button.btn.btn-primary', [
|
||||
h('i.fa.fa-floppy-o'),
|
||||
h('span', Messages.settings_save)
|
||||
]);
|
||||
$(saveBlock).click(function () {
|
||||
$(saveBlock).attr('disabled', 'disabled');
|
||||
|
||||
var getSaveRes = function () {
|
||||
// Get values
|
||||
var values = [];
|
||||
var duplicates = false;
|
||||
|
@ -538,8 +639,10 @@ define([
|
|||
res.type = typeSelect.getValue();
|
||||
}
|
||||
|
||||
cb(res);
|
||||
});
|
||||
return res;
|
||||
};
|
||||
|
||||
var saveAndCancel = saveAndCancelOptions(getSaveRes, cb);
|
||||
|
||||
return [
|
||||
type,
|
||||
|
@ -547,7 +650,7 @@ define([
|
|||
calendarView,
|
||||
h('div.cp-form-edit-options-block', [containerItems, container]),
|
||||
addMultiple,
|
||||
h('div', [cancelBlock, saveBlock])
|
||||
saveAndCancel
|
||||
];
|
||||
};
|
||||
|
||||
|
@ -767,16 +870,33 @@ define([
|
|||
};
|
||||
var TYPES = {
|
||||
input: {
|
||||
defaultOpts: {
|
||||
type: 'text'
|
||||
},
|
||||
get: function (opts, a, n, evOnChange) {
|
||||
var tag = h('input');
|
||||
if (!opts) { opts = TYPES.input.defaultOpts; }
|
||||
var tag = h('input', {
|
||||
type: opts.type
|
||||
});
|
||||
var $tag = $(tag);
|
||||
$tag.on('change keypress', Util.throttle(function () {
|
||||
evOnChange.fire();
|
||||
}, 500));
|
||||
var cursorGetter;
|
||||
var setCursorGetter = function (f) { cursorGetter = f; };
|
||||
return {
|
||||
tag: tag,
|
||||
getValue: function () { return $tag.val(); },
|
||||
getValue: function () {
|
||||
var invalid = $tag.is(':invalid');
|
||||
if (invalid) { return; } // XXX invalid answers are ignored?
|
||||
return $tag.val();
|
||||
},
|
||||
setValue: function (val) { $tag.val(val); },
|
||||
edit: function (cb, tmp) {
|
||||
var v = Util.clone(opts);
|
||||
return editTextOptions(v, setCursorGetter, cb, tmp);
|
||||
},
|
||||
getCursor: function () { return cursorGetter(); },
|
||||
reset: function () { $tag.val(''); }
|
||||
};
|
||||
},
|
||||
|
@ -795,6 +915,46 @@ define([
|
|||
},
|
||||
icon: h('i.fa.fa-font')
|
||||
},
|
||||
textarea: {
|
||||
defaultOpts: {
|
||||
maxLength: 1000
|
||||
},
|
||||
get: function (opts, a, n, evOnChange) {
|
||||
if (!opts) { opts = TYPES.textarea.defaultOpts; }
|
||||
var tag = h('textarea', {maxlength: opts.maxLength});
|
||||
var $tag = $(tag);
|
||||
$tag.on('change keypress', Util.throttle(function () {
|
||||
evOnChange.fire();
|
||||
}, 500));
|
||||
var cursorGetter;
|
||||
var setCursorGetter = function (f) { cursorGetter = f; };
|
||||
return {
|
||||
tag: tag,
|
||||
getValue: function () { return $tag.val(); },
|
||||
setValue: function (val) { $tag.val(val); },
|
||||
edit: function (cb, tmp) {
|
||||
var v = Util.clone(opts);
|
||||
return editTextOptions(v, setCursorGetter, cb, tmp);
|
||||
},
|
||||
getCursor: function () { return cursorGetter(); },
|
||||
reset: function () { $tag.val(''); }
|
||||
};
|
||||
},
|
||||
printResults: function (answers, uid) {
|
||||
var results = [];
|
||||
var empty = 0;
|
||||
Object.keys(answers).forEach(function (author) {
|
||||
var obj = answers[author];
|
||||
var answer = obj.msg[uid];
|
||||
if (!answer || !answer.trim()) { return empty++; }
|
||||
results.push(h('div.cp-form-results-type-textarea-data', answer));
|
||||
});
|
||||
results.push(getEmpty(empty));
|
||||
|
||||
return h('div.cp-form-results-type-text', results);
|
||||
},
|
||||
icon: h('i.fa.fa-font')
|
||||
},
|
||||
radio: {
|
||||
defaultOpts: {
|
||||
values: [1,2].map(function (i) {
|
||||
|
@ -1285,6 +1445,116 @@ define([
|
|||
},
|
||||
icon: h('i.cptools.cptools-poll')
|
||||
},
|
||||
sort: {
|
||||
defaultOpts: {
|
||||
values: [1,2].map(function (i) {
|
||||
return Messages._getKey('form_defaultOption', [i]);
|
||||
})
|
||||
},
|
||||
get: function (opts, a, n, evOnChange) {
|
||||
if (!opts) { opts = TYPES.radio.defaultOpts; }
|
||||
if (!Array.isArray(opts.values)) { return; }
|
||||
var map = {};
|
||||
var invMap = {};
|
||||
var els = opts.values.map(function (data, i) {
|
||||
var uid = Util.uid();
|
||||
map[uid] = data;
|
||||
invMap[data] = uid;
|
||||
var div = h('div.cp-form-type-sort', {'data-id': uid}, [
|
||||
h('span.cp-form-handle', [
|
||||
h('i.fa.fa-ellipsis-v'),
|
||||
h('i.fa.fa-ellipsis-v'),
|
||||
]),
|
||||
h('span.cp-form-sort-order', (i+1)),
|
||||
h('span', data)
|
||||
]);
|
||||
$(div).data('val', data);
|
||||
return div;
|
||||
});
|
||||
var tag = h('div.cp-form-type-sort-container', els);
|
||||
var $tag = $(tag);
|
||||
var reorder = function () {
|
||||
$tag.find('.cp-form-type-sort').each(function (i, el) {
|
||||
$(el).find('.cp-form-sort-order').text(i+1);
|
||||
});
|
||||
};
|
||||
var cursorGetter;
|
||||
var setCursorGetter = function (f) { cursorGetter = f; };
|
||||
|
||||
var sortable = Sortable.create(tag, {
|
||||
direction: "vertical",
|
||||
draggable: ".cp-form-type-sort",
|
||||
forceFallback: true,
|
||||
store: {
|
||||
set: function () {
|
||||
evOnChange.fire();
|
||||
reorder();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(tag).find('input[type="radio"]').on('change', function () {
|
||||
evOnChange.fire();
|
||||
});
|
||||
return {
|
||||
tag: tag,
|
||||
getValue: function () {
|
||||
return sortable.toArray().map(function (id) {
|
||||
return map[id];
|
||||
});
|
||||
},
|
||||
reset: function () {
|
||||
var toSort = (opts.values).map(function (val) {
|
||||
return invMap[val];
|
||||
});
|
||||
sortable.sort(toSort);
|
||||
reorder();
|
||||
},
|
||||
edit: function (cb, tmp) {
|
||||
var v = Util.clone(opts);
|
||||
return editOptions(v, setCursorGetter, cb, tmp);
|
||||
},
|
||||
getCursor: function () { return cursorGetter(); },
|
||||
setValue: function (val) {
|
||||
var toSort = (val || []).map(function (val) {
|
||||
return invMap[val];
|
||||
});
|
||||
sortable.sort(toSort);
|
||||
reorder();
|
||||
}
|
||||
};
|
||||
|
||||
},
|
||||
printResults: function (answers, uid, form) {
|
||||
var opts = form[uid].opts || TYPES.radio.defaultOpts;
|
||||
var l = (opts.values || []).length;
|
||||
var results = [];
|
||||
var empty = 0;
|
||||
var count = {};
|
||||
Object.keys(answers).forEach(function (author) {
|
||||
var obj = answers[author];
|
||||
var answer = obj.msg[uid];
|
||||
if (!Array.isArray(answer) || !answer.length) { return empty++; }
|
||||
answer.forEach(function (el, i) {
|
||||
var score = l - i;
|
||||
count[el] = (count[el] || 0) + score;
|
||||
});
|
||||
});
|
||||
var sorted = Object.keys(count).sort(function (a, b) {
|
||||
return count[b] - count[a];
|
||||
});
|
||||
sorted.forEach(function (value) {
|
||||
results.push(h('div.cp-form-results-type-radio-data', [
|
||||
h('span.cp-value', value),
|
||||
h('span.cp-count', count[value])
|
||||
]));
|
||||
});
|
||||
results.push(getEmpty(empty));
|
||||
|
||||
return h('div.cp-form-results-type-radio', results);
|
||||
},
|
||||
icon: h('i.fa.fa-list-ul')
|
||||
},
|
||||
};
|
||||
|
||||
var renderResults = function (content, answers) {
|
||||
|
@ -1848,7 +2118,7 @@ define([
|
|||
if (editable) {
|
||||
Sortable.create($container[0], {
|
||||
direction: "vertical",
|
||||
filter: "input, button, .CodeMirror",
|
||||
filter: "input, button, .CodeMirror, .cp-form-type-sort",
|
||||
preventOnFilter: false,
|
||||
draggable: ".cp-form-block",
|
||||
forceFallback: true,
|
||||
|
|
Loading…
Reference in New Issue