Im trying to build a simple page, where the user clicks on some 'buttons' which load a corresponding iframe. (url: gnosi.gr/games)
All is working well on Chrome & surprisnlgy enough on IE as well, however Firefox doesn't seem to load any iframe.
Right now, what I'm doing is having several elements conatining the 'buttons' users have to click on :
<ul>
<li class="gamelink hangman-game" data-id="1418235" data-game="hangman"></li>
<li class="gamelink crossword-game" data-id="1418235" data-game="crossword"></li>
<li class="gamelink bugmatch-game" data-id="1418235" data-game="bugmatch"></li>
<li class="gamelink hungrybug-game" data-id="1418235" data-game="hungrybug"></li>
</ul>
my JS:
$(document).ready(function(){
window.gamesinfo={'crossword': ['Crossword','Fill in the words blah blah'],'hangman': ['Hangman','Try to guess the word 1 letter at a time'],'bugmatch': ['Bug Matc','Eat the bug that corresponds to the answer'],'hungrybug': ['Hungry Bug','blah blah'],'wordscramble': ['Word Scramble','ajoidoas'],'studyslide': ['Study Slide','study the words '],'studymatch': ['Match','do the matching']};
window.gamesdimensions={'crossword': [950,540],'hangman': [520,540],'bugmatch': [800,500],'hungrybug': [890,600],'wordscramble': [720,400],'studyslide': [1040,800],'studymatch': [752,670]};
$('.gamelink').click(function(){
$('#game').html('<iframe src="https://www.studystack.com/i'+$(this).attr('data-game')+'-'+$(this).attr('data-id')+'" width="'+window.gamesdimensions[$(this).attr('data-game')][0]+'" height="'+window.gamesdimensions[$(this).attr('data-game')][1]+'" frameborder="0" scrolling="no" style="overflow:hidden;"><style>#highScoreFrame{display: none!important;</style></iframe>');
gameloaded($(this).attr('data-game'),$(this).attr('data-id'));
})
$('#togglehelp').click(function(){
$('#instructions').toggle();
});
})
function gameloaded(game,id){
$('#instructions').html(window.gamesinfo[game][1]);
$('#game').width($('#game iframe').first().width())
$('#moregames').show();
$('#instructions').hide();
$('#moregames .gamelink').each(function(){
$(this).attr('data-id',id);
})
}
WIERD BEHAVIOUR:
Works fine on localhost
If i try to invoke the click event on an element that loads an iframe, typing
$('.gamelink').eq(4).click()
in the console, I get nothing, however if i invoke it on one of the first 4 elements, the iframe loads (missing a parameter it will display an error message, but thats fine since the first 4 buttons have that parameter missing on purpose, it is filled in by JS after the first iframe is loaded)
I tried some suggestions i found in similar questions, such as placing an empty iframe with display:none; before the one i want to load, replacing '&' with '&' etc, nothing seemed to work.
Any help would be highly appreciated, thanks in advance !
Related
I'm having a little difficulty finding a way to insert data programmatically into my ckeditor instance.
An example of what i'm trying to accomplish:
<html>
<body>
<div id="top-area"></div>
<div id="mid-area"></div>
<div id="bottom-area"></div>
</body>
</html>
On a button click I am trying to add data inside of the div with id mid-area. I would even be okay with replacing that div with the data I have.
When I use
.insertHtml(
'<div>This is a test insert for a random area</div>',
);
It just populates that div at the very top.
I have tried targeting the div with
document.getElementById('mid-area')
but even that doesnt return any value.
Any help is appreciated. Thanks!
Since I am using the ckeditor4-angular package I am able to find the element and set the html by doing
#ViewChild('editor', { static: false }) component;
const element = this.component.instance.document.getById('mid-area');
element.setHtml('<div>This is a test insert for a random area</div>');
I will not mark this as the answer incase somebody else comes up with another solution that works better. Thanks!
My page contains two divs at the top (a header and another section) that are fixed while the rest of the page can be scrolled. I need to hover over a link element and then click on a button that appears when hovering over the link. Since I am using the page-object gem I tried to use scroll_into_view. However the link still remains behind the fixed divs. This prevents the button from showing. Is there anything that can be done to force it into view? Links at the top and bottom of the scrollable area of the page work fine but items in the middle of the page have issues as they appear behind the fixed divs when scrolled. I am using ruby+watir-webdriver with page-object gem.
Unfortunately I can't post the site.
My code looks something like this:
class MyPage
div(:items, :class => 'product_items')
def index_for(product)
index = items_elements.find_index{|x| x.h4_element.text == product}
index
end
def add_product(product)
index = index_for(product)
product = items_elements[index.to_i]
product.link_element(:class => 'product_more_info').when_present.scroll_into_view
product.link_element(:class => 'product_more_info').hover
product.button_element(:class => 'product_info_button').when_present.click
end
end
The links in the middle of the page remain behind the fixed divs. When it hovers it actually triggers a nav dropdown that is in the header since the link is directly behind it. Seems to work for 70% of the links. The 30% in the middle are the issue right now.
I think I have reproduced your problem with the following page. When the div element to hover on is scrolled into view, it appears below the menu. Hovering does not cause the onmouseover to trigger.
<html>
<body>
<div style="position:fixed; left:0; top:0; z-index=99999; border:2px solid red; width:100%">menu</div>
<div class="spacer" style="height:2000px"></div>
<div id="hoverable" onmouseover="document.getElementById('target').style.display = '';">to hover</div>
<button id="target" style="display:none;">the button</button>
<div class="spacer" style="height:2000px"></div>
</body>
</html>
One solution that works (at least for this example page), was to try hovering over the element. If the button did not appear, assume that the menu is in the way, scroll back up the page a bit and try again. Assuming the above page, this could be done with the page object:
class MyPage
include PageObject
div(:hoverable, :id => "hoverable")
button(:target, :id => "target")
def hover()
# Try to hover over the element
hoverable_element.when_present.hover
# If the button element does not appear, the menu must be in the way.
# Scroll back up 100 px so that the div appears below the menu and try again.
unless target_element.visible?
execute_script('window.scrollBy(0,-100);')
hoverable_element.hover
end
# Check that the button appears as expected
p target_element.visible?
#=> true
end
end
Applying the same idea to your page object, the add_product method would become:
def add_product(product)
index = index_for(product)
product = items_elements[index.to_i]
product.link_element(:class => 'product_more_info').hover
unless button_element(:class => 'product_info_button').visible?
execute_script('window.scrollBy(0,-100);')
product.link_element(:class => 'product_more_info').hover
end
product.button_element(:class => 'product_info_button').click
end
I currently have endless paging setup like so:
events_controller.rb
class EventsController < ApplicationController
respond_to :html, :js
def index
#events = Event.page(params[:page]).per(5)
respond_with(#events)
end
end
events/index.html.erb
<div id="events-container">
<%= render :partial => 'events', :locals => {events: #events} %>
</div>
events/events.html.erb
<div id="events-table-container" data-events-url="<%= current_url %>">
<table id="events-tbl">
<tbody id="events-tbl-body">
<%= render events %>
</tbody>
</table>
<%= paginate events %>
</div>
assets/javascripts/events/events_endless_paging.js
$(function() {
var isScrolledIntoView;
isScrolledIntoView = function(elem) {
var docViewBottom, docViewTop, elemBottom, elemTop;
docViewTop = $(window).scrollTop();
docViewBottom = docViewTop + $(window).height();
elemTop = $(elem).offset().top;
elemBottom = elemTop + $(elem).height();
return (elemTop >= docViewTop) && (elemTop <= docViewBottom);
};
if ($('#events-container .pagination').length) {
$(window).scroll(function() {
var url;
url = $('#events-container .pagination .next a').attr('href');
if (url && isScrolledIntoView('#events-container .pagination')) {
$('#events-container .pagination').html("<span class='working-notice'>Fetching more...</span>")
return $.getScript(url);
}
});
return $(window).scroll();
}
});
events/index.js.erb
$('#events-tbl-body').append('<%= j render(#events) %>');
<% if (#events.current_page < #events.num_pages) %>
$('.pagination').replaceWith('<%= j paginate(#events) %>');
<% else %>
$('.pagination').remove();
<% end %>
This works like a charm and all. This issue becomes when I try to integrate setTimeout ajax polling to refresh the events page.
assets/javascripts/events/event_poller.js
$(document).on('ready', function() {
App.Pollers.Event.poll();
});
App.Pollers.Event = {
frequency: 170000,
poll: function() {
setTimeout(App.Pollers.Event.request, App.Pollers.Event.frequency);
},
request: function() {
eventsRequest = $.getScript($('#events-table-container').data('events-url'));
return eventsRequest;
},
};
Removing the endless paging code above, here's what the code in the events/index.js.erb would look like for just the refresh behavior to work properly:
events/index.js.erb
$('#events-container').html('<%= j(render :partial => 'events', :locals => {events: #events}, :formats => :html) %>');
App.Pollers.Event.poll();
My challenge is getting the endless paging code and the ajax refresh code working together. If I use the ajax refresh with the endless paging code, then what ends up happening is that duplicate events are appended to the events-tbl-body element. Another issue is let's say a user scrolls down the page and the endless paging appends page 2 results to page 1 results, then how does the ajax refresh code know how to display both pages 1 and 2? These are just a few of the challenges. Hoping that someone can provide guidance. I know this is a verbose question, so appreciate your attention.
I'm not entirely sure about the term 'endless paging', isn't there a limit to the amount of content, even though you don't want to show all content immediately?
This might work for you:
https://github.com/paulirish/infinite-scroll
I would use this, for scrolling and getting more results, which is tried and tested:
I see there being two different uses for the poller, correct me if I'm wrong:
Update existing, already on-page events with updates made to those events (including removal).
Add in new events.
I would suggest, strongly, that you split your poller into two different pollers each responsible for a single actions.
The first one would take all the event ids for those events currently on the page and check for updates to them. Deleted events would be removed from the page; updated events would be updated in place.
The second one would look for events created after a 'last-time-you-polled' timestamp and insert those at the top of the page.
I'm not sure how the second poller would affect the pagination of your events for the endless page, but I think that challenge is solvable.
My suggestion would be to create a shared AJAX method that checks how old the content is and then refreshes a particular piece of content (say an article, orderable item, etc.) and this piece of code is invoked either by the pagination code OR the automated timed poll.
Scenarios as examples
User loads page(1/4) and it contains 4 pieces. The user doesn't scroll and you have 4 pieces to be updated at 170000 ms. Your updated timer would loop through those 4 items and call the independent AJAX updater for those 4.
User loads page(1/4) and then scrolls down to page (2/4). Your pagination code renders out the new 4 pieces. The user keeps the page in place and so after 170000 ms you need to refresh those 4. Just like #1 above the timer call loops through items 5-8 (page 2's content items) and calls the independent updater for those 4.
User loads page(1/4) and then scrolls down to page (4/4). Your pagination code renders out all the pieces (16 sections out of 16). The user keeps the page in place and so after 170000 ms you need to refresh those 4. Just like #1 & 2 above the timer call loops through items 20-24 and calls the independent updated for those 4.
User loads page(1/4) and then scrolls down to page (2/4) and leaves it. Just like #2 above the 4 items are updated by the timer. The user then scrolls back up to page(1/4) and so the pagination/scroll code calls the independent function for (1-4) through a small (250ms) timer which checks to see if the content needs to be refreshed and does so.
User loads page(1/4) and then scrolls down to page (4/4) and leaves it. Just like #4 the content refreshes on the last page and then they scroll up. As the scroll event occurs it triggers the ajax updater through a small (250ms) timer for the already existing items which checks to see if they need to be refreshed and if so does the update.
Considerations
It allows you to break the "does this need to update" logic into a shared function that accommodates the behavior of both the pagination and the user leaving the page still.
It allows you to ensure that you're only updating the content that is displayed and t his logic isn't duplicated in 2 sets of functions so your logic can be updated at a later date with minimal impact.
Having a small delay of this function when called by the pagination code when "scrolling" back up allows for the event where a user scrolls past an element so fast that it isn't worth doing the call and using the server resources to refresh content that isn't on the screen.
Environment:
Ruby 1.8.7
Selenium WebDriver 2
Ubuntu 12.04 Desktop
Firefox 13.0.1
Problem:
I have div tags being used as selects. You click on the div and a dropdown style window shows up with more div tags as the select options. Now I can go in and create a way of clicking on each of these options for each 'div as select' but what I'd really like is to write a piece of code that clicks on the divs I know about and then determines which divs are now displayed and enabled after the click. Then I can click on 1 of the options at random.
So my current code is something like this:
allDivs = brwsr.find_elements(:tag_name, 'div')
origDivs = allDivs
allDivs.each do |e|
if ... # Get the div I want
e.click
newDivs = brwsr.find_elements(:tag_name, 'div')
origDivs.each do |orig|
newDivs.delete(orig)
end
# Do something with remaining new divs here
end
end
The main problem I have is that this is extremely slow. I currently have around 200 divs to spin thru and this method takes a few minutes to complete. Normally, I wouldn't expect spinning thru a couple of hundred array elements to take very long. But it does.
To shorten the time I've attempted filtering the allDivs and newDivs by spinning thru them once and deleting anything that is not displayed and enabled.
So I'm currently stuck with a really slow solution. I don't mind this 'finding of new divs' being a little slower as it should also lead to much shorter script dev times. However, taking minutes to complete is way too long.
First question: Can Selenium return only elements which as displayed and enabled with some extra API string around the find_elements call?
Second question: Does someone have a better way of finding the new div elements without having to go thru the array of elements.
It would be very helpful if you could post some sample HTML of the DOM you are trying to automate.
With that said, the ruby webdriver bindings do support finding elements by chaining. Thus, given some html like this:
<div class="outer">
<div class="one">
<div class="alpha">A</div>
<div class="beta">B</div>
<div class="gamma">C</div>
</div>
<div class="two">
<div class="alpha">A</div>
<div class="beta">B</div>
<div class="gamma">C</div>
</div>
<div class="three">
<div class="alpha">A</div>
<div class="beta">B</div>
<div class="gamma">C</div>
</div>
</div>
You could write something like this to find the "B" div in the second group of divs ("two"):
group = brwsr.find_element(:class => "two")
desired_item = group.find_element(:class => "beta")
Or, even more simply through ruby's chaining capabilities:
desired_item = brwsr.find_element(:class => "two").find_element(:class => "beta")
One other way, which I prefer the most is to select an element via a CSS selector, which selects the element faster with an easy to read syntax:
desired_item = brwsr.find_element(:css => "div.two div.beta")
I've been using a shareware JS accordion-style sidebar (www.dynamicdrive.com/dynamicindex1/slashdot.htm). It's been working beautifully with PHP-based HTML, but is not working with AJAX.
The sidebar builds itself on <div>,<span>and<a> elements. Here is a section of the JS code:
for (var i = 0; i < this.submenus.length; i++)
this.submenus[i].getElementsByTagName("span")[0].onclick = function() {
mainInstance.toggleMenu(this.parentNode);
};
If I use hardcoded HTML like the following (or construct the same with PHP), it works fine:
<div id="navbar_side" class="sdmenu">
<div><span>STUDENTS</span><a>Adding Students</a><a>Deleting Students</a></div>
</div>
However, if I start with:
<div id="navbar_side" class="sdmenu"></div>
and then use this:
document.getElementById("navbar_side").innerHTML="<div><span>STUDENTS</span><a>Adding Students</a><a>Deleting Students</a></div>";
the menu doesn't slide. The info is all there. The <a hrefs> all work (which I've left out here). But the accordion movement doesn't - well... - move!
Why is this? Clearly the menu is not reading the AJAX-constructed node tree the same way as the PHP-constructed one.
Thanks,
Nick
Recommend you to start over your work by using jQuery UI - Accordion. Much cleaner & effective.