How to get a range from start & end index with Office.js while developing MS Word Add-in - ms-word

I want to get a sub range by character index from the parent paragraph. What's the suggest way to do so? The only method I found to shrink the range is "Paragraph.search()"
ref:
Word.Range: https://learn.microsoft.com/en-us/javascript/api/word/word.range?view=office-js
Word.Paragraph: https://learn.microsoft.com/en-us/javascript/api/word/word.paragraph?view=office-js
My use case:
I'm writing a markdown plugin for MS Word and I'm trying to parse the following paragraph.
A **bold** word
The output from markdown parser is {style:"strong",start:2,end:9}. So I want to apply bold style to the targeting range.

Found a way just now. The key is passing an empty separator to Paragraph.getTextRanges([""]) I'm not sure how bad the performance would be.
const makeBold = async (paragraph:Word.Paragraph,start:number,end:number) => {
const charRanges = paragraph.getTextRanges([""])
charRanges.load()
await charRanges.context.sync()
const targetRange = charRanges.items[start].expandTo(charRanges.items[end])
targetRange.load()
await targetRange.context.sync()
targetRange.font.bold = true
await targetRange.context.sync()
}

The existing answer didn't work for me (it seems like getTextRanges() no longer accepts empty strings).
So I have adapted the answer to use paragraph.search() instead.
async function getRangeByIndex(paragraph: Word.Paragraph, start: number, end: number) {
const charRanges = paragraph.search('?', { matchWildcards: true })
charRanges.load()
await charRanges.context.sync()
const targetRange = charRanges.items[start].expandTo(charRanges.items[end])
targetRange.load()
await targetRange.context.sync()
return targetRange
}

Related

String transformation for subject course code for Dart/Flutter

For interaction with an API, I need to pass the course code in <string><space><number> format. For example, MCTE 2333, CCUB 3621, BTE 1021.
Yes, the text part can be 3 or 4 letters.
Most users enter the code without the space, eg: MCTE2333. But that causes error to the API. So how can I add a space between string and numbers so that it follows the correct format.
You can achieve the desired behaviour by using regular expressions:
void main() {
String a = "MCTE2333";
String aStr = a.replaceAll(RegExp(r'[^0-9]'), ''); //extract the number
String bStr = a.replaceAll(RegExp(r'[^A-Za-z]'), ''); //extract the character
print("$bStr $aStr"); //MCTE 2333
}
Note: This will produce the same result, regardless of how many whitespaces your user enters between the characters and numbers.
Try this.You have to give two texfields. One is for name i.e; MCTE and one is for numbers i.e; 1021. (for this textfield you have to change keyboard type only number).
After that you can join those string with space between them and send to your DB.
It's just like hack but it will work.
Scrolling down the course codes list, I noticed some unusual formatting.
Example: TQB 1001E, TQB 1001E etc. (With extra letter at the end)
So, this special format doesn't work with #Jahidul Islam's answer. However, inspired by his answer, I manage to come up with this logic:
var code = "TQB2001M";
var i = course.indexOf(RegExp(r'[^A-Za-z]')); // get the index
var j = course.substring(0, i); // extract the first half
var k = course.substring(i).trim(); // extract the others
var formatted = '$j $k'.toUpperCase(); // combine & capitalize
print(formatted); // TQB 1011M
Works with other formats too. Check out the DartPad here.
Here is the entire logic you need (also works for multiple whitespaces!):
void main() {
String courseCode= "MMM 111";
String parsedCourseCode = "";
if (courseCode.contains(" ")) {
final ensureSingleWhitespace = RegExp(r"(?! )\s+| \s+");
parsedCourseCode = courseCode.split(ensureSingleWhitespace).join(" ");
} else {
final r1 = RegExp(r'[0-9]', caseSensitive: false);
final r2 = RegExp(r'[a-z]', caseSensitive: false);
final letters = courseCode.split(r1);
final numbers = courseCode.split(r2);
parsedCourseCode = "${letters[0].trim()} ${numbers.last}";
}
print(parsedCourseCode);
}
Play around with the input value (courseCode) to test it - also use dart pad if you want. You just have to add this logic to your input value, before submitting / handling the input form of your user :)

How to display Unicode Smiley from json response dynamically in flutter

How to display Unicode Smiley from json response dynamically in flutter. It's display properly when i declare string as a static but from dynamic response it's not display smiley properly.
Static Declaration: (Working)
child: Text("\ud83d\ude0e\ud83d\ude0eThis is just test notification..\ud83d\ude0e\ud83d\ude0e\ud83d\udcaf\ud83d\ude4c")
Dynamic Response:
"message":"\\ud83d\\ude4c Be Safe at your home \\ud83c\\udfe0",
When i'm parse and pass this response to Text then it's consider Unicode as a String and display as a string instead of Smiley Code is below to display text with smiley:
child: Text(_listData[index].message.toString().replaceAll("\\\\", "\\"))
Already go through this: Question but it's only working when single unicode not working with multiple unicode.
Anyone worked with text along with unicode caracter display dynamically then please let me know.
Another alternate Good Solution I would give to unescape characters is this:
1st ->
String s = "\\ud83d\\ude0e Be Safe at your home \\ud83c\\ude0e";
String q = s.replaceAll("\\\\", "\\");
This would print and wont be able to escape characters:
\ud83d\ud83d Be Safe at your home \ud83c\ud83d
and above would be the output.
So what one can do is either unescape them while parsing or use:
String convertStringToUnicode(String content) {
String regex = "\\u";
int offset = content.indexOf(regex) + regex.length;
while(offset > 1){
int limit = offset + 4;
String str = content.substring(offset, limit);
// print(str);
if(str!=null && str.isNotEmpty){
String uni = String.fromCharCode(int.parse(str,radix:16));
content = content.replaceFirst(regex+str,uni);
// print(content);
}
offset = content.indexOf(regex) + regex.length;
// print(offset);
}
return content;
}
This will replace and convert all the literals into unicode characters and result and output of emoji:
String k = convertStringToUnicode(q);
print(k);
😎 Be Safe at your home 🈎
That is above would be the output.
Note: above answer given would just work as good but this is just when you want to have an unescape function and don't need to use third-party libraries.
You can extend this using switch cases with multiple unescape solutions.
Issue resolved by using below code snippet.
Client client = Client();
final response = await client.get(Uri.parse('YOUR_API_URL'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
final extractedData = json.decode(response.body.replaceAll("\\\\", "\\"));
}
Here we need to replace double backslash to single backslash and then decode JSON respone before set into Text like this we can display multiple unicode like this:
final extractedData = json.decode(response.body.replaceAll("\\",
"\"));
Hope this answer help to other

Searching sembast data both caps and small letters

I am using sembast package for local data storage for a flutter app. When I search through the local data, I want to get the results regardless of whether letters are in caps or small. My current code is sensitive to capital and small letters.
Future searchFoodByField(String fieldName, String searchItem) async {
var finder = Finder(filter: Filter.matches(fieldName, searchItem));
final recordSnapshots = await _foodStore.find(
await _db,
finder: finder,
);
return recordSnapshots.map((snapshot) {
final food = Food.fromMap(snapshot.value);
food.foodId = snapshot.key;
return food;
}).toList();
}
How can it be modified to get the desired outcome?
I'm assuming you want to look for the exact word. For non-english language, you might also want to remove the accent. (diacritic package can help help here).
// Using a regular expression matching the exact word (no case)
var filter = Filter.matchesRegExp(
fieldName, RegExp('^$searchItem\$', caseSensitive: false));
You can also use a custom filter, to perform any filtering you want:
// Using a custom filter exact word (converting everything to lowercase)
searchItem = searchItem.toLowerCase();
filter = Filter.custom((snapshot) {
var value = snapshot[fieldName] as String;
return value?.toLowerCase() == searchItem;
});

What ending marks should be used to extend a range to the end of the paragraph?

I am coding a word add-in and am not clear how to use the getNextTextRange(endingMarks, trimSpacing) method of the Range class.
Specifically I want to select a new Range starting from the currently selected range and going to the end of the paragraph.
The API for for the method states
endingMarks string[]
Required. The punctuation marks and/or other
ending marks as an array of strings
That's clear enough if you want to select up to the next comma, period or even space. But what ending marks should you use for a paragraph, a line break, or the end of the document?
I have tried using '\n', '^p' and '¶' but none of these seem to work.
var nr = selection.getNextTextRange(['¶'],true);
nr.load("isEmpty,text");
await context.sync();
console.log('nr='+nr.text);
} catch(e) {
console.log("error, soz");
console.log(e);
}
Given a document consisting of one paragraph of text with a blank paragraph after it, and the first word of the paragraph highlighted, this add-in throws a RichApi.Error
We couldn't find the item you requested.
I would expect it to instead print out the remainder of the paragraph.
If I understand your scenario, you can work with the ParagraphCollection.getFirst() method. Please install the Script Lab tool. Open the sample called "Get paragraph from insertion point" for an example.
Let me expand on rick-kirkham's answer in case it helps anyone else in my situation. This is basically the same answer as given here https://stackoverflow.com/a/51160690/4114053
Ok, here is my sample word document:
The rain in Spain falls. Mainly on the plain.
Alice stepped through the looking glass. What did she see?
And there endeth the lesson. Amen.
The user selects "stepped" in the second paragraph and I want to know what the text for the rest of the paragraph, from that word, says. I also want to know what the text up to that point says.
var doc = context.document;
var selection = doc.getSelection();
selection.load("isEmpty,text");
await context.sync();
console.log(selection.text); //prints stepped
var startRange = selection.getRange("start");
var endRange = selection.paragraphs.getLast().getRange("start");
var deltaRange = startRange.expandTo(endRange);
context.load(deltaRange);
await context.sync();
console.log(deltaRange.text); //prints "Alice"
startRange = selection.getRange("end");
endRange = selection.paragraphs.getLast().getRange("end");
deltaRange = startRange.expandTo(endRange);
context.load(deltaRange);
await context.sync();
console.log(deltaRange.text); // prints "through the looking glass. What did she see?"
My mistake was to get too caught up in trying to work out what "ending marks" might mean and how to use them to achieve this. (Although I still would like that spelled out in the API specification.)

What's wrong with my Meteor publication?

I have a publication, essentially what's below:
Meteor.publish('entity-filings', function publishFunction(cik, queryArray, limit) {
if (!cik || !filingsArray)
console.error('PUBLICATION PROBLEM');
var limit = 40;
var entityFilingsSelector = {};
if (filingsArray.indexOf('all-entity-filings') > -1)
entityFilingsSelector = {ct: 'filing',cik: cik};
else
entityFilingsSelector = {ct:'filing', cik: cik, formNumber: { $in: filingsArray} };
return SB.Content.find(entityFilingsSelector, {
limit: limit
});
});
I'm having trouble with the filingsArray part. filingsArray is an array of regexes for the Mongo $in query. I can hardcode filingsArray in the publication as [/8-K/], and that returns the correct results. But I can't get the query to work properly when I pass the array from the router. See the debugged contents of the array in the image below. The second and third images are the client/server debug contents indicating same content on both client and server, and also identical to when I hardcode the array in the query.
My question is: what am I missing? Why won't my query work, or what are some likely reasons it isn't working?
In that first screenshot, that's a string that looks like a regex literal, not an actual RegExp object. So {$in: ["/8-K/"]} will only match literally "/8-K/", which is not the same as {$in: [/8-K/]}.
Regexes are not EJSON-able objects, so you won't be able to send them over the wire as publish function arguments or method arguments or method return values. I'd recommend sending a string, then inside the publish function, use new RegExp(...) to construct a regex object.
If you're comfortable adding new methods on the RegExp prototype, you could try making RegExp an EJSON-able type, by putting this in your server and client code:
RegExp.prototype.toJSONValue = function () {
return this.source;
};
RegExp.prototype.typeName = function () {
return "regex";
}
EJSON.addType("regex", function (str) {
return new RegExp(str);
});
After doing this, you should be able to use regexes as publish function arguments, method arguments and method return values. See this meteorpad.
/8-K/.. that's a weird regex. Try /8\-K/.
A minus (-) sign is a range indicator and usually used inside square brackets. The reason why it's weird because how could you even calculate a range between 8 and K? If you do not escape that, it probably wouldn't be used to match anything (thus your query would not work). Sometimes, it does work though. Better safe than never.
/8\-K/ matches the string "8-K" anywhere once.. which I assume you are trying to do.
Also it would help if you would ensure your publication would always return something.. here's a good area where you could fail:
if (!cik || !filingsArray)
console.error('PUBLICATION PROBLEM');
If those parameters aren't filled, console.log is probably not the best way to handle it. A better way:
if (!cik || !filingsArray) {
throw "entity-filings: Publication problem.";
return false;
} else {
// .. the rest of your publication
}
This makes sure that the client does not wait unnecessarily long for publications statuses as you have successfully ensured that in any (input) case you returned either false or a Cursor and nothing in between (like surprise undefineds, unfilled Cursors, other garbage data.