Webview delegate's shouldChangeSelectedDOMRange: called with document-fragment instead of full document - macos

My web view has several elements, which can be edited by the user to update model objects in the OS X host application.
For some of these elements, when editing delegate methods like webView:shouldChangeSelectedDOMRange:toDOMRange:affinity:stillSelecting: are called, the range arguments are inside a #document-fragment container -without any attribute information at all.
Thus, it is nearly impossible to figure out, what node is being edited - as all id attributes have been stripped.
po proposedRange.commonAncestorContainer.path
/#document-fragment/DIV/DIV/DIV/#text
For other input elements, I get the whole DOM path, with all attribute information intact:
po proposedRange.commonAncestorContainer.path
/#document/HTML/BODY/DIV/DIV/DIV/TABLE/TBODY/TR/TD/DIV/DIV/DIV/DIV/TABLE/TBODY/TR/TD/DIV/DIV/DIV/DIV/DIV/DIV/DIV/DIV/DIV/DIV/DIV/DIV/DIV/DIV/DIV/DIV/DIV/DIV/H1/SPAN/#text
Any ideas what could cause this difference in behavior?

Related

react: copy component state value to clipboard without dummy element

In my project there is one usage case: user click one button and then copy some data to clipboard for next step.
The copied data is related to the clicked button, and is stored in the component state.
I do some search, and find the potential solution as following:
function copyToClipboard(text){
var dummy = document.createElement("input");
document.body.appendChild(dummy);
dummy.setAttribute('value', text);
dummy.select();
document.execCommand("copy");
document.body.removeChild(dummy);
}
to some extend, we need to create a dummy element, set the copied data to the dummy element and select the element, then execute the execCommand(copy) method.
is it possible to do this without creating dummy element? I know there are some react plugin about clipboard, but I just want to use vanilla javascript. thank you
Your solution works well.
If the value you want to copy is not yet rendered on the DOM, your Document.createElement('input')... method is a good way to create a document node that Document knows about, but that is not visible to the user. Once you use .createElement() you can then call execCommand() on it to copy the value to the clipboard.
The execCommand() method is exposed by HTML5's Document. This means Document has to know about the node you are targeting before you can use the method (this is called Selection).
However, if you want to copy text from an element already rendered on the dom (e.g an input in a form), you could use React's callback ref. Here's a good example of using ref to do this. It's pretty simple, so using a library is likely to be overkill.

How to tell if an element is a Widget? (CKEditor)

Per CKEditor, initialize widget added with insertElement, we are doing an insertElement() and then initializing with initOn(). The problem is that some of the elements we are inserting are not supposed to be widgets and initOn() makes them widgets and the context menu doesn't work right. I am having trouble finding any properties inside the item/element to tell if something is/is not a widget so I can then call initOn().
Cross-posted downstream on Drupal.org here https://www.drupal.org/node/2466297
First of all - which element do you mean?
(Note: In this section I am assuming that a widget was correctly and fully initialised.)
Widget element
A widget can obviously consists of many elements. One of them is called the "widget element" and this is the element which you "upcasted" and which you can later access through widget.element.
Since CKEditor 4.5.0 there will be such method available:
Widget.isDomWidgetElement = function( node ) {
return node.type == CKEDITOR.NODE_ELEMENT && node.hasAttribute( 'data-widget' );
};
You can of course already use this code to check if a given node is a widget element.
Widget wrapper
Second important element is the widget's wrapper. It is created during data processing if a widget element was marked to be upcasted or when initOn() is called if the widget element wasn't wrapped yet. You can access this element through the widget.wrapper property.
Since CKEditor 4.5.0 there will be a following method available:
Widget.isDomWidgetWrapper = function( node ) {
return node.type == CKEDITOR.NODE_ELEMENT && node.hasAttribute( 'data-cke-widget-wrapper' );
};
And again - you can use this code already.
Important note here - since you mention insertElemet() in your question. As I explained in CKEditor, initialize widget added with insertElement editor#insertElement() does not trigger data processing. Therefore, element that you insert is inserted as is. This means that the widget wrapper is not created during insertion and will be created once you call initOn().
Finding widgets by any element
Many times you want to find a widget instance by some element that you have (any element that can be inside a widget). There's a useful method for that: getByElement().
What should become a widget? Aka - how to deal with editor.insertElement()?
You mentioned that you use editor.insertElement() and that you don't know which elements are supposed to be widgets. This should never happen. editor.insertElement() is a quite low level method which will not do all the data processing and upcasting magic which editor.insertHtml() does. It means that it is supposed to be used in a different case - when you want to insert exactly the element that you have.
For instance, your table plugin is building a table structure to be inserted into editor. You know that the table is empty, so you control every bit of it (other plugins should not interfere here). It is also important that it's the table's plugin decision, not e.g. a template's plugin decision. The table's plugin control the table feature, while the template plugin only uses tables. So in such case, when you have a full control, you can use editor.insertElement(). Then you always know what you insert and what is supposed to become a widget.
In all other scenarios you should use editor.insertHtml(), so the whole data processing layer is triggered. Thanks to it other features like the widgets system, the link plugin (which turns empty anchors into fake objects), etc. can prepare the data that you insert to be fully editable and integrated.
Tl;dr
If your plugin knows what it does, it can use editor.insertElement(), but since it knows what it does it will know which inserted element must become a widget.
If your plugin does not fully control the situation, then you should use the editor.isertHtml() method which is far more automated and will turn proper elements into widgets based on the upcast callbacks.

Extjs how to get list of all events of component dynamically

I want to get the list of all events for any particular component dynamically. For example : If I take a Textfield , how can I get all possible events that are mentioned in ExtJs API Doc. so that user can choose and assign the event for any component.
component.events
Contains the list you need. You could have found out by yourself reading the source of addEvents method, which is linked from any event you wanted to find in a list.
For those still wanting an answer to this, https://coderwall.com/p/jnqupq/easily-capture-all-events-on-a-component-in-extjs has provided a nice means of doing so.
When debugging an ExtJS application, you'll often find it useful to listen to all events fired by a specific component. There is actually a handy built-in static method to do this called Ext.util.Observable.capture().
Here's a handy snippet that simply logs the event name and all arguments:
Ext.util.Observable.capture(myObj, function(evname) {console.log(evname, arguments);})
Even better, if you're currently inspecting your component's main element in your browser's developer tools, you can do this:
Ext.util.Observable.capture(Ext.getCmp($0.id), function(evname) {console.log(evname, arguments);})
Where $0 is the currently selected element. Should work fine in Chrome, Firefox, Opera, Safari.
If you don't want those logs to pollute your console anymore, simply call releaseCapture on your object:
Ext.util.Observable.releaseCapture(myObj);
This removes all captures on a given object so you don't have to reference your listener explicitly (which was likely an anonymous function :)).
Bonus tip: also be sure to check out the observe method which does something similar but allows you to listen to all events fired by all instances of a given class.

What exactly is an NSTreeController's "arrangedObjects"?

I'm trying to bind an NSTreeController's "arrangedObjects" to a custom view's "managedContent" (so that it can show a custom outline, for instance). In the setter...
- (void)setManagedContent:(NSArray *)newManagedContentArray {
//code goes here
}
nothing ends up working since newManagedContentArray ("arrangedObjects") apparently isn't an NSArray (and therefore I can't addObject: etc. etc.) Instead it's showing up as an NSControllerTreeProxy. My question is, what exactly is "arrangedObjects" supposed to be? Am I supposed to bind to it? If so, how?
arrangedObjects isn't supposed to be an array for NSTreeController. It states this quite clearly in the documentation. What you do get is the proxy object you are seeing, which you can use the childNodes and descendantNodeAtIndexPath: method on to get your tree structure.

Cocoa NSOutlineView and Drag-and-Drop

I recently started another thread without an account, so I'm reposting the question here with an account so I can edit current links to the program so other users can follow this. I have also updated the code below. Here is my original question:
I read the other post here on Outlineviews and DND, but I can't get my program to work. At the bottom of this post is a link to a zip of my project. Its very basic with only an outlineview and button. I want it to receive text files being dropped on it, but something is wrong with my code or connections. I tried following Apple's example code of their NSOutline Drag and Drop, but I'm missing something. 1 difference is my program is a document based program and their example isn't. I set the File's Owner to receive delegate actions, since that's where my code to handle drag and drop is, as well as a button action. Its probably a simple mistake, so could someone please look at it and tell me what I'm doing wrong? Here is a link to the file: http://dl.dropbox.com/u/7195844/OutlineDragDrop1.zip
You're not responding to NSOutlineView's drag-validation message.
Your original code implemented tableView:validateDrop:proposedRow:proposedChildIndex:. As I pointed out on that question, that's wrong when your table view is an outline view; NSOutlineView will not send a table-view drag-validation message, only an outline-view drag validation message.
You've since changed your drag-validation method to be declared like so:
- (NSDragOperation)outlineView:(NSOutlineView*)view
validateDrop:(id <NSDraggingInfo>)info
proposedRow:(int)row
proposedChildIndex:(NSInteger)index
But nothing actually sends such a message.
Remember that NSOutlineView rarely deals with row indexes, since those can change as parent rows are expanded and collapsed. It deals instead with “items”, which are generally model objects.
Therefore, the correct validation method is:
- (NSDragOperation)outlineView:(NSOutlineView*)view
validateDrop:(id <NSDraggingInfo>)info
proposedItem:(id)item
proposedChildIndex:(NSInteger)index
Notice the name of the third component of the selector, and the type and name of the argument that goes with it.
With this change applied, your data source validates drops.

Resources