How to add a copy/paste context menu to browser element in XULRunner? - contextmenu

I would like to allow the user of my XULRunner based app to be able to do copy/paste via a context menu.
Keyboard shortcuts Ctrl-C and Ctrl-V are already working fine

Here it is without flash. The getInputSelection function is from here: Is there an Internet Explorer approved substitute for selectionStart and selectionEnd?.
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window id="mywin" title="my app"
width="800" height="600" persist="screenX screenY width height sizemode"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<popupset>
<menupopup id="clipmenu">
<menuitem label="Copy" oncommand="copy()"/>
<menuitem label="Paste" oncommand="paste();"/>
</menupopup>
</popupset>
<browser
type="content-primary"
src="http://127.0.0.1/"
flex="1"
disablehistory="true"
id="browserId"
context="clipmenu"
/>
<script>
<![CDATA[
function copy()
{
var tabBrowser = document.getElementById("browserId");
var selectedTagName = tabBrowser.contentWindow.document.activeElement.tagName;
var windowObj;
if(selectedTagName == "IFRAME")
{
windowObj = tabBrowser.contentWindow.frames[tabBrowser.contentWindow.document.activeElement.name];
}
else
{
windowObj = document.getElementById("browserId").contentWindow;
}
var selectedText = windowObj.getSelection();
if(!selectedText || selectedText == "")
{
var focused = windowObj.document.activeElement;
if(focused && focused.value)
{
selectedText = getSelectionFromInput(focused);
}
}
//alert(selectedText + "---");
const clipHelper = Components.classes["#mozilla.org/widget/clipboardhelper;1"].getService(Components.interfaces.nsIClipboardHelper);
clipHelper.copyString(selectedText);
}
function getSelectionFromInput(focused)
{
var focusedValue = focused.value;
var sel = getInputSelection(focused);
var selectedText = "";
if(focusedValue.length == (sel.end))
{
selectedText = focusedValue.substring(sel.start);
}
else
{
selectedText = focusedValue.substring(sel.start, (sel.end));
}
return selectedText;
}
function paste()
{
var clip = Components.classes["#mozilla.org/widget/clipboard;1"].getService(Components.interfaces.nsIClipboard);
var trans = Components.classes["#mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
trans.addDataFlavor("text/unicode");
clip.getData(trans, clip.kGlobalClipboard);
var str = new Object();
var len = new Object();
trans.getTransferData("text/unicode",str,len);
str = str.value.QueryInterface(Components.interfaces.nsISupportsString);
str = str.data.substring(0, len.value / 2);
var focused = document.commandDispatcher.focusedElement;
var focusedValue = focused.value;
var sel = getInputSelection(focused);
focused.value = focusedValue.substring(0,sel.start) + str + focusedValue.substring(sel.end);
}
function getInputSelection(el) {
var start = 0, end = 0, normalizedValue, range,
textInputRange, len, endRange;
if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
start = el.selectionStart;
end = el.selectionEnd;
} else {
range = document.selection.createRange();
if (range && range.parentElement() == el) {
len = el.value.length;
normalizedValue = el.value.replace(/\r\n/g, "\n");
// Create a working TextRange that lives only in the input
textInputRange = el.createTextRange();
textInputRange.moveToBookmark(range.getBookmark());
// Check if the start and end of the selection are at the very end
// of the input, since moveStart/moveEnd doesn't return what we want
// in those cases
endRange = el.createTextRange();
endRange.collapse(false);
if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
start = end = len;
} else {
start = -textInputRange.moveStart("character", -len);
start += normalizedValue.slice(0, start).split("\n").length - 1;
if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
end = len;
} else {
end = -textInputRange.moveEnd("character", -len);
end += normalizedValue.slice(0, end).split("\n").length - 1;
}
}
}
}
return {
start: start,
end: end
};
}
]]>
</script>
</window>
Updated to support iframes.

Create menu using the code below.
<popupset>
<menupopup id="clipmenu">
<menuitem label="Copy" oncommand="copy();"/>
<menuseparator/>
<menuitem label="paste" oncommand="paste();"/>
</menupopup>
</popupset>
<browser type="content" src="chrome://myapp/content/theme1/index.html" flex="1" context="clipmenu"/>
Connect it to whatever you want, here am making it the context menu of the browser element by giving the id of menu in the context attribute of the browser element.
Then for each menu you can give the command to execute in oncommand event. We have given the function copy and paste.
Then write the code to copy text from whatever element you want or if you want to copy the selected data only.
See the below link for copying command.
http://www.deluxeblogtips.com/2010/06/javascript-copy-to-clipboard.html

One more example for "Copy" context menu in XULRunner under SWT Browser (code was implemented for Eclipse v3.5.1, XULRunner v1.8.1.3):
Browser browser = new Browser(parent, style | SWT.MOZILLA);
Menu menu = new Menu(browser);
MenuItem item = new MenuItem(menu, SWT.NONE);
item.setText("Copy");
item.addSelectionListener(new SelectionListener() {
#Override
public void widgetSelected(SelectionEvent e) {
nsIWebBrowser webBrowser = (nsIWebBrowser) browser.getWebBrowser();
nsIInterfaceRequestor req = (nsIInterfaceRequestor) webBrowser.queryInterface(nsIInterfaceRequestor.NS_IINTERFACEREQUESTOR_IID);
nsIDocShell docShell = (nsIDocShell) req.getInterface(nsIDocShell.NS_IDOCSHELL_IID);
nsIClipboardCommands cmds = (nsIClipboardCommands) docShell.queryInterface(nsIClipboardCommands.NS_ICLIPBOARDCOMMANDS_IID);
cmds.copySelection();
}
#Override
public void widgetDefaultSelected(SelectionEvent e) {
}
});
browser.setMenu(menu);

Related

firefox can't follow the link, in other browsers all right

Ggo to https://codepen.io/anon/pen/pVGXZG hover mouse on NAV and try click on "firefox"
Other browser when you click on "firefox" following link without problem
var btn = document.getElementById("main-btn");
btn.addEventListener("mouseover", function (e) {
var nav = document.getElementById("main-nav");
var sub_btns = document.getElementsByClassName("sub-btn");
var pos = [];
e.className += "main-hover";
console.log(e)
nav.addEventListener("mouseover", function (e) {
var total =0;
for(var x = 0;x<sub_btns.length;x++) {
if(x <2) {
sub_btns[x].style.left = "-"+((x+1)*30)+"%";
pos[x] = ((x+1)*20);
} else {
sub_btns[x].style.right = "-"+((x-1)*30)+"%";
pos[x] = ((x-1)*280);
}
sub_btns[x].style.opacity = "1";
}
nav.style.width = 50+"%";
});
nav.addEventListener("mouseout", function(){
nav.style.width = "100px";
for(var x = 0;x<sub_btns.length;x++) {
sub_btns[x].style.left = "0";
sub_btns[x].style.right = "0";
sub_btns[x].style.opacity = "0";
}
})
});
Spec says, that inside of you can have only phrasing content. That is, the element inside won't be interactive (clickable).

for embedded PDFs, can PDFJS support both scrolling and jump to a page number at the same time?

This seems like it should be very standard behavior.
I can display a scrollable PDF with:
var container = document.getElementById('viewerContainer');
var pdfViewer = new PDFJS.PDFViewer({
container: container,
});
PDFJS.getDocument(DEFAULT_URL).then(function (pdfDocument) {
pdfViewer.setDocument(pdfDocument);
});
and I can display the PDF page by page with something like:
PDFJS.getDocument(URL_ANNOTATED_PDF_EXAMPLE).then(function getPdfHelloWorld(pdf) {
pdf.getPage(pageNumber).then(function getPageHelloWorld(page) {
var scale = 1.5;
var viewport = page.getViewport(scale);
var canvas = document.getElementById('the-canvas');
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
var renderContext = {
canvasContext: context,
viewport: viewport
};
page.render(renderContext);
});
But can't seem to find any reference in the API to both allow scrolling and jumping to a particular page, besides:
pdfViewer.currentPageNumber = 3;
which doesn't work...
So I found a way to make this work (mixed with a little Angular code, "$scope.$watch...") I now have other problems with font decoding. But here is a solution that might help someone else.
var me = this;
PDFJS.externalLinkTarget = PDFJS.LinkTarget.BLANK;
var container = document.getElementById('capso-court-document__container');
function renderPDF(url, container) {
function renderPage(page) {
var SCALE = 1;
var pdfPageView = new PDFJS.PDFPageView({
container: container,
id: page.pageIndex + 1,
scale: SCALE,
defaultViewport: page.getViewport(SCALE),
textLayerFactory: new PDFJS.DefaultTextLayerFactory(),
annotationLayerFactory: new PDFJS.DefaultAnnotationLayerFactory()
});
pdfPageView.setPdfPage(page);
return pdfPageView.draw();
}
function renderPages(pdfDoc) {
var pageLoadPromises = [];
for (var num = 1; num <= pdfDoc.numPages; num++) {
pageLoadPromises.push(pdfDoc.getPage(num).then(renderPage));
}
return $q.all(pageLoadPromises);
}
PDFJS.disableWorker = true;
return PDFJS.getDocument(url)
.then(renderPages);
}
$scope.$watch(function() {
return {
filingUrl: me.filingUrl,
whenPageSelected: me.whenPageSelected,
};
}, function(newVal, oldVal) {
if (newVal.filingUrl) {
//newVal.filingUrl = URL_EXAMPLE_PDF_ANNOTATED;
//newVal.filingUrl = URL_EXAMPLE_PDF_ANNOTATED_2;
//newVal.filingUrl = URL_EXAMPLE_PDF_MULTI_PAGE;
if (newVal.filingUrl !== oldVal.filingUrl &&
newVal.whenPageSelected &&
newVal.whenPageSelected.page) {
scrollToPage(newVal.whenPageSelected.page);
}
//HACK - create new container for each newly displayed PDF
container.innerHTML = '';
var newContainerForNewPdfSelection = document.createElement('div');
container.appendChild(newContainerForNewPdfSelection);
renderPDF(newVal.filingUrl, newContainerForNewPdfSelection).then(function() {
if (newVal.whenPageSelected &&
newVal.whenPageSelected.page) {
scrollToPage(newVal.whenPageSelected.page);
}
});
}
}, true);
function scrollToPage(pageNumber) {
var pageContainer = document.getElementById('pageContainer' + pageNumber);
if (pageContainer) {
container.scrollTop = pageContainer.offsetTop;
} else {
console.warn('pdf pageContainer doesn\'t exist for index', pageNumber);
}
}

Marking text in a html document

Lets say I have the following markup:
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1>Some title</h1>
<p>First paragraph</p>
<p>Second paragraph</p>
</body>
<html>
I need to mark some parts of the text, namely "irst paragraph secon"
It would look something like this:
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1>Some title</h1>
<p>F
<mark>
irst paragraph</p><p>Secon
</mark>
d paragraph</p>
</body>
<html>
But the problem is be the html markup would be broken. The more complex the markup, the more problems this approach would have.
Question:
Looking for ideas on how can I take the first HTML example and apply a function to return a html structure where "irst paragraph second" is specifically marked somehow.
What I currently have is:
the parent container of the string "First paragraph"
the text "irst paragraph second"
the offset of the text "irst" in "First paragraph"
If you want to highlight text in a document then this plug-in will be helpful for you.
https://github.com/julmot/jquery.mark
Example fiddle: https://jsfiddle.net/julmot/vpav6tL1/
Usage is as simple as:
$(".context").mark("keyword");
In principle you have to:
split the documents into words
identify the first word by parent element
skip the offset
mark matching words
Making changes at word level will prevent you from breaking the markup.
I added a working example bellow. However I am not sure that it will work with all browsers.
Some of the functions like mergeWords are not used in the example but I included them because they can prove useful.
var splittedToWords = false;
function ignore(el) {
return (el.nodeType == 8) ||
(el.tagName == "BLOCKQUOTE") ||
(el.tagName == "SCRIPT") ||
(el.tagName == "DIV") ||
(!el.hasChildNodes() && el.textContent.match(/\S+/) == null);
}
function splitToWords(el) {
if (el.hasChildNodes()){
var count = el.childNodes.length;
for (var i = count - 1; i >= 0; i--) {
var node = el.childNodes[i];
if (!ignore(node))
splitToWords(node);
}
}
else { //text node
var words = el.textContent.match(/(\S+\s*)/g) || [];
var count = words.length;
var parentNode = el.parentNode;
for (var i = 0; i < count; i++) {
var wordNode = document.createElement("span");
wordNode.className = "word";
wordNode.innerText = words[i];
wordNode.setAttribute["word-index"] = i;
parentNode.insertBefore(wordNode, el);
}
parentNode.removeChild(el);
}
splittedToWords = true;
}
function unwrap(element) {
var next = element.nextSibling;
var parent = element.parentNode;
parent.removeChild(element);
var current;
var frag = document.createDocumentFragment();
do {
current = element.nextSibling;
frag.insertBefore(element, null);
} while ((element = current));
parent.insertBefore(frag, next);
}
function mergeWords(el) {
var words = document.getElementsByClassName("word");
count = words.length;
if (count > 0)
for (var i = 0; i < count; i++)
uwrap(words[i]);
}
function markWord(el, pos, len) {
var text = el.innerText;
var pre = text.substr(0, pos);
var mark = '<mark>' + text.substr(pos, len) + '</mark>';
var post = text.substring(pos + len, text.length);
el.innerHTML = pre + mark + post;
}
function mark(element, offset, text) {
if (!splittedToWords) {
var body = document.body;
splitToWords(body);
}
var words = document.getElementsByClassName("word");
var wordsCount = words.length;
var first = null;
for (var i = 0; i < wordsCount; i++ ) {
if (words[i].parentElement == element) {
first = i;
break;
}
}
done = false;
var i = first;
var pos = 0;
do {
var word = words[i];
var wordLength = word.innerText.length;
if (offset > pos + wordLength) {
i++;
pos += wordLength;
continue;
}
else {
done = true;
}
} while (!done);
var tWords = text.match(/(\S+\s*)/g) || [];
var tWordsCount = tWords.length;
if (tWordsCount == 0)
return;
for (var ti = 0; ti < tWordsCount; ti++) {
var wordEl = words[i++];
var word = wordEl.innerText;
var tWord = tWords[ti].trim();
var pos = word.indexOf(tWord);
if (pos == -1)
continue; //or maybe return.
markWord(wordEl, pos, tWord.length);
}
}
var e = document.getElementById("e");
//do the magic
mark(e, 1, 'irst paragraph Second');
<h1>Some title</h1>
<p id="e">First paragraph</p>
<p>Second paragraph</p>

Bookmarklet to invoke onChange from actionlist in Safari on iPad

My work uses a proprietary system to store medical records. The site is coded in javascript, and we are unable to change the coding of the site. We would like to use iPads to access the site, the site is accessed through a browser which is serving HTML.
There is a drop-down list that has an onChange value, which when an item is selected from the drop-down list onChange="doAction(this)" is invoked. This works fine in a desktop browser, however the iPad doesn't support the onChange. I know that an alternative is to use onBlue, however we do not have access to change the HTML.
What I was hoping we could do was to add a bookmarklet that once clicked, in principle does what the onChange event did.
The current actionlist HTML is:
<select class="actionList" onChange="doAction(this)" style="width:100%"><option class="actionHeading" selected value="nothing">Select action ..</option><option class="action" value="moreInfo"> More Info (shortcut key ' i ')</option><option class="actionHeading" disabled>Add Electronic Form ..</option><option class="action" value="xform-progressnotes-amendment-discharge"> Amendment Discharge Summary</option><option class="action" value="xform-progressnotes-clinical-review"> Clinical Review</option><option class="action" value="xform-dischargesummary"> Discharge Summary</option><option class="action" value="xform-progressnotes-family-work"> Family Work</option><option class="action" value="xform-progressnotes-medical-review"> Medical Review</option><option class="action" value="xform-medicationsummary"> Medication Summary Form</option><option class="action" value="xform-operationrecord"> Operation Sheet</option><option class="action" value="xform-progressnotes-inpatient"> Progress Notes</option><option class="action" value="xform-progressnotes-weekly-summary"> Weekly Summary</option></select></td>
The only option I would like to have in the bookmarklet is to 'select' the medical review option, i.e
<option class="action" value="xform-progressnotes-medical-review"> Medical Review</option>
the javascript for onChange="doAction(this)" is:
function doAction(selectObj)
{
var xformPrefix = 'xform-';
var chartPrefix = 'chart-';
var action = selectObj.value;
selectObj.selectedIndex = 0;
if (action == 'moreInfo')
{
moreInfo();
}
else if (action == 'referForAttn')
{
referForAttn();
}
else if(action.startsWith(chartPrefix)) {
var chartName = action.substring(chartPrefix.length);
var url;
var processedURL;
var checkExistUrl = '/udr/json/?action=chartsdescription';
checkExistUrl += '&patientId=630402';
checkExistUrl += '&chartName=' + chartName;
$.ajax({
async:false,
dataType:"json",
url:checkExistUrl,
success:function(data){
if(data.description != "")
{
var answer = confirm(data.description);
}
if(answer || data.description == "")
{
}
}
});
}
else if (action.startsWith(xformPrefix))
{
var xformName = action.substring(xformPrefix.length);
var url;
var windowWidth;
var windowHeight;
var processedURL;
if (xformName == 'progressnotes-amendment-discharge')
{
url = '/oip-forms-viewer/forms/templates?udrSessionId=BF0C3C8399163439782C67D2757477DC&formName=progressnotes-amendment-discharge&patientId=630402&episodeId=458698&transactionId=&xformAction=new&sectionId=Admission';
processedURL = '%2Foip-forms-viewer%2Fforms%2Ftemplates%3FudrSessionId%3DBF0C3C8399163439782C67D2757477DC%26formName%3Dprogressnotes-amendment-discharge%26patientId%3D630402%26episodeId%3D458698%26transactionId%3D%26xformAction%3Dnew%26sectionId%3DAdmission'
windowWidth = 800;
windowHeight = 500;
}
if (xformName == 'progressnotes-clinical-review')
{
url = '/oip-forms-viewer/forms/templates?udrSessionId=BF0C3C8399163439782C67D2757477DC&formName=progressnotes-clinical-review&patientId=630402&episodeId=458698&transactionId=&xformAction=new&sectionId=Admission';
processedURL = '%2Foip-forms-viewer%2Fforms%2Ftemplates%3FudrSessionId%3DBF0C3C8399163439782C67D2757477DC%26formName%3Dprogressnotes-clinical-review%26patientId%3D630402%26episodeId%3D458698%26transactionId%3D%26xformAction%3Dnew%26sectionId%3DAdmission'
windowWidth = 800;
windowHeight = 500;
}
if (xformName == 'dischargesummary')
{
url = '/oip-forms-viewer/forms/templates?udrSessionId=BF0C3C8399163439782C67D2757477DC&formName=dischargesummary&patientId=630402&episodeId=458698&transactionId=&xformAction=new&sectionId=Admission';
processedURL = '%2Foip-forms-viewer%2Fforms%2Ftemplates%3FudrSessionId%3DBF0C3C8399163439782C67D2757477DC%26formName%3Ddischargesummary%26patientId%3D630402%26episodeId%3D458698%26transactionId%3D%26xformAction%3Dnew%26sectionId%3DAdmission'
windowWidth = 800;
windowHeight = 550;
}
if (xformName == 'progressnotes-family-work')
{
url = '/oip-forms-viewer/forms/templates?udrSessionId=BF0C3C8399163439782C67D2757477DC&formName=progressnotes-family-work&patientId=630402&episodeId=458698&transactionId=&xformAction=new&sectionId=Admission';
processedURL = '%2Foip-forms-viewer%2Fforms%2Ftemplates%3FudrSessionId%3DBF0C3C8399163439782C67D2757477DC%26formName%3Dprogressnotes-family-work%26patientId%3D630402%26episodeId%3D458698%26transactionId%3D%26xformAction%3Dnew%26sectionId%3DAdmission'
windowWidth = 800;
windowHeight = 500;
}
if (xformName == 'progressnotes-medical-review')
{
url = '/oip-forms-viewer/forms/templates?udrSessionId=BF0C3C8399163439782C67D2757477DC&formName=progressnotes-medical-review&patientId=630402&episodeId=458698&transactionId=&xformAction=new&sectionId=Admission';
processedURL = '%2Foip-forms-viewer%2Fforms%2Ftemplates%3FudrSessionId%3DBF0C3C8399163439782C67D2757477DC%26formName%3Dprogressnotes-medical-review%26patientId%3D630402%26episodeId%3D458698%26transactionId%3D%26xformAction%3Dnew%26sectionId%3DAdmission'
windowWidth = 800;
windowHeight = 500;
}
if (xformName == 'medicationsummary')
{
url = '/oip-forms-viewer/forms/templates?udrSessionId=BF0C3C8399163439782C67D2757477DC&formName=medicationsummary&patientId=630402&episodeId=458698&transactionId=&xformAction=new&sectionId=Admission';
processedURL = '%2Foip-forms-viewer%2Fforms%2Ftemplates%3FudrSessionId%3DBF0C3C8399163439782C67D2757477DC%26formName%3Dmedicationsummary%26patientId%3D630402%26episodeId%3D458698%26transactionId%3D%26xformAction%3Dnew%26sectionId%3DAdmission'
windowWidth = 800;
windowHeight = 760;
}
if (xformName == 'operationrecord')
{
url = '/oip-forms-viewer/forms/templates?udrSessionId=BF0C3C8399163439782C67D2757477DC&formName=operationrecord&patientId=630402&episodeId=458698&transactionId=&xformAction=new&sectionId=Admission';
processedURL = '%2Foip-forms-viewer%2Fforms%2Ftemplates%3FudrSessionId%3DBF0C3C8399163439782C67D2757477DC%26formName%3Doperationrecord%26patientId%3D630402%26episodeId%3D458698%26transactionId%3D%26xformAction%3Dnew%26sectionId%3DAdmission'
windowWidth = 800;
windowHeight = 760;
}
if (xformName == 'progressnotes-inpatient')
{
url = '/oip-forms-viewer/forms/templates?udrSessionId=BF0C3C8399163439782C67D2757477DC&formName=progressnotes-inpatient&patientId=630402&episodeId=458698&transactionId=&xformAction=new&sectionId=Admission';
processedURL = '%2Foip-forms-viewer%2Fforms%2Ftemplates%3FudrSessionId%3DBF0C3C8399163439782C67D2757477DC%26formName%3Dprogressnotes-inpatient%26patientId%3D630402%26episodeId%3D458698%26transactionId%3D%26xformAction%3Dnew%26sectionId%3DAdmission'
windowWidth = 800;
windowHeight = 500;
}
if (xformName == 'progressnotes-weekly-summary')
{
url = '/oip-forms-viewer/forms/templates?udrSessionId=BF0C3C8399163439782C67D2757477DC&formName=progressnotes-weekly-summary&patientId=630402&episodeId=458698&transactionId=&xformAction=new&sectionId=Admission';
processedURL = '%2Foip-forms-viewer%2Fforms%2Ftemplates%3FudrSessionId%3DBF0C3C8399163439782C67D2757477DC%26formName%3Dprogressnotes-weekly-summary%26patientId%3D630402%26episodeId%3D458698%26transactionId%3D%26xformAction%3Dnew%26sectionId%3DAdmission'
windowWidth = 800;
windowHeight = 500;
}
var newForm;
var confirmMsg = "There is another e-form opened. \n";
confirmMsg += "Press \"Cancel\" to finish editing the open e-form\n";
confirmMsg += "Press \"OK\" to discard it and open a new one.";
try {
var location = findFrame(top, 'main').win.document.location;
newForm = confirm(confirmMsg);
}
catch(e) {
newForm = true;
}
if(newForm) {
try {
findFrame(top, 'main').win.close();
}
catch(e) {}
findFrame(top, 'main').win = openCentredWindow(url, 'xformWindow', windowWidth, windowHeight);
try {
// setting the window title change on window load
$(findFrame(top, 'main').win).load(changeEformWindowTitle);
}
catch(e) {
// nothing to report
}
try {
// trying to change the window title early if the on load hasn't worked
setTimeout('changeEformWindowTitle()', 2000);
}
catch(e) {
// nothing to report
}
try {
// doing it a second time in case the first attempt was too early.
setTimeout('changeEformWindowTitle()', 8000);
}
catch(e) {
// nothing to report
}
try {
// doing it a third time 40 seconds later in case it there was a pre-fill.
setTimeout('changeEformWindowTitle()', 40000);
}
catch(e) {
// nothing to report
}
}
else {
findFrame(top, 'main').win.focus();
}
}
}
Any help you could provide would be very much appreciated!
Thanks.
Your best bet is to place a proxy server between the ipad and the actual product.
This proxy can then modify the html generated by the proprietary system.
You can look into nginx as a newbie friendly solution for proxying.
Cheers,
T.
PS : I dont believe bookmarklets work on iPads. Even if they did, it would be a terrible UI.

An observer for page loads in a custom xul:browser

In my firefox extension I'm creating a xul:browser element. I want to have an observer that intercepts any url changes within the embedded browser and opens the url in a new browser tab (in the main browser). I'd also like new windows spawned by the xul:browser window to open in a tab instead of a new browser window.
I've created an observer which works, but I don't yet know how to apply that observer only to the xul:browser element.
function myFunction(){
var container = jQuery("#container")[0];
var new_browser_element = document.createElement('browser');
container.appendChild(new_browser_element);
var observerService = Components.classes["#mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
observerService.addObserver(myObserver, "http-on-modify-request", false);
}
var myObserver = {
observe: function(aSubject, aTopic, aData){
if (aTopic != 'http-on-modify-request'){
aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
// alert(aSubject.URI.spec);
// Now open url in new tab
}
},
QueryInterface: function(iid){
if (!iid.equals(Components.interfaces.nsISupports) &&
!iid.equals(Components.interfaces.nsIObserver))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};
You could try:
var myObserver = {
observe: function(aSubject, aTopic, aData){
if (aTopic == 'http-on-modify-request')
{
aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
var url = aSubject.URI.spec;
var postData ;
if (aSubject.requestMethod.toLowerCase() == "post")
{
var postText = this.readPostTextFromRequest(request);
if (postText)
{
var dataString = parseQuery(postText);
postData = postDataFromString(dataString);
}
}
var oHttp = aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
var interfaceRequestor = oHttp.notificationCallbacks.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
var DOMWindow = interfaceRequestor.getInterface(Components.interfaces.nsIDOMWindow);
//check if it is one of your mini browser windows
if (jQuery(DOMWindow).hasClass('mini_browser'))
{
openInTab(url, postData);
var request = aSubject.QueryInterface(Components.interfaces.nsIRequest);
request.cancel(Components.results.NS_BINDING_ABORTED);
}
}
},
QueryInterface: function(iid){
if (!iid.equals(Components.interfaces.nsISupports) &&
!iid.equals(Components.interfaces.nsIObserver))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
},
readPostTextFromRequest : function(request) {
var is = request.QueryInterface(Components.interfaces.nsIUploadChannel).uploadStream;
if (is)
{
var ss = is.QueryInterface(Components.interfaces.nsISeekableStream);
var prevOffset;
if (ss)
{
prevOffset = ss.tell();
ss.seek(Components.interfaces.nsISeekableStream.NS_SEEK_SET, 0);
}
// Read data from the stream..
var charset = "UTF-8";
var text = this.readFromStream(is, charset, true);
// Seek locks the file so, seek to the beginning only if necko hasn't read it yet,
// since necko doesn't seek to 0 before reading (at lest not till 459384 is fixed).
if (ss && prevOffset == 0)
ss.seek(Components.interfaces.nsISeekableStream.NS_SEEK_SET, 0);
return text;
}
else {
dump("Failed to Query Interface for upload stream.\n");
}
}
return null;
},
readFromStream : function(stream, charset, noClose)
{
var sis = Components.classes["#mozilla.org/binaryinputstream;1"]
.getService(Components.interfaces.nsIBinaryInputStream);
sis.setInputStream(stream);
var segments = [];
for (var count = stream.available(); count; count = stream.available())
segments.push(sis.readBytes(count));
if (!noClose)
sis.close();
var text = segments.join("");
return text;
}
};
function openInTab(url, postData)
{
var wm = Components.classes["#mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var recentWindow = wm.getMostRecentWindow("navigator:browser");
if (recentWindow)
{
// Use an existing browser window, open tab and "select" it
recentWindow.gBrowser.selectedTab = recentWindow.gBrowser.addTab(url, null, null, postData);
}
}
function parseQuery() {
var qry = this;
var rex = /[?&]?([^=]+)(?:=([^&#]*))?/g;
var qmatch, key;
var paramValues = {};
// parse querystring storing key/values in the ParamValues associative array
while (qmatch = rex.exec(qry)) {
key = decodeURIComponent(qmatch[1]);// get decoded key
val = decodeURIComponent(qmatch[2]);// get decoded value
paramValues[key] = val;
}
return paramValues;
}
function postDataFromString(dataString)
{
// POST method requests must wrap the encoded text in a MIME
// stream
var stringStream = Components.classes["#mozilla.org/io/string-input-stream;1"]
.createInstance(Components.interfaces.nsIStringInputStream);
if ("data" in stringStream) // Gecko 1.9 or newer
stringStream.data = dataString;
else // 1.8 or older
stringStream.setData(dataString, dataString.length);
var postData = Components.classes["#mozilla.org/network/mime-input-stream;1"].
createInstance(Components.interfaces.nsIMIMEInputStream);
postData.addHeader("Content-Type", "application/x-www-form-urlencoded");
postData.addContentLength = true;
postData.setData(stringStream);
return postData;
}
I'll update this to fill in the blanks in a bit.
edit: see http://forums.mozillazine.org/viewtopic.php?p=2772951#p2772951 for how to get the source window of a request.
Request cancellation code from http://zenit.senecac.on.ca/wiki/index.php/Support_For_OpenID.
see http://mxr.mozilla.org/mozilla-central/source/netwerk/base/public/nsIRequest.idl for details on nsIRequest.
See http://forums.mozillazine.org/viewtopic.php?p=2404533#p2404533 and https://developer.mozilla.org/en/XUL/Method/addTab for the definition of addTab.
parseQuery comes from http://blog.strictly-software.com/2008/10/using-javascript-to-parse-querystring.html.
See https://developer.mozilla.org/en/Code_snippets/Post_data_to_window#Preprocessing_POST_data for how to process post data in a form suitable for addTab.
ReadPostFromText and ReadTextFromStream both come from firebug (though slightly modified)

Resources