So I'm working on a bookmarklet where it would be ideal for me to grab the content selected by the user using the "loop". Both window.getSelection and document.getSelection are functions that I can call, however, they always return an empty string.
I believe the problem is that when you tap on the bookmark icon in Mobile Safari, the selection is released. For example, if you select some text, tap the "+", bookmark or other tab, the selection is unselected even if you cancel.
Any thoughts on if it is possible to get at this data at all? Or is this pretty much impossible?
I think you would have to have the bookmarklet insert some content into the page that would operate on the selection. You might add a button to the top or bottom of the page, and when clicked it would act on the current selection. It could then clean up the added content or leave it there.
The contents of the "loop" are not exposed to javascript in the mobile browser, period. So this is impossible (I am assuming that you are working in the full browser, not in the browser window created when you launch a "saved to home page" icon)
I have a fairly simple idea.
var latestSelection = "";
while (true)
{
var tmp;
if ((tmp = document.getSelection()) != "")
latestSelection = tmp;
}
This way you would always have the latest selection in the latestSelection variable. Of course it would be expensive to have a loop run like this all the time. So you will probably want to play around with listeners or at least timers.
Hope this helps.
Update:
Don't use the above code as is.
Here is how you would write the same thing in objective-c:
- (void) updateSelection
{
NSString * tmp = [webView stringByEvaluatingJavaScriptFromString:#"document.getSelection()"];
if (![tmp isEqualToString:#""])
latestSelection = tmp;
}
You could have a timer execute updateSelection every x time units. If you find some good notification that let's you know that the user has interacted with the webview, you could use that to update latestSelection.
Related
Say I have a simple script
var i = 0;
test();
function test() {
console.log(i++);
setTimeout(test, 1000);
}
I put it in a Google Chrome console. How do I make it continue to run after the page navigates to another (should continue to print out numbers when browsing the web)?
Maybe save the variable 'i' in onbeforeunload() function, and launch a new script with that saved variable?
How do I make it continue to run after the page navigates to another
you can't, the script cannot continue on another page, it's the browser that runs the javascript in the page, and that will stop it when moving to another page.
(or) should continue to print out numbers when browsing the web?
you have yourself answered this. You can certainly save the counter in localstorage and resume counting on the next page, provided this next page contains the same or similar script and the logic to restore the counter from localStorage.
Or, you can move part of this logic to a server-side script.
I suppose this script is an example and displaying numbers is not really what you want to do.
If you are looking for something to run script even when you have left the browser, I suggest you take a look at Service workers.
If you want more resources, you can check Jake Archibald's blog. He is a chrome developer and he is always talking about service workers. An introduction here.
I didn't see any good suggestions posted already for what I was trying to do but I came up with something that worked for me. I wanted to add a navigation element on the page and not have it go away after navigating. This was on a website that was not managed by me. I removed the innerHtml of the body of the page, added an iframe and pointed it at the page I was on, set it to 100% width and height and removed the border. Then I could navigate within the iframe, but still have my script function run in a set timeout to add the navigation element back to the page after it navigated. Something like this:
document.body.innerHTML = ''
iframe = document.createElement('iframe');
iframe.setAttribute('id', 'iframe');
document.body.appendChild(iframe);
iframe.setAttribute('src', window.location.href);
iframe.style.height = "100%";
iframe.style.width = "100%";
iframe.style.border = "0";
function addContent(){
setTimeout(()=>{
elementToAddTo = iframe.contentWindow.document.getElementById('my-element-id')];
contentToAdd = document.createElement('div');
contentToAdd.innerHTML = `<p>My new content</p>`
elementToAddTo.insertBefore(contentToAdd, elementToAddTo.childNodes[0]);
}, 1000);
}
addContent()
Then in that new content somewhere I had an onchange event which would navigate and call the addContent function by saying window.top.addContent();
onchange="window.location.href = window.location.href.replace(/(param1=.*)/, 'param1='+myNewParamValue); window.top.addContent();">
I Understand this approach makes a lot of assumptions about what you're trying to do and maybe it is only working for me because I'm only changing a param value, but I want to leave this hear in case it helps somebody trying to figure out how to do something similar.
I noticed that if I have a gmail tab open with conversation view on/off, and then I open another tab and change the conversation view setting, my original tab stays in the conversation view state it started in such as when doing new searches etc. and the new tab uses the setting I just changed it to.
This led me to think there might be some JavaScript bookmarklet / favelet / "scriptlet" that could easily let us change the setting for a given gmail tab temporarily without having to go into the settings.
Does anyone know of this already in existence or is anyone able to create it? My thought would be to capture a load of gmail with it on and with it off and do a diff / winmerge on the two to see what's different and take it from there, but I'm hoping someone's already created it =).
I'll look into the gmail js and make a bookmarklet :P
Edit: seems the js is obfuscated A lot, copying the function from the original js is gonna be hard...
I'll check what the html changes are between both views and write a js function myself to apply those changes.
I went and instead made it a bit different, I wrote some js that does actually the thing that you would do yourself(it simulates going to settings and changing them).
I made a jsfiddle with a link that can be dragged into the bookmarks bar:
https://jsfiddle.net/randomengineer/0nc4hajp/4/
The bookmarklet code:
javascript:
window.location.hash = 'settings/general';
a = () => document.querySelector('tbody tr:nth-child(13) input:not(:checked)');
b = setInterval(() => {
if(a() != null) {
clearInterval(b);
a().click();
document.querySelector('[guidedhelpid=save_changes_button]').click();
}
}, 5);
Saved settings are just to reload the JS code in the way you prefer, so you are correct it can be made easy to change. seahorsepip did a good one on it, if you need a custom grease script to install to your chrome i would be glad to help.
Love the solution by seahorsepip. I combined it with the "Shortcut Manager" Chrome extension (http://www.makeuseof.com/tag/shortcut-manager-assign-hotkeys-to-various-browser-actions-chrome/) and now I can toggle with a keyboard shortcut!
New solution for 2019 (see Bookmarklet in JavaScript to toggle Gmail conversation view).
This will toggle the current state On/Off and Save:
window.location.href = "https://mail.google.com"+window.location.pathname+"#settings/general";
setTimeout(function() {
convTogs = document.getElementsByName("bx_vmb");
if (convTogs[0].checked) convTogs[1].click();
else convTogs[0].click();
document.querySelector("[guidedhelpid=save_changes_button]").click();
}, 2000);
(Thanks, #Zenoo!)
Note: If you have multiple Gmail accounts open (like me) this will work in your current window (unlike https://mail.google.com/mail/u/0/#settings/general which will go to your default account)
I use JQwidgets ,, I use to print data onclick print-button
as code :
$("#print").click(function () {
var gridContent = $("#jqxgrid").jqxGrid('exportdata', 'html');
var newWindow = window.open('', '', 'width=800, height=500'),
document = newWindow.document.open(),
pageContent =
'<!DOCTYPE html>\n' +
'<html>\n' +
'<head>\n' +
'<meta charset="utf-8" />\n' +
'<title>jQWidgets Grid</title>\n' +
'</head>\n' +
'<body>\n' + gridContent + '\n</body>\n</html>';
document.write(pageContent);
document.close();
newWindow.print();
});
When I close printing-widow(not continue printing), I can't use the grid-scroll (on chrome)..
google-chrome Version 34.0.1847.131 m
This worked fine on Firefox and IE..
How to fix the scroll after closing printing-window on chrome
Fiddle-Demo
It looks like you're not the only one with this issue.
I understand that your code is already setup and you want to run with what you have, but unless someone comes up with a hack or Google decided to fix what is clearly a bug, I think you need to re-think how you are approaching this issue.
If chromeless windows were an option, or if the print dialogue were a modal then you could pull this off with the current strategy, but neither of those options are possible in Chrome. Even if you were able to get around this scrolling issue somehow you're still left with a less than desirable UX problem in that if the user hits "cancel" in the print dialogue then they are left with a still open blank window.
Here is a JS fiddle to demonstrate that you need to change your approach: DEMO
You can see from this demonstration that even if we run a completely separate script from within the new window by passing it as plain text in the content object, it still causes the same issue. This means to me that this is a parent/child type of a relationship that is not easily circumvented with JS.
I recommend 2 alternative possible solutions:
Option1:
<input type="button" value="Print" onclick="window.print(); return false;" />
This triggers a full screen print dialogue that can't be closed from the "Windows Close Button." That way you can avoid the issue all together. Then you can use a combination of JS and Print Styles to target and isolate the information you want to print. I know it's more work but I think may be the better cross-platform solution.
This option is more brute force and simplistic in nature (and you have already commented that you know this but I'm leaving it up because it's still an option).
DEMO
Option2:
User clicks on a link/button that opens a new tab/window
In the same function the data from your table gets loaded into a JSON Object
The JSON object is loaded into a print template in the new tab/window
the template initiates the print function
By taking these actions, I think you will have disassociated the JS instance enough that the new tab will not affect the initiating script.
This is a browser bug - you'd have to find some sort of hack to fix it.
Doesn't sound like you want to put the print dialog code elsewhere thus not affecting your scroll bar. That is the obvious solution but it sounds like you can't do that.
Here's what I would do: Wait until someone has triggered the problematic condition, then put an event listener on the scroll event. when it happens... go ahead and reload the page.
Simple, easy, fun.
var needToReload = false;
$("#print").click(function () {
... as you have
needToReload = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
}
$('#contentjqxgrid').scroll(function () {
if (needToReload) {
window.location.reload();
}
});
$("#jqxscrollbar").jqxScrollBar({
width: 5,
height:180,
theme:'energyblue',
vertical:true
});
$("#jqxscrollbar1").jqxScrollBar({
width: 300,
height:5,
theme:'energyblue'
});
Look at jsfiddle: http://jsfiddle.net/8PtUX/6/
i'm currently working on a function (started after Buttonclick) to print a document in Lotus Notes (IBM Domino Designer 9.0 Social Edition Release 9.0). I have a custom control which creates a new document to the database. After saving the document its opened in read-only-Mode. There you have a button which will redirect you to a new window where the same contents are displayed without any layouts and something else (just the Text). Now its possible to print the page with Ctrl+P. There are two differen xPages for that.
Distribution.xsp
DistributionPrint.xsp
First of all i'm using
path = facesContext.getExternalContext().getRequest().getRequestURL();
to get the current page URL. After that there is an option to replace the current Page of the path (Distribution.xsp) into DistributionPrint.xsp.
var replacePage = #RightBack(path, "/");
path = #ReplaceSubstring(path, replacePage, "DistributionPrint.xsp");
When im testing it the replacement successfully worked. After that i'm bulding a new URL for the specific document to open with the new path. Finally everything is placed into the view.postScript method:
var docid = docApplication.getDocument().getUniversalID();
view.postScript("window.open('"+path.toString() + "?documentId=" + docid + "&action=openDocument"+"')")
Now my Problem starts. At 99% of my trys the new window is opened like i said the programm to do. But there are some kind of documents where i click on the button and he doesn't open a new window and trys to open the old Distribution.xsp url. I already tested out the path he wants to open at these kind of documents by using the debugtoolbar. The result of the button click returns the completly correct URL which should be opened. I can also copy that url and paste it manually into my browser => it works! But if i want to open that URL by a buttonclick and viewPostScript nothing happens.
Has anybody expierenced the same problem like me? Maybe one of you can help me through that problem. Its really annoying that everything works finde at 99% of my documents but at some documents it doesn't work although the given url is 100 percent correct.
Thanks for everyones help!
Try adding you code into a javascript function on the page and call that function from your view.postscript code
Or as Panu suggested add it to onCompete code
If the URL is correct then it sounds like a problem with view.postScript. Try with <xp:this.onComplete>.
Other things to try:
Use var w = window.open(... Plain window.open may change the URL of
current window.
Double check the URL with an alert();
You might be barking up the completely wrong tree. Did you try, instead of creating a second page for printing, create a second CSS stylesheet?
Using #Media Print you can tell the browser to use that stylesheet for printing. There you set all navigational elements to display : none and they won't print.
Removes the need to maintain a separate XPage for the printing stuff.
Thank you everyone for your suggestions. The solution of Fredrik Norling worked for me. I placed the Code into a function and called it at the buttonclick. Now every page is opened as expected. Thank you very much for the help!
I am new to both Javascript and designing for Facebook. I am using Shortstack to create custom tabs and have created a 3 panel sub-tab application using the service. In the 3rd panel, I have 19 div's holding information. By default, I use CSS to hide these DIVs (display:none;) and have a series of links at the top of the panel that change the visibility of each DIV onclick. Only the active onclick content is visible at any time.
The tab functions properly in Firefox, Chrome, and even Safari on the Mac, but fails in all browsers on the PC, and fails differently. In IE, immediately after the swap happens an error message pops up which mentions the publisher not allowing the action in an iFrame. In Firefox the tab just goes blank with no error message.
My script is below. As I stated, I am new to coding for Facebook and working with Javascript as I am a designer and not a programmer, but am eager to learn.
Thank you in advance for your thoughts and ideas.
function showhide(layer_ref) {
var thisDiv;
// check to see if any DIVs are currently showing
var divlist = ["div1","div2","div3","div4","div5","div6","div7","div8","div9","div10","div11","div12","div13","div14","div15","div16","div17","div18","div19"];
// loop through the list of DIVs in "divlist"
for (x = 0; x < divlist.length; x++) {
thisDiv = document.getElementById(divlist[x]);
// if the DIV is showing, hide it
if (thisDiv.style.display == "block") {
thisDiv.style.display = "none";
}
}
// show the appropriate DIV
thisDiv = document.getElementById(layer_ref);
thisDiv.style.display = "block";
}
If you try to change the things in iframe that could be a problem if the iframe is loaded from different domain. It is basically security rule - you don't want to allow rogue code to change/read/write things on the page other than it's own.
To answer your question better we need to know where is changing javascript is located and what it tries to change (are those two things loaded from the same domain or not).
The script itself looks ok to me.