Make a change to Javascript code that renumbers a list - javascript

I am unfamiliar with Javascript, but I would like to make a change to the following code. Currently, it renames macros in the program Keyboard Maestro in the format of 01), 02), etc. I would like it to simply use the format of a number followed by a space instead (i.e. 1 , 2 , etc.) I hope what I described makes sense. Thanks!
Part 1:
(function(inDesignMode) {
'use strict';
function dump(obj, desc) {
console.log((desc ? desc + ": " : "") + JSON.stringify(obj, null, "\t"));
}
var KMEditor = (function() {
var _editorAppName = "Keyboard Maestro";
var _editorApp;
return {
getEditorApp: function() {
return _editorApp ? _editorApp : _editorApp = Application(_editorAppName);
},
getEditorAppName: function() {return _editorAppName;},
getSelectedMacrosOrGroups: function() {
return this.getEditorApp().selectedmacros();
}
};
})();
var KMEngine = (function() {
var _engineApp;
return {
getAllMacrosSourceFileName: function() {
return this.getAppSupportFolderName() + "Keyboard Maestro Macros.plist";
},
getAppSupportFolderName: function() {
var app = Application.currentApplication();
app.includeStandardAdditions = true;
return app.pathTo('application support', { from: 'user domain' }) +
"/Keyboard Maestro/";
},
getEngineAppName: function() {
return "Keyboard Maestro Engine";
},
getEngineApp: function() {
if (!_engineApp)
_engineApp = Application(this.getEngineAppName());
return _engineApp;
},
readPlistBinaryFile: function(path) {
var data = $.NSData.dataWithContentsOfFile(path);
return ObjC.deepUnwrap(
$.NSPropertyListSerialization.propertyListWithDataOptionsFormatError(
data, $.NSPropertyListBinaryFormat_v1_0, 0, null));
},
};
})();
function getMacrosInfo(selectedMacroUUIDs) {
function getMacroName(macro) {
if (macro.Name)
return macro.Name;
throw Error("Un-named Macro UUID: " + macro.UID);
}
function getMacroInfo(macro) {
var info = {
macroUUID: macro.UID,
macroName: getMacroName(macro)
};
var matches = info.macroName.match(/^(\d\d)?(\))?(.*)/);
if (!matches || matches.length != 4)
throw Error("Could not parse macro name '" + info.macroName + "'");
info.prefixNumber = matches[1] || "";
info.macroNameNoPrefix = matches[3].trim();
return info;
}
function reOrderResult(macrosInfo, selectedMacroUUIDs) {
macrosInfo.macros = selectedMacroUUIDs.map(function(selectedMacroUUID) {
var info = macrosInfo.macros.find(function(macroInfo) {
return macroInfo.macroUUID === selectedMacroUUID;
});
if (!info)
throw Error("Could not find macro information for UUID '" + selectedMacroUUID + "'");
return info;
});
}
// getMacrosInfo()
var result = {
macros: []
};
var macroGroup;
var plist = KMEngine.readPlistBinaryFile(KMEngine.getAllMacrosSourceFileName());
plist.MacroGroups.forEach(function(group) {
if (group.Macros) {
group.Macros.forEach(function(macro) {
if (selectedMacroUUIDs.indexOf(macro.UID) >= 0) {
if (!result.groupUUID) {
macroGroup = group;
result.groupUUID = group.UID;
result.groupName = group.Name;
result.groupToggleMacroUID = group.ToggleMacroUID;
} else if (result.groupUUID !== group.UID) {
throw Error("Selected macros must all be from the same group");
}
result.macros.push(getMacroInfo(macro));
}
});
}
});
reOrderResult(result, selectedMacroUUIDs);
return result;
} // getMacrosInfo()
function execute() {
var selectedMacroUUIDs = KMEditor.getSelectedMacrosOrGroups();
if (!selectedMacroUUIDs || selectedMacroUUIDs.length < 2)
throw Error("You must select two or more macros");
var result = getMacrosInfo(selectedMacroUUIDs);
return JSON.stringify(result);
}
if (inDesignMode) {
return execute();
} else {
try {
return execute();
} catch (e) {
return "Error: " + e.message;
}
}
})(false);
Part 2:
(function(inDesignMode, designModeParams) {
'use strict';
var _kme = Application("Keyboard Maestro Engine");
function getKMVariable(name, required) {
var result = undefined;
if (inDesignMode && designModeParams)
result = designModeParams[name];
if (result === undefined)
result = _kme.getvariable(name);
if (required && !result)
throw Error("Variable '" + name + "' is empty");
return result;
}
var _km = Application("Keyboard Maestro");
function execute() {
var macroId = getKMVariable("palorg_MacroUUID", true);
var newName = getKMVariable("palorg_NewMacroName", true);
var macros = _km.macros.whose({id: {"=": macroId}});
if (macros.length == 0)
throw new Error("Macro '" + macroId + "' not found");
var macro = macros[0];
macro.name = newName;
return "OK";
}
if (inDesignMode) {
try {
return execute();
} catch (e) {
return "Error on line: " + e.line + ": " + e.message;
} finally {
try {
Application("Atom").activate();
} catch (e) {
}
}
} else {
try {
return execute();
} catch (e) {
return "Error: " + e.message;
}
}
})(false);

As per clarifications obtained in your comment, this is what you need:
01)macro --> 1 macro
To get that, you can try adding the following lines in execute() function in Part 2:
const regExp = /^0(.)\)/i; //Creates the regular expression
newName.replace(regex, '$1 '); //Replaces the match from the regex with a substring
macro.name = newName;
This is a regular expression substring replacement (more details here). Here's the breakdown on what's being done.
The ^ symbol denotes that a substring is being searched from the beginning of the string.
The next 0 is just a literal search for a 0 at the beginning of the string.
The next ( starts a parenthesized submatch string whose utility will be explained later.
The . indicates any single character.
The next ) end the parenthesized submatch string started earlier.
The next \) is for searching a ) literally which needs to be escaped with \ since ) has a special meaning of ending a parenthesized submatch string as mentioned above.
Now, the parenthesized submatch string is used so that after matching against the regular expression, the result can be used further to replace the matched string with. In this case,
01)macro will match 1 as the parenthesized submatch string since that's a single character after the leading 0 and before the ). This is used as $1 in the replace function so that after matching 01), it's replaced with 1 (notice the extra space, as is required by the question).

Related

How to write a javascript function that checks if first and last characters in a string are equal

I been doing this javascript challenge and I'm pretty close, but something is off.Here's the challenge:
Given an array of strings containing three types of braces: round (), square [] and curly {}
Your task is to write a function that checks whether the braces in each string are correctly matched. Prints 1 to standard output (console.log) if the braces in each string are matched and 0 if they're not (one result per line)
my code is this:
var infoToParse = [ ")(){}", "[]({})", "([])", "{()[]}", "([)]" ];
function checkBraces(infoToParse) {
var tabChars = infoToParse;
for (i= 0; tabChars.length - 1; i+=1) {
if (tabChars[i].charAt(0) === tabChars[i].charAt(tabChars[i].length-1)){
console.log(1);
}else{
console.log(0);
}
}
}
checkBraces(infoToParse);
The output with the current array items should be Output:
0
1
1
1
0
As pointed out in the comment, only having the first and the last character same would not result in a correct solution.
You can try the following technique:
Maintain a stack, each time you encounter an opening bracket i.e round "(", square "[" or curly "{"; push this into stack. Now whenever you encounter a closing bracket, pop an element from the stack. If these two match i.e both are of same type, then carry on till stack and string both are empty. If at any point these don't match then break and return false.
I'll write a code for it and post it soon.
I guess you could do it in this way, keeping a "tree" of starting positions. Didn't test any other testcases than your own though :)
var testCases = [")(){}", "[]({})", "([])", "{()[]}", "([)]"];
var braceType = {
round: ["(", ")"],
curly: ["{", "}"],
square: ["[", "]"]
};
var bracePosition = {
start: ["{", "(", "["],
end: ["}", ")", "]"]
};
function typeOfBraces(sign) {
for (var property in braceType) {
if (braceType[property].indexOf(sign) < 0) {
continue;
}
if (bracePosition.start.indexOf(sign) < 0) {
return {
type: property,
position: "end"
};
} else {
return {
type: property,
position: "start"
};
}
}
throw "Sign is not a brace!";
};
function Braces(brace, parent, type) {
this.brace = brace;
this.parent = parent || null;
this.type = type || {
type: 'init',
position: ''
};
this.children = [];
this.nextBrace = function(nextSign) {
var nextType = typeOfBraces(nextSign);
if (nextType.position === 'start') {
var child = new Braces(nextSign, this, nextType);
this.children.push(child);
return child;
}
if (nextType.position === 'end') {
if (this.type.position === '') {
throw 'Cannot start with an end tag!';
}
if (this.type.position === 'end' && this.parent === null) {
throw 'Cannot end the sequence';
}
if (this.type.position === 'end' && this.parent.position === 'start') {
if (this.type.type === this.parent.type) {
var child = new Braces(nextSign, this.parent, nextType);
this.parent.children.add(child);
return this.parent;
}
}
}
if (this.type.position === 'start' && nextType.type === this.type.type && nextType.position === 'end') {
return this.parent;
}
return new Braces(nextSign, this, nextType);
};
}
for (var i = 0; i < testCases.length; i++) {
var brace = new Braces(testCases[i]);
for (var j = 0, len = testCases[i].length; j < len; j++) {
try {
brace = brace.nextBrace(testCases[i][j]);
} catch (e) {
console.log(e);
brace = null;
break;
}
}
if (brace != null && brace.parent == null) {
// valid entry
console.log(brace);
console.log(testCases[i] + " is a valid sequence");
} else {
// invalid entry
console.log(testCases[i] + " is an invalid sequence");
}
}
or, to make it a bit easier and to check check the brackets:
function validBraces(braceSequence) {
var stack = '',
i, len, lastStack = -1,
toAdd = "{([",
toRemove = "})]",
sign;
for (i = 0, len = braceSequence.length; i < len; i++) {
sign = braceSequence[i];
if (toAdd.indexOf(sign) >= 0) {
stack += sign;
lastStack++;
} else if (toRemove.indexOf(sign) >= 0) {
if (toAdd.indexOf(stack.charAt(lastStack)) !== toRemove.indexOf(sign)) {
// format exception
console.warn('Format exception, didn\'t expect ' + sign + ' (current stack: ' + stack + ')');
return false;
} else {
stack = stack.slice(0, -1);
lastStack--;
}
} else {
console.warn('Invalid character exception, didn\'t expect ' + sign + ' (current stack: ' + stack + ')');
return false;
}
}
return true;
}
var testCases = [")(){}", "[]({})", "([])", "{()[]}", "([)]"];
for (var i = 0; i < testCases.length; i++) {
if (validBraces(testCases[i])) {
console.log(testCases[i] + ' is a valid sequence');
} else {
console.log(testCases[i] + ' is an invalid sequence');
}
}
If you can use Regular Expressions, you can really slim it down:
var stringArray = [ ")(){}", "[]({})", "([])", "{()[]}", "([)]" ];
function checkBraces(infoToParse) {
for (i = 0; i < infoToParse.length; i += 1) {
var regX = /^\[.*\]$|^\{.*\}$|^\(.*\)$/gi;
var str = infoToParse[i];
console.log(str.match(regX) ? 1 : 0);
}
}
checkBraces(stringArray);
Also, as I stated in my comment, your for syntax was off. Oh, and instead of i+=1, you can use i++ to simplify it.

Autocompleting XML values and attributes in Ace editor

I'm looking to autocomplete XML tags and attributes. The valid values will come from the server. For example,
If I have a tag such as,
<status></status>
and my cursor is inside the open and closing tags, I'd like to hit control + space and have only valid values appear in the drop-down. Such as: ok, error, warning, ...
Similarly for attributes,
<status audience="">ok</status>
If my cursor has focus inside the quotes I'd like only valid audiences to appear in the drop-down when hitting control + space.
Here's what I have so far. This completer completes words I'm typing. I just can't figure out how to know what kind of tag I'm inside and how to send specific values for that tag or attribute.
Any ideas or examples to point me to? Thanks, /w
function loadEditor() {
var langTools = ace.require("ace/ext/language_tools");
editor = ace.edit("editor");
editor.setOptions({
enableBasicAutocompletion: true,
enableLiveAutocompletion: true,
enableSnippets: true,
});
editor.getSession().setMode("ace/mode/xml");
var myCompleter = {
getCompletions: function(editor, session, pos, prefix, callback) {
if (prefix.length === 0) {
callback(null, []);
return;
}
$.getJSON("completions.php?a=completions&prefix="
+ prefix + "&content=" + session, function(json) {
callback(null, json.map(function(c) {
console.log("value: " + c.value);
return {value: c.value, caption: c.caption, meta: c.meta, score:c.score};
}));
})
}
};
langTools.addCompleter(myCompleter);
}
So far I haven't been able to find any projects with XML completion, so this is what I have implemented.
The XhtmlTagInterpreter has one function getCompleteInfo() that returns a JavaScript object of the form {completeType: "attribute", tagName: "feline", attributeName: "breed"}. In this example it would try to auto-complete the breed attribute of <feline breed="" />.
It sends that data to the server for the appropriate breed values. This service is up to you to implement. e.g. https://www.example.com/services/mock/autocompleter/attribute.json?tagName=feline&attributeName=breed
The JSON returned will be something like this.
[
{"score":"1000","meta":"cats","caption":"siamese","value":"siamese"},
{"score":"1000","meta":"cats","caption":"burmese","value":"burmese"},
{"score":"1000","meta":"cats","caption":"bengal","value":"bengal"}
]
Here is the working JavaScript.
function XHtmlTagInterpreter(row, col, session) {
"use strict";
this.row = row;
this.col = col;
this.session = session;
this.leftOfCursor = null;
this.rightOfCursor = null;
this.leftType = null;
this.rightType = null;
}
/**
* Sets the left of cursor property used by other methods. This is a
* string without new lines from the beginning of the document to the
* letter just before the cursor.
*/
XHtmlTagInterpreter.prototype.setLeftOfCursor = function() {
"use strict";
this.leftOfCursor = "";
for (var r=0; r<=this.row; r++) {
if (r === this.row) {
var line = this.session.getLine(r);
for (var c=0; c<this.col; c++) {
this.leftOfCursor += line[c];
}
} else {
this.leftOfCursor += this.session.getLine(r);
}
}
};
/**
* Sets the right of cursor property used by other methods. This is a
* string without new lines from the letter just to the right of the cursor
* to the end of the document.
*/
XHtmlTagInterpreter.prototype.setRightOfCursor = function() {
"use strict";
this.rightOfCursor = "";
for (var r=this.row; r<=this.session.getLength(); r++) {
if (r === this.row) {
var line = this.session.getLine(r);
for (var c=this.col; c<line.length; c++) {
this.rightOfCursor += line[c];
}
} else {
this.rightOfCursor += this.session.getLine(r);
}
}
};
/**
* Sets the left type depending on first non-whitespace character to the
* left of the cursor position. We look for a right angle or a quotation.
* If a right angle we assume the cursor is inside a tag. If quotation the
* cursor is inside an attribute. We set the left type value to 'value'
* or 'attribute'.
*/
XHtmlTagInterpreter.prototype.setLeftType = function() {
"use strict";
this.setLeftOfCursor();
if (this.leftOfCursor === undefined || this.leftOfCursor.length === 0) {
this.leftType = "";
return;
}
for (var i=this.leftOfCursor.length-1; i>=0; i--) {
if (this.leftOfCursor[i] === " " || this.leftOfCursor[i] === "\t") {
continue;
}
if (this.leftOfCursor[i] === ">") {
this.leftType = "value";
return;
} else if (this.leftOfCursor[i] === '"') {
this.leftType = "attribute";
return;
} else {
this.leftType = "";
return;
}
}
};
/**
* Sets the right type depending on first non-whitespace character to the
* right of the cursor position. We look for a left angle or a quotation.
* If a left angle we assume the cursor is inside a tag. If quotation the
* cursor is inside an attribute. We set the right type value to 'value'
* or 'attribute'.
*/
XHtmlTagInterpreter.prototype.setRightType = function() {
"use strict";
this.setRightOfCursor();
if (this.rightOfCursor === undefined
|| this.rightOfCursor.length === 0) {
this.rightType = "";
return;
}
for (var i=0; i<this.rightOfCursor.length; i++) {
if (this.rightOfCursor[i] === " "
|| this.rightOfCursor[i] === "\t") {
continue;
}
if (this.rightOfCursor[i] === "<") {
this.rightType = "value";
return;
} else if (this.rightOfCursor[i] === '"') {
this.rightType = "attribute";
return;
} else {
this.rightType = "";
return;
}
}
};
/**
* Returns the tag name to be sent to autocompleter service.
* #returns {_L1.XHtmlTagInterpreter.prototype#pro;leftOfCursor#call;trim#call;replace|String}
*/
XHtmlTagInterpreter.prototype.getCompleteInfo = function() {
"use strict";
this.setLeftType();
this.setRightType();
if (this.leftType !== this.rightType) {
return "";
}
if (this.leftType === "value") {
var tagName = this.leftOfCursor.trim()
.replace(new RegExp("^.*<([a-z:]+).*?>$"), "$1");
return {completeType: "value", tagName: tagName};
} else if (this.leftType === "attribute") {
var tagName = this.leftOfCursor.trim()
.replace(new RegExp("^.*<([a-z:]+).*?([a-z:]+)\s*=\s*\"$"), "$1");
var attributeName = this.leftOfCursor.trim()
.replace(new RegExp("^.*<([a-z:]+).*?([a-z:]+)\s*=\s*\"$"), "$2");
return {completeType: "attribute", tagName: tagName,
attributeName: attributeName};
} else {
return null;
}
};
var loadEditor = function(editor) {
var chileCompleter = {
getCompletions: function(editor, session, pos, prefix, callback) {
if (prefix.length === 0) {
var line = session.getLine(pos.row);
if (undefined !== line) {
var interpreter = new XHtmlTagInterpreter(pos.row,
pos.column, session);
var completeInfo = interpreter.getCompleteInfo();
if (undefined === completeInfo || completeInfo === null
|| undefined === completeInfo.completeType
|| completeInfo.completeType === null
|| completeInfo.completeType.length === 0
|| undefined === completeInfo.tagName
|| completeInfo.tagName === null
|| completeInfo.tagName.length === 0) {
callback(null, []);
return;
}
$.getJSON(chileContextPath
+ "services/mock/autocompleter/"
+ encodeURIComponent(completeInfo.completeType)
+ ".json?tagName="
+ encodeURIComponent(completeInfo.tagName)
+ "&attributeName="
+ encodeURIComponent(completeInfo.attributeName),
function(json) {
callback(null, json.content.map(function(c) {
return {value: c.value, caption: c.caption,
meta: c.meta, score:c.score};
}));
})
}
} else {
callback(null, []);
return;
}
}
};
editor = ace.edit("chile-editor");
editor.setOptions({
enableBasicAutocompletion: [chileCompleter],
enableLiveAutocompletion: true,
enableSnippets: true,
});
editor.setTheme("ace/theme/clouds");
editor.getSession().setMode("ace/mode/xml");
editor.getSession().setUseWrapMode(true);
editor = loadXKbml(editor);
return editor;
};

display the recursion line by line

I am trying to make a function in javascript that would expand/split a string with dashes and show the process ( line by line ) using recursion.
for example, the string "anna" would become:
expand("anna") = expand("an")+"---"+expand("na") ->
"a"+"---"+"n"+"---"+"n"+"---"+"a"
and the desired output would be:
anna
an---na
a---n---n---a
I have achieved doing the following so far (I know it might not be the solution I am looking):
expand("anna") = an+"---"+expand("na")
= an+"---"+n+"---"+expand("a");
= an+"---"+n+"---+"a"
the output I am getting is:
an---n---a
I can't seem to concatenate the head though to do the first example.
My javascript function of expand is as follows:
function expand(word) {
if (word.length<=1) {
return word;
} else {
mid = word.length/2;
return word.substr(0,mid) + " " + expand(word.substr(mid,word.length));
}
}
document.write(expand("anna"));
I would need some tips to do this, otherwise (if it's the wrong stackexchange forum), please guide me where to post it.
this is my crazy attempt
var Word = function(str) {
this.isSplitable = function() {
return str.length > 1;
}
this.split = function() {
var p = Math.floor(str.length / 2);
return [
new Word(str.substr(0,p)),
new Word(str.substr(p,p+1))
];
}
this.toString = function() {
return str;
}
}
var expand = function(words) {
var nwords = [];
var do_recur = false;
words.forEach(function(word){
if(word.isSplitable()) {
var splitted = word.split();
nwords.push(splitted[0]);
nwords.push(splitted[1]);
do_recur = true;
}else{
nwords.push(word);
}
});
var result = [];
nwords.forEach(function(word){
result.push( word.toString() );
});
var result = result.join("--") + "<br/>";
if(do_recur) {
return result + expand(nwords);
}else{
return "";
}
}
document.write( expand([new Word("anna")]) );
This is what you need
expand = function(word) {
return [].map.call(word, function(x) {return x+'---'}).join('')
};
The joy of functional programming.
And with added code to deal with last character:
function expand(word) {
return [].map.call(word, function(x, idx) {
if (idx < word.length - 1)
return x+'---';
else return x
}).join('')
}
As I said that it is impossible to display the "process" steps of recursion while using recursion, here is a workaround that will output your desired steps:
var levels = [];
function expand(word, level) {
if (typeof level === 'undefined') {
level = 0;
}
if (!levels[level]) {
levels[level] = [];
}
levels[level].push(word);
if (word.length <= 1) {
return word;
} else {
var mid = Math.ceil(word.length/2);
return expand(word.substr(0, mid), level+1) + '---' + expand(word.substr(mid), level+1);
}
}
expand('anna');
for (var i = 0; i < levels.length; i++) {
console.log(levels[i].join('---'));
}
to see all steps the best that I whold do is:
function expand(word) {
if (word.length<=1) {
return word;
} else {
var mid = word.length/2;
var str1 = word.substr(0,mid);
var str2 = word.substr(mid,word.length);
document.write(str1 + "---" + str2 + "<br></br>");
return expand(str1) + "---" + expand(str2);
}
}
document.write(expand("anna"));
You have to return the two parts of the string:
function expand(word) {
output="";
if (word.length<=1) {
output+=word;
return output;
} else
{
var mid = word.length/2;
output+=word.substr(0,mid)+"---"+word.substr(mid)+" \n";//this line will show the steps.
output+=expand(word.substr(0,mid))+"---"+expand(word.substr(mid,word.length-1))+" \n";
return output;
}
}
console.log(expand("anna"));
Edit:
I added the output var and in every loop I concatenate the new output to it.
It should do the trick.
Hope the problem is in your first part. According to your algorithm, you are splitting your string anna in to two parts,
an & na
so you need to expand both parts until the part length is less than or equal to one. so your required function is the below one.
function expand(word) {
if (word.length<=1) {
return word;
} else {
mid = word.length/2;
return expand(word.substr(0,mid)) + " --- " + expand(word.substr(mid,word.length));
}
}
document.write(expand("anna"));

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/

Toggle query string variables

I've been banging my head over this.
Using jquery or javascript, how can I toggle variables & values and then rebuild the query string? For example, my starting URL is:
http://example.com?color=red&size=small,medium,large&shape=round
Then, if the user clicks a button labeled "red", I want to end up with:
http://example.com?size=small,medium,large&shape=round //color is removed
Then, if the user clicks "red" again, I want to end up with:
http://example.com?size=small,medium,large&shape=round&color=red //color is added back
Then, if the user clicks a button labeled "medium", I want to end up with:
http://example.com?size=small,large&shape=round&color=red //medium is removed from list
Then, if the user clicks the labeled "medium" again, I want to end up with:
http://example.com?size=small,large,medium&shape=round&color=red //medium added back
It doesn't really matter what order the variable are in; I've just been tacking them to the end.
function toggle(url, key, val) {
var out = [],
upd = '',
rm = "([&?])" + key + "=([^&]*?,)?" + val + "(,.*?)?(&.*?)?$",
ad = key + "=",
rmrplr = function(url, p1, p2, p3, p4) {
if (p2) {
if (p3) out.push(p1, key, '=', p2, p3.substr(1));
else out.push(p1, key, '=', p2.substr(0, p2.length - 1));
} else {
if (p3) out.push(p1, key, '=', p3.substr(1));
else out.push(p1);
}
if (p4) out.push(p4);
return out.join('').replace(/([&?])&/, '$1').replace(/[&?]$/, ''); //<!2
},
adrplr = function(s) {
return s + val + ',';
};
if ((upd = url.replace(new RegExp(rm), rmrplr)) != url) return upd;
if ((upd = url.replace(new RegExp(ad), adrplr)) != url) return upd;
return url + (/\?.+/.test(url) ? '&' : '?') + key + '=' + val; //<!1
}
params self described enough, hope this help.
!1: changed from ...? '&' : '' to ... ? '&' : '?'
!2: changed from .replace('?&','?')... to .replace(/([&?]&)/,'$1')...
http://jsfiddle.net/ycw7788/Abxj8/
I have written a function, which efficiently results in the expected behaviour, without use of any libraries or frameworks. A dynamic demo can be found at this fiddle: http://jsfiddle.net/w8D2G/1/
Documentation
Definitions:
The shown example values will be used at the Usage section, below
  -   Haystack - The string to search in (default = query string. e.g: ?size=small,medium)
  -   Needle - The key to search for. Example: size
  -   Value - The value to replace/add. Example: medium.
Usage (Example: input > output):
qs_replace(needle, value)
If value exists, remove: ?size=small,medium > ?size=small
If value not exists, add: ?size=small > size=small,medium
qs_replace(needle, options)     Object options. Recognised options:
findString. Returns true if the value exists, false otherwise.
add, remove or toggleString. Add/remove the given value to/from needle. If remove is used, and the value was the only value, needle is also removed. A value won't be added if it already exists.
ignorecaseIgnore case while looking for the search terms (needle, add, remove or find).
separatorSpecify a separator to separate values of needle. Default to comma (,).
Note :   A different value for String haystack can also be defined, by adding it as a first argument: qs_replace(haystack, needle, value) or qs_replace(haystack, needle, options)
Code (examples at bottom). Fiddle: http://jsfiddle.net/w8D2G/1/:
function qs_replace(haystack, needle, options) {
if(!haystack || !needle) return ""; // Without a haystack or needle.. Bye
else if(typeof needle == "object") {
options = needle;
needle = haystack;
haystack = location.search;
} else if(typeof options == "undefined") {
options = needle;
needle = haystack;
haystack = location.search;
}
if(typeof options == "string" && options != "") {
options = {remove: options};
var toggle = true;
} else if(typeof options != "object" || options === null) {
return haystack;
} else {
var toggle = !!options.toggle;
if (toggle) {
options.remove = options.toggle;
options.toggle = void 0;
}
}
var find = options.find,
add = options.add,
remove = options.remove || options.del, //declare remove
sep = options.sep || options.separator || ",", //Commas, by default
flags = (options.ignorecase ? "i" :"");
needle = encodeURIComponent(needle); //URL-encoding
var pattern = regexp_special_chars(needle);
pattern = "([?&])(" + pattern + ")(=|&|$)([^&]*)(&|$)";
pattern = new RegExp(pattern, flags);
var subquery_match = haystack.match(pattern);
var before = /\?/.test(haystack) ? "&" : "?"; //Use ? if not existent, otherwise &
var re_sep = regexp_special_chars(sep);
if (!add || find) { //add is not defined, or find is used
var original_remove = remove;
if (subquery_match) {
remove = encodeURIComponent(remove);
remove = regexp_special_chars(remove);
remove = "(^|" + re_sep + ")(" + remove + ")(" + re_sep + "|$)";
remove = new RegExp(remove, flags);
var fail = subquery_match[4].match(remove);
} else {
var fail = false;
}
if (!add && !fail && toggle) add = original_remove;
}
if(find) return !!subquery_match || fail;
if (add) { //add is a string, defined previously
add = encodeURIComponent(add);
if(subquery_match) {
var re_add = regexp_special_chars(add);
re_add = "(^|" + re_sep + ")(" + re_add + ")(?=" + re_sep + "|$)";
re_add = new RegExp(re_add, flags);
if (subquery_match && re_add.test(subquery_match[4])) {
return haystack;
}
if (subquery_match[3] != "=") {
subquery_match = "$1$2=" + add + "$4$5";
} else {
subquery_match = "$1$2=$4" + sep + add + "$5";
}
return haystack.replace(pattern, subquery_match);
} else {
return haystack + before + needle + "=" + add;
}
} else if(subquery_match){ // Remove part. We can only remove if a needle exist
if(subquery_match[3] != "="){
return haystack;
} else {
return haystack.replace(pattern, function(match, prefix, key, separator, value, trailing_sep){
// The whole match, example: &foo=bar,doo
// will be replaced by the return value of this function
var newValue = value.replace(remove, function(m, pre, bye, post){
return pre == sep && post == sep ? sep : pre == "?" ? "?" : "";
});
if(newValue) { //If the value has any content
return prefix + key + separator + newValue + trailing_sep;
} else {
return prefix == "?" ? "?" : trailing_sep; //No value, also remove needle
}
}); //End of haystack.replace
} //End of else if
} else {
return haystack;
}
// Convert string to RegExp-safe string
function regexp_special_chars(s){
return s.replace(/([[^$.|?*+(){}\\])/g, '\\$1');
}
}
Examples (Fiddle: http://jsfiddle.net/w8D2G/1/):
qs_replace('color', 'red'); //Toggle color=red
qs_replace('size', {add: 'medium'}); //Add `medium` if not exist to size
var starting_url = 'http://example.com?color=red&size=small,medium,large&shape=round'
starting_url = qs_replace(starting_url, 'color', 'red'); //Toggle red, thus remove
starting_url = qs_replace(starting_url, 'color', 'red'); //Toggle red, so add it
alert(starting_url);
This is the solution for your task: http://jsfiddle.net/mikhailov/QpjZ3/12/
var url = 'http://example.com?size=small,medium,large&shape=round';
var params = $.deparam.querystring(url);
var paramsResult = {};
var click1 = { size: 'small' };
var click2 = { size: 'xlarge' };
var click3 = { shape: 'round' };
var click4 = { shape: 'square' };
var clickNow = click4;
for (i in params) {
var clickKey = _.keys(clickNow)[0];
var clickVal = _.values(clickNow)[0];
if (i == clickKey) {
var ar = params[i].split(',');
if (_.include(ar, clickVal)) {
var newAr = _.difference(ar, [clickVal]);
} else {
var newAr = ar;
newAr.push(clickVal);
}
paramsResult[i] = newAr.join(',');
} else {
paramsResult[i] = params[i];
}
}
alert($.param(paramsResult)) // results see below
Init params string
{ size="small, medium,large", shape="round"} // size=small,medium,large&shape=round
Results
{ size="small"} => { size="medium,large", shape="round"} //size=medium%2Clarge&shape=round
{ size="xlarge"} => { size="small,medium,large,xlarge", shape="round"} // size=small%2Cmedium%2Clarge%2Cxlarge&shape=round
{ shape="round"} => { size="small,medium,large", shape=""} //size=small%2Cmedium%2Clarge&shape=
{ shape="square"} => { size="small,medium,large", shape="round,square"} //size=small%2Cmedium%2Clarge&shape=round%2Csquare
productOptions is the only thing you need to modify here to list all the available options and their default state. You only need to use the public API function toggleOption() to toggle an option.
(function(){
//Just keep an object with all the options with flags if they are enabled or disabled:
var productOptions = {
color: {
"red": true,
"blue": true,
"green": false
},
size: {
"small": true,
"medium": true,
"large": true
},
shape: {
"round": true
}
};
//After this constructing query becomes pretty simple even without framework functions:
function constructQuery(){
var key, opts, qs = [], enc = encodeURIComponent, opt,
optAr, i;
for( key in productOptions ) {
opts = productOptions[key];
optAr = [];
for( i in opts ) {
if( opts[i] ) {
optAr.push( i );
}
}
if( !optAr.length ) {
continue;
}
qs.push( enc( key ) + "=" + enc( optAr.join( "," ) ) );
}
return "?"+qs.join( "&" );
};
//To toggle a value and construct the new query, pass what you want to toggle to this function:
function toggleOption( optionType, option ) {
if( optionType in productOptions && option in productOptions[optionType] ) {
productOptions[optionType][option] = !productOptions[optionType][option];
}
return constructQuery();
}
window.toggleOption = toggleOption;
})()
Example use:
// "%2C" = url encoded version of ","
toggleOption(); //Default query returned:
"?color=red%2Cblue&size=small%2Cmedium%2Clarge&shape=round"
toggleOption( "color", "red" ); //Red color removed:
"?color=blue&size=small%2Cmedium%2Clarge&shape=round"
toggleOption( "color", "blue" ); //Blue color removed, no color options so color doesn't show up at all:
"?size=small%2Cmedium%2Clarge&shape=round"
toggleOption( "color", "blue" ); //Blue color enabled again:
"?color=blue&size=small%2Cmedium%2Clarge&shape=round"
toggleOption( "shape", "round" ); //The only shape option removed
"?color=blue&size=small%2Cmedium%2Clarge"
I have tried this and this may give the desire result
<script>
var url='http://example.com?color=red&size=small,medium,large&shape=round';
var mySplitResult = url.split("?");
var domain=mySplitResult[0];
var qstring=mySplitResult[1];
var proparr=new Array();
var valarr=new Array();
var mySplitArr = qstring.split("&");
for (i=0;i<mySplitArr.length;i++){
var temp = mySplitArr[i].split("=");
proparr[i]=temp[0];
valarr[i]=temp[1].split(",");
}
function toggle(property,value)
{
var index;
var yes=0;
for (i=0;i<proparr.length;i++){
if(proparr[i]==property)
index=i;
}
if(index==undefined){
proparr[i]=property;
index=i;
valarr[index]=new Array();
}
for (i=0;i<valarr[index].length;i++){
if(valarr[index][i]==value){
valarr[index].splice(i,1);
yes=1;
}
}
if(!yes)
{
valarr[index][i]=value;
}
var furl=domain +'?';
var test=new Array();
for(i=0;i<proparr.length;i++)
{
if(valarr[i].length)
{
test[i]=valarr[i].join(",");
furl +=proparr[i]+"="+test[i]+"&";
}
}
furl=furl.substr(0,furl.length-1)
alert(furl);
}
</script>
<div>
<input id="color" type="button" value="Toggle Red" onclick="toggle('color','red')"/>
<input id="shape" type="button" value="Toggle shape" onclick="toggle('shape','round')"/>
<input id="size" type="button" value="Toggle Small" onclick="toggle('size','small')"/>
<input id="size" type="button" value="Toggle large" onclick="toggle('size','large')"/>
<input id="size" type="button" value="Toggle medium" onclick="toggle('size','medium')"/>
<input id="size" type="button" value="Toggle new" onclick="toggle('new','yes')"/>
</div>

Categories

Resources