How to enforce a formatting on paste? - quill

I found how to strip any existing formatting from pasted content, but I didn't find a graceful way to enforce a format to it.
I use the current hack:
quill.clipboard.addMatcher (Node.ELEMENT_NODE, (node, delta) => {
quill.format('header', 1); // <-- hacky sneaky set format in quill
return new Delta().insert(node.innerText); // <-- returns stripped text
});
Although this works, what is the appropriate way to set a format before text is added by pasting? I suspect I need to register an event handler or hook somewhere.

The answer is simpler than I thought:
quill.clipboard.addMatcher (Node.ELEMENT_NODE, (node, delta) => {
// return stripped and reformatted text
return new Delta().insert(node.innerText).insert('\n', { header: 1 });
});
The trick is to utilize the Delta DSL properly. It didn't realize at first how header formatting works with that weird newline approach, but it seems that's just how Quill works.

Related

Reactjs convert input string to upper case

I'm creating an app in Reactjs using react-strap. I would like to convert an input field to upper case.
From googling, it looks like simply appending "toUpperCase()" to the field would work, but this doesn't appear as an option in Visual Studio code.
I had a similar issue with doing a replace all, but finally got that to work using "const" field:
// replace ":" with "-"
const phrase = item.macs;
const replaced = phrase.replace(/:/g, '-')
item.macs = replaced;
However, converting to a const field doesn't work for making the "toUpperCase()" available.
What should I do to turn this into a string so I can call the "toUpperCase()" function?
Edit: change references from "toUpper" to "toUpperCase". The problem is this is not available as a function.
For example of I do
'myString'.toUpperCase();
it works. But it I can't get it to bring that up in Visual Studio Code, and it's ignored if I code it anyway.
I believe you are looking after toUpperCase.
To make a string uppercase in javascript you can call .toUpperCase() method on it. For example
const foo = 'foo'
const fooUpper = foo.toUpperCase()
console.log(fooUpper) // expected result 'FOO'
I got around this problem by forcing the input item to be regarded as a string by prepending it with a '', like so:
item.macs = '' + item.macs;
item.macs = item.macs.replace(/:/g, '-');
item.macs = item.macs.toUpperCase();
After that, all the string functions were available.

Determining if a delta was generated by an undo

I'm implementing a simple "track changes" type of interface that replaces deleted content with the same content, but highlighted and with a strike-through line. This works fine for normal content the user deletes, but when undoing an insertion, the delta looks the same as a regular user deletion. Is there any way to determine if the delta was from the undo extension? Or is this fundamentally the wrong approach?
You might want to check the keyboard Module to detect here that an undo command is done and modify the to-be-applied Delta in order to remove its "deleted style".
This pice of code might help you bootstrap your needs:
'undo': {
key: 90,
shortKey: true,
handler: function (range, context) {
// return true to keep normal Quill behaviour
// or else return a new Delta that modify context
console.log(range, context)
return true
}
}
Best

Load Delimiter Separated Values in D3

I am trying to load a pipe separated value file in D3 using the generic d3.dsvFormat() function. While I do not get an error, nothing happens which I think is because the callback function is not executed.
I did check the documentation here but did not find it that helpful: https://github.com/d3/d3-dsv/blob/master/README.md#dsvFormat
Is there a problem with my syntax?
var psv = d3.dsvFormat("|");
psv.parse("my_file.txt", function(error, data) {
Do a bunch of stuff with the data....
console.log(data); //nothing happens here
});
psv.parse wants text, you are passing text - just that it doesn't have any pipe in it: "my_file.txt". As this is one line of text and the first line of text translates into column names, you won't get any data with this.
Your problem is that psv.parse won't fetch a file for you like d3.csv or d3.tsv (Rather psv.parse() acts like d3.csvParse() or d3.tsvParse()). Luckily this is not too difficult to fix.
If we look at the API documentation for d3.csv we can recreate the same functionality for any delimited file. With d3.csv,
If a callback is specified, a GET request is sent, making it
equivalent to:
d3.request(url)
.mimeType("text/csv")
.response(function(xhr) { return d3.csvParse(xhr.responseText, row); })
.get(callback);
(from API docs)
We just have to emulate this for a pipe separated file:
var psv = d3.dsvFormat("|");
d3.request("my_file.txt")
.mimeType("text/plain")
.response(function(data) { return psv.parse(data.response) })
.get(function(data) {
console.log(data);
});
It's a little bit more verbose than a plain old d3.csv() or d3.tsv(), but achieves the same result with the callback function located in the get method.
You could also use data.responseText in the response method, I'm not sure what the difference is though, both appear identical in my quick testing.
You may have also noted that I did not specify a row function in the response method, this is an optional function that allows "conversion of row objects to a more-specific representation", eg: returning numbers rather than strings. API documentation).
One last note:
In relation to your original code, psv.parse("text") returns the data, you don't use a callback function for this method. The following snippet demonstrates how you might parse straight pipe delimited text:
var psv = d3.dsvFormat("|");
var data = psv.parse("a|b\n1|2\n4|3")
console.log(data);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

clear text field using DELETE or BACK SPACE key in webdriver

I am trying to clear a text field using this action:
emailField.sendKeys("gmail.com");
emailField.sendKeys(Keys.CONTROL,"a",Keys.DELETE);
In above code, the last line only selects the text, does not delete it, but if I separate the actions it works.
emailField.sendKeys(Keys.CONTROL,"a");
emailField.sendKeys(Keys.DELETE);
From the JavaDoc for WebElement.clear():
If this element is a text entry element, this will clear the value.
Has no effect on other elements. Text entry elements are INPUT and
TEXTAREA elements. Note that the events fired by this event may not be
as you'd expect. In particular, we don't fire any keyboard or mouse
events. If you want to ensure keyboard events are fired, consider
using something like sendKeys(CharSequence) with the backspace key. To
ensure you get a change event, consider following with a call to
sendKeys(CharSequence) with the tab key.
Most likely you simply need to call:
emailField.sendKeys("gmail.com");
emailField.clear();
But if you need the clearing to be done via the keyboard for some reason, use Keys.BACKSPACE.
keys.DELETE can not work to delete the input text,you should use keys.BACKSPACE.
emailField.sendKeys(Keys.BACKSPACE)
From the JavaDoc for Keys.chord
chord(java.lang.CharSequence... value)
Simulate pressing many keys at once in a "chord".
You should be able to use
emailField.sendKeys(Keys.chord(Keys.CONTROL,"a",Keys.DELETE));
Tested in chrome driver
WE.send_keys(' \b')
This will add space then delete it (backspace)
I use in javascript and it's working fine:
await textBox.sendKeys(value);
await textBox.sendKeys(Key.BACK_SPACE);
emailField.sendKeys(Keys.BACKSPACE)
doesn't worked for me .
I used 'Key' instead of 'Keys'
emailField.sendKeys(protractor.Key.BACKSPACE)
emailField.sendKeys(Keys.CONTROL + "a",Keys.DELETE);
In PHP:
if you use php-webdriver (https://github.com/php-webdriver/php-webdriver) you must:
use Facebook\WebDriver\WebDriverKeys AS Keys;
.
.
.
$this->driver->findElement(By::id('demo'))->sendKeys([Keys::BACKSPACE,'Any other text']);
Just adding another working C# example using the Google Chrome webdriver.
SendKeys only takes one parameter so created a string with the Crtl + A. This code sequence will select the current text in the field then delete the text.
Code example:
var crtlA = Keys.Control + "a";
driver.FindElement(By.XPath("//div[3]/div[1]/div[2]/div/div[2]/div[2]/div/div/div[1]/div/span/input")).SendKeys(crtlA); Wait(5000); // Select current text
driver.FindElement(By.XPath("//div[3]/div[1]/div[2]/div/div[2]/div[2]/div/div/div[1]/div/span/input")).SendKeys(Keys.Delete); Wait(5000); // Clear current text
driver.FindElement(By.XPath("//div[3]/div[1]/div[2]/div/div[2]/div[2]/div/div/div[1]/div/span/input")).SendKeys(newItemSku); Wait(5000); // Input SKU name
1. in WebdriverIO, i tried to edit the text by clear text (which contains special charactes like #, +, _) in text field by below following step. Eventhough it was not successful.
example: text=> abc+1234#gmail.com
step1:browser.clearElement(selector);
step2:browser.execute(function () {
document.querySelector(>>>Cssselector<<<).value="";
});
step3: browser.doubleClick(selector);
browser.keys("Delete");
step4: browser.click(selector);
browser.keys(['Meta',a]);
browser.keys('Meta');
browser.keys('Delete');
Note: below step is resolved this issue.
var count= browser.getAttribute(selector, value).length;
for (var i=0;i<count;i++)
{
if (browser.getAttribute(selector, value)=='')
break;
}
else
{
browser.doubleClick(selector);
browser.keys("Delete");
}
browser.pause(200);
// it will clear your text field easily.
Note:
You can add the new text now.

Textangular HTML mode clears model value

We decided to change our backend CMS to use text-angular's WYSIWYG editor. The content pulls from the database just fine, it gets rendered just fine, but the instant we go to view the HTML source, the text is there for an instant and then it disappears. I've turned off sanitization with the ta-unsafe-sanitizer="true" . The weird thing is, if I manually step through the angular code that does the digesting, eventually the text is rendered and it stays on the screen. If I run it without breakpoints, it clears the text.
I'm not sure if it is sanitization or some sort of race condition inside Angular. Anyone else run into this?
View
<div text-angular ta-toolbar="[['h1','h2','h3'],['bold','italics','underline'],['ul','ol'],['outdent','indent'],['html'],['insertImage']]" ng-model="updatePageTranslation.Content" ta-unsafe-sanitizer="true"></div>
Controller
$scope.updatePageTranslation.Content = 'large html portion here';
The scope of the form is set as follows:
<div class="widget" ng-controller="PageController">
Everything gets loaded fine and other fields of the form show the values correctly. The initial render of the content is correct. It is just when switching to HTML view that it goes blank. Clicking Html again switches back to the visual view, which is correct. But if I save, the value sent to the server is now blank.
I can even copy and paste the value into textangular.com site's demo textbox and have the same issue.
This was a strange one to figure out, but thanks to #HanletEscaño, I was able to find my way. When returning the content from the server, I had to do the following in order to pre-sanitize it so that you could switch back and forth between the HTML and rendered view:
Content.Replace(Environment.NewLine, "").Replace("\n", "").Replace("\r", "").Replace("\t", "").Replace(" ", "");
The important one is that last replace, where we replace two spaces with nothing. This seemed to be the final trick. We were coming from a previous WYSIWYG editor where we could make the HTML look nice, but with this editor, everything has to be condensed.
As mentioned above, this seems to be due to the parser struggling to handle whitespace and newlines correctly.
If you take a look at the textAngular source, in taBind.js, _taBlankTest service seems to returns true when the bound value contains spaces, newlines etc, which in turn causes the model to get set to undefined.
I replaced mine with the following to avoid that situation:
angular.module('textAngular.taBind', ['textAngular.factories', 'textAngular.DOM'])
.service('_taBlankTest', [function(){
var INLINETAGS_NONBLANK = /<(a|abbr|acronym|bdi|bdo|big|cite|code|del|dfn|img|ins|kbd|label|map|mark|q|ruby|rp|rt|s|samp|time|tt|var)[^>]*(>|$)/i;
return function(_defaultTest){
return function(_blankVal){
if(!_blankVal) return true;
var _matchVal = _blankVal.replace(/( |\t|\n)/gm, '');
// find first non-tag match - ie start of string or after tag that is not whitespace
var _firstMatch = /(^[^<]|>)[^<]/i.exec(_matchVal);
var _firstTagIndex;
if(!_firstMatch){
// find the end of the first tag removing all the
// Don't do a global replace as that would be waaayy too long, just replace the first 4 occurences should be enough
_matchVal = _matchVal.toString().replace(/="[^"]*"/i, '').replace(/="[^"]*"/i, '').replace(/="[^"]*"/i, '').replace(/="[^"]*"/i, '');
_firstTagIndex = _matchVal.indexOf('>');
}else{
_firstTagIndex = _firstMatch.index;
}
_matchVal = _matchVal.trim().substring(_firstTagIndex, _firstTagIndex + 100);
// check for no tags entry
if(/^[^<>]+$/i.test(_matchVal)) return false;
// this regex is to match any number of whitespace only between two tags
if (_matchVal.length === 0 || _matchVal === _defaultTest || /^>(\s| |\n|\t)*<\/[^>]+>$/ig.test(_matchVal)) return true;
// this regex tests if there is a tag followed by some optional whitespace and some text after that
else if (/>\s*[^\s<]/i.test(_matchVal) || INLINETAGS_NONBLANK.test(_matchVal)) return false;
else return true;
};
};
}])
Hopefully that may help someone out there!

Resources