Drag n' Drop spark List Itemrenders betwen components - drag-and-drop

I'm trying to do some drag and drop between 2 spark List located in different components.
Because my first attempt didn't work, I decide to Google it and read some more about DragAndDrop ... tried all the examples I could find but nothing seams to work for me.
So let's go to the point.
Component A has List1
Component B has List2
Component A - List 1 has dragEnabled="true" and mouseDown="initiateDrag(event)"
private function initiateDrag(e:MouseEvent):void{
var dragInitiator:IUIComponent = e.target as IUIComponent;
var de:DragSource = new DragSource;
de.addData(dragInitiator, 'artist');
DragManager.doDrag(dragInitiator, de, e);
}
By what I read, usind the mouseDown I'm starting a the drag event creating what kind of data I'm going to drag ... this case 'artist'
Component B - List 2 has dropEnabled="true", dragEnter="dragEnterHandler(event)" and dragDrop="dragDropHandler(event)"
private function dragEnterHandler(e:DragEvent):void{
if(e.dragSource.hasFormat('artist')){
DragManager.acceptDragDrop(List(e.currentTarget));
}
}
Now, what I'm expecting was, when I drag the itemRender from Component A List 1 over Component B List 2 is to call the function dragEnterHandler(event), and it does ... but I was also expecting that the DragManager.acceptDragDrop(List(e.currentTarget)) whould change indicator from the "red cross" to the "green plus" and that's not happening ... and because of that, the dragged itemRender (proxi) moves back to its original list in this case it moves back to Component A List 1
I already spent hours and hours debugging and testing other approaches and none seams to work for me.
Is there anyone here familiarize with drag and drop between components that may help me?

Well guys, looks like after 2 days and 4h later I got the solution :)
I was looking to this in a complete wrong way.
When using Drag and Drop with List based components, the 'format' is always 'itemsByIndex' and I was trying to be accepted with 'artist' 'format'.
Problem:
You have more than one List accepting data with a drag-and-drop method.
Different lists has to accept different types of data.
Solution:
Wrap the <s:List/> in <s:Group/> and manually call the dragEnter event and with it you call a function that can accept or reject the dragged data by checking it's 'format'.
Accepting the drag source, the dragDrop event is dispatched and with that you can call a function to do whatever you want in your app ... for example, add the dragged data to the list.
NOTE:
Remember if tou set the dragEnter and dragDrop directly on the component, you will ne be able to check the dragged data 'format' given all list controls uses the 'format' 'itemsByIndex'
Demo:
<fx:Script>
<![CDATA[
private function dragEnterHandler(e:DragEvent):void{
if(e.dragSource.hasFormat('artist')){
var dropTarget:Group = Group(e.currentTarget);
DragManager.acceptDragDrop(dropTarget);
}
}
private function dragDropHandler(e:DragEvent):void{
// Check is the data alreay exists in the list;
// Adds the data to the list dataGroup;
// Do whatever you want ...
}
]]>
</fx:Script>
<s:Group id="myGroup"
dragDrop="dragDropHandler(event)"
dragEnter="dragEnterHandler(event)">
<s:List id="myList"
dataProvider="{myDataProvider}"/>
</s:Group>
Hope this helps other people with the same problem! :)

Related

Is it possible to drag & drop between custom VS Code tree views?

The 1.66 (March 2022) release introduces a TreeDragAndDropController API which allows for handling drag & drop events for custom tree views.
However in the docs for the DataTransfer object is says:
Drag and drop controllers that implement {#link TreeDragAndDropController.handleDrag handleDrag} can add additional mime types to the data transfer. These additional mime types will only be included in the handleDrop when the the drag was initiated from an element in the same drag and drop controller.
Does this mean that you cannot drag & drop between custom tree views as they would typically have a custom drag & drop controller per view? Or that you're meant to re-use a drag & drop controller between tree views in order to enable dragging & dropping between views?
I have tried various combinations and been unsuccessful in getting a full drag & drop between two tree views. I do see an error in the console on drop in some situations but that is about it.
It took me a while to figure out how to get drag & drop to work between two different treeviews. For me, the problem was a combination of:
Misunderstanding the purpose / usage of dragMimeTypes.
Misunderstanding the purpose / usage of treeDataTransfer.set().
Using an incorrect naming convention for mime types.
This is probably best described by way of example.
Let's assume we're only going to drag from TreeView_A and we'll only drop onto TreeView_B.
For TreeView_A
dropMimeTypes can be an empty array as we're not expecting to receive any drops.
We don't really need a handleDrop() method, again we're not expecting to receive any drops.
dragMimeTypes needs to include the mime type of the treeview that we're going to drop onto (i.e. TreeView_B). A word of warning here, this MUST be in the format application/vnd.code.tree.<treeidlowercase>. So, for this example it would read something like this:
dragMimeTypes = ['application/vnd.code.tree.treeView_b'];
handleDrag() method needs to set using a mime type of the target treeview (Treeview_B), (remember lowercase!)
public async handleDrag(source: TreeItem[], treeDataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise<void> {
treeDataTransfer.set('application/vnd.code.tree.treeView_b', new vscode.DataTransferItem(source));
}
The lowercase requirement seems more like a suggestion if you read the comments in the underlying code... but no from my experience it seems more like a requirement. Had me stumped for ages!
For TreeView_B
dragMimeTypes can be an empty array as we won't be dragging anything from here.
similarly, we don't really need a handleDrag() method.
dropMimeTypes needs to include the mime type of the treeview that we're going to drop onto (i.e. this treeview, TreeView_B)
dropMimeTypes = ['application/vnd.code.tree.treeView_b'];
the handleDrop() method needs to get the correct mime type (you guessed it, Treeview_B in lowercase). In this method, I just log to console.
public async handleDrop(target: TreeItem | undefined, sources: vscode.DataTransfer): Promise<void> {
const transferItemAppContent = sources.get('application/vnd.code.tree.treeView_b');
if (transferItemAppContent) {
console.log(JSON.stringify(transferItemAppContent));
return;
}
}
I'm still not sure that I've 100% understood how this is supposed to be implemented, but I can tell you that the above method works. Hope it helps.

Issues with Drupal's autocomplete test with Behat

I'm trying to test a form generated by Drupal where there are some autocompletion to help people do the right choice.
In this form, there are 3 fields that let the user select 3 articles ('Actualités'), and once you start typing things, the auto-completes generates a list of Articles that have a similar title.
Here is an example:
The problem is that I realized while doing some tests that using $this->getSession()->getPage()->fillField() makes Behat loose focus on the field, like if it presses Tab once done filling the field.
So I tried a lot of tricks to gain focus of this field, like the following:
$field = $this->getSession()->getPage()->findField('field_mb_actualites[0][target_id]');
if($field) {
// Solution #1
// the dropdown menu is inside a `ul#ui-id-1` element
$this->getSession()->executeScript("jQuery('#ui-id-1').show();");
// Solution #2
$field->focus();
// Solution #3
// Consists of pressing "shift + tab" for a "reverse tab" and trying to get back to the field
$this->getSession()->getDriver()->keyDown($xpath, 16);
$this->getSession()->getDriver()->keyDown($xpath, 9);
$this->getSession()->getDriver()->keyUp($xpath, 9);
$this->getSession()->getDriver()->keyUp($xpath, 16);
// And I take a screenshot at the end to see if anything worked
file_put_contents('screenshot-focus.png', $this->getSession()->getDriver()->getScreenshot());
}
But I always get the same result, which is the following:
All I need to do once I have the focus is to press the "right" directional arrow to make the dropdown visible again, then the "down" directional arrow to select a suggestion, then "Enter" to confirm the choice.
However, I'm starting to run out of ideas, even though I found a couple questions on Behat's github about this problem, but I couldn't manage to make the answers work. How can I trigger the auto-complete?
Thank you in advance
You can use a JavaScript function to trigger the event like this:
public function triggerEventOn($css_selector){
$function = <<<JS
(function(){
var element = document.querySelector("$css_selector");
var event = document.createEvent('Event');
event.initEvent('change', true, true);
element.dispatchEvent(event);
})()
JS;
try{
$this->getSession()->getDriver()->executeScript($function);
}catch (Exception $e){
}
}
If you want you can also adapt this to fill the field and trigger the event after.
For checking the event that you need to trigger you need to inspect that element and check that ev in the inspector.

Waiting for sap.ui.table.Table rendered after bound model has changed

I have sap.ui.table.Table which rows are bound to an JSONModel.
var oListModel = new sap.ui.model.json.JSONModel();
//oTable created here (sap.ui.table.Table)
oTable.setModel(oListModel);
oTable.bindRows("/");
When the table is rendered, i.e. the DOM is created for this table, i need to reference to the DOM to pass the DOM elements (table rows) to a library which will make them draggable.
My problem is: How do i know when the DOM for the table is created after the model has been changed and the table is rerendered? I didnt find any listener. The view controller's listener onAfterRendering() didn't help me.
The model is filled with data after a XMLHTTPRequest is successful. When i set the model in the success handler of the xht request and try to access the DOM elments directly afterwards they don't exist yet.
Thank you for your help!
You can add an event delegate
var oMyTable = new sap.ui.table.Table();
oMyTable.addEventDelegate({
onAfterRendering: function() {
$table = this.getDomRef() ....
}
});
a better way is to extend the control see Using addDelegate to extend a control to use third party functionality
UPDATE
the example in that blog doesn't work anymore fixed here
I had a similar issue recently where i had to access an element after a smartform (where the element is present) rendered onto the view. I posted my query here as well as my final solution (based on the accepted answer of #Dopedev). I am using XML views - including nested XML views - here however and the onAfterRendering didn't help for me as well.
I guess you could look at this solution - like it's mentioned in the accepted answer, it may not be an optimal solution, but it sure works. In my case there is not much of a performance issue with the binding of the DOMNodeInserted since it is being called in the onAfterRendering of the nested view that consists of only the smartform with an immediate unbinding upon finding.
The condition if (id === "yourtableid") { } should be enough to identify and pass on. Since you have a table and thus several child nodes, unbinding is imperative at this point.
Mutation Observer is the preferred method but i guess you may need to check the browser compatibility table at the end of the page to see if it matches your requirements. There is an example here. I have used Mutation Observer (outside of a SAPUI5/openUI5 environment) earlier and found it very convenient(and performant) to listen to DOM insert events. In fact the sap.ui.dt package consists of MutationObserver.js

ExtJS 4 - How to load grid store with its params carrying latest values from a form?

I have a window with a search form at the top and grid at the bottom.
User can enter values in the search form and click button - Get Records.
At the click of this button, I load the store of the grid by passing the values in form fields as parameters in following way:
store.load({
params:{
key1:Ext.getCmp('field1').getValue();
}
});
I tried giving parameters in the store proxy itself, but it unfortunately always takes up initial values (values when the form is rendered) and not the latest one entered by the users in the form fields. Following is the method I used for assigning values to params while creating the store:
extraParams:{
key1:Ext.getCmp('field1').getValue();
}
I wanted to seek guidance at two things:
a. While defining a store, can I ensure that store takes latest/current values from the form fields before querying server, so that I don't have to provide these values while calling load function?
This becomes more necessary as I have a paging toolbar at the bottom which carries a refresh button (along with next, last, previous, first icons for navigation).
Now, whenever user clicks at refresh (or any navigation icon), the store gets loaded without the query parameters.
Thus the second thing is:
b. If the answer of 'a' is that - Pass the latest values to parameters manually when calling load function - then how can I write the handler for 'refresh' button and navigation icons (that is, next, last, previous and first) in the paging toolbar, so that I can pass the latest form values to load function.
Thanks for any help in advance.
PS: I am using ExtJS 4.
yourStore.on('beforeload',function(store, operation,eOpts){
operation.params={
status:cmbStatus.getValue(),
value:txtBuscarPor.getValue(),
empresa:'saasd',
app:'dsads'
};
},this);
Related to your question (b) (and because you especially asked for this in the comments section):
I see only one standard way to hook into the PagingToolbar button handlers which is very limited.
Ext.toolbar.Paging fires a 'beforechange' event before it actually changes the current page. See API docs. A listener that returns false will stop the page change.
All other methods require extending Ext classes which wouldn't be a problem if the ComboBox would make it easier to use your own implementation of BoundList (which is the class that renders the dropdown) or pass through config parameters to BoundList resp. the paging toolbar.
I tried to bring this lack of flexibility up on the Ext message board once but was pretty much ignored.
A possible solution for this is to use 'beforeload' event of the store and provide the list of parameters in it. This way, whenever the store is loaded, then its beforeload event is fired and the values picked up are always the latest. Hope this helps someone looking for something similar.

Jeditable: muliple events

how can we implement a multiple event in jeditable, i want to bind two events for a certain div, like dblclick and Enter key
$('.edit').editable('some.php', {
event : "dblclick",
tooltip : "Double click or press Enter Key to edit..."
});
thanks
Well obviously, this is a property managed by the jEditable script, so your only solution would be to dig in jEditable.js and add another possibility for the event property, which would include the events of your liking ;)
GL - I'm about to do just the same right now. - I'll post some info when I'm done.
Ok so it was pretty easy --
Two changes in the jquery.jeditable.mini.js
find and replace :
$(this).bind(settings.event,function(e){if(true===$(this).data('disabled.editable')){return;}
with
var eventlist=settings.event.split(',');$(this).bind(eventlist[0],function(e){if(true===$(this).data('disabled.editable')){return;}
And then, at the end of the bound function -->
find and replace
$(self).attr('title',settings.tooltip);return false;});});
with
for(z=1;z<eventlist.length;z++){
var funcname_of_no_collide_doom=eventlist[0];
$(this).bind(eventlist[z],function(){$(this)[funcname_of_no_collide_doom]();});
}
And tadaam you just need to set the event property using a list of valid jQuery events, like event : 'dblclick,click,blur,tomato'
Actually that mod was funny ... but the real simple solution is offered by jQuery directly :
http://api.jquery.com/bind/
rtfm --