Twitter style (stock) mention with Slate.js - javascript

I am building a note taking app and for text I use the Slate.js editor. Twitter mention also works with stocks like this
It basically turns into a mention if /\$[a-zA-Z]{1,6}/ is true. What I have tried is to use the normalizeNode callback to change if the regex matches, by deleting the text and inserting a new node at that location but so far I've been unsuccessful.
Slate.js also has a nice set of examples but unfortunately haven't found any of them to demonstrate what I'm trying to do. What would be a good way to go about implementing this feature? Am I wrong to assume it's through using normalizeNode?

I solved this question when working on typed in emojis. For example, when a person typed :smile: we wanted the emoji to appear (a la Slack). The only differences with stock symbols and emojis would be the stock lookup and the usage of Transforms.insertNodes instead of Transforms.insertText.
The code below should be enough to help someone solve their use case. The key is startIndex and endIndex which targets the replacement.
Here's my solution:
editor.normalizeNode = entry => {
const [node, path] = entry;
if (!Text.isText(node)) {
return normalizeNode([node, path]);
}
const emojiMatch = node.text.match(EMOJI_REGEX);
if (!emojiMatch) {
return normalizeNode([node, path]);
}
const [searchMatch, colonMatch] = emojiMatch;
const { index: startIndex } = emojiMatch;
const endIndex = startIndex + searchMatch.length;
const [matchedEmoji] = emojiIndex.search(colonMatch).map(emoji => emoji) as BaseEmoji[];
if (!matchedEmoji) {
return normalizeNode([node, path]);
}
Transforms.insertText(editor, matchedEmoji.native, {
at: {
anchor: { path, offset: startIndex },
focus: { path, offset: endIndex },
}
})
normalizeNode([node, path]);
}

Related

how to Sequelize "where" accessing table and column

I am attempting to port an application that had used sequelize 3.30.4 and I'm updating to 6.13, I'm assuming some things have changed because I can't use string literals in a where clause, or so the debugger tells me.
That said, I've done some googling and have found some basic examples that make sense sure but I'm not entirely sure how to convert this string to a format acceptable for findAndCountAll to be happy.
I've attempted something like this, thinking it might at least point me in the right direction however it does not.
let attributes = ['id', 'name', 'locationId'];
let where = undefined;
let order = [['name', 'ASC']];
where = {
classroom: {
locationId: request.query.locationId
}
}
this is the line that did at one time work but no longer works.
where = `"classroom"."locationId" = ${request.query.locationId}`;
const classrooms = await model.classroom.findAndCountAll(_.assign({},
requestHelper.computePaginationObject(request.query.limit, request.query.page), {
attributes,
where: where ? [where] : undefined,
order
}));
how would I go about porting this into the proper format?
Try something like this:
let where = {}
if (<some condition>) {
where = {
locationId: request.query.locationId
}
}
const classrooms = await model.classroom.findAndCountAll(_.assign({},
requestHelper.computePaginationObject(request.query.limit, request.query.page), {
attributes,
where: where,
order
}));
You can also try that even if the first comment of ANATOLY works wonders :
const where = <some condition> ? {locationId: request.query.locationId} :{};
const classrooms = await model.classroom.findAndCountAll(_.assign({},
requestHelper.computePaginationObject(request.query.limit, request.query.page), {
attributes,
where,
order
}));

Filtering an array based on presence of string value

I know filter questions are covered extensivly on SO - but I'm struggling to implement my idea:
I want to filter through my panels & return an array filteredPanelTabItems for any that include the layouthint: "tab-view-item" and then the remainder of the array (without "tab-view-item") to another const so I can use it elsewhere, can anyone guide where I'm going wrong?
The screenshot above shows what's happening in the console when I log:
panel.panelLinks.links
const hasTabItemViewHint() => {
//check for string
}
const filteredPanelTabItems = panel.panelLinks.links.filter<Node>(
(panelLink) => panelLink.(call hasTabItemViewHint function?)
);
Consider something like this.
var filteredPanelTabItems = $.map(panel.panelLinks.links, function(l, i) {
if (l.LinkModal.layouthint._collections.indexOf("tab-view-item") >= 0) {
return l;
}
});
See more: https://api.jquery.com/jquery.map/

Check if two URL strings are equal

I'm building out a function to handle dynamic phone number swapping, identifying the referral url, mapping through a data set, and then outputting the promoUrl's related phone number. The data is formatted like this:
const phoneNumbers = [
{
promoUrl: '/interior-doors/',
promoNumber: '589-918-0710',
},
{
promoUrl: '/promo4/',
promoNumber: '307-789-8615',
},
];
And the function maps through the data and reduces it, allowing me to sort through it like this:
const url = location.pathname.replace(/\/+$/, '');
const promoNumber = phoneNumbers.reduce((promoNumber, results) => {
const hasPromo = results.promoUrl.includes(url);
if (hasPromo) {
return results.promoNumber;
}
return promoNumber;
}, '');
I'm having some issues with hasPromo. The way it's built right now allows for the promoUrl to have some variance and still work, meaning as long as it includes what is returned from url then it works i.e. /interior-doors/, /interior-doors, and interior-doors will all work, which is great, but it also works if url is /interior-do. I need it to not do that. It should work independent of formatting, but only return the promoNumber if the string of letters is exact.
I'm assuming this is a regex thing, but I don't know what I'm doing with regex. Any help would be greatly appreciated.
Use == to do an exact match. And since the promoURL property always has / around it, add those delimiters when you set url
const url = '/' + location.pathname.replace(/\/+$/, '') + '/';
const promoNumber = phoneNumbers.reduce((promoNumber, results) => {
const hasPromo = results.promoUrl == url;
if (hasPromo) {
return results.promoNumber;
}
return promoNumber;
}, '');
reduce also seems like the wrong function for this. You just need to find the matching promoUrl, you don't have to continue reducing, since the reduction function doesn't merge the results in any way.
const promo = phoneNumbers.find(({promoUrl}) => promoUrl == url);
const promoNumber = promo ? promo.promoNumber : '';

Is there some kind of find method on Arrays that returns [item | undefined] rather than item | undefined?

Here is some code from I project I am working in:
const profile = userdataDocs
.filter(isValidUserdataDocument)
.find((document: ICouchDBDocumentDoc) => document._id === profileId);
if (profile) {
return {
id: hashSensitive(profile._id, environment),
type: profile.type,
creationDate: profile.creationDate,
updatedDate: profile.updatedDate,
entityVersion: profile.entityVersion,
};
}
Here is how I would like to have my code look:
return userdataDocs
.filter(isValidUserdataDocument)
.filter((document: ICouchDBDocumentDoc) => document._id === profileId)
.map((profile: ICouchDBDocumentDoc) => ({
id: hashSensitive(profile._id, environment),
type: profile.type,
creationDate: profile.creationDate,
updatedDate: profile.updatedDate,
entityVersion: profile.entityVersion,
}))
.slice(0, 1);
But I get feedback from the rest of my team that I should not use filter because it will continue searching after having found an item. Premature optimization in mind, but still a pretty valid and popular opinion.
Is there some other array method (or altogether different solution) that I can use to write code the way I want, with 'pipes', without getting the performance penalty of moving from find to filter?
Also let me know if I am an idiot and should let go of the pipe dream (pun intended).
Let me start that I like the first solution. In my opinion, it looks good.
But if you are really desperate for a solution that fulfills your pipe dream
const array = [10, 20, 30];
function singleMapFind(args, fn) {
const currentArray = args[2];
const duplicate = [...currentArray];
currentArray.splice(1, currentArray.length - 1);
return duplicate.find(fn);
}
const modified = array.map((...args) => singleMapFind(args, (e) => e > 20));
I would never use it though. Wish you luck with the PR.

Custom word translator in React

Update: scroll to see my solution, can it be improved?
So I have this issue, I am building a word translator thats translates english to 'doggo', I have built this in vanilla JS but would like to do it React.
My object comes from firebase like this
dictionary = [
0: {
name: "paws",
paws: ["stumps", "toes beans"]
}
1: {
name: "fur",
fur: ["floof"]
}
2: {
name: "what"
what: ["wut"]
}
]
I then convert it to this format for easier access:
dictionary = {
what : ["wut"],
paws : ["stumps", "toe beans"],
fur : ["floof"]
}
Then, I have two text-area inputs one of which takes input and I would like the other one to output the corresponding translation. Currently I am just logging it to the console.
This works fine to output the array of the corresponding word, next I have another variable which I call 'levelOfDerp' which is basically a number between 0 - 2 (set to 0 by default) which I can throw on the end of the console.log() as follows to correspond to the word within the array that gets output.
dictionary.map(item => {
console.log(item[evt.target.value][levelOfDerp]);
});
When I do this I get a "TypeError: Cannot read property '0' of undefined". I am trying to figure out how to get past this error and perform the translation in real-time as the user types.
Here is the code from the vanilla js which performs the translation on a click event and everything at once. Not what I am trying to achieve here but I added it for clarity.
function convertText(event) {
event.preventDefault();
let text = inputForm.value.toLowerCase().trim();
let array = text.split(/,?\s+/);
array.forEach(word => {
if (dictionary[word] === undefined) {
outputForm.innerHTML += `${word} `;
noTranslationArr.push(word);
} else {
let output = dictionary[word][levelOfDerp];
if (output === undefined) {
output = dictionary[word][1];
if (output === undefined) {
output = dictionary[word][0];
}
}
outputForm.innerHTML += `${output} `;
hashtagArr.push(output);
}
});
addData(noTranslationArr);
}
Also here is a link to the translator in vanilla js to get a better idea of the project https://darrencarlin.github.io/DoggoSpk/
Solution, but could be better..
I found a solution but I just feel this code is going against the reason to use react in the first place.. My main concern is that I am declaring variables to store strings inside of an array within the function (on every keystroke) which I haven't really done in React, I feel this is going against best practice?
translate = evt => {
// Converting the firebase object
const dict = this.state.dictionary;
let dictCopy = Object.assign(
{},
...dict.map(item => ({ [item["name"]]: item }))
);
let text = evt.target.value.toLowerCase().trim();
let textArr = text.split(/,?\s+/);
let translation = "";
textArr.forEach(word => {
if (dictCopy[word] === undefined) {
translation += `${word} `;
} else {
translation += dictCopy[word][word][this.state.derpLvl];
}
});
this.setState({ translation });
};
levelOfDerp is not defined, try to use 'levelOfDerp' as string with quotes.
let output = dictionary[word]['levelOfDerp' ];
The problem happens because setState() is asynchronous, so by the time it's executed your evt.target.value reference might not be there anymore. The solution is, as you stated, to store that reference into a variable.
Maybe consider writing another function that handles the object conversion and store it in a variable, because as is, you're doing the conversion everytime the user inputs something.

Categories