node_modules select2 replace wrappedMatcher with startMatcher - javascript

I'm trying to change the select2.julll.js file from node_modules Angular 6 project.
So far I found some ways to do that tho, nothing has worked for me, would you fave any suggestions of how I can replace wrappedMatcher with startMatcher in select2 file?
S2.define('select2/compat/matcher',[
'jquery'
], function ($) {
function oldMatcher (matcher) {
function wrappedMatcher (params, data) {
var match = $.extend(true, {}, data);
if (params.term == null || $.trim(params.term) === '') {
return match;
}
if (data.children) {
for (var c = data.children.length - 1; c >= 0; c--) {
var child = data.children[c];
// Check if the child object matches
// The old matcher returned a boolean true or false
var doesMatch = matcher(params.term, child.text, child);
// If the child didn't match, pop it off
if (!doesMatch) {
match.children.splice(c, 1);
}
}
if (match.children.length > 0) {
return match;
}
}
if (matcher(params.term, data.text, data)) {
return match;
}
return null;
}
return wrappedMatcher;
}
return oldMatcher;
});

Adding the following code to my select2.directives.ts has solved my problem
if (data.text.toString().toLowerCase().indexOf(params.term) > -1 &&
!!data.text.toString().toLowerCase().startsWith(params.term.toString().toLowerCase())) {
var modifiedData = $.extend({}, data, true);
// modifiedData.text += ' (matched)';
// You can return modified objects from here
// This includes matching the `children` how you want in nested data sets
return modifiedData;
}

Related

JavaScript Promise Method not returning any data

I am creating a react native application.
I have a back button that fires the function findItem. findItem the uses async method searchJson. searchJson searches recursive json to find parent object based on id. However it never returns any results.
findItem:
findItem() {
//Pass null so top level json will be pulled
let result = this.searchJson(null).done();
let abv = 2;
// this.setState(previousState => {
// return {
// data: result,
// parentID: result.parentid
// };
// });
}
searchJson:
async searchJson(object) {
return new Promise(resolve => {
//use object or pull from porp - all data
let theObject = object == null ? this.props.data : object;
var result = null;
if (theObject instanceof Array) {
for (var i = 0; i < theObject.length; i++) {
result = this.searchJson(theObject[i]);
if (result) {
break;
}
}
}
else {
for (var prop in theObject) {
console.log(prop + ': ' + theObject[prop]);
if (prop == 'id') {
if (theObject[prop] == this.state.parentID) {
return theObject;
}
}
if (theObject[prop] instanceof Object || theObject[prop] instanceof Array) {
result = this.searchJson(theObject[prop]);
if (result) {
break;
}
}
}
}
if(result != null)
resolve(result);
});
}
Any help will be greatly appreciated.
Ok so I never got this to work but my workaround was this.
I Modified the findItem method:
findItem() {
let FinNode = null;
for (var node in this.props.data) {
FinNode = this.searchJson(this.state.parentID, this.props.data, this.props.data[node].book);
if (FinNode != null) {
this.setState(previousState => {
return {
data: FinNode[0].book.parentid == "" ? null : FinNode,
parentID: FinNode[0].book.parentid
};
});
break;
}
}
}
And then the searchJson:
searchJson(id, parentArray, currentNode) {
if (id == currentNode.id) {
return parentArray;
} else {
var result;
for (var index in currentNode.books) {
var node = currentNode.books[index].book;
if (node.id == id)
return currentNode.books;
this.searchJson(id, currentNode.books, node);
}
return null;
}
}
This allowed for all my nodes to be searched and the for loop made so that there is no need for async. This does have some drawbacks but seems to work decently without any massive performance issues.

Regex to change a html element class with javascript not working

I have the following javascript function to open and close sub list elements on an onclick event:
function ShowHideDtls(itId) {
var subMen = document.getElementById(itId);
if (subMen != null) {
if (subMen.className == "nav nav-second-level collapse in") {
subMen.className = "nav nav-second-level collapse";
} else {
subMen.className += " in";
}
}
}
The "collapse" is a css class which makes display=none hiding the sub list and "in" is a class which makes display=block showing the sub list, creating a menu with submenus.
I found in this question Change an element's class with JavaScript in the first(accepted) answer use of a regex in order to do this. I tried it like this:
function ShowHideDtls(itId) {
var subMen = document.getElementById(itId);
if (subMen != null) {
if (subMen.className.match(/(?:^|\s)in(?!\S)/)) {
subMen.className.replace(/(?:^|\s)in(?!\S)/g, '');
} else {
subMen.className += " in";
}
}
}
The code without the regex works perfectly but with the regex it doesn't. I checked the regex in regex101.com and it seems to work there. As I understand it's more appropriate to use the regex than a long string of all the class names and also I also have a nav-third-level class that I have to close and open so the regex seems to be the convenient and proper way to do it.
What's wrong?
Thank you.
No need of regex here. You can use classList
Using classList is a convenient alternative to accessing an element's list of classes as a space-delimited string via element.className.
function ShowHideDtls(itId) {
var subMen = document.getElementById(itId);
if (subMen != null) {
subMen.classList.toggle('in');
}
}
toggle() will toggle the class of the element. If the element already has the class, it'll remove it, if not then toggle will add the class to the element.
Check the Browser Compatibility.
You can use following SHIM from MDN for IE9,
/*
* classList.js: Cross-browser full element.classList implementation.
* 2014-07-23
*
* By Eli Grey, http://eligrey.com
* Public Domain.
* NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
*/
/*global self, document, DOMException */
/*! #source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/
if ("document" in self) {
// Full polyfill for browsers with no classList support
if (!("classList" in document.createElement("_"))) {
(function (view) {
"use strict";
if (!('Element' in view)) return;
var
classListProp = "classList",
protoProp = "prototype",
elemCtrProto = view.Element[protoProp],
objCtr = Object,
strTrim = String[protoProp].trim || function () {
return this.replace(/^\s+|\s+$/g, "");
},
arrIndexOf = Array[protoProp].indexOf || function (item) {
var
i = 0,
len = this.length;
for (; i < len; i++) {
if (i in this && this[i] === item) {
return i;
}
}
return -1;
}
// Vendors: please allow content code to instantiate DOMExceptions
,
DOMEx = function (type, message) {
this.name = type;
this.code = DOMException[type];
this.message = message;
},
checkTokenAndGetIndex = function (classList, token) {
if (token === "") {
throw new DOMEx(
"SYNTAX_ERR", "An invalid or illegal string was specified"
);
}
if (/\s/.test(token)) {
throw new DOMEx(
"INVALID_CHARACTER_ERR", "String contains an invalid character"
);
}
return arrIndexOf.call(classList, token);
},
ClassList = function (elem) {
var
trimmedClasses = strTrim.call(elem.getAttribute("class") || ""),
classes = trimmedClasses ? trimmedClasses.split(/\s+/) : [],
i = 0,
len = classes.length;
for (; i < len; i++) {
this.push(classes[i]);
}
this._updateClassName = function () {
elem.setAttribute("class", this.toString());
};
},
classListProto = ClassList[protoProp] = [],
classListGetter = function () {
return new ClassList(this);
};
// Most DOMException implementations don't allow calling DOMException's toString()
// on non-DOMExceptions. Error's toString() is sufficient here.
DOMEx[protoProp] = Error[protoProp];
classListProto.item = function (i) {
return this[i] || null;
};
classListProto.contains = function (token) {
token += "";
return checkTokenAndGetIndex(this, token) !== -1;
};
classListProto.add = function () {
var
tokens = arguments,
i = 0,
l = tokens.length,
token, updated = false;
do {
token = tokens[i] + "";
if (checkTokenAndGetIndex(this, token) === -1) {
this.push(token);
updated = true;
}
}
while (++i < l);
if (updated) {
this._updateClassName();
}
};
classListProto.remove = function () {
var
tokens = arguments,
i = 0,
l = tokens.length,
token, updated = false,
index;
do {
token = tokens[i] + "";
index = checkTokenAndGetIndex(this, token);
while (index !== -1) {
this.splice(index, 1);
updated = true;
index = checkTokenAndGetIndex(this, token);
}
}
while (++i < l);
if (updated) {
this._updateClassName();
}
};
classListProto.toggle = function (token, force) {
token += "";
var
result = this.contains(token),
method = result ?
force !== true && "remove" :
force !== false && "add";
if (method) {
this[method](token);
}
if (force === true || force === false) {
return force;
} else {
return !result;
}
};
classListProto.toString = function () {
return this.join(" ");
};
if (objCtr.defineProperty) {
var classListPropDesc = {
get: classListGetter,
enumerable: true,
configurable: true
};
try {
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
} catch (ex) { // IE 8 doesn't support enumerable:true
if (ex.number === -0x7FF5EC54) {
classListPropDesc.enumerable = false;
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
}
}
} else if (objCtr[protoProp].__defineGetter__) {
elemCtrProto.__defineGetter__(classListProp, classListGetter);
}
}(self));
} else {
// There is full or partial native classList support, so just check if we need
// to normalize the add/remove and toggle APIs.
(function () {
"use strict";
var testElement = document.createElement("_");
testElement.classList.add("c1", "c2");
// Polyfill for IE 10/11 and Firefox <26, where classList.add and
// classList.remove exist but support only one argument at a time.
if (!testElement.classList.contains("c2")) {
var createMethod = function (method) {
var original = DOMTokenList.prototype[method];
DOMTokenList.prototype[method] = function (token) {
var i, len = arguments.length;
for (i = 0; i < len; i++) {
token = arguments[i];
original.call(this, token);
}
};
};
createMethod('add');
createMethod('remove');
}
testElement.classList.toggle("c3", false);
// Polyfill for IE 10 and Firefox <24, where classList.toggle does not
// support the second argument.
if (testElement.classList.contains("c3")) {
var _toggle = DOMTokenList.prototype.toggle;
DOMTokenList.prototype.toggle = function (token, force) {
if (1 in arguments && !this.contains(token) === !force) {
return force;
} else {
return _toggle.call(this, token);
}
};
}
testElement = null;
}());
}
}
If you're using jQuery, you can use toggleClass():
function ShowHideDtls(itId) {
$('#' + itId).toggleClass('in');
}
Edit
If you still want to use regex:
if (/\bin\b/.test(subMen.className))
subMen.className.replace(/\bin\b/, '');
} else {
subMen.className += " in";
}
You can also use split() and indexOf as follow to check if a class is present on element.
var classes = className.split(/\s+/),
classIndex = classes.indexOf('in');
if (classIndex > -1) {
classes.splice(classIndex, 1);
subMen.className = classes.join(' ');
} else {
subMen.className += " in";
}
replace function returns the resultant value, it do not assign value indirectly.
So do following:
function ShowHideDtls(itId) {
var subMen = document.getElementById(itId);
if (subMen != null) {
if (subMen.className.match(/(?:^|\s)in(?!\S)/)) {
subMen.className = subMen.className.replace(/(?:^|\s)in(?!\S)/g, '');
}
else {
subMen.className += " in";
}
}
}

Recursively pass through Json to get all values for a specific key

I have a json object which looks like this:
var testJ = {"ROOT":{
dir : 'app',
files : [
'index.html',
{
dir : 'php',
files: [
'a.php',
{
dir : 'extras',
files : [
'a.js',
'b.js'
]
}
]
}
]
}};
I need to extract all the files and append into an array (index.html,a.php,a.js..etc)
For this I wrote a javascript code as follows:
var arr=[];
function scan(obj,append)
{
var k;
if (obj instanceof Object) {
for (k in obj){
if (obj.hasOwnProperty(k)){
if(k=='files')
{
scan( obj[k],1 );
}
}
}
} else {
body += 'found value : ' + obj + '<br/>';
if(append == 1)
arr.push(obj);
alert("Arr"+ arr);
};
};
scan(testJ,0);
I am not able to figure out where am I going wrong. Could some give me pointers?
var res = [];
function gather(j) {
for (var k in j) {
if (k === 'files') {
addFiles(j[k]);
} else if (typeof j[k] === 'object') {
gather(j[k]);
}
}
}
function addFiles(f) {
for (var i = 0; i < f.length; i++) {
if (typeof f[i] === "string") {
body += 'found value : ' + obj + '<br/>';
res.push(f[i]);
} else {
gather(f[i]);
}
}
}
gather(testJ);
Free tips:
instanceof is some cancerous stuff. Why does instanceof return false for some literals?
Always, always use === for comparison, not ==
I also wouldn't blindly use hasOwnProperty unless you're afraid the thing you're operating on might have a modified prototype, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in just for simplicity.
How about a map reduce approach?:
function mapJ(subject) {
return subject.files.map(function(item) {
if (typeof item === "string") {
return item;
} else {
return parseJ(item);
}
});
}
function reduceJ(subject) {
return subject.reduce(function(prev, cur) {
return prev.concat(cur);
}, []);
}
function parseJ(subject) {
return reduceJ(mapJ(subject));
}
var result = parseJ(testJ));

Loop through JQuery array

I'm creating a self updating match/fixture script, which return data from a JSON Script which automatically updates. However the JSON script include 3 arrays live, upcoming and recent. How can i loop through all of these arrays instead of just matches[0] which is live? i've tried using loop, but it cant loop through the functions?
var lastLoadedMatch = 0,
ajaxInterval = 5000;
$(function() {
getMatches();
});
function getMatches(lastId) {
$.getJSON('data.json', function(resp) {
console.log(JSON.stringify(resp));
var matches = [resp.live, resp.upcoming, resp.recent];
if (lastId) {
matches[0] = matches[0].filter(
function(match) {
return match.id > lastId;
});
}
if (matches[0].length) {
$.each(matches[0], function(_, match) {
console.log([match.match_id,lastLoadedMatch ])
if (match.match_id > lastLoadedMatch) {
lastLoadedMatch = match.match_id
}
if ($.trim(match.game) == "lol") {
$('#part-1').append(matchHtml(this))
} else if ($.trim(match.game) == "counterstrike") {
$('#part-2').append(matchHtml(this))
} else if ($.trim(match.game) == "dota2") {
$('#part-3').append(matchHtml(this))
} else if ($.trim(match.game) == "hearthstone") {
$('#part-4').append(matchHtml(this))
}
});
}else{
}
setTimeout(function() {
getMatches(lastLoadedMatch);
}, ajaxInterval);
});
}
Just wrap your code in one more $.each that will iterate of your matches array:
var matches = [resp.live, resp.upcoming, resp.recent];
$.each(matches, function(_, match) {
if (lastId) {
match = match.filter(
function(match) {
return match.id > lastId;
});
}
if (match.length) {
$.each(match, function(_, match) {
...
or you can concatenate the arrays:
var matches = resp.live.concat(resp.upcoming, resp.recent);

Add space between numbers/digits and letters/characters

I have a code like this
(function($, window, document, undefined) {
$.fn.quicksearch = function (target, opt) {
var timeout, cache, rowcache, jq_results, val = '', e = this, options = $.extend({
delay: 100,
selector: null,
stripeRows: null,
loader: null,
noResults: '',
bind: 'keyup',
onBefore: function () {
return;
},
onAfter: function () {
return;
},
show: function () {
this.style.display = "";
},
hide: function () {
this.style.display = "none";
},
prepareQuery: function (val) {
return val.toLowerCase().split(' ');
},
testQuery: function (query, txt, _row) {
for (var i = 0; i < query.length; i += 1) {
if (txt.indexOf(query[i]) === -1) {
return false;
}
}
return true;
}
}, opt);
this.go = function () {
var i = 0,
noresults = true,
query = options.prepareQuery(val),
val_empty = (val.replace(' ', '').length === 0);
for (var i = 0, len = rowcache.length; i < len; i++) {
if (val_empty || options.testQuery(query, cache[i], rowcache[i])) {
options.show.apply(rowcache[i]);
noresults = false;
} else {
options.hide.apply(rowcache[i]);
}
}
if (noresults) {
this.results(false);
} else {
this.results(true);
this.stripe();
}
this.loader(false);
options.onAfter();
return this;
};
this.stripe = function () {
if (typeof options.stripeRows === "object" && options.stripeRows !== null)
{
var joined = options.stripeRows.join(' ');
var stripeRows_length = options.stripeRows.length;
jq_results.not(':hidden').each(function (i) {
$(this).removeClass(joined).addClass(options.stripeRows[i % stripeRows_length]);
});
}
return this;
};
this.strip_html = function (input) {
var output = input.replace(new RegExp('<[^<]+\>', 'g'), "");
output = $.trim(output.toLowerCase());
return output;
};
this.results = function (bool) {
if (typeof options.noResults === "string" && options.noResults !== "") {
if (bool) {
$(options.noResults).hide();
} else {
$(options.noResults).show();
}
}
return this;
};
this.loader = function (bool) {
if (typeof options.loader === "string" && options.loader !== "") {
(bool) ? $(options.loader).show() : $(options.loader).hide();
}
return this;
};
this.cache = function () {
jq_results = $(target);
if (typeof options.noResults === "string" && options.noResults !== "") {
jq_results = jq_results.not(options.noResults);
}
var t = (typeof options.selector === "string") ? jq_results.find(options.selector) : $(target).not(options.noResults);
cache = t.map(function () {
return e.strip_html(this.innerHTML);
});
rowcache = jq_results.map(function () {
return this;
});
return this.go();
};
this.trigger = function () {
this.loader(true);
options.onBefore();
window.clearTimeout(timeout);
timeout = window.setTimeout(function () {
e.go();
}, options.delay);
return this;
};
this.cache();
this.results(true);
this.stripe();
this.loader(false);
return this.each(function () {
$(this).bind(options.bind, function () {
val = $(this).val();
e.trigger();
});
});
};
}(jQuery, this, document));
I try to figure out where and how I can make a split/add space between numbers and letters. Cause some people type for example "ip1500" and the script cant match the input with an element that is like "ip 1500". My problem ist that Im a js beginner.
I was trying and trying but i cant get it work. I also tried this
I found this spot and I think it can be done here where the everything get splitted by an " " (space):
prepareQuery: function (val) {
return val.toLowerCase().split(' ');
},
Would be very nice if somebody can help me.
If you want "123abc345def" to "123 abc 345 def". The replace function may help. The code is like this.
var str = "123abc345def";
str = str.replace(/(\d+)/g, function (_, num){
console.log(num);
return ' ' + num + ' ';
});
str = str.trim();
The code you linked didn't work mainly because it's using a different programming language to javascript. In theory, it should work, but javascript does not support regular expression lookbehinds (at this present time)..
Instead, I have re-wrote that fragment of code:
prepareQuery: function (val) {
function isNotLetter(a){
return (/[0-9-_ ]/.test(a));
}
var val=val.toLowerCase().split("");
var tempArray=val.join("").split("");
var currentIndex=1;
for (var i=0;i<val.length-1;i++){
if (isNotLetter(val[i]) !== isNotLetter(val[i+1])){
tempArray.splice(i+currentIndex, 0, " ");
currentIndex++;
}
}
return tempArray.join("");
}
Since you're new to javascript, I'm going to explain what it does.
It declares a function in prepareQuery to check whether or not a string contains a letter [this can be moved somewhere else]
It then splits val into an array and copies the content of val into tempArray
An index is declared (explained later)
A loop is made, which goes through every single character in val
The if statement detects whether or not the current character (val[i] as set by the loop) is the same as the character next to it (val[i+1]).
IF either one are different to the other (ie the current character is a letter while the next isn't) then a space is added to the tempArray at that "index"
The index is incremented and used as an offset in #6
The loop finishes, joins the "array" into a string and outputs the result.
DEMO:
http://jsbin.com/ebitus/1/edit
(JSFiddle was down....)
EDIT:
Sorry, but I completely misinterpreted your question... You failed to mention that you were using "quicksearch" and jQuery. In that case I'm assuming that you have a list of elements that have names and you want to search through them with the plugin...
A much easier way to match the user's query (if there is no space) is to strip the space from the search table along with the query itself - though original reverse method will work (just not as efficiently) [aka: expanding the user's query]
In this case, stripping the space from both the search table and user input would be a better method
prepareQuery: function (val) {
return val.toLowerCase().replace(/ /ig,'').split(" ");
},
testQuery: function (query, txt, _row) {
txt=txt.toLowerCase().replace(/ /ig,'');
for (var i = 0; i < query.length; i += 1) {
if (txt.indexOf(query[i]) === -1) {
return false;
}
}
return true;
}
DEMO:
http://jsfiddle.net/q9k9Y/3/
Edit 2:
It seems like your real intent is to create a fully functioning search feature on your website, not to just add spaces between letters and numbers. With this, I suggest using Quicksilver. I would love to work out an algorithm to extend quickSearcher but at the current time I cannot (timezones). Instead, I suggest using Quicksilver
http://jsbin.com/oruhet/12/

Categories

Resources