Setting cursor position in a contentEditable div - cross browser - javascript

I am facing a problem with setting cursor position in a contentEditable div and seek some assistance.
I have already looked at several SO and other online solutions without success, including:
jquery Setting cursor position in contenteditable div, and
Set cursor position on contentEditable <div> and many other online resources.
Basically, we are using a Telerik Editor with the contentAreaMode set to DIV which forces it to use a contentEditable div instead of an iFrame. When a user clicks in the editor, we wish to be able to move the cursor to the click point so the user may enter/edit content wherever they wish in the editor. Using the example code below, I am able to set the cursor position in FF, Chrome, and IE9 to AFTER the inner div. However, in IE8 (which falls into the else if (document.selection) block), I am unable to get the cursor position to move after the div, so any typed text ends up either before or inside the div - never after. I would be GREATLY appreciative of any help.
ADDITIONAL INFO: Need this to work in IE8 standards document mode - NOT in Quirks mode (which does work).
UPDATE: Here is a jsfiddle of the issue to play with: http://jsfiddle.net/kidmeke/NcAjm/7/
<html>
<head>
<style type="text/css">
#divContent
{
border: solid 2px green;
height: 1000px;
width: 1000px;
}
</style>
<script type="text/javascript">
$(document).ready(function()
{
$("#divContent").bind('click', function()
{
GetCursorPosition();
});
$("#divContent").bind('keydown', function()
{
GetCursorPosition();
});
});
function GetCursorPosition()
{
if (window.getSelection)
{
var selObj = window.getSelection();
var selRange = selObj.getRangeAt(0);
cursorPos = findNode(selObj.anchorNode.parentNode.childNodes, selObj.anchorNode) + selObj.anchorOffset;
$('#htmlRadEdit_contentDiv').focus();
selObj.addRange(selRange);
}
else if (document.selection)
{
var range = document.selection.createRange();
var bookmark = range.getBookmark();
// FIXME the following works wrong when the document is longer than 65535 chars
cursorPos = bookmark.charCodeAt(2) - 11; // Undocumented function [3]
$('#htmlRadEdit_contentDiv').focus();
range.moveStart('textedit');
}
}
function findNode(list, node)
{
for (var i = 0; i < list.length; i++)
{
if (list[i] == node)
{
return i;
}
}
return -1;
}
</script>
</head>
<body>
<div id="divContent" contentEditable="true">
<br>
<div style="background-color:orange; width: 50%;">
testing!
</div>
</div>
</body>
</html>

Using Rangy (disclosure: I'm the author) works for me in IE 7 and 8 in the window load event. Trying to move the caret when the user clicks on an editable element is a bad idea: it conflicts with default browser behaviour hence may not work, and does not do what he user expects (which is to place the caret at or near where they clicked).
<html>
<head>
<style type="text/css">
#divContent
{
width: 1000px;
height: 1000px;
border: solid 2px green;
padding: 5px
}
</style>
<script src="http://rangy.googlecode.com/svn/trunk/currentrelease/rangy-core.js"></script>
<script type="text/javascript">
window.onload = function() {
rangy.init();
var el = document.getElementById("divContent");
el.focus();
var range = rangy.createRange();
range.setStartAfter(el.getElementsByTagName("div")[0]);
range.collapse(true);
rangy.getSelection().setSingleRange(range);
};
</script>
</head>
<body>
<div id="divContent" contentEditable="true">
<br>
<div style="background-color:orange; width: 50%;">
testing!
</div>
</div>
</body>
</html>

Related

Change text colour on text scroll

I am using the Neve Theme on WordPress for my website development and I am customizing my header block and I am having an issue. I am using a plugin to give my header a background after 100px on scroll of the page this changes the background colour to where the text in the header is difficult to read.
The plugin offers the functionality to change the text colour but Neve overrides anything this plugin or myself can do through it. This way I am wondering if there is a way I can change the text colour through code after 100px of scroll on the website. The classes for the content are as follows
a.button.button-primary & .book-now-header * header.header
header.header is for the entire header block so that is used to change the background colour and the other 2 are for the content needing to change colour.
Any help with this would be appreciated as I am unsure where to begin.
this code below is detect the element scroll postition you can put the result in equation but first change number of position to hex and then use it with color you have and that will change color in your text
let lastPostition = 0;
function myFunction() {
const element = document.getElementById("myDIV");
let x = element.scrollLeft;
let y = element.scrollTop;
document.getElementById ("demo").innerHTML = "Horizontally: " + x.toFixed() + "<br>Vertically: " + y.toFixed();
console.log(lastPostition);
if(y.toFixed() === lastPostition ){
alert("the end of document");
}
lastPostition = y.toFixed()
}
<!DOCTYPE html>
<html>
<style>
#myDIV {
height: 250px;
width: 250px;
overflow: auto;
}
#content {
height: 800px;
width: 2000px;
background-color: coral;
}
</style>
<body>
<h1>The Element Object</h1>
<h2>The scrollTop and scrollLeft Properties</h2>
<p>Scroll the content below to display the number of pixels it is scrolled.</p>
<div id="myDIV" onscroll="myFunction()">
<div id="content">Scroll me!</div>
</div>
<p id="demo"></p>
</body>
</html>
let lastPostition = 0;
function myFunction() {
const element = document.getElementById("myDIV");
let x = element.scrollLeft;
let y = element.scrollTop;
document.getElementById ("demo").innerHTML = "Horizontally: " + x.toFixed() + "<br>Vertically: " + y.toFixed();
if(y.toFixed() === lastPostition ){
alert("the end of document");
}
lastPostition = y.toFixed()
}

How can I make this javascript marquee manually scrollable?

I am trying to make an automatic scrolling marquee using javascript and CSS but, I also want to be able to manually scroll the marquee with the mouse wheel. The marquee functions as expected ie. it scrolls automatically and loops well but I can't figure out how to incorporate manual scrolling. Here is the code that I am using. Any ideas?
<doctype HTML>
<body onload="init()">
<main>
<div id="marquee_replacement" class="scrollbar" onmouseout="startit();" onmouseover="stop();">
<p>some text some text some text some text some text some text some text some text</p>
<p>some text some text some text some text some text some text some text some text</p>
<p>some text some text some text some text some text some text some text some text</p>
<p>images are also present</p>
<p class="spacer"></p>
</div>
<script type="text/javascript">
//
var speed = 2; // change scroll speed with this value
/**
* Initialize the marquee, and start the marquee by calling the marquee function.
*/
function init() {
var el = document.getElementById("marquee_replacement");
el.style.overflow = 'hidden'; //issue is fixed by setting this to auto
scrollFromBottom();
}
var go = 0;
var timeout = '';
/**
* This is where the scroll action happens.
* Recursive method until stopped.
*/
function scrollFromBottom() {
clearTimeout(timeout);
var el = document.getElementById("marquee_replacement");
if (el.scrollTop >= el.scrollHeight - 150) {
el.scrollTop = 0;
};
el.scrollTop = el.scrollTop + speed;
if (go == 0) {
timeout = setTimeout(scrollFromBottom, 50);
};
}
/**
* Set the stop variable to be true (will stop the marquee at the next pass).
*/
function stop() {
go = 1;
}
/**
* Set the stop variable to be false and call the marquee function.
*/
function startit() {
go = 0;
scrollFromBottom();
}
</script>
<!--CSS for Marquee-->
<style type="text/css">
#marquee_replacement.scrollbar {
width: auto;
height: 150px;
overflow-y: scroll; /*issue is fixed by setting this to auto*/
}
.scrollbar::-webkit-scrollbar {
display: none;
}
#marquee_replacement {
-ms-overflow-style: none;
/* IE and Edge */
scrollbar-width: none;
/* Firefox */
}
#marquee_replacement p.spacer {
height: 150px;
}
</style>
</main>
</body>
Edit:
Sorry for the newbie mistake of not providing a minimal reproducible example. I will update the code above to provide an MREX so that the issue is easier to understand for future readers. Also, I solved the issue. If I set the overflow values in both CSS and javascript portions to auto instead of scroll and hidden respectively it works as an auto-scrolling marquee and manual scrolling text box.
setTimeout takes a function, not a string with code. Do it like this: setTimeout(scrollFromBottom, 50)
I figured it out. If anyone needs this in the future I had to set el.style.overflow = 'auto';to auto instead of hidden and set the CSS overflow to overflow-y: auto; to auto instead of scroll. Now it scrolls automatically and manually!

How to show div with slide down effect only with javascript

I Want to show div on click with slideup effect using javascript(not jquery).
Here is my HTML code:-
<div class="title-box">show text</div>
<div class="box"><span class="activity-title">our regions bla bla</span></div>
Kindly advise me asap.
The question states that the solution needs to be done with pure JavaScript as opposed to jQuery, but it does not preclude the use of CSS. I would argue that CSS is the best approach because the slide effect is presentational.
See http://jsfiddle.net/L9s13nhf/
<html><head>
<style type="text/css">
#d {
height: 100px;
width: 100px;
border: 1px solid red;
margin-top: -200px;
transition: margin-top 2s;
}
#d.shown {
margin-top: 100px;
}
</style>
</head>
<body>
<button id="b">Toggle slide</button>
<div id="d">Weeeeeeee</div>
<script type="text/javascript">
var b = document.getElementById('b');
var d = document.getElementById('d');
b.addEventListener('click', function() {
d.classList.toggle('shown');
});
</script>
</body></html>
The basic algorithm is to add a class to the element you want to slide in/out whenever some button or link is clicked (I'd also argue that a button is more semantically appropriate here than an anchor tag which is more for linking web pages).
The CSS kicks in automatically and updates the margin-top of the sliding element to be visible on-screen. The transition property of the element tells the browser to animate the margin-top property for two seconds.
You can try below code:
Working Demo
document.getElementById('bar').onclick = (function()
{
var that, interval, step = 20,
id = document.getElementById('foo'),
handler = function()
{
that = that || this;
that.onclick = null;
id = document.getElementById('foo');
interval =setInterval (function()
{
id.style.top = (parseInt(id.style.top, 10) + step)+ 'px';
if (id.style.top === '0px' || id.style.top === '400px')
{
that.onclick = handler;
clearInterval(interval);
if (id.style.top === '400px')
{
id.style.display = 'none';
}
step *= -1;
}
else
{
id.style.display = 'block';
}
},100);
};
return handler;
}());
You can refer following below:
<div class="title-box">
show text
</div>
<div class="box" id="slidedown_demo" style="width:100px; height:80px; background:#ccc; text-align:center;">
<span class="activity-title">our regions bla bla</span>
</div>

How to override standard browser print and print an iframe by default

I have a documentation type page with an iframe inside. I'm trying to override standard browser print (Ctrl + p) to print contents of an iframe only.
I know how to print an iframe content using javascript:
window.frames['webcontent'].focus();
window.frames['webcontent'].print();
I know how to do run javascript before printing e.g. as described here: Check for when a user has selected to print using javascript
Any advise?
Thanks
It can be easily achieved through CSS: See thisJSfiddle: Tested
<style>
#media print{
body * {display:none;}
.toPrint{display:block; border:0; width:100%; min-height:500px}
}
</style>
Let an HTML File be:
<body>
<h3>I do not want this title Printed</h3>
<p> This paragraph should not be printed</p>
<iframe class="toPrint" src="http://akitech.org"></iframe>
<button onclick="window.print()">Print</button>
</body>
It's not possible (using Javascript). There is some experimental support for user-initiated print events in modern browsers, but those are not cancelable ("simple events") so the entire page will still print even if you interject custom code to print the frame of interest.
Given this limitation, your best bet is probably to offer users a large button that fires your custom frame printing function (see printContentFrameOnly below, fire it without arguments) and hope that they'll use the button instead of ctrl-p.
If it would be possible, this would be the way to do it (based on this answer):
// listener is a function, optionally accepting an event and
// a function that prints the entire page
addPrintEventListener = function (listener) {
// IE 5.5+ support and HTML5 standard
if ("onbeforeprint" in window) {
window.addEventListener('beforeprint', listener);
}
// Chrome 9+, Firefox 6+, IE 10+, Opera 12.1+, Safari 5.1+
else if (window.matchMedia) {
var mqList = window.matchMedia("print");
mqList.addListener(function (mql) {
if (mql.matches) listener(); // no standard event anyway
});
}
// Your fallback method, only working for JS initiated printing
// (but the easiest case because there is no need to cancel)
else {
(function (oldPrint) {
window.print = function () {
listener(undefined, oldPrint);
}
})(window.print);
}
}
printContentFrameOnly = function (event) {
if (event) event.preventDefault(); // not going to work
window.frames['webcontent'].focus();
window.frames['webcontent'].print();
}
addPrintEventListener(printContentFrameOnly);
The idea is to set the iframe content somewhere on the page, and print ONLY that content, by hiding the original content.
This can be done by getting the iframe content when Ctrl+P event is being initiated (via JavaScript), and print only its content (via CSS #media type).
HTML Code:
<div id="dummy_content"><!-- Here goes the iframe content, which will be printed --></div>
<div id="content_wrapper">
<div id="current_content">Current Content that the user see<div>
<iframe id="myIframe" src="iframe.html"></iframe>
</div>
CSS Code:
#media screen {
#dummy_content {
display:none; /* hide dummy content when not printing */
}
}
#media print {
#dummy_content {
display:block; /* show dummy content when printing */
}
#content_wrapper {
display:none; /* hide original content when printing */
}
}
JavaScript Code:
var dummyContent = document.getElementById("dummy_content");
function beforePrint() {
var iFrame = document.getElementById("myIframe");
dummyContent.innerHTML = iFrame.contentWindow.document.body.innerHTML; // populate the dummy content (printable) with the iframe content
}
document.onkeydown = function(e) {
if (e.ctrlKey && e.keyCode == 80) {
beforePrint();
}
}
You can define a css file for printing:
#media print {
* { display: none; }
iframe { display: block; }
}
EDIT
Mybad didnt tested it.
* { display: none; } is somehow overwriting all
But this is working like a charm
http://jsfiddle.net/c4e3H/
#media print {
h1, p{ display: none; }
}
The only way i can think of is hiding all the content in the document except for the iframe and making it fit the whole document.
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<style type="text/css">
body.hide *, body #backdrop
{
display: none !important;
}
body.hide #my_print_iframe, body.hide #backdrop
{
background: white;
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
border: 0;
width: 100%;
height: 100%;
display: block !important;
}
#media print {
body.hide #backdrop
{
display: none !important;
}
}
</style>
<script>
$(document).on('keydown', function(e){
if (e.keyCode == 80 && ( e.metaKey || e.ctrlKey ) ) {
$("body").addClass('hide');
setTimeout(function(){
$("body").removeClass('hide');
},1000)
}
})
</script>
</head>
<body>
<div>
this is some visible text
</div>
<iframe id="my_print_iframe" src="//example.com"></iframe>
</body>
</html>
I used timeout ( nasty i know ) because at least chrome 38 does not send the keyup event after ctrl+p
Hi might be this code will help you..
function PrintElem(elem)
{
Popup($(elem).html());
}
function Popup(data)
{
var mywindow = window.open('', 'printMe', 'height=400,width=600');
mywindow.document.write('<html><head><title>Print Me</title>');
mywindow.document.write('</head><body >');
mywindow.document.write(data);
mywindow.document.write('</body></html>');
mywindow.print();
mywindow.close();
return true;
}
and call the function PrintElem('iframe') on you page.

Textarea scrollbar doesn't disappear despite width:0;

No scrollbar in Chrome, but in Firefox and IE, it doesn't disappear although the element width is 0:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Textarea Scrollbar</title>
<style>
textarea {
height: 200px;
width: 0;
margin: 0;
border: 0;
padding: 0;
}
</style>
</head>
<body>
<textarea id="textarea">
Hello, world!
...
</textarea>
<input type="text" value="0" id="input" oninput="resize();">
<script>
function resize() {
document.getElementById('textarea').style.width = document.getElementById('input').value + 'px';
}
</script>
</body>
</html>
DEMO
What's the reason? What's a cross-browser solution so the textarea behaves like in Chrome?
Try overflow:hidden; in the css for the text area attributed ID
EDIT
DEMO
Javascript
//this function attaches eventListener to the element and it is compatible with legacy browsers as well
function attach(element,listener,ev,tf){
if(element.attachEvent) {
//support for older IE (IE7 inclusive)
element.attachEvent("on"+listener,ev);
}else{
//modern browsers
element.addEventListener(listener,ev,tf);
}
}
var newInterval; //we use this to set interval and check say every 200 milliseconds
//whether the *height* of our *textarea* has changed and if it has
//than we set its *overflow* to *auto*, so the *scrollbar* will be
//visible, but when the *height* is *less or equal to 200* we set
//its *overflow* to *hidden*, so the *scrollbar* isn't visible!
var textarea = document.getElementById('textarea');
var input = document.getElementById('input');
//here we check if the value of our input element has changed than we change the width of our textarea
attach(input,'input',function(){
textarea.style.width = input.value + 'px';
},false);
//when our textarea recieves focus (is clicked on) we start running the interval and
//check every 200 milliseconds if the height of the textarea is equal or greater than
//200px we set its overflow to auto so the scrollbar becomes visible, and when the
//height is equal or less than 200px we set our textareas overflow to hidden, so no
//scrollbar is visible
attach(textarea,'focus',function(){
newInterval = setInterval(function(){
height = textarea.scrollHeight;
if(height>=200){
textarea.style.overflow = 'auto'
}else textarea.style.overflow = 'hidden';
},200);
},false);
//here we clear our interval, as our textarea has lost focus
// and there is no need to further run our interval
attach(textarea,'blur',function(){ clearInterval(newInterval); },false);
HTML
<textarea id="textarea">
Hello, world!
...
</textarea>
<input type="text" value="0" id="input" oninput="resize();">
CSS
textarea{
height: 200px;
width: 0;
margin: 0;
border: 0;
padding: 0;
overflow:hidden;
border:1px solid red;
}

Categories

Resources