I have HTML form with a textarea and a button which calls the function below when a part of the text is selected. With de id of the clicked button and the selected text I want to call a php script by the POST method.
$(document).ready(function() {
$(".postbit_buttons").on("click", ".quoted_clicked", function() {
var post = this.id;
var selected = GetSelectedText();
alert(" post = " + post + " seleted text = " + selected);
$.post("test_quoted.php", {
pid: post,
selection: selected
})
.done(function() {
alert("done")
});
});
});
Function GetSelectedText() to get the selection was found here.
The first alert is shown with the correct information. However, after clicking OK I get the following error message on the browser console:
TypeError: 'collapse' called on an object that does not implement
interface Selection.
I have used a similar construct in another part of the forum software of which this is a part, and that works.
I have pain in my eyes of staring at this, but cannot find the cause. Is there anybody who can help me on this?
#Rory
The code of function GetSelectedText() is:
function GetSelectedText()
{
var selectedText=(
window.getSelection
?
window.getSelection()
:
document.getSelection
?
document.getSelection()
:
document.selection.createRange().text
);
if(!selectedText || selectedText=="")
{
if(document.activeElement.selectionStart)
{
selectedText = document.activeElement.value.substring(
document.activeElement.selectionStart
. document.activeElement.selectionEnd);
}
}
return selectedText;
}
Thanks to Rory's question I tried things out. I discovered that is was the variable "selected" in which the selected text is stored was the cause of the error. I now use the following version of GetSelectedText():
function GetSelectedText () {
if (window.getSelection) { // all browsers, except IE before version 9
var range = window.getSelection ();
return range.toString ();
}
else {
if (document.selection.createRange) { // Internet Explorer
var range = document.selection.createRange ();
return range.text;
}
}
}
and it works!!
Sorry for bothering you. I do practice programming since 1968, but almost 100% was scientific computing with FORTRAN. Javascript is very new to me.
Regards, Ad Bakker
Related
Could someone please share experience / code how we can detect the browser back button click (for any type of browsers)?
We need to cater all browser that doesn't support HTML5
The 'popstate' event only works when you push something before. So you have to do something like this:
jQuery(document).ready(function($) {
if (window.history && window.history.pushState) {
window.history.pushState('forward', null, './#forward');
$(window).on('popstate', function() {
alert('Back button was pressed.');
});
}
});
For browser backward compatibility I recommend: history.js
In javascript, navigation type 2 means browser's back or forward button clicked and the browser is actually taking content from cache.
if(performance.navigation.type == 2) {
//Do your code here
}
there are a lot of ways how you can detect if user has clicked on the Back button. But everything depends on what your needs. Try to explore links below, they should help you.
Detect if user pressed "Back" button on current page:
Is there a way using Jquery to detect the back button being pressed cross browsers
detect back button click in browser
Detect if current page is visited after pressing "Back" button on previous("Forward") page:
Is there a cross-browser onload event when clicking the back button?
trigger event on browser back button click
Found this to work well cross browser and mobile back_button_override.js .
(Added a timer for safari 5.0)
// managage back button click (and backspace)
var count = 0; // needed for safari
window.onload = function () {
if (typeof history.pushState === "function") {
history.pushState("back", null, null);
window.onpopstate = function () {
history.pushState('back', null, null);
if(count == 1){window.location = 'your url';}
};
}
}
setTimeout(function(){count = 1;},200);
In case of HTML5 this will do the trick
window.onpopstate = function() {
alert("clicked back button");
}; history.pushState({}, '');
You can use this awesome plugin
https://github.com/ianrogren/jquery-backDetect
All you need to do is to write this code
$(window).load(function(){
$('body').backDetect(function(){
// Callback function
alert("Look forward to the future, not the past!");
});
});
Best
In my case I am using jQuery .load() to update DIVs in a SPA (single page [web] app) .
Being new to working with $(window).on('hashchange', ..) event listener , this one proved challenging and took a bit to hack on. Thanks to reading a lot of answers and trying different variations, finally figured out how to make it work in the following manner. Far as I can tell, it is looking stable so far.
In summary - there is the variable globalCurrentHash that should be set each time you load a view.
Then when $(window).on('hashchange', ..) event listener runs, it checks the following:
If location.hash has the same value, it means Going Forward
If location.hash has different value, it means Going Back
I realize using global vars isn't the most elegant solution, but doing things OO in JS seems tricky to me so far. Suggestions for improvement/refinement certainly appreciated
Set Up:
Define a global var :
var globalCurrentHash = null;
When calling .load() to update the DIV, update the global var as well :
function loadMenuSelection(hrefVal) {
$('#layout_main').load(nextView);
globalCurrentHash = hrefVal;
}
On page ready, set up the listener to check the global var to see if Back Button is being pressed:
$(document).ready(function(){
$(window).on('hashchange', function(){
console.log( 'location.hash: ' + location.hash );
console.log( 'globalCurrentHash: ' + globalCurrentHash );
if (location.hash == globalCurrentHash) {
console.log( 'Going fwd' );
}
else {
console.log( 'Going Back' );
loadMenuSelection(location.hash);
}
});
});
It's available in the HTML5 History API. The event is called 'popstate'
Disable the url button by following function
window.onload = function () {
if (typeof history.pushState === "function") {
history.pushState("jibberish", null, null);
window.onpopstate = function () {
history.pushState('newjibberish', null, null);
// Handle the back (or forward) buttons here
// Will NOT handle refresh, use onbeforeunload for this.
};
}
else {
var ignoreHashChange = true;
window.onhashchange = function () {
if (!ignoreHashChange) {
ignoreHashChange = true;
window.location.hash = Math.random();
// Detect and redirect change here
// Works in older FF and IE9
// * it does mess with your hash symbol (anchor?) pound sign
// delimiter on the end of the URL
}
else {
ignoreHashChange = false;
}
};
}
};
Hasan Badshah's answer worked for me, but the method is slated to be deprecated and may be problematic for others going forward. Following the MDN web docs on alternative methods, I landed here: PerformanceNavigationTiming.type
if (performance.getEntriesByType("navigation")[0].type === 'back_forward') {
// back or forward button functionality
}
This doesn't directly solve for back button over the forward button, but was good enough for what I needed. In the docs they detail the available event data that may be helpful with solving your specific needs:
function print_nav_timing_data() {
// Use getEntriesByType() to just get the "navigation" events
var perfEntries = performance.getEntriesByType("navigation");
for (var i=0; i < perfEntries.length; i++) {
console.log("= Navigation entry[" + i + "]");
var p = perfEntries[i];
// dom Properties
console.log("DOM content loaded = " + (p.domContentLoadedEventEnd -
p.domContentLoadedEventStart));
console.log("DOM complete = " + p.domComplete);
console.log("DOM interactive = " + p.interactive);
// document load and unload time
console.log("document load = " + (p.loadEventEnd - p.loadEventStart));
console.log("document unload = " + (p.unloadEventEnd -
p.unloadEventStart));
// other properties
console.log("type = " + p.type);
console.log("redirectCount = " + p.redirectCount);
}
}
According to the Docs at the time of this post it is still in a working draft state and is not supported in IE or Safari, but that may change by the time it is finished. Check the Docs for updates.
suppose you have a button:
<button onclick="backBtn();">Back...</button>
Here the code of the backBtn method:
function backBtn(){
parent.history.back();
return false;
}
may someone of you can help me to find this problem?
I've got an xpage with client-side js-code included which should be executed when you decide to leave the page. In the client-side js you refer to a button and click it automatically. This button got some server-side js code included and change the flag from a document from ("opened by ..." to "").
The thing is that somehow the client-side js did not work in all different browsers except the current IE (10.0.5) and throws the error:
unable to load http://urlofthedocument/... status:0
The funny thing about this is, when I insert an alert()-method right after the click()-method everything works fine in every browser. But as I don't want to include this alert statement I figure out there must be something different to avoid this. (A short pause instead of the alert-method also did not work.)
My CS JS-Code:
window.onbeforeunload = WarnEditMode;
function WarnEditMode(){
if(needUnloadConfirm == true){
var el = window.document.getElementById("#{id:Hidden4SSJS}");
el.click();
//document.open();
//document.write(el);
//document.close();
//alert("You're about to leave the page");
//pause(5000);
}
}
function pause(millis){
var date = new Date();
var curDate = null;
do { curDate = new Date(); }
while(curDate-date < millis)
}
This refers to to button, which executes following SS JS code, after it is clicked:
try{
print("Hidden4SSJS-Button-Test # Person");
var db:NotesDatabase = database;
var agt:NotesAgent;
var doc:NotesDocument = XPPersonDoc.getDocument()
agt = db.getAgent("(XPUnlockDocument)");
agt.run(doc.getNoteID());
}catch(e){
_dump(e);
}
May you guys can help me with this?
I would do this using the XSP object with a hidden computed field (and not your special button)...
Something like this:
function WarnEditMode(){
if(needUnloadConfirm == true){
XSP.partialRefreshGet("#{id:unlockDocCF1}", {
params: {
'$$xspsubmitvalue': 'needToUnlock'
},
onComplete: function () {
alert('You are about to leave this page and the document has been unlocked.');
},
onError : function (e) {
alert('You are about to leave this page and the document has NOT been unlocked.\n' + e);
}
);
}
pause(5000);
}
Then the computed field's javascript would be something like this:
try{
var sval = #Explode(context.getSubmittedValue(), ',');
if (sval == null) return result + " no action.";
if (!"needToUnlock".equals(sval[0])) return result + " no action.";
print("Hidden4SSJS-Button-Test # Person");
var db:NotesDatabase = database;
var agt:NotesAgent;
var doc:NotesDocument = XPPersonDoc.getDocument()
agt = db.getAgent("(XPUnlockDocument)");
agt.run(doc.getNoteID());
return 'document unlocked.';
}catch(e){
_dump(e);
}
I have a site I'm working on which uses ajax to load page segments when js is available - this used to work in all browsers, the only problem being that the browser history was only updated in HTML5 broswers.
I have recently been doing a lot of work on the site and most recently decided to try to sort the history out for html4 browsers, in doing so I have checked the site in IE and found that a problem has developed with the way the data from some of the ajax calls is being displayed (only affecting IE - not FF).
The URLS are structured as follows:
sitename.dev/main_category/sub_category
if I just enter sitename.dev/main_category everything works fine but if I click the link for one of the sub categories at sitename.dev/main_category/sub_category the results are loaded but not displayed properly in IE. If I type the address into the browser for hard reload all works fine
WORKING (through hard reload):
Not working through ajax:
Because it is ajax loaded content I cannot inspect the dom, but my function appears to be firing correctly and the ajax call is returning the correct results.
Here is the code for my ajax call
function leftsort_click(event) { //main sort click (left menu)
var page = window.name, page_index,
api = $('#right_pane').jScrollPane({
showArrows: true,
maintainPosition: false
}).data('jsp');
if (!$(this).hasClass('sort_cat')) {
$('ul.sort_ul li, ul.cat_items li').removeClass('active');
$(this).addClass('active');
var sid = $(this).attr('id');
var title = $(this).html();
var loadUrlx= page;
if ((sid != '') && (sid != 'undefined')) {
loadUrlx += '/'+sid;
}
if($('.rpp_btn.active').length>=1){
var res_per_page = $.trim($('.rpp_btn.active').html());
page_index = $.trim($('.res_page_select.active a').html());
if (($('.rpp_btn.active').hasClass('just_clicked'))||(!$('.res_page_select').hasClass('just_clicked'))) {
page_index = '1';
}
if ((page_index != 1) || (res_per_page != 25)) {
loadUrlx += '/' + page_index + '/' + res_per_page;
}
$('.rpp_btn, .res_page_select').removeClass('just_clicked');
}
loadUrlx = b_url + loadUrlx;
if (History.enabled) {
History.pushState(null, null, loadUrlx);
}
$.ajaxSetup({
cache: false
});
$("#result_area").load(loadUrlx, function() {
$("#result_table").trigger("update");
api.reinitialise();
tsizer();
});
}
}
Any help or suggestions would be very much appreciated
worked this one out, i was injecting a div into a tbody - Ie's not happy about that.
I'm using struts1.3.8. I'm using struts ValidatorPlugIn for generating client side and server side validation messages.
Now client side javascript is generated by validator plugin. If there is any validation errors it is displaying in alert messages. But i want to display them besides the text field.
I'm still now working with alert messages only.. But now requirement changed. I tried but no use...
How to do it?
This is the code generated by plugin
`enter code here` function jcv_handleErrors(messages, focusField) {
if (focusField && focusField != null) {
var doFocus = true;
if (focusField.disabled || focusField.type == 'hidden') {
doFocus = false;
}
if (doFocus &&
focusField.style &&
focusField.style.visibility &&
focusField.style.visibility == 'hidden') {
doFocus = false;
}
if (doFocus) {
focusField.focus();
}
}
alert(messages.join('\n'));
}
Without specific information, all I can really suggest is a variation of the following:
window.alert = function(message){
console.log(message);
}
JS Fiddle demo.
Which simply ensures that any messages passed to alert() get passed, instead, to the console.log().
You could, instead, target the messages to a particular element:
window.alert = function(message) {
var output = document.getElementById('output'),
newTextContainer = document.createElement('p'),
text = document.createTextNode(message);
newTextContainer.appendChild(text);
output.appendChild(newTextContainer);
}
JS Fiddle demo.
Using either of these will break any usage of your alert() function in your page, though. So I'd suggest, instead, creating a new function with the latter example (immediately above) and calling that function, rather than over-writing alert().
With regards to creating a custom function to handle your alerts, as well as specify a particular element to which the new 'alerts' should be appended:
function newAlert(message, elem) {
// message is a string containing the message to display.
// elem is the id of the element into which the message should be displayed,
// defaults to an id of 'output' if no element is specified.
var output = elem ? document.getElementById(elem) : document.getElementById('output'),
newTextContainer = document.createElement('p'),
text = document.createTextNode(message);
newTextContainer.appendChild(text);
output.appendChild(newTextContainer);
}
JS Fiddle demo.
Edited in response to question from OP, below:
Next again submit the form I want to overwrite the previous error message. Not twice display the same message.
There are a couple of ways of doing this, assuming you only want to show the last of the error messages, rather than appending those error messages; in the first example I'm using a while loop to remove the firstChild of the output element and, when empty, appending the new error message:
function newAlert(message, elem) {
var output = elem ? document.getElementById(elem) : document.getElementById('output'),
newTextContainer = document.createElement('p'),
text = document.createTextNode(message);
while (output.firstChild){
output.removeChild(output.firstChild);
}
newTextContainer.appendChild(text);
output.appendChild(newTextContainer);
}
JS Fiddle demo.
An alternative is to get a reference to the first paragraph element in the output element (if one exists, otherwise create one) and then simply overwrite the text in that element:
function newAlert(message, elem) {
var output = elem ? document.getElementById(elem) : document.getElementById('output'),
textContainer = output.getElementsByTagName('p')[0] || output.appendChild(document.createElement('p'));
if (textContainer.firstChild){
textContainer
.firstChild
.nodeValue == message;
}
else {
textContainer
.appendChild(document
.createTextNode(message));
}
}
I am trying to add an attribute when using a wysiwyg editor that uses "createLink" command. I thought it would be trivial to get back the node that is created after the browse executes that command.
Turns out, I am only able to grab this newly created node in IE. Any ideas?
The following code demonstrates the issue (debug logs at bottom show different output in each browser):
var getSelectedHTML = function() {
if ($.browser.msie) {
return this.getRange().htmlText;
} else {
var elem = this.getRange().cloneContents();
return $("<p/>").append($(elem)).html();
}
};
var getSelection = function() {
if ($.browser.msie) {
return this.editor.selection;
} else {
return this.iframe[0].contentDocument.defaultView.getSelection();
}
};
var getRange = function() {
var s = this.getSelection();
return (s.getRangeAt) ? s.getRangeAt(0) : s.createRange();
};
var getSelectedNode = function() {
var range = this.getRange();
var parent = range.commonAncestorContainer ? range.commonAncestorContainer :
range.parentElement ? range.parentElement():
range.item(0);
return parent;
};
// **** INSIDE SOME EVENT HANDLER ****
if ($.browser.msie) {
this.ec("createLink", true);
} else {
this.ec("createLink", false, prompt("Link URL:", "http://"));
}
var linkNode = $(this.getSelectedNode());
linkNode.attr("rel", "external");
$.log(linkNode.get(0).tagName);
// Gecko: "body"
// IE: "a"
// Webkit: "undefined"
$.log(this.getSelectedHTML());
// Gecko: "foo"
// IE: "<A href="http://site.com" rel=external>foo</A>"
// Webkit: "foo"
$.log(this.getSelection());
// Gecko: "foo"
// IE: [object Selection]
// Webkit: "foo"
Thanks for any help on this, I've scoured related questions on SO with no success!
This is the code I've used to get the "parentNode" of the text cursor:
var getSelectedNode = function() {
var node,selection;
if (window.getSelection) {
selection = getSelection();
node = selection.anchorNode;
}
if (!node && document.selection) {
selection = document.selection
var range = selection.getRangeAt ? selection.getRangeAt(0) : selection.createRange();
node = range.commonAncestorContainer ? range.commonAncestorContainer :
range.parentElement ? range.parentElement() : range.item(0);
}
if (node) {
return (node.nodeName == "#text" ? node.parentNode : node);
}
};
I tweaked my IE method to approximate yours. Tested and working IE8, FF3.6, Safari4, Chrome5. I set up a jsbin preview that you can test with.
I have found that selection can get complicated and buggy across browsers. Throw in the magic of browser document editing, and it gets worse!
I took a look at how TinyMCE implements what I am trying to do, and took the same approach to modify jHtmlArea.
Basically, a link is created with a fake href. Then, it finds that dom element by searching for links with that particular href. You can then add any desired attributes and update the href with the actual url.
The solution above by gnarf is a great example of getting a selected node, and will work for most scenarios.
Below is the code for my work around:
var url = prompt("Link URL:", "http://");
if (!url) {
return;
}
// Create a link, with a magic temp href
this.ec("createLink", false, "#temp_url#");
// Find the link in the editor using the magic temp href
var linkNode = $(this.editor.body).find("a[href='#temp_url#']");
linkNode.attr("rel", "external");
// Apply the actual desired url
linkNode.attr("href", url);
It's a hacky workaround, but should work unless somebody makes two identical links.
this.getSelection() seems to get the same in both needed browser, so:
var link=prompt('gimme link');
//add the thing
var text=this.getSelection();
var whatYouNeed=$('a:contains("'+text+'")[href="'+link+'"');