Drag and drop using nightwatch - node.js

I am trying to drag and drop the element to particular location using drag and drop in nightwatch with selenium but when i drop more than i element to same droppable it is overlapping.
var dragAndDrop = require('html-dnd').codeForSelectors;
this.dragModule = function (draggable, droppable, posX, posY) {
browser.pause(3000);
var dndSimulateConfig = { dropOffset: [posX, posY] };
browser
.execute(dragAndDrop, [draggable, droppable, dndSimulateConfig])
.pause(2000);
};
It should not overlap i want in particular co-ordinates

locator1: can be xpath (or cssSelector) of your first element you want
to drag locator2: can be xpath (or cssSelector ) is where you want to
drop
this is tried and tested code, might be you need to little modify but
it's working great for me.
return browser
.useXpath()
.moveToElement(locator1, XOffset1, Yoffset1)
.pause(100) // if you want to give wait
.mouseButtonDown(0) // press click, down
.moveToElement(locator2, XOffset2, Yoffset2) // move to element
.mouseButtonUp(0); // press release , up
read here docs- http://nightwatchjs.org/api and search for "moveToElement"
how to call:
myFunction moveToSpecificElement(locator, x, y) {
return browser
.moveToElement(locator, x, y, function (result) {
this.assert.equal("your assertion goes here");
});
}

I was using html-dnd version 1.2.0. So drag and drop was overlapping. Use any older version of 'html-dnd' it will work.

Related

keep footer last in list when dragging new item into the list from another

I have Vue Draggable working like a Kanban board with multiple columns, and I have made each column at least the height of the viewport so that each item can easily be dragged into the column next to it (for cases where one column is much longer than the next, for example).
I also have a button in the footer slot to add new cards to the column. This works well in that it is generally always at the bottom of the list, is not draggable, etc.
The issue arises when I drag an item from another list in below the footer (but still within the height of the draggable element). When I do this, the footer does not stay below the new item, which looks odd.
Once I drop the element, it snaps into place and the footer is one again at the bottom - it is only when the new card is being moved that it appears below the footer.
Is there any way to make sure that even during the move event and a new card being added to a list that the footer stays as the last element?
This issue seems to be captured in this comment on Github issues - https://github.com/SortableJS/Vue.Draggable/issues/673#issuecomment-554149705 - but no solution is provided in that thread.
Any help greatly appreciated.
So for anyone having the same issue I solved this by doing the following:
Hooking into the onMove event using the :move prop to run a function each time an item is moved... e.g. :move="fixFooter"
Creating a function that checks if the moved item would be the last in the new list (thus by default it would sit below the footer without this fix), and if so on the $nextTick append the footer to the Draggable container so it gets moved below the item coming in to the list... (just learnt that .appendChild will move an existing element to the end)
It then checks if the from/to list is the same to account for the item being dragged back into the list it's coming from during the same drag event (otherwise you get the same undesirable footer behaviour as before if you drag an item out of a list and back below the footer without dropping it).
fixFooter(e) {
if(e.relatedContext.list.length === e.draggedContext.futureIndex) {
var newListDom = e.relatedContext.component.$el;
var newListFooter = e.relatedContext.component.$slots.footer[0].elm;
this.$nextTick(() => {
newListDom.appendChild(newListFooter);
});
} else if(e.from === e.to && (e.from.children.length - 1) === e.draggedContext.futureIndex) {
var currentListDom = e.from;
var currentListFooter = e.from.lastChild;
this.$nextTick(() => {
currentListDom.appendChild(currentListFooter);
});
}
}
Seems like for vue draggable next this is enough:
fixFooter(e) {
if (e.relatedContext.list.length === e.draggedContext.futureIndex) {
var newListDom = e.to
var newListFooter = e.to.lastChild
this.$nextTick(() => {
newListDom.appendChild(newListFooter);
});
}
}

pdfkit nodejs, one element per page from page 2

Im using pdfkit to generate pdf invoice.
When all my content fit in one page I have no issue.
However when it doesn't fit and need an extra page, I have a strange behaviour:
Instead of adding the elements in the second page, it only add one line and the rest of the page is blank.
Then on 3rd page I have another element, and the rest it blank, then 4th page, 5th etc.
Here is the code corresponding to this part:
for (let i = 0; i < data.items.length; i++) {
const item = data.items[i];
this.itemPositionY = this.itemPositionY + 20;
if (item.bio) this.containBioProduct = true;
let itemName = item.bio ? `${item.item}*` : item.item;
this.generateTableRow(
doc,
this.itemPositionY,
itemName,
"",
this.formatCurrency(item.itemPriceDf.toFixed(2)),
item.quantity,
this.formatCurrency(item.itemPriceTotalDf.toFixed(2))
);
this.generateHr(doc, this.itemPositionY + 15);
}
Basically I just iterate over an array of products. For each line my Y position has +20.
Thanks for your help.
In case someone has this issue, here is a solution:
Everywhere in the code I know that an extra page could be generated, I add this:
if (this.position > 680) {
doc.addPage();
this.position = 50;
}
It allows you to control the generation of new pages (instead of pdfkit doing it automatically with potential problems)
You just need to track the position from the initialization of "this.position".
In that way, evertime it's superior than an Y position (680 in my case, it's a bit less than a page with pdfkit), you just do "doc.addPage()", which will create another page, and you reinitialize your position to the beginning of the new page.

Select UI Element by filtering properties in coded ui

I have a web application. And I am using coded ui to write automated tests to test the application.
I have a dropdown with a text box. Which on entering values in the textbox, the values in the dropdown gets filtered based on the text entered.
If I type inside textbox like 'Admin', I will get below options like this:
And I need to capture the two options displayed.
But using IE Developer tool (F12), I am not able to capture the filtered options, because the options that are displayed do not have any unique property (like this below). And the options that are NOT displayed have a class="hidden" property
Any way to capture the elements that are displayed by applying some kind of filter like 'Select ui elements whose class != hidden'
Thanks in advance!!
HI please try below code will it works for you or not.By traversing all those controls that have class ="hidden"
WpfWindow mainWindow = new WpfWindow();
mainWindow.SearchProperties.Add(HtmlControl.PropertyNames.ClassName, "hidden");
UITestControlCollection collection = mainWindow.FindMatchingControls();
foreach (UITestControl links in collection)
{
HtmlHyperlink mylink = (HtmlHyperlink)links;
Console.WriteLine(mylink.InnerText);
}
I'm not sure there is a way to do it by search properties, but there are other approaches.
One way would be to brute force difference the collections. Find all the list items, then find the hidden ones and do a difference.
HtmlControl listControl = /* find the UL somehow */
HtmlControl listItemsSearch = new HtmlControl(listControl);
listItemsSearch.SearchProperties.Add(HtmlControl.PropertyNames.TagName, "li");
HtmlControl hiddenListItemsSearch = new HtmlControl(listControl);
hiddenListItemsSearch.SearchProperties.Add(HtmlControl.PropertyNames.TagName, "li");
hiddenListItemsSearch.SearchProperties.Add(HtmlControl.PropertyNames.ClassName, "hidden");
var listItems = listItemsSearch.FindMatchingControls().Except(hiddenListItemsSearch.FindMatchingControls());
You will only be able to iterate this collection one time so if you need to iterate multiple times, create a function that returns this search.
var listItemsFunc = () => listItemsSearch.FindMatchingControls().Except(hiddenListItemsSearch.FindMatchingControls());
foreach(var listItem in listItemsFunc()){
// iterate 1
}
foreach(var listItem in listItemsFunc()){
// iterate 2
}
The other way I would consider doing it would be to filter based on the controls which have a clickable point and take up space on the screen (ie, not hidden).
listItemsSearch.FindMatchingControls().Where(x => {
try { x.GetClickablePoint(); return x.Width > 0 && x.Height > 0; } catch { return false; }
});

How to call wxGrid's Render function - sequentially to achieve pagination?

Pagination can be accomplished by using sequential Render() calls from http://docs.wxwidgets.org/trunk/classwx_grid.html
I understand How - sequential pages can be got from top left and bottom right coordinates.
But I dont get what needs to be the wxDC in the Render() call . ?
I want to get the first three rows in the grid
BigGridFrame::BigGridFrame(long sizeGrid)
: wxFrame(NULL, wxID_ANY, wxT("Plugin Virtual Table"),
wxDefaultPosition, wxSize(500, 450))
{
m_grid = new wxGrid(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_table = new BigGridTable(sizeGrid);
m_grid->SetTable(m_table, true);
//The above code gave me the table
//trying to get first three rows by render() function but it still gets the all of the grid values
**const wxGridCellCoords topLeft(0, 0);
const wxGridCellCoords bottomRight(3,4 );
wxClientDC clientDC(this); //this place I am not sure.. I couldnt find documentation
//m_grid->SelectBlock(topLeft, bottomRight, false);
m_grid->Render(clientDC, wxDefaultPosition, wxDefaultSize, topLeft, bottomRight, wxEXPAND);**
}
The DC is whatever you want to render the grid on, typically a wxMemoryDC to save the grid as a bitmap. This can't be used to partially render the grid on screen, which you appear to want to do, because it's just a static snapshot of the control.
I also have really no idea how can the code using this->Render() above compile considering that this is a wxFrame* and not a wxGrid*.
I misunderstood Render() function .
For pagination, I used the same logic used in
Changing Size of Grid when grid data is changed

How can I set the default value in a SharePoint list field, based on the value in another field?

I have a custom list in SharePoint (specifically, MOSS 2007.) One field is a yes/no checkbox titled "Any defects?" Another field is "Closed by" and names the person who has closed the ticket.
If there are no defects then I want the ticket to be auto-closed. If there are, then the "Closed by" field ought to be filled in later on.
I figured I could set a calculated default value for "Closed by" like this:
=IF([Any defects?],"",[Me])
but SharePoint complains I have referenced a field. I suppose this makes sense; the default values fire when the new list item is first opened for entry and there are no values in any fields yet.
I understand it is possible to make a calculated field based on a column value but in that case the field cannot be edited later.
Does anyone have any advice how to achieve what I am trying to do?
Is it possible to have a "OnSubmit" type event that allows me to execute some code at the point the list item is saved?
Thank you.
Include a content editor web part in the page (newform.aspx / editform.aspx) and use jQuery (or just plain javascript) to handle the setting of default values.
Edit: some example code:
In the lists newform.aspx, include a reference to jquery. If you look at the html code, you can see that each input tag gets an id based on the field's GUID, and a title that's set to the fields display name.
now, using jquery we can get at these fields using the jQuery selector like this:
By title:
$("input[title='DISPLAYNAMEOFFIELD']");
by id (if you know the field's internal guid, the dashes will ahve to be replaced by underscores:
// example field id, notice the guid and the underscores in the guid ctl00_m_g_054db6a0_0028_412d_bdc1_f2522ac3922e_ctl00_ctl04_ctl15_ctl00_ctl00_ctl04_ctl00_ctl00_TextField
$("input[id*='GUID']"); //this will get all input elements of which the id contains the specified GUID, i.e. 1 element
We wrap this in the ready() function of jQuery, so all calls will only be made when the document has fully loaded:
$(document).ready(function(){
// enter code here, will be executed immediately after page has been loaded
});
By combining these 2 we could now set your dropdown's onchange event to the following
$(document).ready(function(){
$("input[title='DISPLAYNAMEOFFIELD']").change(function()
{
//do something to other field here
});
});
The Use jQuery to Set A Text Field’s Value on a SharePoint Form article on EndUserSharePoint.com shows you how to set a default value for a field using JavaScript/jQuery.
They also have a whole series of articles on 'taming calculated columns' that will show you many more powerful options you have for calculated fields with the use of jQuery.
One thing to be aware of when inserting JavaScript into a SharePoint page and modifying the DOM is support. There is a small chance that a future service pack will break the functionality you add, and it is quite likely that the next version of SharePoint will break it. Keeping this mind however, I believe it's a good solution at this time.
I've got a walk through with sample code that may help
Setting a default duration for new calendar events
It sets the End Time/Date fields to Start Time + 1.5 hours when you create a new event.
Its complicated a little by the steps need to do the time/date work, but you'll see examples of how to find the elements on the form and also one way to get your script onto the newform.aspx without using SPD.
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js">
</script>
<script type="text/javascript">
// Set the hours to add - can be over 24
var hoursToAdd = 1;
// Mins must be 0 or div by 5, e.g. 0, 5, 10, 15 ...
var minutesToAdd = 30;
// JavaScript assumes dates in US format (MM/DD/YYYY)
// Set to true to use dates in format DD/MM/YYYY
var bUseDDMMYYYYformat = false;
$(function() {
// Find the start and end time/minutes dropdowns by first finding the
// labels then using the for attribute to find the id's
// NOTE - You will have to change this if your form uses non-standard
// labels and/or non-english language packs
var cboStartHours = $("#" + $("label:contains('Start Time Hours')").attr("for"));
var cboEndHours = $("#" + $("label:contains('End Time Hours')").attr("for"));
var cboEndMinutes = $("#" + $("label:contains('End Time Minutes')").attr("for"));
// Set Hour
var endHour = cboStartHours.attr("selectedIndex") + hoursToAdd;
cboEndHours.attr("selectedIndex",endHour % 24);
// If we have gone over the end of a day then change date
if ((endHour / 24)>=1)
{
var txtEndDate = $("input[title='End Time']");
var dtEndDate = dtParseDate(txtEndDate.val());
if (!isNaN(dtEndDate))
{
dtEndDate.setDate( dtEndDate.getDate() + (endHour / 24));
txtEndDate.val(formatDate(dtEndDate));
}
}
// Setting minutes is easy!
cboEndMinutes.val(minutesToAdd);
});
// Some utility functions for parsing and formatting - could use a library
// such as www.datejs.com instead of this
function dtParseDate(sDate)
{
if (bUseDDMMYYYYformat)
{
var A = sDate.split(/[\\\/]/);
A = [A[1],A[0],A[2]];
return new Date(A.join('/'));
}
else
return new Date(sDate);
}
function formatDate(dtDate)
{
if (bUseDDMMYYYYformat)
return dtDate.getDate() + "/" + dtDate.getMonth()+1 + "/" + dtDate.getFullYear();
else
return dtDate.getMonth()+1 + "/" + dtDate.getDate() + "/" + dtDate.getFullYear();
}
</script>

Resources