"Opening"/Divinding an HTML paragraph - javascript

This question could be an interesting problem to solve…
On a web page that displays a text, I need a specific behavior : when the user clicks on some special words, an explanation of this word opens just below the clicked word. All the problem is : it should really open below the words, like "opening" the paragraph in two, without making the text that follows to jump to the next line.
I found a solution that works pretty well, using the CSS float property.
You can see it there (would speak more than the code below) : http://jsfiddle.net/3gwzx/3/
The main problem of this solution, is that it uses nested span. And, as span aren't block tags, the padding wouldn't work with them. So, inside the gray box, the text will never have any horizontal padding (vertical padding is ok) - otherwise it changes the size of the box itself - or did I missed something ? - And that's bad. Has anybody got a solution ? Should I rethink the problem in a whole other way ?
Thanks you very, very much !
Here is what the HTML looks like :
<body onload="putListeners()">
<p>This is the normal text here, you cannot click it. But some words needs long
explanations, like this one : <span class="note">click on me
<span class="noteTxt">The explanation begins here <a class="foo" href="bar.html"> and
could have link</a> that one should be able to click.
And the note can be loooong, long, long, very, very long.
</span>
</span>
And here, the text carry on. It could carry on for a long, long time.
And with all the other solutions I tried, this part of the text "jumps" after the note,
on a new line, when it appears. What I like here is that, when you open the note,
it really "open the paragraphs in two". But i cannot give a padding
to those nested span… I should have a div… but you cannot put a div
inside a span !</p>
</body>
Here is the JS
function putListeners() {
//just listens to the text…
var elements = document.getElementsByClassName("note");
for (var i = 0; i < elements.length; i++) {
elements[i].addEventListener("click", showNote, false);
}
};
function showNote()
{
//content to show
var currentTxt;
//finds the nested noteTxt
for (var i = 0; i < this.childNodes.length; i++) {
if (this.childNodes[i].className == "noteTxt") {
currentTxt = this.childNodes[i];
break;
}
}
//displays it or hides it
if(currentTxt.style.display=="none" || currentTxt.style.display=="")
{
currentTxt.style.display="block";
}
else
{
currentTxt.style.display="none";
}
return true;
};
And, for information, the relevant part of the CSS (you probably figured out what it looks like - complete code in the Jfiddle) :
span.note {
position: static;
}
span.note span.noteTxt {
display: none;
float: left;
color: black;
width: 100%;
background-color: #eaeaea;
}

If you want to change the layout behavior of a tag, in your case <span> you can set css property display: block to change it to a div style layout.
span.asblock {
display: block;
}
this will give you a span that behaves like a div.

Related

How to change text to invisible, but still show underline?

I made a studying tool using Javascript and PHP. There's a toggle that shows/hides keywords in a paragraph, so the user can mentally "fill in the blanks".
How I've done this so far is that the all the keywords are underlined, and I use a DOM selector to select all innerHTML in u tags.
<p>
Example sentence, <u>this</u> is a <u>keyword</u>.
</p>
<button onClick='hideKeywords()'>Hide Keywords</button>
<script>
function hideKeywords() {
var x = Array.from(document.getElementsByTagName('u'));
for (var i = 0; i < x.length; i++) {
x[i].style.visibility = "hidden";
}
}
</script>
This works as intended - the "keywords" are blanked out and the flow of the document is unaffected, since the keywords still take up the same space that they would normally take.
One downside is that in paragraphs with particularly long "keywords", the paragraph's line structure is disrupted and it looks like text is just floating randomly in space. This would be fixable if I could somehow change visibility such that the words in the keywords are hidden and the text-decoration (underline) still shows. This retains the line structure.
I thought about using Javascript to replace every character in the keyword with underscores, but two more problems pop up. One thing is that even if the number of characters stay the same, the width might change.. For example, "apple" is not the same physical length as "______". This is not ideal as the document flow would change. A second problem is that I can't think of any way to get the keywords back after converting them into underscores.
One workaround is instead of changing the visibility to "hidden", I could change the background-color to the same color as the text. This blocks out the text, but the line structure and document flow are both preserved. However, I do hope to find a way to implement my original idea, so any suggestion is appreciated!
Update: I would prefer not to add any additional divs to the keywords. The user can add new entries using a rich text editor, so declaring a keyword is as easy as underlining it in the text editor.
You can do it with css adding a pseudo-element and instead of using visibility hidden, using color: transparent, like this:
u{
position:relative;
}
u::after{
content: ' ';
display:block;
position:absolute;
bottom:0;
left:0;
width: 100%;
height:1px;
background-color:#000;
}
And in the script
<script>
function hideKeywords() {
var x = Array.from(document.getElementsByTagName('u'));
for (var i = 0; i < x.length; i++) {
x[i].style.color = "transparent";
}
}
</script>
https://codepen.io/anon/pen/ROoMaM
I would probably implement this using your second method. Set the text colour to the same as the background then add a bottom border to the element. Preserves the spacing and allows you to quickly check if you are right by just highlighting the line. Also, if you give the keyword wrapper element a class you can easily just toggle the color of the hidden text, and retain the underlines so you can see what has changed.
div {
color: black;
}
span {
color: white;
text-decoration: none;
border-bottom: 2px solid green;
}
<div>
This <span>is hidden</span> with an underline
</div>
You'd have to find some way to get the div positioned under the hidden text, but you can use the following code to create a div with the width of the text. I might come back later after answering and find a way to position the div.
In your HTML, let's say you have a phrase, foo bar, that you want hidden. You will assign an id to it with the code: <p id="foo">foo bar</p>
Here is the CSS:
#foo {
position: absolute;
visibility: hidden;
height: auto;
width: auto;
white-space: nowrap;
}
Then in your Javascript, you can use the following code:
var fontSize = 20; //this defines a font size
var foo = document.getElementById("foo");
foo.style.fontSize = fontSize; //this sets the style as the font size
var width = (foo.clientWidth) + "px"
var div = document.createElement("div");
div.style.width = width;
div.style.height = 2px;
div.style.background = "red"; //makes the underline visible
document.getElementById("main").appendChild(div);
From here, you could probably just reposition the div how you want so it appears under the text. This way, the div is the exact length of the text.
An alternative solution would be to use a monospace font and then manually calculuate the width.

CKEditor break <div>

CKEditor works great. There is just minor thing which I would like to improve
We have message system which uses CKEditor. The original (old) text is in a with a vertical blue line. See the screenshot:
I would like to break the <div>.
Up to now I found no way to break it.
In my case a RETURN key should break the <div>.
You can config the enter key with the following modes:
ENTER_P – new <p> paragraphs are created;
ENTER_BR – lines are broken with <br> elements;
ENTER_DIV – new <div> blocks are created.
So in your case, to break a div:
CKEDITOR.replace( 'textarea_id', {
enterMode: CKEDITOR.ENTER_DIV
});
Here are the docs for ENTER_BR
If setting enterMode = CKEDITOR.ENTER_DIV doesn't work for you, another solution is to capture the enter keypress and manually break the div by:
1) inserting a closing </div> tag to split the blue line div, creating the upper half.
2) inserting a new tag <div class="novertline"> which opens a div without a vertical line - This is the break.
3) insert a closing </div>
4) insert another which makes the bottom half of the split text retain its vertical line.
Because insertHtml doesn't allow splitting a div, I used insertText with a flag to subsequently replace with my html.
CKEDITOR.instances.textarea.on( 'key', function (evt) {
if (evt.data.keyCode == 13){
CKEDITOR.instances.textarea.insertText('SOME FLAG');
var data = CKEDITOR.instances.textarea.getData();
data = data.replace('SOME FLAG', '</div><div class="novertline"></div><div class="vertline">');
CKEDITOR.instances.textarea.setData(data);
}
});
In my ckeditor.css file, I added my two classes - but you obviously already have your equivalent div class which is creating the blue line:
.vertline {
margin-left: 10px;
border-left: 1px solid blue;
height: 100%;
}
.novertline {
margin-left: 10px;
border-left: none;
height: 100%;
}
This will need to be customized to your situation. However, it does break the div as you require.

Drawing links among words in a web page

I would like to know if something like this (see the picture above) is possible in HTML/CSS/Javascript and if so, what are the frameworks/technology that I should look at.
I have a text in a HTML page and I would like to highlight some words in it using different colours according to different meanings (let's say 3 types, 'name of software': blue, 'numbers': grey, 'name of people: 'red'). Then, an this is the tricky part for me, I would like to draw directed arrows among these highlighted words in a way that resizing the window will automatically keep anchored the arrows regardless to the changed position of the words.
Right now I am solving the highlighting part using a particular tag for the words to be highlighted and an ad-hoc CSS decorator with the property background colour accordingly set. The linking part is literally a mystery for me.
I thank you all for your help,
michele.
PS. I would prefer doing that on the client side.
You need to do loads of JavaScript code for this but I will simply tell you the steps. To achive your goal you need to:
parse every word in your paragraph by using split() method.
var words = yourparagraph.split(" ");
create an array that contains called name_of_software and push the software names in this array.
do the very above thing for people names and call the array people_names.
var name_of_software = ["html", "css", "javascript"];
var people_names = ["michele", "george", "john"];
create corresponding css for the highlightings.
span.red { background: red; overflow: hidden; display: block; }
span.grey { background: grey; overflow: hidden; display: block; }
span.blue { background: blue; overflow: hidden; display: block; }
Do a loop like this:
.
for(var i = 0; i < words.length; i++)
{
if($.inArray(words[i].toLowerCase(), name_of_software)) {
// The word is a name of a software. Give blue class.
} else if($.inArray(words[i].toLowerCase(), people_names)) {
// The word is a name of a person. Give red class.
} else if(isNaN(words[i])) {
// The word is a number. Give grey class.
}
}
I didn't test it or create a working version of it. Hope this steps will guide you to achive your goal.

textarea immitation is not working well. any replacements?

I have this html and css: http://jsfiddle.net/b7rDL/6/
HTML:
<div class="text-block" contenteditable="true" spellcheck="false">Some Text</div>
css:
.text-block {
resize: none;
font-size:40px;
border: none;
line-height: 1;
-moz-appearance: textfield-multiline;
-webkit-appearance: textarea;
min-width: 30px;
overflow: visible;
white-space: nowrap;
display: inline-block;
}
This code allows me to write text with no width limit or height limit. It displays no scroll bar and it grows with the text. Those are basically the features I need.
How can I convert this to regular textarea that will act the same? I want this to work on browser that doesn't implemented "contenteditable". Therefore I want to replace the div with textarea or other basiv element. How can I do it? (I don't mind using JavaScript).
How can I disable the spellchecker? spellcheck=false doesn't work. In the example, when I focus on the text box, I get that buggy red line. I am using Firefox.
How can I get rid of the border when I am focused? - SOLVED
I don't mind using JavaScript to solve those issues.
Any answer for those questions will help me.
Thanks
UPDATES:
#Oylex helped me with 3
#1
Working fiddle is here: http://jsfiddle.net/d9H9w/11/ (tested in IE8, Chrome and Firefox)
What you need is to set the width and height attributes as a user is typing within a text box.
Height
This is pretty straightforward:
Get the content of the textarea
Match for newline characters
Set the height to total number of newline characters(plus one for the first line and 1.5 for wiggle room) in em's.
Setting the height in em's makes this font-size agnostic, so it'll work with multiple font-sizes.
function getNewlines(){
// get the value(text) of the textarea
var content = textEl.value;
//use regex to find all the newline characters
var newLines = content.match(/\n/g);
// use the count of newlines(+1 for the first line + 1 for a buffer)
// to set the height of the textarea.
textEl.style.height = ((newLines && newLines.length || 0)+2.5)+'em';
};
Width
This is fairly easy, too, with one gotcha.
Get the content of the textarea
Split on newline characters to get an array consisting of lines of the textarea
Sort to get the longest line
Set the width to the length of the longest string in em's, multiplied by about .6(emRatio in my code), plus 2 ems for buffer space.
That last part is the kicker. The 'em' measurement is supposed to be a square representing the width and height that a single character takes up. This doesn't take kerning into account, so the height of a char is usually accurate, but the width is dependent on the chars around it. So, by guess and check, I figured that .6 em is about the average width of a character after kerning. .6 is pretty close, so I add 2 ems to the width for a bit of buffer space.
var emRatio = .6;
function longestLine(){
// get the value(text) of the textarea
var content = textEl.value;
// split on newline's. this creates an array, where each item in
// the array is the text of one line
var a = content.split('\n');
// use a sorting function to order the items in the array:
// longest string to shortest string
a.sort(function(a,b){return b.length - a.length});
// use the longest string * the emRatio to set the width
// Due to kerning, the letters aren't ever really 1em x 1em
// So I'm multiplying by an approximate ratio here (guess and check)
textEl.style.width = (a[0].length * emRatio + 2)+ 'em';
};
Existing problems with this implementation
To support resizing during long-held key presses, an onkeydown handler has to be included as well(this is not optimal for all cases that don't include long key presses)
All things considered, I think this fits what you need.
EDITS
Instead of having emRatio be .7, I changed it to .6 and added a buffer of 2 ems to the width. This addresses both issues #Naor mentioned in his comments.
I've updated the fiddle link and the Width section to reflect the changes.
EDIT 0
Request #1 Update
Working Solution: http://jsfiddle.net/7aeU2/
JQuery
$(function() {
// changes mouse cursor when highlighting loawer right of box
$("textarea").mousemove(function(e) {
var myPos = $(this).offset();
myPos.bottom = $(this).offset().top + $(this).outerHeight();
myPos.right = $(this).offset().left + $(this).outerWidth();
if (myPos.bottom > e.pageY && e.pageY > myPos.bottom - 16 && myPos.right > e.pageX && e.pageX > myPos.right - 16) {
$(this).css({ cursor: "nw-resize" });
}
else {
$(this).css({ cursor: "" });
}
})
// the following simple make the textbox "Auto-Expand" as it is typed in
.keyup(function(e) {
// the following will help the text expand as typing takes place
while($(this).outerHeight() < this.scrollHeight + parseFloat($(this).css("borderTopWidth")) + parseFloat($(this).css("borderBottomWidth"))) {
$(this).height($(this).height()+1);
};
});
});​
Request #2 Update
Also, here's a good explanation of why you can't outright disable spell check.
This does not belong to the realm of CSS (which is optional
presentational suggestions). It is not about stylistic features of
rendering data but about processing data interactively.
On browsers that support “spell checking” (which may involve grammar
and style checks), the HTML attribute spellcheck or the corresponding
IDL (DOM) attribute, settable in JavaScript, is effective.
In practice, those browsers tend to have “spelling checking” enabled
by default for textareas only, and as textareas normally contain human
language texts, turning it off does not sound useful. It is in any
case user-controllable (the user can switch it off or select
language).
via https://stackoverflow.com/a/9209791/1085891
Request #1
Simple Solution is pretty straight forward.
Working example: http://jsfiddle.net/b7rDL/12/
JQuery
$("#Solution0").keyup(function(e) {
while($(this).outerHeight() < this.scrollHeight) {
$(this).width($(this).width()+50);
};
});
HTML
<textarea id="Solution0" rows="1" style="height: 1.2em;"></textarea>
Fancier solution that will require some updating if you want the
width, rather than the height, to expand. Still, it's pretty nice.
http://jsfiddle.net/edelman/HrnHb/
https://github.com/ultimatedelman/autogrow
Other solutions - I know these all expand height. Let me know if you need width implementation of one of the below solutions.
http://bgrins.github.com/ExpandingTextareas/
http://blogs.sitepointstatic.com/examples/tech/textarea-expander/index.html
http://code.google.com/p/xautoresize-jquery/downloads/list
http://www.impressivewebs.com/textarea-auto-resize/
http://www.technoreply.com/autogrow-textarea-plugin-3-0/
Request #2
spellcheck="true" should work as described in the Mozilla docs: Controlling spell checking in HTML forms. It works for me in my first simple example running in Firefox 13.0.1. What version are you running?
for #3, the css option you are looking for is: outline: none;
I was having trouble figuring out the bounds of the textarea's content, so with this approach I'm copying the content of the textarea into a similarly styled p element, which is set to float: left; and then resizing the textarea based on the size of the p. This handles both width and height.
I've tested on Mac 10.8.1 FF 18.0, Safari 6.0, Chrome 25.0.1362.0 canary, iOS Safari 6.0.1 and iOS Simulator 5.1 (272.21). I don't have a PC or IE handy.
http://jsfiddle.net/b7rDL/34/
HTML
<textarea id="tx" class="text-block" spellcheck="false"></textarea>
<p id="dupe" class="text-block"></p>
CSS
.text-block {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
resize: none;
font-size:14px;
border: none;
line-height: 1;
min-width: 30px;
overflow: hidden;
white-space: pre;
display: block;
outline: none;
width: 30px;
height: auto;
border: 1px solid #ddd;
background-color: #f7f7f7;
}
#dupe {
float: left;
display: none;
width: auto;
height: auto;
}
I added a background and border so I could see what's going on.
JavaScript
// no `var` so they are global and easier to work
// with in the inspector when using jsFiddle
$tx = $('#tx');
$dupe = $('#dupe');
lineH = Number($tx.css('line-height').replace('px',''));
update();
$tx.on('keydown', function() {
setTimeout(update, 0);
});
$tx.on('propertychange input keyup change', update);
function update() {
$dupe.text($tx.val());
$tx.css({
width: $dupe.width() + 7,
height: $dupe.height() + lineH
});
}
// not sure if this is needed, leaving it because
// I don't have many browsers to test on
$tx.on('scroll', function() {
tx.scrollLeft = 0;
tx.scrollTop = 0;
});
I'm adding extra space on the right and at the bottom because it seems to perform more consistently that way. Also, in the HTML, the wrap="off" is necessary for the version of Firefox, I'm using.
I got some good tips from this blog post.
Request #2
Working Demo
<body spellcheck="false">
<div class="text-block" contenteditable="true">
Some Text SpellCheck</div>
Hi Naor, The only problem with this thing is it will disable the spellcheck for all the elements in the <body> tag. If it doesn't matter you then you can go with it.
Your question is really interesting and challenging really liked it. I hope this may help you..!!
Best efficient way which was worked for me while I did something very close in the past was creating hidden out of flow div with the same exactly styles as the textarea has. And than setting out the timeout to update its html source based on information from textarea. This sounds bit scary but yet, after some testing and playing around nothing was better, that was already suggested, so just my variant.
http://jsfiddle.net/f2gAD/16/
and jQuery based script:
var textarea = $('textarea'),
textBlock = $('div.text-block'),
interval, value, freq = 10,
doTextAreaAdjust = function(){
textarea.css({
height: textBlock.outerHeight(),
width: textBlock.outerWidth()
});
};
doTextAreaAdjust();
textarea
.focus(function(){
interval = window.setInterval(
function() {
value = textarea.val().replace(/(\r\n|\n|\r)/gm, '[rnnr]');
value = value.replace(/</gm, '||'); // break html tags
value = value.replace(/\[rnnr\]/gm, '<br>');
value = value + '|'; // or <span>|</span> for better pixel perfect
textBlock.html(value);
doTextAreaAdjust();
}, freq
);console.log(interval);
})
.blur(function(){
window.clearInterval(interval);
});
​
For performance wise did it as self starting/stopping timeout on focus/blur, though here is yet some workaround is required. While testing in Chrome noted that interval not properly stopped if you made blur by clicking on another tab. So probably replacement for self calling function into the setTimeout will be better.
It works more or less fine in IE 7-8 which suppose the main targets but still some text jumps time to time occur, while for others it is okay, but guess you will use editable feature for modern browsers. Would recommend use modernizer for its detection.
Working here
http://jsfiddle.net/H2GSx/
Code here:
HTML:
<div style="overflow: scroll; width: 200px; height: 100px;">
<div class="text-block" contenteditable="true" spellcheck="false">Some Text</div>
</div>​
CSS:
.text-block {
resize: none;
font-size:40px;
border: none;
line-height: 1;
-moz-appearance: textfield-multiline;
-webkit-appearance: textarea;
min-width: 30px;
overflow: visible;
white-space: nowrap;
display: inline-block;
}
​

Making a DOS-style window in ASP.net

I'm trying emulate the MS-DOS command prompt on my website. I don't need to accept keystrokes, but I'd like to append data at the bottom and optionally scroll upwards.
At first I looked at the asp:TextBox and asp:Label, but the flicker of using postbacks seemed to be too much. I'm now considering DIV tags and Javascript where I simply update the InnerHTML property, but there too I get flicker, and have issues with scrolling.
What solution would you recommend in this situation? Essentially I'm trying to count to infinity, with a 1 sec delay, only need the most current 300 or so entries, with the most current entry at the bottom of the screen.
Is this even possible with JS/CSS?
Do you wish to make it a little more stylous ? :)
see this page...
http://www.klaus.dk/Some_unknown_page
or this one
http://www.harryovers.com/404.html?aspxerrorpath=/Account/LoginPartial
here is the javascript source code.
http://code.google.com/p/c64-404-page/
With a little change, you can append your text on this code :)
I just built something very similar using jQuery. You can use the append method to add content to the bottom of your DIV. You can then set the scrollTop attribute to keep things scrolled to the bottom as follows:
$("#someDiv").attr({ scrollTop: $("#someDiv").attr("scrollHeight") });
I think "DOS-style window" is a bit misleading considering all you want to do is append text to a div and make sure it stays scrolled to the bottom.
function addLine(text) {
var box = document.getElementById('DOSBox') //teehee
var line = document.createElement('p');
line.innerHTML = text;
box.appendChild(line);
box.scrollTop = box.scrollHeight;
}
And style it as such
#DOSBox {
overflow: auto;
display: block;
height: 400px; width: 500px; /* or whatever */
/* and if you want it to look DOS-like */
background: #000;
color: rgb(192, 192, 192);
font-family: fixedsys;
}
#DOSBox p {
margin: 0;
}

Categories