DOM manipulation with PhantomJS - dom

I am using PhantomJS to create screenshots from arbitrary URLs. Before the screenshot is taken, I want to manipulate the page DOM to remove all drop-down menus, as PhantomJS renders them incorrectly in the top left-hand corner of the page (a known Phantom issue.)
I have a simple DOM script to do this with:
var selects = document.getElementsByTagName('select');
for (var i=0; i < selects.length; i++) {
document.getElementsByTagName('select')[i].style.visibility="hidden";
}
This has been tested and works fine as stand-alone Javascript. It doesn't however work inside the PhantomJS code I am using to collect the screenshots (last part shown):
page.open(address, function (status) {
if (status !== 'success') {
console.log('Unable to load the address!');
} else {
window.setTimeout(function () {
var selects = document.getElementsByTagName('select');
for (var i=0; i < selects.length; i++) {
document.getElementsByTagName('select')[i].style.visibility="hidden";
}
page.render(output);
phantom.exit();
}, 200);
}
});
Some pages are still rendering with a select box in the wrong place. I'd appreciate help either solving the original PhantomJS rendering bug or hiding the drop-down menus in the DOM. Thanks.

Run it in the right context, i.e. inside the page with page.evaluate. There are many examples included with PhantomJS which demonstrate this, e.g. useragent.js.

This code doesn't work?
I used your cached selects variable in the for loop instead of re-selecting the elements from the DOM to improve performance.
var selects = document.getElementsByTagName('select');
for (var i=0; i < selects.length; i++) {
selects[i].style.visibility="hidden";
}

Related

SAPUI5 / OPA5 Tests: How to iterate over several controls

any idea how i can iterate over a list of controls and for each run the same test?
Example:
I have a generated list of buttons. I want to press each button and check the functionality.
How can I do this?
Starting scenario:
opaTest("Test if popover is closing.", function (Given, When, Then) {
Given
.iStartMyAppInAFrame(linkTestPage);
When
.onTheTestPage
.iPressAButton();
Then
.onTheTestPage
.iShouldSeeTheRequiredAction();
});
I need something like that:
var buttons = readAllButtonsOfList();
opaTest("Test if popover is closing.", function (Given, When, Then) {
Given
.iStartMyAppInAFrame(linkTestPage);
for(var i = 0; i < buttons.length; i++)
{
When
.onTheTestPage
.iPressAButton(buttons[i]);
Then
.onTheTestPage
.iShouldSeeTheRequiredAction(buttons[i]);
}
}
});
Hope that anybody can help here.
OpaDynamicWait demos recursive action testing, ie while more buttons keep pressing, for a test put an assertion in a success, you can also nest waitfor's

ckeditor + smartgwt modal window + dialog dropdown gains focus but does not show options

I am using the ckEditor along with GWT and SmartGWT. I have a problem that whenever the ckEditor displays a dialog (e.g. link button, table button), although the items in the dialog gain focus (input texts work fine, I can write inside them), the dropdowns (select elements) when clicking on them, do not expand to show their option items (they expand only when they have focus and user hits "spacebar"). This happens only in firefox and chrome (latest versions) while on IE11 it works as expected.
Note that I am already aware of the "focus" problem existing if a ckEditor instance exists in a GWT/jquery modal and I have already included a fix:
$wnd.CKEDITOR.on('dialogDefinition', function (evt) {
var dialog = evt.data.definition.dialog;
dialog.on('show', function () {
var element = this.getElement();
var labelledby = element.getAttribute('aria-labelledby');
var nativeElement = $wnd.document.querySelector("[aria-labelledby='" + labelledby + "']");
nativeElement.onclick = function (evt) {
if ((evt.target.tagName == "INPUT" || evt.target.tagName == "SELECT" || evt.target.tagName == "TEXTAREA") &&
-1 != evt.target.className.indexOf("cke_dialog_ui_input")) {
evt.target.focus();
};
}
});
});
Any hint how I can make the dropdowns to behave correctly? To me it looks like the dropdown element does not receive the click event (although on click it gets focus) or somehow the event's propagation stops unexpectedly.
EDIT
Forgot to mention that the problem appears if the ckEditor instance is inside a modal SmartGWT window. More specifically if I set
Window win = new Window(); //com.smartgwt.client.widgets.Window
win.setIsModal(false);
and then add the DynamicForm form which contains the ckEditor item on that window then the dialog dropdowns work fine, however if I set
win.setIsModal(true);
I get the faulty behavior described above
In case anyone else has the same problem with me, the solution is to call win.hideClickMask() upon show event of the dialog. This can be achieved in many ways depending on how ckEditor is integrated with SmartGWT. In my implementation this is achieved by overriding onDialogShow() as below:
final CKEditor ckEditor = new CKEditor(conf) {
#Override
public void onDialogShow() {
// to overcome the problem that smartgwt modality obstruct the dropdowns of a ckeditor dialog to be pressed
final NodeList<Element> allWindowsWithModalMask = findAllWindowsWithModalMask();
if(allWindowsWithModalMask != null ) {
for(int i =0; i<allWindowsWithModalMask.getLength(); i++) {
Element el = allWindowsWithModalMask.getItem(i);
String id = el.getAttribute("eventproxy");
if(Canvas.getById(id) != null) {
hideClickMask(Canvas.getById(id).getOrCreateJsObj());
}
}
}
}
};
and
protected native NodeList<Element> findAllWindowsWithModalMask() /*-{
return $wnd.document.querySelectorAll("[class='windowBackground']");
}-*/;
protected native void hideClickMask(JavaScriptObject windowCanvas) /*-{
windowCanvas.hideClickMask();
}-*/;

How do I get the Onmouseover method to apply universally to all links?

We're aware of that amazing trick which allows users to highlight a link. But, you must repeat it for each link. for example: a href="https://www.yahoo.com" Onclick="window.open(this.href); return false" onmouseout="this.style.color = '#0000ff';" onmouseover="this.style.color = '#e3FF85';" align="justify">Yahoo. But, I would like this code to apply to every link on the page. I've explored 2 possible methods. One is to use STYLE TYPE and CLASS= methods. Another possibility is using STYLE H1 /H1 (similar to W3 schools). But, I haven't even come close to getting a universal application.
1. You can try this:
var links = document.getElementsByTagName('a');
for (var i = 0; i < links.length; ++i)
{
links[i].onmouseenter = function() {links[i].style.color = '#e3FF85';};
links[i].onmouseout= function() {links[i]..style.color = '#0000ff';};
}
You get the list of all links using getElementsByTagName('a') ('a' is tag name for links), and you can do anything you want with them.
2. You can also try it with jquery:
var allLinks = $('a');
allLinks.mouseenter(function() { $(this).css('color', '#e3FF85'); });
allLinks.mouseout(function() { $(this).css('color', '#0000ff'); })
3. If you just care about changing style (like color or background) when mouse is over your link, you can do it from CSS:
a:hover
{
color: #123456;
}

How to show Camera Preview in metro app using javascript

i have StartPreviewAsync api to show camera preview on screen in C#
but not available in javascript ,so how can i get same preview(output) in javascript template??
or is any way to deploy xaml on javascript??
WinJS seems to have a different API for handling Camera Previews. I'd take a look at this example on MSDN for more details. Namely, in BasicCapture.js, we see the following function, startPreview:
function startPreview() {
displayStatus("Starting preview");
id("btnStartPreview" + scenarioId).disabled = true;
var video = id("previewVideo" + scenarioId);
video.src = URL.createObjectURL(mediaCaptureMgr, { oneTimeOnly: true });
video.play();
displayStatus("Preview started");
getCameraSettings();
// Initialize sliders.
for (var i = 0; i < cameraControlSliders.length; i++) {
cameraControlSliders[i].slider.disabled = false;
initSlider(cameraControlSliders[i]);
}
}
To answer your second question, the only way to load Javascript into a XAML application would be through the WebView control, and even that would not be allowed to directly control the different controls of the XAML UI. If you want to do XAML, you have to stick to C#, VB, or C++.

jsTree Node Expand/Collapse

I ran into the excellent jstree jQuery UI plug in this morning. In a word - great! It is easy to use, easy to style & does what it says on the box. The one thing I have not yet been able to figure out is this - in my app I want to ensure that only one node is expanded at any given time. i.e. when the user clicks on the + button and expands a node, any previously expanded node should silently be collapsed. I need to do this in part to prevent the container div for a rather lengthy tree view from creating an ugly scrollbar on overflow and also to avoid "choice overload" for the user.
I imagine that there is some way of doing this but the good but rather terse jstree documentation has not helped me to identify the right way to do this. I would much appreciate any help.
jsTree is great but its documentation is rather dense. I eventually figured it out so here is the solution for anyone running into this thread.
Firstly, you need to bind the open_node event to the tree in question. Something along the lines of
$("tree").jstree({"themes":objTheme,"plugins":arrPlugins,"core":objCore}).
bind("open_node.jstree",function(event,data){closeOld(data)});
i.e. you configure the treeview instance and then bind the open_node event. Here I am calling the closeOld function to do the job I require - close any other node that might be open. The function goes like so
function closeOld(data)
{
var nn = data.rslt.obj;
var thisLvl = nn;
var levels = new Array();
var iex = 0;
while (-1 != thisLvl)
{
levels.push(thisLvl);
thisLvl = data.inst._get_parent(thisLvl);
iex++;
}
if (0 < ignoreExp)
{
ignoreExp--;
return;
}
$("#divElements").jstree("close_all");
ignoreExp = iex;
var len = levels.length - 1;
for (var i=len;i >=0;i--) $('#divElements').jstree('open_node',levels[i]);
}
This will correctly handle the folding of all other nodes irrespective of the nesting level of the node that has just been expanded.
A brief explanation of the steps involved
First we step back up the treeview until we reach a top level node (-1 in jstree speak) making sure that we record every ancestor node encountered in the process in the array levels
Next we collapse all the nodes in the treeview
We are now going to re-expand all of the nodees in the levels array. Whilst doing so we do not want this code to execute again. To stop that from happening we set the global ignoreEx variable to the number of nodes in levels
Finally, we step through the nodes in levels and expand each one of them
The above answer will construct tree again and again.
The below code will open the node and collapse which are already opened and it does not construct tree again.
.bind("open_node.jstree",function(event,data){
closeOld(data);
});
and closeOld function contains:
function closeOld(data)
{
if($.inArray(data.node.id, myArray)==-1){
myArray.push(data.node.id);
if(myArray.length!=1){
var arr =data.node.id+","+data.node.parents;
var res = arr.split(",");
var parentArray = new Array();
var len = myArray.length-1;
for (i = 0; i < res.length; i++) {
parentArray.push(res[i]);
}
for (var i=len;i >=0;i--){
var index = $.inArray(myArray[i], parentArray);
if(index==-1){
if(data.node.id!=myArray[i]){
$('#jstree').jstree('close_node',myArray[i]);
delete myArray[i];
}
}
}
}
}
Yet another example for jstree 3.3.2.
It uses underscore lib, feel free to adapt solution to jquery or vanillla js.
$(function () {
var tree = $('#tree');
tree.on('before_open.jstree', function (e, data) {
var remained_ids = _.union(data.node.id, data.node.parents);
var $tree = $(this);
_.each(
$tree
.jstree()
.get_json($tree, {flat: true}),
function (n) {
if (
n.state.opened &&
_.indexOf(remained_ids, n.id) == -1
) {
grid.jstree('close_node', n.id);
}
}
);
});
tree.jstree();
});
I achieved that by just using the event "before_open" and close all nodes, my tree had just one level tho, not sure if thats what you need.
$('#dtree').on('before_open.jstree', function(e, data){
$("#dtree").jstree("close_all");
});