How can I edit html inside an iframe using javascript - javascript

I am working on automating a process within my business, part of which is sending an email through SalesForce. We don't have access to the SF API and the email has to be sent through salesforce in order to keep the communication searchable for the coworkers.
I need to use a template which can be selected in SalesForce, however this function does not work in IE (which our RPA solution uses) so I need to build this email from scratch.
I see two options for this:
Use the HTML to recreate the format with the right variables. This entails inserting/injecting/manipulating HTML.
Copy the format into memory/the clipboard, edit it programatically and paste it into the SF interface
This question will be about option 1. I will post an additional question with regards to the second option separately and edit this question to include that link. EDIT: Here is the link to the other question!
Now on to the question:
We use the Blue Prism RPA software suite. It has a possibility to insert javascript fragments into a website and subsequently invoke them. I was hoping that I could create a javascript fragment that recreates the template, insert it and then invoke it. I have been working on this for the past week and have hardly gotten any further.
I now am able to add basic text into the required field, but have found that to be able to use the template structure I need to use a different, HTML based, field. This field I find lives inside an iframe.
I have had zero experience with javascript prior to this week (luckily it seems similar to c# in which I do have experience) and now this iframe has me stumped. Apparently when you use Selenium or similar you can switch the driver to the new iframe but I don't have that option, it needs to be done through surface automation. Within javascript as well as the console I can not get it to target the separate document within the iframe. Apparently the iframe contents are not incorporated in that way in the bigger webpage.
So my question is this: How can I "switch focus" to the iframe using javascript? How can I then edit the iframe contents through javascript? Any help, tips etc. would be highly appreciated!

If you go to developer tools in the browser (F12 or right-click inspect) you can use the inpsect tool to get the path you are looking for. an iframe is just another window inside the window and once you have the 'base path' you can then extend further into the window from the iframe base path.
You can access frames one of two ways I know of;
document.getElementById('the frame you are looking for goes here').contentWindow.targetFunction();
and/or
window.frames[0].otherfunctions
where 0 is the Nth order of frame on the window in case there are others.
once you find that path you can interact with sub-elements on that iframe by getting the path to it from within the iframe.
some things to watch out for. frames not loading yet so make sure the frame you want is loaded and no other frame is moving it around the screen at run time. Also make sure the child frame is in the same domain, I think calling javascript has issues when going cross-domain i.e. it doesn't work (stand to be corrected there though maybe it depends on group settings)
Supply some code or the layout of the page and could give you a code example but top of my head the format will look like this
var doc = window.frames[0]
var thing = getElementById(doc.getElementByPath('maybePath')
'perform some set operations like set innerhtml to thing you desire

Related

Inserting user provided content into a document--validating HTML string, insertAdjacentHTML and iframe usage?

If I want to accept HTML built by a user of an extension, and not from a web source, and display it within an existing extension document, is there an alternative to using an iframe?
For example, if a user provides mathematical expresions using MathML and they are to be displayed in the current web page, and the user may add a <div> or <p> tag inaccurately and have incomplete HTML, how can it be added to the page without corrupting the layout of the page, apart from an iframe?
Does insertAdjacentHTML really accomplish this? This MDN article seems to imply so, where it reads, "It does not reparse the element it is being used on, and thus it does not corrupt the existing elements inside that element."
Or, is there a way to validate the HTML string before inserting into the DOM, such as DOMParser?
Also, for users that are knowledgeable in HTML, CSS, JS and can construct a small interactive document rather than just an expression, to be dislayed within the page, is an iframe the only option? The user provided code will be stored in indexedDB and rendered only on the user's machine and within this extension tool. So, something similar to a snippet on stackoverflow. I have this working in an iframe now but the user could add about a dozen of these to the page at any one time and I wondered if there is a better way of accomplishing this, regarding memory usage and in general.
Thank you.

Dynamically loading content on local HTML page [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
Context:
Basically I'm attaching a little HTML help doc to go with my program (not meant to be on a server, viewed locally). HTML just because I'm most comfortable in making docs in it but I also want it to have some interactivity/dynamic content which I can't do in a PDF or whatever.
I'm dynamically replacing the content when you click on a link instead of making every page need it's own HTML page, which is just something I'm used to doing so I can change the menu and banner and whatever else on a single 'main' html file without having to adjust every single other html file for one tiny change in the shared stuff.
Current Method:
Right now it's all done through javascript and jQuery. When a user clicks a link, I use jQuery's load() function to load the appropriate content (an html file) and replace the content div with what's in the loaded html file. Currently just using relative links. E.g. the core function is something like below:
$("#ContentBox").load("content/faq.html");
This actually worked a few weeks ago when I first wrote it. It's not like I built the whole thing and didn't test its core concept until just now. But now it seems all the browsers are blocking it. Chrome says:
XMLHttpRequest cannot load file:///C:/[....]/content/home.html. Cross origin requests are only supported for protocol schemes: http, data, chrome-extension, https, chrome-extension-resource. `
Question:
So I understand why it's happening as it's a potential security risk to allow that, I just want to figure a good way around it that still does what I want (if it's possible). I mean I could just preload all the content as huge string variables in the javascript file or as hidden divs that get turned on and off, but I was hoping for something a little more elegant.
And I can't expect all users of my program to setup a local web server just to view to help doc.
I've considered the File and FileReader classes but they require a user input for a lot of functions. There's also iFrames but that introduces all sorts of weirdness that needs to be accounted for and I hate iFrames.
If this is all local content then you should not be loading it via ajax. One option you have at your disposal is to set up your help files as local Javascript templates. You can then refer to them using a template library like mustache or underscore and link to them in your application like so:
<script type="text/template" src="local/helpfile.js" />
If you don't want to use a templating library then you can set up helpfile.js as JSON data, but you'll need to escape quote characters first.
If your help docs are to be viewed on a Windows machine only, you should look into using HTML Applications to get rid of the cross-origin issues. Or you can work around it by combining all of the source code files in hidden textareas. I've done it lol
To anyone still interested this is the solution I settled on as of now. At the end of the body are all the divs with the different page content styled like so:
<div id='PageName' class='content-div'>
<!-- content goes here -->
</div>
<div id='AnotherPage' class='content-div'>
<!-- content goes here -->
</div>
The id is important as that becomes the name of the page and the class type, which you can name whatever, I used to hide them with visibility:hidden; as well as gave it absolute positioning at 0,0 - just in case - so that they don't interact with other elements and screw up the layout.
On the page loading, along with a bunch of other functions, I store the elements into a javascript associative object by page name.
var content = {};
function onLoadThisGetsCalledSomewhere() {
// loop through all of those divs
$(".div-content").each(
function() {
// using $(this) to grab the div in the scope of the function here
var element = $(this).element;
var name = $(this).attr('id');
// remove it from the html (now it exists only in the content object)
element.detach();
// remove that style class that makes it invisible
element.removeClass('content-div');
// put it into memory
content[name] = element;
}
);
}
So when a link to another page is clicked, the onclick does something like switchPage(pageName) let's say.
function switchPage(requestedPage) :
// somewhat simplified, real version has case and null checks that take you to 404 page
var contentElement = content[requestedPage];
// replace content in some container div where you want content to go
$("#TheContentContainer").empty().append( contentElement );
// have to adjust size (width possibly too but I had a fixed width)
$("#TheContentContainer").height( contentElement.height() );
}
I'm not at the same computer so I'm writing all this up anew, not copy/pasting so there may be some bugs/typos (Caveat emptor - I'll fix it tomorrow). The version I used is somewhat more complicated as well since I have subpages as well as dynamically handled menu bar changes. Also features so that you can open the "links" correctly in new windows/tabs if such an action is made. But that's not important here now.
It's not too different I suppose with hidden divs (the benefit here is the detach() function to remove it from the html) or just storing long strings of html code in java vars (much more readable than that though), but I think it's advantage is is much cleaner (IMHO) and so far I like it. The one downside is with lots of pages you get one huge HTML doc that can be a pain to go through to edit one specific page but any decent editor should have a bookmark feature to make it a little easier to get to the line you're looking for. Also cause of that a bad idea if not local, but then again if it's online just use the jQuery load() function.

Serialization of the full page DOM. Can I get at the JS code that is loaded up, or must I AJAX it separately?

I have a bug I'm trying to track down, and it is very difficult to do so because of the complexity of the web app. There are many frames, and many instances of Javascript code that is embedded into the HTML in different ways.
The thing that needs to be fixed is a sub-page created with showModalDialog (so you already know it's going to be a disaster), and I am hoping that I can find a way to serialize as much of the DOM as possible within this dialog page context, so that I may open it to the same content both when the bug is present and when it is not, in hopes of detecting missing/extra/different Javascript, which would become apparent by pumping the result through a diff.
I tried jQuery(document).children().html(). This gets a little bit of the way there (it's able to serialize one of the outer <script> tags!) but does not include the contents of the iframe (most of the page content is about 3 iframe/frame levels deep).
I do have a custom script which I'm very glad I made, as it's able to walk down into the frame hierarchy recursively, so I imagine I can use .html() in conjunction with that to obtain my "serialization" which I can then do some manual checking to see if it matches up with what the web inspector tells me.
Perhaps there exists some flag I can give to html() to get it to recurse into the iframes/frames?
The real question, though, is about how to get a dump of all the JS code that is loaded in this particular page context. Because of the significant server-side component of this situation, javascript resources can be entirely dynamic and therefore should also be checked for differences. How would I go about (in JS on the client) extracting the raw contents of a <script src='path'> tag to place into the serialization? I can work around this by manually intercepting these resources but it would be nice if everything can go into one thing for use with the diff.
Is there no way to do this other than by separately re-requesting those JS resources (not from script tags) with ajax?

Get full actual html page source including the frameset

For our functional test automation we use QTP with the Webtest Plugin. I have control over the DOM (but not in an easy manner) and can use VBScript and partially Javascript to find a solution.
Whenever we encounter an error during a test I'd like to capture the full HTML page source at that moment. Later, when we are inspecting the error from our reports, we can see what happened and how the DOM looked like at that moment.
Therefore I look for a posibility to capture this source. Normally I did it with
htmlSource = browser("micClass:=Browser").page("micClass:=Page").Object.documentElement.outerHTML
or
htmlSource = browser("micClass:=Browser").page("micClass:=Page").Object.getElementsByTagName("html")(0).innerHTML
Unfortunately this will only capture the full content of the tag the frameset, and the frames, but not the actual content that is located in the frames. (classic frames here, not IFrames)
Now I'd like a way to capture the full DOM source at real time including the content in the framesets. And I'd like them in the right order and place, just like the source appears in the HTML view of the IE Developer Tool.
Does anyone have an idea how I could manage that?
If you really need to have the frames' source inline in the page's HTML the only way I know of achieving this is build the HTML recursively for each element. This may be a lot of work since for every element you'll have to remove the innerHTML from the outerHTML before going to the child elements (and insert them correctly).
If you can live with the frames' HTML being outside you can use Page.ChildObjects() with a description micclass=Frame and then use the same mechanism you used for the page (frames(i).Object.documentElement.outerHTML).
Note that you'll get all the frames under the page so there's no need to get the child objects of the Frame test objects even if the frames are nested in the DOM.

How does one properly test a javascript widget?

So, I've written a little javascript widget. All a user has to do is paste a script tag into the page, and right below it I insert a div with all of the content the user has requested.
Many sites do similar things, such as Twitter, Delicious and even StackOverflow.
What I'm curious about is how to test this widget to make sure that it will work properly on everyone's webpage. I'm not using an iframe, so I really want to make sure that this code will work when inserted most places. I know it looks the same in all browsers.
Suggestions? Or should I just build one hundred web pages and insert my script tag and see if it works? I would hope there is an easier way than that.
Once you have confirmed that your javascript works cross-browser in a controlled environment, here are some things that might cause problems when used on an actual website:
CSS
You're using a CSS class that is already being used (for a different purpose) by the target website
You're using positioning that might interfere with the site's CSS
The elements you are using are being styled by the website's CSS (you might want to use some sort of "reset" CSS that applies only to your widget)
HTML
You're creating elements with the same id attribute as an element that already exists on the website
You're specifying a name attribute that is already being used (while name can be used for multiple elements, you may not be expecting that)
Javascript
What is the expected behaviour without Javascript enabled? If your script creates everything, is it acceptable for nothing to be present without JS?
At very basic you should make sure your widget works for following test-cases. I am sure then it will work on all web-pages -
http/https: There should not be any warning for HTTPS pages for unencrypted content.
<script> / <no-script>: What if JavaScript is disabled? Is your widget still visible?
What happens when third-party cookies are disabled? Does your widget still work?
Layout-box restrictions: When parent div element's size is less than your widget. Does your widget overflow the given size and destroys owners page?
By keeping all your Javascripts under a namespace (global object) with a very unique name, you should be pretty much OK. Also, you can simply use an anonymous function if you just want to print out something.
Similar question: How to avoid name clashes in JavaScript widgets

Categories

Resources