Search for Text in Loaded HTML document - javascript

I have a web page on which my sidebar links will cause an 'external' HTML document to be loaded into a content div.
However after it is successfully loaded and displayed, the loaded HTML content does not appear in the Page Source.
Regardless, I now need to do a client-side Text Search of that 'external' HTML document using a Javascript function.
My webpage looks like the following:
The Search textbox and button are 'outside' of the Content Div (bordered in Red).
And, at the time that one of the link's HTML documents is appearing on-screen the page source looks like:
<!-- Page Content -->
<div id="page-content-wrapper" style="border: thick solid #FF0000; height:660px">
<!--Loaded content goes here-->
</div>
Notice that the 'loaded' HTML document is not showing.
I have found a Javascript function findInPage() which looks promising, but it is not finding the 'loaded' HTML document and its text.
// =====================================
function findInPage() {
var str = document.getElementById("ButtonForm").elements["txtSearch"].value;
var n = 0;
var txt, i, found;
if (str == "")
return false;
// Find next occurance of the given string on the page, wrap around to the
// start of the page if necessary.
if (window.find) {
// Look for match starting at the current point. If not found, rewind
// back to the first match.
if (!window.find(str)) {
while (window.find(str, false, true))
n++;
} else {
n++;
}
// If not found in either direction, give message.
if (n == 0)
alert("Not found.");
} else if (window.document.body.createTextRange) {
txt = window.document.body.createTextRange();
// Find the nth match from the top of the page.
found = true;
i = 0;
while (found === true && i <= n) {
found = txt.findText(str);
if (found) {
txt.moveStart("character", 1);
txt.moveEnd("textedit");
}
i++;
}
// If found, mark it and scroll it into view.
if (found) {
txt.moveStart("character", -1);
txt.findText(str);
txt.select();
txt.scrollIntoView();
n++;
} else {
// Otherwise, start over at the top of the page and find first match.
if (n > 0) {
n = 0;
findInPage(str);
}
// Not found anywhere, give message. else
alert("Not found.");
}
}
return false;
}
Is there some way to modify the function and/or use a different function such that it can find the 'loaded' HTML document and search it for the entered Text?

try selecting the div by id instead of reading the whole window...
document.getElementById('page-content-wrapper').find(str)

This is a duplicate of How to get html elements from an object tag?.
The answer lies in replacing all instances of window.document with document.getElementById('page-content-wrapper').contentDocument, such that the searched document is the page document.
However, the search function you have there is quite broken, it depends on window.find to search the window instead of searching the document text.
You could build a better search function:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Wrapper</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
Body Here
<object id="page-content-wrapper" type="text/html" data="about.html" name="content"></object>
<input id="txtSearch" placeholder="Search..." />
<button onclick="findInPage()">Search</button>
<script>
function findInPage() {
var needle = document.getElementById('txtSearch').value;
var haystack = document.getElementById('page-content-wrapper').contentDocument.body.innerHTML;
var match = haystack.indexOf(needle);
if(match != -1) {
console.log(match);
} else {
console.log('Not Found');
}
}
</script>
</body>
</html>
Fill about.html with anything you want to load and search in.
Note that this just logs the index of the match. It doesn't scroll it into view or select it. With a little more javascript you can do those though. You just have to go through document.getElementById('page-content-wrapper').contentDocument.body

I finally found how to access the HTML content of the Object's innerHTML.
Upon clicking on a specific Sidebar link, using Javascript, I build its Object.
function MenuClick(doc) {
var Tutorial = doc;
var DisplayObj = "<object id='ThisObj' type='text/html' data='" + Tutorial + "' style='min-width:100%; min-height: 101%; overflow: hidden'></object>";
document.getElementById("page-content-wrapper").innerHTML = DisplayObj;
}
But now I have added an ID to the Object ('ThisObj').
With that ID now defined I was able to 'drill-down' into that Object to get to its innerHTML.
var sourceObj = document.querySelector("#ThisObj");
var sourceBody = sourceObj.contentDocument.body
var haystack = sourceBody.innerHTML;
var match = haystack.indexOf(needle);
if (match != -1) {
// --- Text match found ---
} else {
// --- Text match NOT found ---
}
I still need to create the Javascript to highlight the 'found' text and scroll it into view but I'll ask that question in a separate post.
Thanks for your suggestions/advice.

Related

How to select/hide elements inside an object of type "text/html" using javascript [duplicate]

I'm using the object tag to load an html snippet within an html page.
My code looks something along these lines:
<html><object data="/html_template"></object></html>
As expected after the page is loaded some elements are added between the object tags.
I want to get those elements but I can't seem to access them.
I've tried the following
$("object").html() $("object").children() $("object")[0].innerHTML
None of these seem to work. Is there another way to get those elements?
EDIT:
A more detailed example:
consider this
<html><object data="http://www.YouTube.com/v/GGT8ZCTBoBA?fs=1&hl=en_US"></object></html>
If I try to get the html within the object I get an empty string.
http://jsfiddle.net/wwrbJ/1/
As long as you place it on the same domain you can do the following:
HTML
<html>
<object id="t" data="/html_template" type="text/html">
</object>
</html>
JavaScript
var t=document.querySelector("#t");
var htmlDocument= t.contentDocument;
Since the question is slightly unclear about whether it is also about elements, not just about the whole innerHTML: you can show element values that you know or guess with:
console.log(htmlDocument.data);
The innerHTML will provide access to the html which is in between the <object> and </object>. What is asked is how to get the html that was loaded by the object and inside the window/frame that it is producing (it has nothing to do with the code between the open and close tags).
I'm also looking for an answer to this and I'm afraid there is none. If I find one, I'll come back and post it here, but I'm looking (and not alone) for a lot of time now.
No , it's not possible to get access to a cross-origin frame !
Try this:
// wait until object loads
$('object').load(function() {
// find the element needed
page = $('object').contents().find('div');
// alert to check
alert(page.html());
});
I know this is an old question, but here goes ...
I used this on a personal website and eventually implemented it in some work projects, but this is how I hook into an svg's dom. Note that you need to run this after the object tag has loaded (so you can trigger it with an onload function). It may require adaptation for non-svg elements.
function hooksvg(elementID) { //Hook in the contentDocument of the svg so we can fire its internal scripts
var svgdoc, svgwin, returnvalue = false;
var object = (typeof elementID === 'string' ? document.getElementById(elementID) : elementID);
if (object && object.contentDocument) {
svgdoc = object.contentDocument;
}
else {
if (typeof object.getSVGDocument == _f) {
try {
svgdoc = object.getSVGDocument();
} catch (exception) {
//console.log('Neither the HTMLObjectElement nor the GetSVGDocument interface are implemented');
}
}
}
if (svgdoc && svgdoc.defaultView) {
svgwin = svgdoc.defaultView;
}
else if (object.window) {
svgwin = object.window;
}
else {
if (typeof object.getWindow == _f) {
try {
svgwin = object.getWindow();//TODO look at fixing this
}
catch (exception) {
// console.log('The DocumentView interface is not supported\r\n Non-W3C methods of obtaining "window" also failed');
}
}
}
//console.log('svgdoc is ' + svgdoc + ' and svgwin is ' + svgwin);
if (typeof svgwin === _u || typeof svgwin === null) {
returnvalue = null;
} else {
returnvalue = svgwin;
}
return returnvalue;
};
If you wanted to grab the symbol elements from the dom for the svg, your onload function could look like this:
function loadedsvg(){
var svg = hooksvg('mysvgid');
var symbols = svg.document.getElementsByTagName('symbol');
}
You could use the following code to read object data once its loaded completely and is of the same domain:
HTML-
<html>
<div class="main">
<object data="/html_template">
</object>
</div>
</html>
Jquery-
$('.main object').load(function() {
var obj = $('.main object')[0].contentDocument.children;
console.log(obj);
});
Hope this helps!
Here goes a sample piece of code which works. Not sure what the problem is with your code.
<html>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var k = $("object")[0].innerHTML;
alert(k);
$("object")[0].innerHTML = "testing";
});
</script>
<object data="/html_template">hi</object>
</html>
UPDATED
I used this line of Javascript to change the value of a input filed inside an iFrame, taken from How to pick element inside iframe using document.getElementById:
document.getElementById('iframeID').contentWindow.document.getElementById('inputID').value = 'Your Value';
In your case, since you do not have a frame, and since you want to get and not set the value, log it for example with:
console.log(document.getElementById('object').value);
And if you guess or choose an element:
console.log(document.getElementById('object').data);

Do an action based on presence of ALT attribute with Javascript

I have some javascript which looks at the body and finds words and if one is present, it outputs a div. This is useful for many things, however...
What I need to do is also look at the body and all the ALT tags for the page as well.
I found this: Use javascript to hide element based on ALT TAG only?
Which seems to change the ALT attribute, however I want to perform an action.
Here's my JS so far.
var bodytext = $('body').text();
if(bodytext.toLowerCase().indexOf('one' || 'two')==-1)
return;
var elem = $("<div>Text Here</div>");
Thank you.
P.S. I am a N00B/ relatively new at JS, I am doing this for a small project, so I am not sure where to start for this in terms of JS functions.
Updated Answer
Try this out, I commented the code to explain it a bit.
// build array of triggers
var triggers = ['trigger1','trigger2','trigger3'];
// wait for page to load
$(function() {
// show loading overlay
$('body').append('<div id="mypluginname-overlay" style="height:100%;width:100%;background-color:#FFF;"></div>');
// check page title
var $title = $('head title');
for(trigger of triggers) {
if($($title).innerHTML.toLowerCase().indexOf(trigger) >= 0) {
$($title).innerHTML = '*censored*';
}
}
// check all meta
$('meta').each(function() {
var $meta = $(this);
for(trigger of triggers) {
if($($meta).attr('name').toLowerCase().indexOf(trigger) >= 0) {
censorPage();
return; //stop script if entire page must be censored
} else if($($meta).attr('content').toLowerCase().indexOf(trigger) >= 0) {
censorPage();
return; //stop script if entire page must be censored
}
}
});
// check all img
$('img').each(function() {
var $img = $(this);
for(trigger of triggers) {
if($($img).attr('alt').toLowerCase().indexOf(trigger) >= 0) {
censor($img);
}
}
});
// check all video
$('video').each(function() {
var $video = $(this);
for(trigger of triggers) {
if($($video).attr('alt').toLowerCase().indexOf(trigger) >= 0) {
censor($video);
}
}
});
// if you want to be extra careful and check things like background image name,
// you'll have to run this code here - very inefficent
// but necessary if you want to check every single element's background image name:
for($element of $('body').children()) {
for(trigger of triggers) {
if($($element).css('background-image').toLowerCase().indexOf(trigger) >= 0) {
$($element).css('background-image','');
}
}
}
, function() { // Not sure if this is totally correct syntax, but use a callback function to determine when
// when the rest of the script has finished running
// hide overlay
$('#mypluginname-overlay').fadeOut(500);
}});
function censor($element) {
// just a basic example, you'll probably want to make this more complex to overlay it properly
$element.innerHTML = 'new content';
}
function censorPage() {
// just a basic example, you'll probably want to make this more complex to overlay it properly
$('body').innerHTML = 'new content';
}
---Original Answer---
I'm not sure exactly what you would like to do here, you should add more detail. However if you choose to use jQuery, it provides tons of useful methods including the method .attr(), which lets you get the value of any attribute of any element.
Example:
var alt = $('#my-selector').attr('alt');
if (alt == 'whatYouWant') {
alert('yay');
} else {
alert('nay');
}
You're using jQuery lib, you could select elements by attribute like:
$('[alt="one"]').each(function(el){
// do something
var x = $(el).arrt('alt');
});
If you use selector $('[alt]') you can get elements that have this attribute set, and then check the value of the element if you have a more complicated selection.
Than you have to change your return, as you could not put a div inside an ALT tag, it didn't work.
Here is about what is your expected output.
UPDATE
As you want to change all images and video in a page, the way to do this with jquery is through $.replaceWith():
$('img,video').replaceWith($('<div>Text Here</div>'));
If you need to filter the elements:
$('img,video').each(function(el){
if($(el).prop('tagName') == 'IMG' &&
$(el).attr('alt') == 'the text...') {
$(el).replaceWith($('<div>Text Here</div>'));
}
})
But I'm not an expert on Chrome Extensions, I just put this code here in jQuery, as you was using jQuery.
Of course it could be done, with much code with plain javascript and the DOM API.

HTML section identified by URL segment not found within webpage

How can I notify the user when the section identified by the url fragment is not found on a webpage?
Example:
website1 contains:
bring me to the foo section of website2
and website 2 contains:
<div id="foo"> I'm the foo section </div>
So if I click the link and the identifier of the div is not "foo" but "bar" the webpage displays an alert like "foo section not found".
Context: I'm exposing on an html page a JSON response for an API and I want the attributes of the JSON to link to a documentation page. If the section describing that attribute is not found an alert should suggest to update the documentation.
UPDATE: without using javascript frameworks if possible
Thanks
This should do the trick.
On "onLoad" of website2 I check if the url contains a segment and then look for that Id in the document using getElementById(segment) ..
<html>
<body onload="myFunction()">
<h1>Hello World!</h1>
<script>
function myFunction() {
var segment;
if(window.location.hash){
segment = window.location.hash.substring(1);
if( document.getElementById(segment) == null ){
alert("html element with id "+segment+" not found");
}
}
}
</script>
</body>
</html>
Are you using jQuery?
You can't do this with html or css, but you can do it very easily with jQuery, like this:
$('.navigation a').on("click", function(){
//This gets the href and splits it on "#". Grabs the value after "#"
//Make sure to only have 1 # in a link
var idToFind = $(this).attr("href").split("#")[1];
//Check if a div with this ID exists
if($('#'+idToFind).length > 0){
//it has been found, you could turn the scrolling to the section into a neat animation here, if you want
}
else{
//It has not found it. Alert.
alert('"' + idToFind + '" section not found');
}
});
edit
Here's a vanilla js solution:
html:
bring me to the foo section
Javascript:
function checkSection(section){
var idToFind = $(this).getAttribute("href").split("#")[1];
//Get the element
var element = document.getElementById(idToFind);
//check if element exists
if (typeof(element) != 'undefined' && element != null)
{
// exists.
}
else{
//doesn't exist
alert(idToFind + "doesn't exist");
}
}

How to load iframe content correctly in to <div in main page (same domain iframe)?

I got an ifram that has many links in it and i am trying to copy those link correctly to my main page. My current code copy the links incorectly .For example if the
actual hyper link is like this in iframe:
5
after coping it in to main page the hyper links become like this :
http://ok.mysite24.com/spring/./ok/doit.php
so after clicking to those links from within my main page i go to dead links instead of actual links. is there away to fix this problem by copying iframe content correctly or should i modify my iframe content ?
<script type='text/javascript'>
function getFrameContents(){
var iFrame = document.getElementById('myframe');
var iFrameBody;
if ( iFrame.contentDocument )
{ // FF
iFrameBody = iFrame.contentDocument.getElementsByTagName('body')[0];
}
else if ( iFrame.contentWindow )
{ // IE
iFrameBody = iFrame.contentWindow.document.getElementsByTagName('body')[0];
}
alert(iFrameBody.innerHTML);
document.getElementById('response').innerHTML = iFrameBody.innerHTML
}
</script>
<iframe id ='myframe' src='http://www.mysite.com/ok.php'></iframe>
<div id="response">
<p>getFrameContents! </p>
Before retrieving the innerHTML loop over all links and replace their DOM-href-attribute with their JS-href-property. This will turn the href-attributes into absolute URIs.
//clone the body to keep the original untouched
iFrameBody = iFrameBody.cloneNode(true);
var links = iFrameBody.getElementsByTagName('a');
for (var i = 0; i < iFrameBody.getElementsByTagName('a').length; ++i) {
if (links[i].hasAttribute('href')) {
links[i].setAttribute('href', links[i].href);
}
}
It looks like you want to resolve one relative address to the iframe's source address, which may also be relative. Psuedo code (ish):k
function resolveAddress(source, link) {
if(link.indexOf("../") == 0) {
index--; // go up one directory .//
return resolveAddress(source.substr(0,source.lastIndexOf("/")-1),
link.substr(1, link.length-1));
}
else if(link.indexOf("./") == 0) {
// reduce to current directory ./
return resolveAddress(source.substr(0,source.lastIndexOf("/"),
link.substr(2, link.length-1));
}
return source + link;
}
frame_src = "http://www.mysite.com/ok.php"
link = "./ok/doit.php";
resolveAddress(frame_src, link);
//=> "http://www.mysite.com/ok/doit.php"

Searching HTML img title attributes

Basically I have a html page with hundreds of images on it each with a title attribute describing the image. Ideally I would change all this but the page has to stay as it is for now.
I want to search these title attributes and scroll the page to the corresponding image if possible. - I've played around with some javascript search scripts but cannot get it to work with straightforward "On page" searches as the tags are in the code rather than displayed on page.
Can anyone point me in the right direction on how to do something like this?
This was the "Search on page" code I was using
var n = 0;
function findInPage(str) {
var txt, i, found;
if (str == "") {
return false;
}
// Find next occurance of the given string on the page, wrap around to the
// start of the page if necessary.
if (window.find) {
// Look for match starting at the current point. If not found, rewind
// back to the first match.
if (!window.find(str)) {
while (window.find(str, false, true)) {
n++;
}
} else {
n++;
}
// If not found in either direction, give message.
if (n == 0) {
alert("Not found.");
}
} else if (window.document.body.createTextRange) {
txt = window.document.body.createTextRange();
// Find the nth match from the top of the page.
found = true;
i = 0;
while (found === true && i <= n) {
found = txt.findText(str);
if (found) {
txt.moveStart("character", 1);
txt.moveEnd("textedit");
}
i += 1;
}
// If found, mark it and scroll it into view.
if (found) {
txt.moveStart("character", -1);
txt.findText(str);
txt.select();
txt.scrollIntoView();
n++;
} else {
// Otherwise, start over at the top of the page and find first match.
if (n > 0) {
n = 0;
findInPage(str);
}
// Not found anywhere, give message. else
alert("Not found.");
}
}
return false;
}
You can select by html attribute.
Using plain JS (in modern browsers incl. IE8+):
document.querySelectorAll('[title*="my text"]')
Using jQuery:
$('[title*=my text]')
would find:
<img src="/path" title="this is a title with my text" />
From there, you would need to get the page position of the image returned by the selector, and then scroll your page to that point, optionally (likely) with some offset so it doesn't bang up against the top of the viewport
EDIT:
function findElementsByTitle(str) {
return document.querySelectorAll('[title*="' + str + '"]');
}
function scrollToElement(el) {
var yOffset = el.offset().top; //this is a jQuery method...you don't want to write this in plain JS
window.scrollTo(0, yOffset - 10) //params are x,y. the - 10 is just so your image has some "padding" in the viewport
}

Categories