Collect DOM elements from external HTML documents - javascript

I am trying to write a report-generator to collect user-comments from a list of external HTML files. User-comments are wrapped in < span> elements.
Can this be done using JavaScript?
Here's my attempt:
function generateCommentReport()
{
var files = document.querySelectorAll('td a'); //Files to scan are links in an HTML table
var outputWindow = window.open(); //Output browser window for report
for(var i = 0; i<files.length; i++){
//Open each file in a browser window
win = window.open();
win.location.href = files[i].href;
//Scan opened window for 'comment's
comments = win.document.querySelectorAll('.comment');
for(var j=0;j<comments.length;j++){
//Add to output report
outputWindow.document.write(comment[i].innerHTML);
}
}
}

You will need to wait for onload on the target window before you can read content from its document.
Also what type of element is comment? In general you can't put a name on just any element. Whilst unknown attributes like a misplaced name may be ignored, you can't guarantee that browsers will take account of them for getElementsByName. (In reality, most browsers do, but IE doesn't.) A class might be a better bet?

Each web browse works in a defined and controlled work space on a user computer where certain things are restrict to code like file system - these are safety standards to ensure that no malicious code from internet runs into your system to phishing sensitive information stored on in it. Only ways a webbrowser is allowed if access granted explicitly by the user.
But i can suggest you for Internet Application as
- If List of commands is static then cache either by XML, Json or Cookies [it will store on user's system until it expires]
- If dynamic then Ajax to retrieve it

I think I have the solution to this.
var windows = [];
var report = null;
function handlerFunctionFactory(i,max){
return function (evt){
//Scan opened window for 'comment's
var comments = windows[i].document.querySelectorAll('.comment');
for(var j=0;j<comments.length;j++){
//Add to output report
report.document.write(comments[j].innerHTML);
}
if((i+1)==max){
report.document.write("</div></body></html>");
report.document.close();
}
windows[i].close();
}
}
function generateReport()
{
var files = document.querySelectorAll('td a'); //The list of files to scan is stored as links in an HTML table
report = window.open(); //Output browser window for report
report.title = 'Comment Report';
report.document.open();
report.document.write('<!DOCTYPE html PUBLIC"-// W3C//DTD XHTML 1.0 Transitional//EN"" http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
+ '<html><head><title>Comment Report</title>'
+ '</head><body>');
for(var i = 0; i<files.length; i++){
//Open each file in a browser window
win = window.open();
windows.push(win)
win.location.href = files[i].href;
win.onload = handlerFunctionFactory(i,files.length);
}
}
Any refactoring tips are welcome. I am not entirely convinced that factory is the best way to bind the onload handlers to an instance for example.
This works only on Firefox :(

Related

Add attachment by url to Outlook mail

The context
There is a button on the homepage of each document set in a document library on a SharePoint Online environment. When the button is clicked, an Outlook window opens with the title and body set and all the files in the document set should be added as the attachments.
The code
Here's the code I have so far:
var olApp = new ActiveXObject("Outlook.Application");
var olNs = olApp.GetNameSpace("MAPI");
var olItem = olApp.CreateItem(0);
var signature = olItem.HTMLBody;
signature.Importance = 2;
olItem.To = "";
olItem.Cc = "";
olItem.Bcc = "";
olItem.Subject = "Pre filled title";
olItem.HTMLBody =
"<span style='font-size:11pt;'>" +
"<p>Pre filled body</p>" +
"</span>";
olItem.HTMLBody += signature;
olItem.Display();
olItem.GetInspector.WindowState = 2;
var docUrl = "https://path_to_site/Dossiers/13245_kort titel/New Microsoft Word Document.docx";
olItem.Attachments.Add(docUrl);
The Problem
When I run this code, an Outlook window opens with everything set correctly. But on the line where the attachment is added I get following very vague error message:
SCRIPT8: The operation failed.
I thought it could be the spaces in the url so I replaced them:
docUrl = docUrl.replace(/ /g, "%20");
Also didn't work (same error) and providing all parameters like this also didn't work:
olItem.Attachments.Add(docUrl, 1, 1, "NewDocument");
Passing a path to a local file (e.g. C:/folder/file.txt) or a publicly available url to an image does work. So my guess is it has something to do with permissions or security. Does anybody know how to solve this?
PS: I know using an ActiveX control is not the ideal way of working (browser limitations, security considerations, ...) but the situation is what it is and not in my power to change.
You cannot pass a url to MailItem.Attachments.Add in OOM (it does work in Redemption - I am its author - for RDOMail.Attachments.Add). Outlook Object Model only allows a fully qualified path to a local file or a pointer to another item (such as MailItem).

Open XML content in another window, using JavaScript

I understand I cannot save XML content to a local file, because of security restrictions. but is there a way I can show the XML content in another browser window, as
Window.Open(xmlString, . .. );
that would work the same as -
Window.Open(URL, . . .);
I cannot use server-side language.
I can use javaScript \ jQuery. (I already use them to create the XML)
I can have a template XML file, near my HTML. Is there a way to display the template file and change its content ? almost the same as window.open: is it possible open a new window with modify its DOM or How to write JavaScript to a separate window? but I need to change XML nodes, and not HTML.
EDIT 1: try using myXmlWindow.document.write(xmlString)
=> I tried the suggested code -
var xmlString = xml2Str(xmlDocument);
myXmlWindow = window.open();
myXmlWindow.document.write(xmlString);
myXmlWindow.focus();
but it does not display the whole XML content, just the intern node values. and the new window still display "Connecting..." as it did not finish loading the content (missing close tag ???)
maybe I need to tell it is XML content and not HTML ???
my xmlString :
<root><device1>Name</device1><device2/><device3><Temprature_1>23.5</Temprature_1><Temprature_2>23.4</Temprature_2><Temprature_3>23.4</Temprature_3><Temprature_4>23.3</Temprature_4><Temprature_5>23.2</Temprature_5></device3></root>
the displayed content:
Name23.523.423.423.323.2
EDIT 2: my code -
function xml2Str(xmlNode) {
try {
// Gecko- and Webkit-based browsers (Firefox, Chrome), Opera.
return (new XMLSerializer()).serializeToString(xmlNode);
}
catch (e) {
try {
// Internet Explorer.
return xmlNode.xml;
}
catch (e) {
//Other browsers without XML Serializer
// alert('Xmlserializer not supported');
return('Xmlserializer not supported');
}
}
return false;
}
function fShow_xml_in_win() {
var xmlDocument = $.parseXML("<root/>");
var dev1 = xmlDocument.createElement('device1');
var dev2 = xmlDocument.createElement('device2');
var dev3 = xmlDocument.createElement('device3');
dev1.appendChild(xmlDocument.createTextNode('Name'));
xmlDocument.documentElement.appendChild(dev1);
xmlDocument.documentElement.appendChild(dev2);
xmlDocument.documentElement.appendChild(dev3);
var i;
var xNode;
for (i = 0; i < 5; i++) {
xNode = xmlDocument.createElement('Temprature_' + (i+1));
xNode.appendChild(xmlDocument.createTextNode( "myVal " + ((i+1) * 10) ));
dev3.appendChild(xNode);
}
var xmlString = xml2Str(xmlDocument);
alert(xmlString);
xmlString = "<?xml version='1.0' ?>" + xmlString; // I do not know how to add this node using parseXML :(
alert(xmlString);
myXmlWindow = window.open();
myXmlWindow.document.write(xmlString);
myXmlWindow.document.close(); // !! EDIT 3
myXmlWindow.focus();
return false;
}
EDIT 3: solved the "connecting..." problem
I just needed to add myXmlWindow.document.close();
You can open a blank window and then write content to it as follows:
myWindow=window.open('','','width=200,height=100')
myWindow.document.write(xmlString);
myWindow.focus()
You may need to do some work to format your xmlString, but I think this approach will do what you want. If your xmlString is formatted, try adding:
<?xml version="1.0" ?>
to the start of your string.
My understanding from your post, are
1.(From your firts point)
you get xml from somewhere which is not your control. My suggestion is why don't you get as JSON?
2.(From your second point)
If those XML is created by you means, Why aren't you try to write those XML from reference?
For example:
var reference = window.open();
reference.document.write(<some string goes here>)
3.(From your third point)
As per understanding from your second point. You can create xml. So why are you changing after write the document?
Note: Generally XML is used for Server-to-server communication, JSON is used for Server-to-client(browser) communication.

Multiple HTML DOMs - Parse and Transfer Data

I am requesting full HTML5 documents via Ajax using jQuery. I want to be able to parse them and transfer elements to my main page DOM, ideally with all major browsers, including mobile. I don't want to create an iframe as I want the process to be as quick as possible. With Chrome & Firefox I can do the following:
var contents = $(document.createElement('html'));
contents[0].innerHTML = data; // data : HTML document string
This will create a proper document, somewhat surprisingly, just without a doctype. In IE9, however, one may not use the innerHTML to set the contents of the html element. I tried to do the following, without any luck:
Create a DOM, open it, write to it and close it. Issue: on doc.open, IE9 throws an exception called Unspecified error..
var doc = document.implementation.createHTMLDocument('');
doc.open();
doc.write(data);
doc.close();
Create an ActiveX DOM. This time, the result is better but upon transferring / copying elements between documents IE9 crashes. Bad because no IE8 support (adoptNode / importNode support).
var doc = new ActiveXObject('htmlfile');
doc.open();
doc.write(data);
doc.close();
contents = $(doc.documentElement);
document.adoptNode(contents);
I was thinking about recursively recreating the elements, instead of transferring them between my documents, but that seems like an expensive task, given that I can have a lot nodes to transfer. I like my last ActiveX example as that will most likely work in IE8 and earlier (for parsing, at least).
Any ideas on this? Again, not only I need to be able to parse the head and body, but I also need to be able to append these new elements to my main dom.
Thanks much!
Answering my own question... To solve my issue I used all solutions mentioned in my post, with try/catch blocks if a browser throws an error (oh, how we love thee IE!). The following works in IE8, IE9, Chrome 23, Firefox 17, iOS 4 and 5, Android 3 & 4. I have not tested Android 2.1-2.3 and IE7.
var contents = $('');
try {
contents = $(document.createElement('html'));
contents[0].innerHTML = data;
}
catch(e) {
try {
var doc = document.implementation.createHTMLDocument('');
doc.open();
doc.write(data);
doc.close();
contents = $(doc.documentElement);
}
catch(e) {
var doc = new ActiveXObject('htmlfile');
doc.open();
doc.write(data);
doc.close();
contents = $(doc.documentElement);
}
}
At this point we can find elements using jQuery. Transferring them to a different DOM creates a bit of a problem. There are a couple of methods that do this, but they are not widely supported yet (importNode & adoptNode) and/or are buggy. Given that our selector string is called 'selector', below I re-created the found elements and append them to '.someDiv'.
var fnd = contents.find(selector);
if(fnd.length) {
var newSelection = $('');
fnd.each(function() {
var n = document.createElement(this.tagName);
var attr = $(this).prop('attributes');
n.innerHTML = this.innerHTML;
$.each(attr,function() { $(n).attr(this.name, this.value); });
newSelection.push(n);
});
$('.someDiv').append(newSelection);
};

Vista Gadget - Write to a XML file

I have built a Vista Gadget. It grabs a local XML file called "settings.xml".
It loads it and I change a few things. then I call the xmldoc.Save("settings.xml") method which works fine of you run it in Internet Explorer... but if you run it in the sidebar it does not write to the XML - only loads from.
How do I get it to write to the XML file?
settingsxmldoc = new ActiveXObject("Microsoft.XMLDOM");
settingsxmldoc.async = false;
settingsxmldoc.onreadystatechange = readSettingsXML;
settingsxmldoc.load("settings.xml");
if (Favorites.length > 0)
{
for (i = 0; i < Favorites.length; i++)
{
var newElement = settingsxmldoc.createElement("db");
newElement.appendChild(settingsxmldoc.createTextNode(Favorites[i]));
favdbs[0].appendChild(newElement);
}
}
settingsxmldoc.save("settings.xml");
Within a gadget, a partially qualified file name evaluates to the x-gadget:/// protocol. ActiveXObjects don't know anything about this protocol, so they don't know where to put the file and they throw an error. Use a fully qualified file name and it should work fine:
settingsxmldoc.save(System.Gadget.path + "\\settings.xml");

Is robust javascript-only upload of file possible

I want a robust way to upload a file. That means that I want to be able to handle interruptions, error and pauses.
So my question is: Is something like the following possible using javascript only on the client.
If so I would like pointers to libraries, tutorials, books or implementations.
If not I would like an explanation to why it's not possible.
Scenario:
Open a large file
Split it into parts
For each part I would like to
Create checksum and append to data
Post data to server (the server would check if data uploaded correctly)
Check a web page on server to see if upload is ok
If yes upload next part if no retry
Assume all posts to server is accompanied by relevant meta data (sessionid and whatnot).
No. You can, through a certain amount of hackery, begin a file upload with AJAX, in which case you'll be able to tell when it's finished uploading. That's it.
JavaScript does not have any direct access to files on the visitor's computer for security reasons. The most you'll be able to see from within your script is the filename.
Firefox 3.5 adds support for DOM progress event monitoring of XMLHttpRequest transfers which allow you to keep track of at least upload status as well as completion and cancellation of uploads.
It's also possible to simulate progress tracking with iframes in clients that don't support this newer XMLHTTPRequest additions.
For an example of script that does just this, take a look at NoSWFUpload. I've been using it succesfully for about few months now.
It's possible in Firefox 3 to open a local file as chosen by a file upload field and read it into a JavaScript variable using the field's files array. That would allow you to do your own chunking, hashing and sending by AJAX.
There is some talk of getting something like this standardised by W3, but for the immediate future no other browser supports this.
Yes. Please look at the following file -
function Upload() {
var self = this;
this.btnUpload;
this.frmUpload;
this.inputFile;
this.divUploadArea;
this.upload = function(event, target) {
event.stopPropagation();
if (!$('.upload-button').length) {
return false;
}
if (!$('.form').length) {
return false;
}
self.btnUpload = target;
self.frmUpload = $(self.btnUpload).parents('form:first');
self.inputFile = $(self.btnUpload).prev('.upload-input');
self.divUploadArea = $(self.btnUpload).next('.uploaded-area');
var target = $(self.frmUpload).attr('target');
var action = $(self.frmUpload).attr('action');
$(self.frmUpload).attr('target', 'upload_target'); //change the form's target to the iframe's id
$(self.frmUpload).attr('action', '/trnUpload/upload'); //change the form's action to the upload iframe function page
$(self.frmUpload).parent("div").prepend(self.iframe);
$('#upload_target').load(function(event){
if (!$("#upload_target").contents().find('.upload-success:first').length) {
$('#upload_target').remove();
return false;
} else if($("#upload_target").contents().find('.upload-success:first') == 'false') {
$('#upload_target').remove();
return false;
}
var fid = $("#upload_target").contents().find('.fid:first').html();
var filename = $("#upload_target").contents().find('.filename:first').html();
var filetype = $("#upload_target").contents().find('.filetype:first').html();
var filesize = $("#upload_target").contents().find('.filesize:first').html();
$(self.frmUpload).attr('target', target); //change the form's target to the iframe's id
$(self.frmUpload).attr('action', action); //change the form's
$('#upload_target').remove();
self.insertUploadLink(fid, filename, filetype, filesize);
});
};
this.iframe = '' +
'false' +
'';
this.insertUploadLink = function (fid, filename, filetype, filesize) {
$('#upload-value').attr('value', fid);
}
}
$(document).ready(event) {
var myupload = new Upload();
myupload.upload(event, event.target);
}
With also using PHP's APC to query the status of how much of the file has been uploaded, you can do a progress bar with a periodical updater (I would use jQuery, which the above class requires also). You can use PHP to output both the periodical results, and the results of the upload in the iframe that is temporarily created.
This is hackish. You will need to spend a lot of time to get it to work. You will need admin access to whatever server you want to run it on so you can install APC. You will also need to setup the HTML form to correspond to the js Upload class. A reference on how to do this can be found here http://www.ultramegatech.com/blog/2008/12/creating-upload-progress-bar-php/

Categories

Resources