Option group does not work with a function - select

I have an option group. When you select an option, a filter function should be called and output accordingly. Only with select it works.
So it must be the option group. The individual options are loaded with the function. This works perfectly.
Here is the code:
<label for="slc">Select a Filter:</label>
<select class="selectpicker" id="slcfilter">
<optgroup
label="Period"
class="form-control"
id="filterPeriod"
onchange="filter2var(periods, this)">
</optgroup>
<optgroup
label="Language"
class="form-control"
id="filterLanguage"
onchange="filter3var(languages, 'language', this)">
</optgroup>
</select>
And here arte the funktions. I have two filter functions and two functions which are for the options:
function resetDropdown(exclude) {
dropdown_ids = ['filterPeriod', 'filterLanguage', 'filterGenre', 'filterSubgenre', 'filterMaterial', 'filterProvenience']
for(const elem of dropdown_ids) {
if(elem != exclude) {
var dropdown = document.getElementById(elem)
dropdown.value = ""
}
}
}
function filter2var(toBeFiltered, selected) {
resetDropdown(selected.id)
const keys = Object.keys(toBeFiltered);
var value = selected.value
var $select = $(document.getElementById('images')).selectize(options);
var selectize = $select[0].selectize;
selectize.clearOptions(true)
for(const obj of keys) {
if(toBeFiltered[obj] == value) {
selectize.addOption({value: obj, text: obj});
selectize.refreshOptions();
}
}
document.getElementById('images').innerHTML = options
}
function filter3var(toBeFiltered, entry, selected) {
resetDropdown(selected.id)
const keys = Object.keys(toBeFiltered);
var value = selected.value
var $select = $(document.getElementById('images')).selectize(options);
var selectize = $select[0].selectize;
selectize.clearOptions(true)
for(const obj of keys) {
if(toBeFiltered[obj][entry] == value) {
selectize.addOption({value: obj, text: obj});
selectize.refreshOptions();
}
}
document.getElementById('images').innerHTML = options
}
function setUniqueEntriesAsOptions1(select_id, object) {
var select = document.getElementById(select_id)
var unique = []
var options = "<option value=\"\">--Please choose an option--</option>"
const keys = Object.keys(object);
for(const obj of keys) {
if(!unique.includes(object[obj]) && object[obj] != "") {
unique.push(object[obj])
options+= "<option value=\""+object[obj]+"\">"+object[obj]+"</option>"
}
}
select.innerHTML = options
}
function setUniqueEntriesAsOptions(select_id, object, uniqueEntry) {
var select = document.getElementById(select_id)
var unique = []
var options = "<option value=\"\">--Please choose an option--</option>"
const keys = Object.keys(object);
for(const obj of keys) {
if(!unique.includes(object[obj][uniqueEntry]) && object[obj][uniqueEntry] != "") {
unique.push(object[obj][uniqueEntry])
options+= "<option value=\""+object[obj][uniqueEntry]+"\">"+object[obj][uniqueEntry]+"</option>"
}
}
select.innerHTML = options
}
setUniqueEntriesAsOptions1('filterPeriod', periods)
setUniqueEntriesAsOptions('filterLanguage', languages, 'language')
setUniqueEntriesAsOptions('filterGenre', languages, 'genre')
setUniqueEntriesAsOptions('filterSubgenre', languages, 'subgenre')
setUniqueEntriesAsOptions('filterMaterial', languages, 'material')
setUniqueEntriesAsOptions('filterProvenience', languages, 'provenience')

Related

Limit size of entered data in tinyMCE 5

I use tinyMCE 5 in my web site to enter data stored in a database. Therefore I need to limit the entered size, including format information, to the size of the data field. How can I prohibit the user to enter more then the allowed number of bytes, say 2000?
Best of all if I could add some information like "42/2000" on the status bar.
We had a similar requirement in our project (difference: the output should be <entered_chars>/<chars_left> instead of <entered_chars>/<max_chars>), and it ended up being a custom plugin, based on the wordcount plugin. There is some hacks in there, which could make it fail whenever tinyMCE changes, since there is no API for the statusbar in version 5 at this point of time.
But maybe you will still find it useful:
(function () {
'use strict';
var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
var maxChars = function (editor) {
return editor.getParam('number_max_chars', 3600);
};
var applyMaxChars = function (editor) {
return editor.getParam('restrict_to_max_chars', true);
};
var Settings = {
maxChars: maxChars,
applyMaxChars: applyMaxChars
};
var global$1 = tinymce.util.Tools.resolve('tinymce.dom.TreeWalker');
var getText = function (node, schema) {
var blockElements = schema.getBlockElements();
var shortEndedElements = schema.getShortEndedElements();
var isNewline = function (node) {
return blockElements[node.nodeName] || shortEndedElements[node.nodeName];
};
var textBlocks = [];
var txt = '';
var treeWalker = new global$1(node, node);
while (node = treeWalker.next()) {
if (node.nodeType === 3) {
txt += node.data;
} else if (isNewline(node) && txt.length) {
textBlocks.push(txt);
txt = '';
}
}
if (txt.length) {
textBlocks.push(txt);
}
return textBlocks;
};
var strLen = function (str) {
return str.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, '_').length;
};
var countCharacters = function (node, schema) {
var text = getText(node, schema).join('');
return strLen(text);
};
var createBodyCounter = function (editor, count) {
return function () {
return count(editor.getBody(), editor.schema);
};
};
var createMaxCount = function (editor) {
return function () {
return Settings.maxChars(editor);
}
}
var createRestrictToMaxCount = function (editor) {
return function () {
return Settings.applyMaxChars(editor);
}
}
var get = function (editor) {
return {
getCount: createBodyCounter(editor, countCharacters),
getMaxCount: createMaxCount(editor),
getRestrictToMaxCount: createRestrictToMaxCount(editor)
};
};
var global$2 = tinymce.util.Tools.resolve('tinymce.util.Delay');
function isAllowedKeycode(event) {
// allow arrow keys, backspace and delete
const key = event.keyCode;
return key === 37 || key === 38 || key === 39 || key === 40 || key === 8
|| key === 46;
}
var updateCount = function (editor, api) {
editor.getContainer().getElementsByClassName(
'tox-statusbar__text-container')[0].textContent = String(
api.getCount()) + " / " + String(
Settings.maxChars(editor) - api.getCount());
};
var setup = function (editor, api, delay) {
var debouncedUpdate = global$2.debounce(function () {
return updateCount(editor, api);
}, delay);
editor.on('init', function () {
updateCount(editor, api);
global$2.setEditorTimeout(editor, function () {
editor.on('SetContent BeforeAddUndo Undo Redo keyup', debouncedUpdate);
editor.on('SetContent BeforeAddUndo Undo Redo keydown', function (e) {
if (!isAllowedKeycode(e) && Settings.applyMaxChars(editor) &&
api.getCount() >= Settings.maxChars(editor)) {
e.preventDefault();
e.stopPropagation();
}
});
}, 0);
});
};
function Plugin(delay) {
if (delay === void 0) {
delay = 300;
}
global.add('charactercount', function (editor) {
var api = get(editor);
setup(editor, api, delay);
return api;
});
}
Plugin();
}());
Currently I'm working on a preprocessor for the paste plugin, so that the max_length effects also pasted text. That's why you see the charactercount API in the code.

MVC app does not show selected values on a form reedition

I am building a Framework7 MVC app and found myself in a dead end alley. I have a form which I need to evaluate. This form contains selects. I am using localStorage to store the form values and everything works OK in that sense, I mean everything is stored correctly. ¿What is the issue? When I fill the form I answer some questions on textareas inputs, select inputs and inputs. everything goes fine until I try to reedit the form, then everything is display correctly on the form, including the score i got from my previous answers, but, the selects appears as if I have never touch them. Their previously selected value is stored but not display on the form. I have found that the issue is caused by the fact that I have set numerical values to the options values but what the form show is "yes" or "no". If I change the option values to "yes" or "no" then the form displays correctly but I need to set "5" or "0" because I need to evaluate the user's answers.
This is my code
The form
<li style="margin-top:-10px;">
<input style="visibility:hidden;height:1px;" value="0" name="choice" onchange="checkTotal()"/>
<input style="visibility:hidden;height:1px;" value="1" type="checkbox" name="choice" onchange="checkTotal()" checked="on">
</li>
<li><div class="item-content">1. ¿Sueles quejarte de sentirte mal?</div>
<div class="item-content">
<div class="item-inner">
<div class="item-input">
<select name="pr1" id="pr1" onchange="checkTotal()">
<option class="item-inner" value="5">No</option>
<option class="item-inner" value="0">Si</option>
</select>
</div>
</div>
</div>
<div class="item-content">En tal caso,</div>
<div class="item-content">
<div class="item-inner">
<div class="item-input">
<textarea class="resizable" id="pr1notes" placeholder="¿cuál es la causa?">{{model.pr1notes}}</textarea>
</div>
</div>
</div>
</li>
The functions on the editController
function init(query){
var protections = JSON.parse(localStorage.getItem("f7Protections"));
if (query && query.id) {
protection = new Protection(_.find(protections, { id: query.id }));
state.isNew = false;
}
else {
protection = new Protection({ isFavorite: query.isFavorite });
state.isNew = true;
}
View.render({ model: protection, bindings: bindings, state: state, doneCallback: saveProtection });
showSelectedValues();
}
function showSelectedValues(){
var fieldNames = protection.getSelectFields();
for (var i = 0, len = fieldNames.length; i < len; i++) {
var itemname = fieldNames[i];
var selectObj = document.getElementById(itemname);
if (selectObj!=null) {
var objOptions = selectObj.options;
var selIndex=0;
for (var j = 0, len2 = objOptions.length; j < len2; j++) {
if ((objOptions[j].label).localeCompare(protection[itemname])==0){
selIndex=j;
}
}
selectObj.options[selIndex].setAttribute("selected","selected");
}else{
}
}
}
and the model
Protection.prototype.setValues = function(inputValues, extras) {
for (var i = 0, len = inputValues.length; i < len; i++) {
var item = inputValues[i];
if (item.type === 'checkbox') {
this[item.id] = item.checked;
}
else {
this[item.id] = item.value;
}
}
for (var i = 0, len = extras[0].length; i < len; i++) {
var item = extras[0][i];
if((item.id).localeCompare("pr1notes")==0) {this[item.id] = item.value;}
}
console.log('starting loop for extras 3...');
for (var i = 0, len = extras[2].length; i < len; i++) {
var item = extras[2][i];
this[item.name] = item.value;
}
};
Protection.prototype.validate = function() {
var result = true;
if (_.isEmpty(this.prdate)
) {result = false;}
return result;
};
Protection.prototype.getSelectFields = function() {
return ['pr1'];
}
What should I change in order to keep my "5" or "0" values on the select options while the form options still show "yes" or "no" to the user just like this: <select name="pr1" id="pr1" onchange="checkTotal()"><option class="item-inner" value="5">No</option><option class="item-inner" value="0">Si</option></select>?
need anything else to help you understand the issue?
The simplest solution
function init(query){
var protections = JSON.parse(localStorage.getItem("f7Protections"));
if (query && query.id) {
protection = new Protection(_.find(protections, { id: query.id }));
state.isNew = false;
}
else {
protection = new Protection({ isFavorite: query.isFavorite });
state.isNew = true;
}
View.render({ model: protection, bindings: bindings, state: state, doneCallback: saveProtection });
showSelectedValues();
}
function showSelectedValues(){
var fieldNames = protection.getSelectFields();
for (var i = 0, len = fieldNames.length; i < len; i++) {
var itemname = fieldNames[i];
var selectObj = document.getElementById(itemname);
if (selectObj!=null) {
var objOptions = selectObj.options;
var selIndex=0;
for (var j = 0, len2 = objOptions.length; j < len2; j++) {
if ((objOptions[j].value).localeCompare(protection[itemname])==0){
selIndex=j;
}
}
selectObj.options[selIndex].setAttribute("selected","selected");
}else{
}
}
}
Just changed this line
if ((objOptions[j].label).localeCompare(protection[itemname])==0){
selIndex=j;
and changed .label for .value.

Svelte doesn't reorder Meteor collection

My Svelte component is set up to find all people in a MongoDB document and list them in a table. When clicking on a column header the collection should sort by that column/field and it should toggle the sort direction with subsequent clicks.
My script section:
$: sortColumn = 'name';
$: sortDirection = 'asc';
$: sortParameters = setSortParams(sortColumn, sortDirection);
$: contactList = [];
function getContactList(sortObj) {
contactList = Contacts.find({
isBlocked: false,
isDeleted: { $ne: true }
},
{
sort: sortObj
}).fetch();
contactList = contactList;
}
onMount(() => {
getContactList(setSortParams(sortColumn, sortDirection));
});
function changeSortDirection() {
if (sortDirection === 'asc') {
sortDirection = 'desc';
} else {
sortDirection = 'asc';
}
}
function sortByColumn(col) {
if (col === sortColumn) {
changeSortDirection();
} else {
sortDirection = 'asc';
}
sortColumn = col;
getContactList(setSortParams(sortColumn, sortDirection));
}
function setSortParams(sortField, sDirection) {
let sortParams = [];
let direction = sDirection || 1;
let field = sortField || 'name';
if (direction === 'asc') {
direction = 1;
} else {
direction = -1;
}
if (field === 'name') {
sortParams.push(['firstName', direction]);
sortParams.push(['lastName', direction]);
} else {
sortParams.push([field, direction]);
}
sortParams = sortParams;
return sortParams;
}
And the relevant part of my svelte file:
{#each columns as column}
<th class="contact-table__column contact-table__column-header"
on:click={() => sortByColumn(column.type)}>
<span class="contact-table__title">{column.display} {sortDirection}</span>
</th>
{/each}
The collection reorders when I click on a different column header, but it doesn't reorder when I click on the same header (it should switch between ASC and DESC sort order).
I'm new to Svelte and Meteor so I'm sure there's a few things I'm doing wrong. I appreciate any help.

algolia/instantsearch: connectMenu refine() remove current refined value

Is there any way to REMOVE a refined value with connectMenu’s connector?
These are the things I tried that did not work:
passing an empty string refine('')
passing a null value refine(null)
passing a false value refine(false)
passing no parameter refine()
The reason why I’d like to do this is because otherwise currentRefinedValues widget shows an attribute as refined even if it’s not.
var customMenuRenderFn = function (renderParams, isFirstRendering) {
var container = renderParams.widgetParams.containerNode;
var title = renderParams.widgetParams.title || 'dropdownMenu';
var templates = renderParams.widgetParams.templates;
var hideIfIsUnselected = renderParams.widgetParams.hideIfIsUnselected || false;
var cssClasses = renderParams.widgetParams.cssClasses || "";
if (isFirstRendering)
{
$(container).append(
(templates.header || '<h1>' + renderParams.widgetParams.attributeName + '</h1>') +
'<select class="' + cssClasses.select + '">' +
'<option value="__EMPTY__">Tutto</option>' +
'</select>'
).hide();
var refine = renderParams.refine;
if (! hideIfIsUnselected)
{
$(container).show();
}
else
{
$(hideIfIsUnselected).find('select').on('items:loaded', function () {
if (isFirstRendering) {
var valueToCheck = $(hideIfIsUnselected).find('select').val();
$(container).toggle(valueToCheck !== '__EMPTY__');
$(container).find('select').off('items:loaded');
}
});
$(hideIfIsUnselected).find('select').on('change', function (event) {
var value = event.target.value === '__EMPTY__' ? '' : event.target.value;
if (value === '') {
refine();
}
$(container).toggle(value !== '');
});
}
$(container).find('select').on('change', function (event) {
var value = event.target.value === '__EMPTY__' ? '' : event.target.value;
refine(value);
});
}
function updateHits (hits)
{
var items = renderParams.items;
optionsHtml = ['<option class="' + cssClasses.item + '" value="__EMPTY__" selected>Tutto</option>']
.concat(
items.map(function (item) {
return `<option class="${cssClasses.item}" value="${item.value}" ${item.isRefined ? 'selected' : ''}>
${item.label} (${item.count})
</option>`;
})
);
$(container).find('select').html(optionsHtml);
$(container).find('select').trigger('items:loaded');
}
if (hideIfIsUnselected && $(hideIfIsUnselected).val() !== '__EMPTY__') {
updateHits(renderParams.items);
} else if (! hideIfIsUnselected) {
updateHits(renderParams.items);
}
}
var dropdownMenu = instantsearch.connectors.connectMenu(customMenuRenderFn);
The refine function actually toggles the value (setting it if not set, or unsetting if set). If you want to unselect any item in the menu, you need to find the currently selected value and use refine on it.
connectMenu(function render(params, isFirstRendering) {
var items = params.items;
var currentlySelectedItem = items.find(function isSelected(i) {
return i.isRefined;
});
params.refine(currentlySelectedItem);
});
This example won't solve your code completely, but it shows how to find the currently selected item and unselect it.

Start search after 2 character typed in Chosen drop down

In Chosen drop down plugin, a search is started after 2 characters are typed in chosen drop down.
I need the search to not start until after inputing at least two characters in the search box.
Can any one suggest how to do this?
I did a small change to start to search after the third character, is not the best option but works, in the chosen JS in the AbstractChosen.prototype.winnow_results function after the line searchText = this.get_search_text(); add the following code: if (searchText != "" && searchText.length < 3) return;. Remember to change the < 3 by your own size.
Hope this help you
See part of the code below:
AbstractChosen.prototype.winnow_results = function() {
var escapedSearchText, option, regex, regexAnchor, results, results_group, searchText, startpos, text, zregex, _i, _len, _ref;
this.no_results_clear();
results = 0;
searchText = this.get_search_text();
if (searchText != "" && searchText.length < 3) return;
escapedSearchText = searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
I know this post it's old but i had to face this problem just now and wanted to share my result. I wrapped everything in a function extendedSearch and set it as a callback while chosen is emitting the chosen:showing_dropdown event.
My problem was that i need the search to show the results after the 2nd character typed in search and must filter out certain strings from the results.
Bellow you'll find a demo which shows results on the 3rd character typed in, and will keep visible only those results that end with letter "E".
$(function() {
/**
* By default the results are hidden when clicking a dropdown.
* {
* toggleResults: false, // a function(searchValue) that returns a boolean
* filterResults: false, // a function(dropDownValue, selectValue) that returns a boolean
* }
* #param options
*/
const extendedSearch = (options = {}) => {
const defaultOptions = {
toggleResults: false,
filterResults: false,
};
options = { ...{},
...defaultOptions,
...options
};
/**
* Main element
*/
return (evt, params) => {
let originalElement = $(evt.currentTarget);
let searchInput = params.chosen.search_field;
const customSearch = (options = {}) => {
let defaultOptions = {
originalElement: null,
searchInput: null
};
options = { ...{},
...defaultOptions,
...options
};
if (!(options.originalElement instanceof jQuery) || !options.originalElement) {
throw new Error('Custom Search: originalElement is invalid.');
}
if (!(options.searchInput instanceof jQuery) || !options.searchInput) {
throw new Error('Custom Search: searchInput is invalid.');
}
let res = options.searchInput
.parent()
.next('.chosen-results');
res.hide();
if (typeof options.toggleResults !== 'function') {
options.toggleResults = (value) => true;
}
if (options.filterResults && typeof options.filterResults !== 'function') {
options.filterResults = (shownText = '', selectValue = '') => true;
}
/**
* Search Input Element
*/
return (e) => {
let elem = $(e.currentTarget);
let value = elem.val() || '';
if (value.length && options.toggleResults(value) === true) {
res.show();
if (options.filterResults) {
let children = res.children();
let active = 0;
$.each(children, (idx, item) => {
let elItem = $(item);
let elemIdx = elItem.attr('data-option-array-index');
let shownText = elItem.text();
let selectValue = options.originalElement.find('option:eq(' + elemIdx + ')').attr('value') || '';
if (options.filterResults(shownText, selectValue) === true) {
active++;
elItem.show();
} else {
active--;
elItem.hide();
}
});
if (active >= 0) {
res.show();
} else {
res.hide();
}
}
} else {
res.hide();
}
};
};
options = {
...{},
...options,
...{
originalElement,
searchInput
}
};
let searchInstance = customSearch(options);
searchInput
.off('keyup', searchInstance)
.on('keyup', searchInstance)
}
};
/** This is the final code */
const inputValidator = (value) => {
console.log('input', value);
return $.trim(value).length > 2;
};
const textResultsValidator = (dropDownValue, selectValue) => {
if ($.trim(dropDownValue).substr(-1, 1) === 'E') {
console.log('results shown', dropDownValue, '|', selectValue);
return true;
}
return false;
};
$(".chosen-select")
.chosen()
.on('chosen:showing_dropdown', extendedSearch({
toggleResults: inputValidator,
filterResults: textResultsValidator
}));
});
#import url("https://cdnjs.cloudflare.com/ajax/libs/chosen/1.8.7/chosen.min.css")
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chosen/1.8.7/chosen.jquery.min.js"></script>
<select class="chosen-select">
<option value="">Pick something</option>
<option value="APPLE">APPLE</option>
<option value="APPLE JUICE">APPLE JUICE</option>
<option value="BANANA">BANANA</option>
<option value="ANANAS">ANANAS</option>
<option value="ORANGE">ORANGE</option>
<option value="ORANGES">ORANGES</option>
<option value="STRAWBERRY">STRAYBERRY</option>
</select>