How to stop extensions/add ons like grammarly on contenteditable editors
Asked Answered
M

6

47

We are making contenteditable editor. Wondering how to stop extensions like grammarly (if enabled) on editor page using javascript as these extensions insert their own html in the editor itself. It's giving us lot of problems while saving the data.

Checked Medium editor and extnesion/add-on doesn't work over there. Any reference or solution to this kind of problem? Searched a lot but couldn't find a solution for it. Thanks in advance

Martell answered 25/5, 2016 at 18:22 Comment(2)
Yes, I had an issue with Grammarly as well (but for Chrome). It seems to be currently massively bloating the payload being posted and that causes to exceed the allowed size configured in IIS causing a 500 error.Souvenir
I emailed them regarding the issue and they disabled the plugin for my website. Worked for meMartell
F
105

To disable Grammarly, you can add attributes on the <textarea> element. The attributes keep changing, but you can add all of them to be safe.

  • data-gramm="false"
  • data-gramm_editor="false"
  • data-enable-grammarly="false"
Flashback answered 16/10, 2017 at 19:33 Comment(7)
If it works, this is very interesting. Do you have a reference or link to documentation?Gagger
I'd be curious to see docs on this. I tested and it seems to work with either true or false.Faustinafaustine
You can check this issue for more information.Banks
Looks like that only works for the Chrome extension, the Firefox extension still runs with that setting on.Shaggy
This has changed to data-gramm="false" now as I have been advised by Grammarly team.Interpreter
Fun fact: Neither of them works on the latest Chrome.Interpreter
@zed: Try the newest one? data-enable-grammarly="false"Gagger
T
7

So for Grammarly in particular, if you are patient/persistent you can submit a ticket and they will disable their plugin on your site. They won't fix the actual problem, they still inject almost 4MB of extra payload into your editor, I still see the problem when using their plugin on our Dev and QA sites.

I took the approach of Detecting / Alerting Users / Disabling the page. The message was slightly different for Firefox but to keep the sample below brief I stripped out the FF variables and the logging of the offending user.

/* vars intentionally over complicated to make detection more difficult */
//Chrome Message: gc;
var r = /\{0\}/g;
var gc = "PHN0eWxlPg0KCS5pY29uIHsNCgkJLXdlYmtpdC11c2VyLXNlbGVjdDogbm9uZTsNCgkJZGlzcGxheTogaW5saW5lLWJsb2NrOw0KCX0NCgkuaWNvbiB7DQoJCWJhY2tncm91bmQtcmVwZWF0OiBuby1yZXBlYXQ7DQoJCWJhY2tncm91bmQtc2l6ZTogMTAwJTsNCgkJaGVpZ2h0OiA3MnB4Ow0KCQltYXJnaW46IDAgMCA0MHB4Ow0KCQl3aWR0aDogNzJweDsNCgl9DQoJLmljb24tZ2VuZXJpYyB7DQoJCWJhY2tncm91bmQtaW1hZ2U6IHVybCgiZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFKQUFBQUNRQVFNQUFBRGRpSEQ3QUFBQUJsQk1WRVVBQUFCVFUxT29hU2YvQUFBQUFYUlNUbE1BUU9iWVpnQUFBRkpKUkVGVWVGN3QwY0VOZ0RBTVE5RndZZ3hHNldqcGFJekNDQXhReFZnZ0Z1RGlDdmxMT2VSZEhSOXl6am5jSFZvcTNucHUrd1FVclV1Skh5bFNUbUJhZXNwSnlKUW9PYlVleXhEUWIzYkVtNUF1ODFjMHBTQ0Q4SFlBQUFBQVNVVk9SSzVDWUlJPSIpOw0KCX0NCgkuaW50ZXJzdGl0aWFsLXdyYXBwZXIgew0KCQlib3gtc2l6aW5nOiBib3JkZXItYm94Ow0KCQlmb250LXNpemU6IDFlbTsNCgkJbGluZS1oZWlnaHQ6IDEuNmVtOw0KCQltYXJnaW46IDEwMHB4IGF1dG8gMDsNCgkJbWF4LXdpZHRoOiA2MDBweDsNCgkJd2lkdGg6IDEwMCU7DQoJfQ0KCS5ibHVlLWJ1dHRvbiB7DQoJCS13ZWJraXQtdXNlci1zZWxlY3Q6IG5vbmU7DQoJCWJhY2tncm91bmQ6IHJnYig2NiwgMTMzLCAyNDQpOw0KCQlib3JkZXI6IDA7DQoJCWJvcmRlci1yYWRpdXM6IDJweDsNCgkJYm94LXNpemluZzogYm9yZGVyLWJveDsNCgkJY29sb3I6ICNmZmY7DQoJCWN1cnNvcjogcG9pbnRlcjsNCgkJZmxvYXQ6IHJpZ2h0Ow0KCQlmb250LXNpemU6IC44NzVlbTsNCgkJbWFyZ2luOiAwOw0KCQlwYWRkaW5nOiAxMHB4IDI0cHg7DQoJCXRyYW5zaXRpb246IGJveC1zaGFkb3cgMjAwbXMgY3ViaWMtYmV6aWVyKDAuNCwgMCwgMC4yLCAxKTsNCgl9DQo8L3N0eWxlPg0KPGJvZHkgaWQ9InQiIGNsYXNzPSJuZXRlcnJvciIgc3R5bGU9ImZvbnQtZmFtaWx5OiAnU2Vnb2UgVUknLCBUYWhvbWEsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogNzUlO2JhY2tncm91bmQtY29sb3I6ICNmN2Y3Zjc7IGNvbG9yOiAjNjQ2NDY0OyI+DQo8ZGl2IGlkPSJtYWluLWZyYW1lLWVycm9yIiBjbGFzcz0iaW50ZXJzdGl0aWFsLXdyYXBwZXIiIGpzdGNhY2hlPSIwIj4NCiAgICA8ZGl2IGlkPSJtYWluLWNvbnRlbnQiIGpzdGNhY2hlPSIwIj4NCiAgICAgIDxkaXYgY2xhc3M9Imljb24gaWNvbi1nZW5lcmljIj48L2Rpdj4NCiAgICAgIDxkaXYgaWQ9Im1haW4tbWVzc2FnZSIganN0Y2FjaGU9IjAiPg0KICAgICAgICA8aDEgY2xhc3M9ImhlYWRpbmciPlBvdGVudGlhbGx5IGRhbmdlcm91cyBwbHVnaW4gezB9IGRldGVjdGVkLjwvaDE+DQogICAgICAgIDxwPlBsZWFzZSBkaXNhYmxlIG9yIHJlbW92ZSB0aGUgezB9IHBsdWdpbiB0byBjb250aW51ZS48L3A+DQogICAgICAgIDxkaXYgaWQ9InN1Z2dlc3Rpb25zLWxpc3QiPg0KICAgICAgICAgIDxwPjwvcD4NCiAgICAgICAgICA8ZGl2IGNsYXNzPSJ6aXBweS1vdmVyZmxvdyI+PGRpdiBjbGFzcz0iemlwcHktY29udGVudCIgc3R5bGU9Im1hcmdpbi10b3A6IDBweDsgdHJhbnNpdGlvbjogbWFyZ2luLXRvcCAwLjIxOHMgZWFzZS1vdXQ7IG92ZXJmbG93OiBhdXRvOyI+DQoJCQkgIDxwPlRvIHJlbW92ZSBhbiBleHRlbnNpb24gZnJvbSBHb29nbGUgQ2hyb21lOjwvcD4NCgkJCTxvbD4NCgkJCQk8bGk+SWYgdGhlIGV4dGVuc2lvbiBoYXMgYW4gaWNvbiBpbiB5b3VyIENocm9tZSB0b29sYmFyLCB5b3UgY2FuIHJpZ2h0LWNsaWNrIG9uIHRoZSBpY29uLjwvbGk+DQoJCQkJPGxpPlNlbGVjdCA8c3Ryb25nPlJlbW92ZSBmcm9tIENocm9tZS48L3N0cm9uZz48L2xpPiAJCQkJDQoJCQkJPGxpPkEgbm90aWNlIHRvIHJlbW92ZSB0aGUgZXh0ZW5zaW9uIHdpbGwgYXBwZWFyLiBDbGljayZuYnNwOzxzdHJvbmc+UmVtb3ZlPC9zdHJvbmc+LjwvbGk+DQoJCQk8L29sPg0KCQkJICBvcjogPGJyIC8+DQoJCQkgIDxvbD4NCgkJCQk8bGk+T24geW91ciBicm93c2VyLCBjbGljayZuYnNwOzxzdHJvbmc+bWVudTwvc3Ryb25nPiZuYnNwOzxpbWcgc3JjPSJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vSE96dGhvamdJOFQyWUMxbi0xUmlxWnQ3eEQ0T2xyWGJhc0RzbXQ0RFJZR01zX3JoUXduRmhvQVdVc1Q0PXcxOCIgd2lkdGg9IjE4IiBoZWlnaHQ9IjE4IiBhbHQ9IiI+LjwvbGk+DQoJCQkJPGxpPlNlbGVjdCZuYnNwOzxzdHJvbmc+TW9yZSB0b29scyAmZ3Q7IEV4dGVuc2lvbnM8L3N0cm9uZz4uPC9saT4NCgkJCQk8bGk+T24gdGhlIGV4dGVuc2lvbiB5b3Ugd2FudCB0byByZW1vdmUsIGNsaWNrJm5ic3A7PHN0cm9uZz5SZW1vdmUgZnJvbSBDaHJvbWU8L3N0cm9uZz4mbmJzcDs8aW1nIHNyYz0iaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2I2ZkxLbGUyRUFjaEsycEJpOTBzTWlpYmJzaGU5TWdPQ2JmTVN2R21DUTh2UUs4Y1pRMW91RmpBMm9zTz13MTgiIHdpZHRoPSIxOCIgaGVpZ2h0PSIxOCIgYWx0PSIiPi48L2xpPg0KCQkJCTxsaT5BIG5vdGljZSB0byByZW1vdmUgdGhlIGV4dGVuc2lvbiB3aWxsIGFwcGVhci4gQ2xpY2smbmJzcDs8c3Ryb25nPlJlbW92ZTwvc3Ryb25nPi48L2xpPg0KCQkJICA8L29sPg0KCQkJPC9kaXY+PC9kaXY+DQoJCQk8YnV0dG9uIGlkPSJyZWxvYWQtYnV0dG9uIiBjbGFzcz0iYmx1ZS1idXR0b24iIG9uY2xpY2s9IndpbmRvdy5sb2NhdGlvbi5ocmVmPXdpbmRvdy5sb2NhdGlvbi5ocmVmOyI+UmVsb2FkPC9idXR0b24+ICAgICAgICANCiAgICAgICAgPC9kaXY+DQogICAgICA8L2Rpdj4NCiAgICA8L2Rpdj4NCiAgPC9kaXY+DQogIDwvYm9keT4=";
var s = "";

MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

var observer = new MutationObserver(function (mutations, observer) {
    for (mutation in mutations) {
    /*console.log(mutations[mutation].target.outerHTML);*/
    var m = mutations[mutation].target.hasAttribute("data-gramm_id");
    if (m) {
        s = window.atob(gc).replace(r, "Grammarly");

        var newDoc = document.open("text/html", "replace");
        newDoc.write(s);
        newDoc.close();
    }
}
});
observer.observe(document, {
    subtree: true,
    attributes: true
});
Tremayne answered 13/7, 2017 at 16:22 Comment(2)
Amusing. We flag the content and refuse to publish it.Gagger
We found it was better to not have to deal with the bloated form post since the affected page was attempting to send the payload back to the server and then email the content to a third party. so we just prompt our users to remove the plugin.Tremayne
T
5

In general you cannot fight extensions. They represent user intent which is prioritized by browser vendors over author intent. They also have more privileges than the website, e.g. they can bypass CSP.

It's not a fight you can win.

Options you have

  • try anyway. in that case you could inspect the addon source - since they're shipped in source form - and see if some particular sequence of events (loss of focus? disabling contenteditable before saving?) make them remove the injected markup
  • contact the addon authors and ask them to be less invasive
  • warn the user if you detect such behavior

Checked Medium editor

They don't use contenteditable.

https://medium.engineering/why-contenteditable-is-terrible-122d8a40e480

Transom answered 26/5, 2016 at 0:10 Comment(1)
Grammarly converts plain HTML text areas into contenteditable. That is the only way they are able to underline your text.Brambling
V
5

I did the following in CSS, which is working fine. Tested on Firefox:

[contenteditable] ~ grammarly-extension,
input ~ grammarly-extension,
textarea ~ grammarly-extension {
  display: none;
}

Should be far better than adding custom attributes which the Grammarly team changing frequently without any notice.

Vivie answered 27/7, 2021 at 3:39 Comment(0)
S
1

I had a similar problem: my webapp needs know the exact representation of the DOM tree.

Grammarly's extension, however, adds random bits of custom HTML into the DOM tree. I solved the problem by disallowing grammarly, or anything, from modifying the HTML.

I use code similar to @jbranj. But I remove any added HTML from the page. I see a minor slow down on first click into the textarea on safari but it's fine otherwise.

var observer = new MutationObserver(function (mutationsList, observer) {
    for (let mutation of mutationsList) {
        if (mutation.type === 'childList') {
            for (let node of mutation.addedNodes) node.remove()
        }
    }
})

I run observer.observe(document, { attributes: false, childList: true, subtree: true }) when I want to prevent HTML additions. And observer.disconnect() when I want to allow it so I can modify the DOM myself.

(I'm not entirely sure why but both childList and subTree need to be true when you enable the observer.)


Edit:

Because some anti-virus software can hang the browser if you straight out refuse to let them inject scripts in your html:

var added_nodes = []
var observer = new MutationObserver(function (mutationsList, observer) {
    for (let mutation of mutationsList) {
        if (mutation.type === 'childList') {
            for (let node of mutation.addedNodes) added_nodes.push(node)
        }
    }
})

Then later added_nodes.forEach(n => n.remove()) to remove all the injected tags.

Shortwave answered 18/6, 2020 at 9:9 Comment(0)
S
0

The grammarly can be identfied by tag names - GRAMMARLY-EXTENSION, GRAMMARLY-POPUP

You can get the tagName from you target as target.tagName

So this works for me to check if user clicked on grammerly popups

target.tagName.includes('GRAMMARLY')
Stelly answered 5/2 at 9:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.