Detecting text input to VSCode activeTextEditor - javascript

I'm working on a VScode extension for my school open source project.
I was wondering there was a way to detect text input to the activeTextEditor window?
For example if someone were to paste a string in, could I grab detect that string similar to an OnInput in JavaScript? A setup would be spell checking or doing a replacement for commands, similar to Visual Studios' intellisense you type prop +tab +tab it auto generates code.
Let me know if you've heard of something that might work. Thanks

The api you are looking for is vscode.workspace.onDidChangeTextDocument. This event is fired whenever a document that VS Code knows about changes. It is fired with a TextDocumentChangeEvent object which includes all the text changes:
import * as vscode from 'vscode'
export function activate() {
vscode.workspace.onDidChangeTextDocument(changeEvent => {
console.log(`Did change: ${changeEvent.document.uri}`);
for (const change of changeEvent.contentChanges) {
console.log(change.range); // range of text being replaced
console.log(change.text); // text replacement
}
});
}
If you only care about changes to the active editor's text, just check to see if changeEvent.document matches the active editor's document.

Related

Share Quill toolbar across multiple editors

With the great Quill rich text editor for Javascript I'm trying to make two or more editors share the same toolbar.
I suppose (from documentation) that this is not possible right away at the moment, so I'm trying to "simulate" this by adding the toolbar module through API on the editor that has been clicked as the latter:
// this uses jQuery
$editorTag.click(function(e){
var tag = e.target;
var editor = getEditorByTag(tag);
if( editor )
editor.addModule('toolbar',{container:'#toolbar'});
});
It seems to work, but I suspect that Quill doesn't like adding many times the same module over and over on the same object since eventually it spits:
(node) warning: possible EventEmitter memory leak detected. 11
listeners added. Use emitter.setMaxListeners() to increase limit.
quill.js (row 4727)
So is there a way to remove a previously added module? Something like:
// installs editor
var editor = new Quill('#editor');
// adds toolbar module
editor.addModule('toolbar',{container:'#toolbar'});
// removes just added toolbar module
editor.removeModule('toolbar');
I encountered the same problem the other day, and have found a solution that works for our usecase. This is basically what I've done:
I'm creating one instance of Quill, using a custom toolbar positioned
at the top. The editor element is placed in a temporary, hidden,
container. When the user double clicks any of the three text
containers (Editables), the editor element will be transplanted form
the temporary container to a new location inside the Editable. If a
user hits the escape key, the Editable will be deactivated, moving the
editor element back to the temporary container.
You can test it here: https://codesandbox.io/s/hungry-pine-o8oh9?file=/src/App.js
GitHub repo: https://github.com/maxfahl/Quill-Edit-Multiple
Feel free to use the code however you'd like.
A solution that keeps the history of your Quills is to extends Toolbar and register it has a module
class ToolbarAlt extends Toolbar {
resetToolbar () {
this.container.childNodes.forEach(el => {
const clone = el.cloneNode(true);
el.parentNode.replaceChild(clone, el);
});
this.container.childNodes.forEach((input) => {
this.attach(input);
}, this);
}
}
Quill.register('modules/toolbar', ToolbarAlt, true);
Then call your Toolbar with the quill.getModule('toolbar') when you go focusin one editor

CLEditor, pasting content as text functionality in main window

I am using CLEditor, http://premiumsoftware.net/cleditor/, for my text editor. There is a function for 'paste as text' that when the button is clicked a pop up window appears with a textarea to paste your content in and the styles are stripped out.
What I would like to do is take this same functionality, but anytime someone paste into the primary textarea this action is performed automatically. How would I trigger this?
I have created a JS Fiddle, http://jsfiddle.net/helpinspireme/naubS/, but was unable to paste all the JS in there so to link to the main JS file for CLEditor visit their site: http://premiumsoftware.net/cleditor/
Thank you for your help.
I am aware that I am not answering your actual question, but in case your real problem is the garbage generated by a user who tries pasting text from Microsoft Office (Word for example) I would recommend to consider an alternative solution.
The CLEditor itself can switch between an iFrame (rich text mode) and a textarea (source mode). The 'Paste as text' functionality makes use of a textarea which does not support rich text by ifself, so it will not allow garbage html in the first place.
However if the editor is in rich text mode, it is very difficult to prevent a user pasting from Word (he can use the regular paste button, press CTRL-V or even use the right-mouse button context menu, which are all different events and hard to intercept using javascript). So now the damage is already done; you have messy html inside your editor. So instead of trying to sanitize the garbage produced by Word I implemented the following check (javascript) upon saving the captured input:
if(clEditorValue && (clEditorValue.indexOf('<!--') !== -1 || clEditorValue.indexOf('mso-ansi-language') !== -1 ) ) {
alert('Unable to process text pasted from Word, please use "Paste as text" or modify your input');
return;
}
I hope this answer is useful for other people trying to achieve the same.
When pasting into cleditor, the editor picks up all the html from the source. I ended up editing jquery.cleditor.js and added a bind function to the $doc.click(hidePopups) function. I used setTimeouts to allow the text to populate the input and the updateTextArea function to complete.
.bind("paste", function() {
setTimeout(function() {
refreshButtons(editor);
updateTextArea(editor, true);
//remove any and all html from the paste action
setTimeout(function() {
//clean up the html with removeHtml function
$(editor.doc.body).html(removeHtml($(editor.doc.body).html()));
//change the input value with new clean string
$("#" + editor.$area[0].id).val($(editor.doc.body).html());
}, 100);
}, 100);
})
I use the removeHtml function below to remove all the HTML from the pasted content.
//remove html altogether
function removeHtml(str) {
var regex = /(<([^>]+)>)/ig;
var result = str.replace(regex, "");
return result;
}
This solution is now in production.

Stripping styles from TinyMCE copy+paste?

is there a way to strip specific tags from coming into tiny MCE through a copy+paste from an external source (e.g. Word)? I'd like to prevent font-family and image tags from being copy+pasted over, but have no problem with font-size etc.
Thank you!
You can't really stop someone from pasting something, so I believe your best bet would be to filter out the unwanted tags by calling a function on form submit, or onchange of the tiny MCE textarea. Then you could use some regular expression replacement to get rid of the unwanted tags.
EDIT: Actually there is a simple way. check the TinyMCE documentation.
Here is the link to a similar SO question with a detailed description of howto strip out unwanted tags: TinyMCE Paste As Plain Text
I don't know how useful this will be, but you might want to take a look at this jQuery plugin which allows you to filter tags and attributed from the text your are pasting.
FilteredPaste.js - A jQuery Plugin To Filter & Clean Pasted Input
Although "You can't really stop someone from pasting something" indeed, you can transform what your web app inserts into your TinyMCE textbox (or any other input).
Listen to the browser's native paste event.
Parse the clipboard's text/html string with DOMParser.
Make changes in the generated DOM tree.
Set the textbox content to the stripped content.
Prevent the paste default action.
Check this out:
editor.on ('paste', event => {
// Get clipboard's original HTML string
const clipboard = event.clipboardData
const originalHtml = clipboard.getData ('text/html')
// Parse HTML string into a DOMElement
const parser = new DOMParser
const doc = parser.parseFromString (originalHtml, 'text/html')
// Modify DOM tree
const elems = doc.body.querySelectorAll ('*')
elems.forEach (elem => {
elem.style.fontFamily = ''
// Do other modifications here...
})
// Set textbox content to modified HTML
editor.setContent (doc.body.innerHTML)
// Prevent pasting original content
event.preventDefault ()
})

Detecting and manipulating CKEditor areas

I need to write a javascript function that can look at the WYSIWYG on the page (CKEditor) that is rendered after the page loads with the Drupal WYSIWYG module. I am having difficulty using jQuery even finding the editor.
$(textarea#textarea-id).change or .keyup do nothing.
I can do this:
console.log(CKEDITOR.instances);
That at least shows me the instance where CKEditor is attaching itself to. I can't seem to reference anything after that:
CKEDITOR.instances.myinstance-name or CKEDITOR.instances[0] both return undefined.
I've gone in circles for 2 hours now and not sure what else to try.
All I want to do is when the user is typing (keyup), count the characters input. If the input is greater than a certain length, I want to force a line break right in the text.
How can I go about implementing this? I thought it would be fairly straightforward.
Using other examples I have seen:
for (var i in CKEDITOR.instances) {
CKEDITOR.instances[i].on('change', function() {alert('test 1 2 3')});
}
Resulted in no alert.
The editor is being loaded/displayed in an iframe (via CKEditor/WYSIWYG in Drupal).
There's a plugin available that provides an onChange event for CKEditor, you can find it (along with instructions) here.
It suggests using code like this:
editor.on( 'saveSnapshot', function(e) { somethingChanged(); });

Detecting local file drag'n'drop with HTML/JavaScript

There is a HTML textarea. I'm able to catch that event when a local file is dragged and dropped onto the textarea. But how to obtain the name of the dropped file? (To be modified and inserted into the textarea finally.)
The following expressions returns None in that case:
event.dataTransfer.files
event.dataTransfer.getData('text/plain')
I made a short example for Firefox 3 that is my target platform currently.
<script>
function init() {
document.getElementById('x').addEventListener('drop', onDrop, true)
}
function onDrop(event) {
var data = event.dataTransfer.getData('text/plain')
event.preventDefault()
alert('files: ' + event.dataTransfer.files + ' && data: ' + data + '.')
}
</script>
<body onload='init()'>
<textarea cols=70 rows=20 id='x'></textarea>
This is a bit late - but I think what you are looking for is this:
event.dataTransfer.files[0].name
You can also get the following properties:
event.dataTransfer.files[0].size
event.dataTransfer.files[0].type
And you can loop thru these files with the following:
var listOfNames='';
for(var i=0,tot=event.dataTransfer.files.length; i<tot; i++){
listOfNames+=event.dataTransfer.files[i].name + '\r\n';
}
Btw - if you are using jQuery then the dataTransfer object can be found here:
event.originalEvent.dataTransfer.files[0].name
Don't know if it's still relevant, but I faced the same problem. Here's how I solved it:
Create a normal upload form with a single input field (type="file")
Add this HTML attribute to the input field:
dropzone="copy file:image/png file:image/jpg file:image/jpeg"
Set JQuery listener or whatever to catch the "drop"-event on the input field
When you drag & drop a local image on the input field, the "value" attribute is filled automatically and you can process it like any other HTML form.
I also wrapped the form into another HTML element (div), set the size of the div and set overflow:hidden via CSS - this way, you can get rid of the "browse" button. It's not nice, but it works. I also used the AjaxForm plugin to upload the image in the background - works very nice.
as far as I know, you need to obtain an instance of nsIFile in order to get the file path (the File class does not offer this feature).
This MDC page explains how to do this: https://developer.mozilla.org/En/DragDrop/Recommended_Drag_Types#file.
Note that although not listed in the previous link, obtaining an nsIFile instance requires privileges escalation (cf. my answer to Can I drag files from the desktop to a drop area in Firefox 3.5 and initiate an upload? show how to do this).
im doing it by detecting mouseover and mousedown over the "Drop" zone
Alemjerus is correct, you don't have access to what you're looking for.
The behavior you mentioned in reply to his comment is the default behavior of certain browsers. For instance, with the stackoverflow textarea for this entry, if I use Safari and drag a file into it, it places the file's path into the textarea. With firefox 3.5, on the other hand, it attempts to open the file with the browser.
Basically, the "drag and drop" functionality you're attempting to implement is something thats handled by the browser and OS on the client machine -- you can't use Javascript for this purpose.
You can not do it with Javascript because of security reasons. Javascript VM has no direct access to OS file system. You can only drag and drop text.

Categories

Resources