PDA

View Full Version : Resolved textarea using ENTER



auriaks
11-15-2009, 12:18 AM
hi. I have textarea whish i use to store max 500 characters. What i want?
I want to save ENTER push's, because when my output comes, I got all written in one line. But user pushed enter to start writing from new line... If you need more info - ask. Thanks a lot :)

Schmoopy
11-15-2009, 12:24 AM
That's because the key for enter comes back as "\n", so you have to replace all of those with "<br />" tags.

Here you go:



$text = str_replace('\n', '<br />', $_POST['textarea']);


Remember to escape the text as well, if you're going to be inserting this into a database.

james438
11-15-2009, 09:35 AM
Actually, returns are
\r\n, but Schmoopy's code will still work just fine. I'm just being nit picky ;)

jscheuer1
11-15-2009, 10:11 AM
Actually the type of line break produced by the enter key depends upon the OS:


Windows - CR LF (0d0a)
'nix - LF (0a)
Mac - CR (0d)


The Carriage Return (CR) is represented in a regular expression by either \r or \x0d, the Line Feed (LF) by either \n or \x0a.

Schmoopy
11-15-2009, 02:40 PM
Thanks for pointing that out guys :)

A quick question then. Based on what you've said, the code I currently put up would only count as a line break in Windows and Linux, but not in Mac?

jscheuer1
11-15-2009, 03:39 PM
I would tend to think so. However, it is unclear to me if, since this is on the server side, whether the server would convert to its method. In any case though, if one used an or operator (|) one should be OK, something like (I'm not certain of PHP regular expression syntax, or what the order of precedence would be here):


'(\r\n|\r|\n)'

in place of:



'\n'

as long as that doesn't result in the Windows style line break generating two <br> tags for each. If that happened, then one would have to also employ negative look ahead and negative look behind for the single character portions of the expression.

thetestingsite
11-15-2009, 05:51 PM
There is a function in PHP that already does this and it is called nl2br() (http://www.php.net/nl2br)

Hope this helps.

jscheuer1
11-15-2009, 06:04 PM
nl2br — Inserts HTML line breaks before all newlines in a string

That would leave out Mac OS's. However, there is a strategy in the comments section of that page on nl2br that is just what I was talking about.



function Only1br($string)
{
return preg_replace("/(\r\n)+|(\n|\r)+/", "<br />", $string);
}

auriaks
11-16-2009, 12:04 AM
Thanks guys... :) Also it was interesting to read all the information about OS's. Btw, is is hard to create textarea like in this forum? with insertings php bold italic size style etc? maybe someone have links, tutorials. Any info is welcome. Thanks :)

jscheuer1
11-16-2009, 01:18 AM
Btw, is is hard to create textarea like in this forum? with insertings php bold italic size style etc?

I was thinking that something like that might be useful for what you are trying to do. It requires javascript enabled on the user's end. I found that out recently when I disabled javascript and tried posting here. I was able to, but none of the editor's features were available.

You should look here:

http://www.dynamicdrive.com/dynamicindex16/richtexteditor/index.htm

it (also requires javascript) may be a good adjunct to your current project.

Also, if you already have a forum package, it may include an option for this sort of thing. The vBulletin package used by DD includes this javascript powered input as an option, but it must be configured to do all of what the current 'editor' here does.

james438
11-16-2009, 02:36 AM
Is this what you are looking for Auriaks?


<script type="text/javascript">
function insertAtCursor(myField, myValue) {
//IE support
if (document.selection) {
myField.focus();
sel = document.selection.createRange();
sel.text = myValue;
}
//MOZILLA/NETSCAPE support
else if (myField.selectionStart || myField.selectionStart == �e0�Œ) {
var startPos = myField.selectionStart;
var endPos = myField.selectionEnd;
myField.value = myField.value.substring(0, startPos)
+ myValue
+ myField.value.substring(endPos, myField.value.length);
} else {
myField.value += myValue;
}</script>
<script type="text/javascript">
function saveCurRng() {
curRng = document.selection.createRange().duplicate();
}
function surround(btag, etag){
if (curRng) {
document.editform.article.focus();
curRng.text= btag + curRng.text + etag;
return false;
}
}
</script>
</head>
<body>
<form name="editform">
<textarea rows=5 cols=40 name="article" onKeyup="saveCurRng()" onMouseup="saveCurRng()"></textarea>
</form>
<a href="#" onclick="return surround('<b>', '</b>');">bold</a><br>
<a href="#" onclick="return surround('<i>', '</i>');">italic</a>


Actually the type of line break produced by the enter key depends upon the OS:
Do you mean it depends on what type of server PHP is running on? For example I use PHP that runs on a remote server that is Linux based. My home computer is Windows XP. The PHP code that I use to convert enter key into <BR> is
$text=str_replace('\r\n','<br>',$text);

jscheuer1
11-16-2009, 08:01 AM
//MOZILLA/NETSCAPE support
else if (myField.selectionStart || myField.selectionStart == �e0�Œ) {


This may be an OS/installed fonts thing, but the above quoted and highlighted code looks like garbage here. Also, if the value of myField.selectionStart is that highlighted thing, and that highlighted thing is truthy, it need not be tested for at all because as soon as if (myField.selectionStart evaluates as truthy, the code conditional upon the else if statement will execute. Unless, of course, if you really meant &&, not ||.



Do you mean it depends on what type of server PHP is running on?

I'm really unclear myself on that one. I would tend to think though that the sending or client computer would dictate what sort of line break is issued when the user hits ENTER. However, it is entirely possible that some sort of automatic conversion occurs on the server, in which case it would be the server that determines this.

Somewhat related, in a textarea, if the enter key is not used and the textarea's wrap attribute (deprecated but still used and supported) is set to 'hard', when the form is submitted text wrapped by the textarea's dimension's constraints will get the server's OS's style of line break applied to the form's generated POST or Get data.

james438
11-16-2009, 08:30 AM
thanks for catching that jschuer1. That wasn't the code I originally posted, so it looks like some of it was lost in translation.

What is a truthy?

Try this Auriaks,

<script type="text/javascript">
function insertAtCursor(myField, myValue) {
//IE support
if (document.selection) {
myField.focus();
sel = document.selection.createRange();
sel.text = myValue;
}
else {
myField.value += myValue;
}</script>
<script type="text/javascript">
function saveCurRng() {
curRng = document.selection.createRange().duplicate();
}
function surround(btag, etag){
if (curRng) {
document.editform.article.focus();
curRng.text= btag + curRng.text + etag;
return false;
}
}
</script>
</head>
<body>
<form name="editform">
<textarea rows=5 cols=40 name="article" onKeyup="saveCurRng()" onMouseup="saveCurRng()"></textarea>
</form>
<a href="#" onclick="return surround('<b>', '</b>');">bold</a><br>
<a href="#" onclick="return surround('<i>', '</i>');">italic</a> It isn't perfect though because it doesn't work in Firefox. I never took the time to get it to work in Firefox. The code is not originally mine either, but some code I got from somewhere else on this forum some time ago. If anyone knows how to get it to work in Firefox I would be very grateful. Either way, I use Opera almost exclusively and have found this script to be quite handy and customizable.

jscheuer1
11-16-2009, 08:59 AM
The term 'truthy' is used in reference to if, if else and other coding constructs that need to determine if something is true or false. It's opposite is, you guessed it, 'falsey'. These are useful concepts because they help us understand what will happen in these constructs, and to determine if they are really set up in such a way to accomplish our aims for them.

If something has any value other than false, null, or 0, and is not undefined or an empty string, it is truthy. If you have something that tests on the basis of || (or), once one item in the series tests truthy, the rest are disregarded and the code conditional upon the test executes. So to 'ask':


if(something || something == 'bob')

is superfluous because if something equals 'bob', it is truthy and the second half of the expression will be ignored because the script parser already knows the answer to be true or truthy with the first half, will skip evaluating the second part, and go straight to the code this condition executes when it is true.

auriaks
11-16-2009, 02:34 PM
YES, thats what I was looking for :) No possibility for using in firefox? Because i have webpage designed for opera and firefox.

Schmoopy
11-16-2009, 02:53 PM
JavaScript will work in the same way regardless of the browser. Or is this not what you meant?

jscheuer1
11-16-2009, 03:47 PM
JavaScript will work in the same way regardless of the browser.

Er, no. Different browsers have different names for the same or similar objects and methods.

Opera is a bit odd in that it supports several of the IE centric methods and objects while at the same time supporting most of the standard methods and objects used by most others.

IE is playing a slow game of catch up in supporting the standard objects and methods. With each new IE version, they add in support for a few more.

Virtually all browsers have quirks - methods or objects that only it supports, and/or a slightly different 'take' on some of the standard objects or methods it does support.

Schmoopy
11-16-2009, 04:22 PM
Ah right, well I knew they all behaved slightly differently, but I thought it was a rare occurrence that what works for one browser won't work for another.
Thanks for the correction.

jscheuer1
11-16-2009, 04:54 PM
Well, with basic stuff, yes most modern browsers now behave the same. The major difference/exception that I can think of offhand is addEventListener vs. attachEvent. This is fairly basic stuff, and frankly IE gets it wrong clinging exclusively to its non-standard attachEvent. Opera supports both, all others afaik, just the standard addEventListener.

Now as far as the code from james438 goes, he even stated that it didn't support Firefox. The methods for manipulating selections do still vary widely between IE and the rest, with Opera possibly supporting both methods.

When I get a chance I will probably look this up. I have working code for it somewhere.

auriaks
11-16-2009, 10:50 PM
So, if i will use this script it will not work in firefox? It is possible to change script somehow?

james438
11-16-2009, 11:25 PM
It can almost certainly be improved and altered to work in Firefox. I don't know how, because I am not fluent in javascript at all, but maybe someone else knows how to alter it. It probably is not even that hard to update it either. Since it would be nice to have it work in Firefox as well, I posted the script in the javascript forums (http://www.dynamicdrive.com/forums/showthread.php?t=50051).

jscheuer1, do you happen to know if work is being done in Firefox to get more javascript/CSS to be more standards compliant? I know that IE is working at it as well as Opera, but I wasn't sure if Firefox was going to go down IE's old route of letting everyone else conform to them. IE, thankfully, eventually gave up on that idea. I want to add that I love Opera, Firefox, and I am learning to like IE again too and am not trying to bash Firefox.

gurmeet
11-17-2009, 05:07 AM
just simply use the function
nl2br() in PHP, u ll get desired output... of use the PRE tag while giving output on the screen....
hop it l work 4 u

jscheuer1
11-17-2009, 05:11 AM
All browsers with the exception of IE pretty much follow standards, and IE is slowly improving in that regard with each new version. All this stuff with document.selection and createRange is non-standard.

I've been playing around with this off and on today. I'm not really happy with the code yet, as it is pretty sloppy - I was just trying to get it to work. And, I cant get IE to move the insertion point to the end of the inserted text in all cases (the move and collapse methods for the created range, which are supposed to move the insertion point, seem to have no effect unless you do something to the range after moving or collapsing it, and I'm not sure if there is a way to do this that will yield what I want here). I was able to do what I want in all the other browsers. So, if anyone has information on moving the insertion point (cursor) in IE (preferably independently of the selection object, but either way is OK), I'd appreciate that. Most likely I will be cleaning up the code now that I at least have a working version. Here's what I have so far:


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<script type="text/javascript">
function insertAtCursor(myField, myValue) {
//Standard Method support
if (myField.selectionStart || myField.selectionStart === 0) {
var startPos = myField.selectionStart;
var endPos = myField.selectionEnd;
myField.value = myField.value.substring(0, startPos)
+ myValue
+ myField.value.substring(endPos, myField.value.length);
myField.selectionStart = myField.selectionEnd = startPos + myValue.length;
}
}
function getMozRng(el){
if(typeof el.selectionStart !== 'number')
return false;
return el.value.substring(el.selectionStart, el.selectionEnd);
}

surround.curRng = '';
function saveCurRng(el){
surround.curRng = document.selection? document.selection.createRange() : getMozRng(el);
}
function surround(btag, etag){
if(surround.curRng === false){return;}
var el = document.editform.elements.article;
el.focus();
if(document.selection){
surround.curRng.text = btag + surround.curRng.text + etag;
document.selection.empty();
el.blur();
el.focus();
}
else{
insertAtCursor(el, btag + surround.curRng + etag);
}
saveCurRng(el);
return false;
}
</script>
</head>
<body>
<form name="editform">
<textarea rows=5 cols=40 name="article" onkeyup="saveCurRng(this)" onouseup="saveCurRng(this)" onmouseout="saveCurRng(this)"></textarea>
</form>
<a href="#" onclick="return surround('<b>', '</b>');">bold</a><br>
<a href="#" onclick="return surround('<i>', '</i>');">italic</a>
</body>
</html>

james438
11-17-2009, 07:18 AM
Woot! Much appreciated! I have zero knowledge of javascript, so this is awesome for me.

Thanks :)

jscheuer1
11-17-2009, 09:33 AM
Here's a cleaned up version (still needs some work), but at least I solved the problem I was having in IE with the cursor:


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript">
/* editText Script 2009 John Davenport Scheuer
as first seen in http://www.dynamicdrive.com/forums/
username: jscheuer1 - This Notice Must Remain for Legal Use
*/
var editText = {
init: function(){return;}
};
(function(){
if(!document.getElementById){
return;
}
editText = {
saveCurRng: (function(){return document.selection?
function(el){this.el = el; el.focus(); this.curRng = document.selection.createRange();}:
function(el){this.el = el, this.curRng = typeof el.selectionStart === 'number'?
el.value.substring(el.selectionStart, el.selectionEnd) : null;}
})(),
insert: (function(){return document.selection?
function(btag, etag){
this.el.focus();
if(!window.opera){
document.selection.empty();
}
this.curRng.text = btag + this.curRng.text + etag;
this.el.blur();
this.el.focus();
this.saveCurRng(this.el);
}:function(btag, etag){
if (typeof this.el.selectionStart === 'number'){
var el = this.el, startPos = el.selectionStart, endPos = el.selectionEnd,
l = [btag, this.curRng, etag].join('').length; el.focus();
el.value = [el.value.substring(0, startPos), btag, this.curRng, etag,
el.value.substring(endPos, el.value.length)].join('');
el.selectionStart = el.selectionEnd = startPos + l;
this.saveCurRng(el);
}
};
})(),
init: (function(){
return window.addEventListener? function(cfg){
window.addEventListener('load', function(){
var ctrls = document.getElementById(cfg.controls).getElementsByTagName(cfg.controlTag), i = 0,
area = document.getElementById(cfg.el);
area.addEventListener('change', function(){editText.saveCurRng(area);}, false);
for(i; i < ctrls.length; ++i){
ctrls[i].addEventListener('click', function(e){
var t = this[cfg.controlInfo].split(cfg.controlDelimit);
if(cfg.controlDelimit === '><' && t.length === 2){
t[0] += '>';
t[1] = '<' + t[1];
}
if(t.length === 1){
t.unshift('');
}
editText.saveCurRng(area);
editText.insert(t[0], t[1]);
e.preventDefault();
}, false);
}
}, false);
}:window.attachEvent? function(cfg){
window.attachEvent('onload', function(){
var ctrls = document.getElementById(cfg.controls).getElementsByTagName(cfg.controlTag), i = 0,
area = document.getElementById(cfg.el);
area.attachEvent('onchnage', function(){editText.saveCurRng(area);});
for(i; i < ctrls.length; ++i){
(function(el){
el.attachEvent('onclick', function(){
var t = el[cfg.controlInfo].split(cfg.controlDelimit);
if(cfg.controlDelimit === '><' && t.length === 2){
t[0] += '>';
t[1] = '<' + t[1];
}
if(t.length === 1){
t.unshift('');
}
editText.saveCurRng(area);
editText.insert(t[0], t[1]);
return false;
});
})(ctrls[i]);
}
});
}:function(){return;};
})()
};
})();
editText.init({
el: 'myArea',
controls: 'myControls',
controlTag: 'input',
controlInfo: 'title',
controlDelimit: '><'
});
</script>
</head>
<body>
<form action="#">
<div>
<textarea id="myArea" rows=5 cols=40>The Slow Pink Fox Jumped Over the Quick Green Dog.</textarea><br>
<input type="reset" value="Reset">
</div>
</form>

<div id="myControls">
<input type="button" title="<b></b>" value="B">
<input type="button" title="<i></i>" value="I">
<input type="button" title="<br>" value="BR">
</div>
</body>
</html>

Schmoopy
11-17-2009, 01:02 PM
just simply use the function
nl2br() in PHP

Weirdly, when I tried using that function, it didn't actually work, not even this worked:


$comment = str_replace(array("\r\n", "\r", "\n"), "<br />", $comment);

The only way I managed to get mine to do what I wanted was to use the above, but then escape all the backslashes, like so:


$comment = str_replace(array("\\r\\n", "\\r", "\\n"), "<br />", $comment);

Anyone else having the same issue?

thetestingsite
11-17-2009, 03:19 PM
is your server on a Windows platform? This was the only time I ever noticed this type of behavior. Either that or a certain module is not being loaded into php that does the auto escaping of certain characters.

Hope this helps nonetheless.

Schmoopy
11-17-2009, 05:01 PM
Well this is just on my local server, so WAMP. I guess that explains it.

jscheuer1
11-18-2009, 05:36 AM
You never can be certain as far as portable server side code goes. Best to cover all bases. If on the other hand you are writing for your own use on a known server, you can just do what works.

In javascript at least, probably PHP as well, it rarely hurts to be formal, and escaping escapes in regular expressions expressed as strings (quoted), is generally a good idea.

PHP (in my limited experience with it) is more forgiving in general in these sort of things than is javascript. Like quotes don't always have to be employed for bracketed strings as property names. But, as I say, doing it right usually never hurts.

james438
11-26-2009, 06:53 AM
Not sure where the best place is to post this question but...

jscheuer, in the javascript tags program you wrote is there a way to get it to work for multiple textareas?

jscheuer1
11-26-2009, 10:54 AM
It already does, or should, that's how I wrote it. But I don't believe I actually tested it for that. You can, and let me know if there are any problems. Here is the crucial part of the code for that:


editText.init({
el: 'myArea',
controls: 'myControls',
controlTag: 'input',
controlInfo: 'title',
controlDelimit: '><'
});

As you will see in my post presenting it in its 'cleaned up' version (#25 (http://www.dynamicdrive.com/forums/showpost.php?p=210810&postcount=25) in this thread, which is the code one should use for multiple textareas), that bit follows the main body of the script code. It is a function that takes an object as its sole parameter for the purpose of initializing a given textarea to the functionality of the main code. This is a rather common method used in a number of scripts. Let's annotate it:


editText.init({
el: 'myArea', // id of the textarea to init
controls: 'myControls', // id of the division holding the editing controls for this textarea
controlTag: 'input', // tagName used for the controls within that division
controlInfo: 'title', // attribute used within those tags to express what they will do
controlDelimit: '><' // delimiter used within that attribute to separate beginning and end tags
});

Now these should be even clearer as to what each does. Currently they are all required. Just make up separate inits for each textarea you wish the code to apply to. The only property that really needs a bit of further explanation is the controlDelimit property. It only applies to controls that have a beginning and end tag, so a bit of care should be used in choosing it so as not to inadvertently split up tags that don't have begin and end tags. In the above init, it uses the one special case the script affords - utilizing the >< between tags as the delimeter. Writ that way, it will take a tag like <b></b> and split it into it's opening and closing tags and add back in the >< used to split them, example from the markup in that post:


<input type="button" title="<i></i>" value="I">

This button will surround the highlighted text with its title attribute, the <i></i> tag. But if the controlDelimit property for this textarea had been a dash (-), the title would have had to have been like:


<input type="button" title="<i>-</i>" value="I">

The fact that it is the title that is used is set by the controlInfo property of the init functions parameter object. Like if the controlTag property were set to 'a', and the controlInfo property set to 'rel', the rel attribute of links could be used in place of the title attribute of inputs.

Anyways, I think you get the general idea. Let me know if you have any problems or questions.

james438
11-26-2009, 11:55 AM
I have not taken up javascript yet, but I think I understood 90% - 95% of your description.

I was planning on asking you about the delimiters in another post, so thanks for explaining :). It looks like I could also use ][ as delimiters as well, but wrapping code in text like CODE would not work out so well.

Anyway, when I tried it out with 2 textareas and giving each one its own personalized id tag I still get the same problem. The tags only work on one textarea. I figure I am having a bit of trouble with the syntax. Here is the section I am working with. The altered sections have been highlighted.


editText.init({
el: 'myArea','myArea2',
controls: 'myControls',
controlTag: 'input',
controlInfo: 'title',
controlDelimit: '><'
});
</script>
</head>
<body>
<form action="#">
<div>
<textarea id="myArea" rows=5 cols=40>The Slow Pink Fox Jumped Over the Quick Green Dog.</textarea><br>
<input type="reset" value="Reset">
</div>
</form>
<form action="#">
<div>
<textarea id="myArea2" rows=5 cols=40>The Slow Pink Fox Jumped Over the Quick Green Dog.</textarea><br>
<input type="reset" value="Reset">
</div>
</form>
<div id="myControls">
<input type="button" title="<b></b>" value="B">
<input type="button" title="<i></i>" value="I">
<input type="button" title="<br>" value="BR">
</div>
</body>
</html>
I have tried lots of different variations and have tried adding separate id tags for the controls as well, but just can't seem to get it to work.

I have already updated the code on my site with yours. If it is alright with you I would like your permission to post a link on my site to this thread as well as the code and reference you as the creator.

jscheuer1
11-26-2009, 12:25 PM
Well you would need two sets of controls, at least the way the script is written now. I believe I updated it a bit from its last published version, but that shouldn't make a difference to the multi-use functionality, though it may have. Anyways, here is a working version with two textareas:


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript">
/* editText Script 2009 John Davenport Scheuer
as first seen in http://www.dynamicdrive.com/forums/
username: jscheuer1 - This Notice Must Remain for Legal Use
*/
var editText = {
init: function(){return;}
};
(function(){
if(!document.getElementById){
return;
}
editText = {
saveCurRng: (function(){return document.selection?
function(el){this.el = el; el.focus(); this.curRng = document.selection.createRange();}:
function(el){this.el = el, this.curRng = typeof el.selectionStart === 'number'?
el.value.substring(el.selectionStart, el.selectionEnd) : null;}
})(),
insert: (function(){return document.selection?
function(btag, etag){
this.el.focus();
if(!window.opera){
document.selection.empty();
}
this.curRng.text = btag + this.curRng.text + etag;
this.el.blur();
this.el.focus();
}:function(btag, etag){
if (typeof this.el.selectionStart === 'number'){
var el = this.el, startPos = el.selectionStart, endPos = el.selectionEnd,
l = .join('').length; el.focus();
el.value = [el.value.substring(0, startPos), btag, this.curRng, etag,
el.value.substring(endPos, el.value.length)].join('');
el.selectionStart = el.selectionEnd = startPos + l;
}
};
})(),
controlsFront: function(el, cfg, area){
var t = el[cfg.controlInfo].split(cfg.controlDelimit);
if(cfg.controlDelimit === '><' && t.length === 2){
t[0] += '>';
t[1] = '<' + t[1];
}
else if(t.length === 1){
t.unshift('');
}
this.saveCurRng(area);
this.insert(t[0], t[1]);
},
addEvent: (function(){return window.addEventListener? function(el, ev, f){
el.addEventListener(ev, f, false);
}:window.attachEvent? function(el, ev, f){
el.attachEvent('on' + ev, f);
}:function(){return;};
})(),
init: function(cfg){
this.addEvent(window, 'load', function(){
var ctrls = document.getElementById(cfg.controls).getElementsByTagName(cfg.controlTag), i = 0,
area = document.getElementById(cfg.el);
editText.addEvent(area, 'change', function(){editText.saveCurRng(area);});
if(cfg.clearSelect){
editText.addEvent(document.getElementById(cfg.clearSelect), 'click', function(e){
area.value = area.value;
if(e && e.preventDefault){
e.preventDefault();
}
return false;
});
}
for(i; i < ctrls.length; ++i){
(function(el){
editText.addEvent(el, 'click', function(e){
editText.controlsFront(el, cfg, area);
if(e && e.preventDefault){
e.preventDefault();
}
return false;
});
})(ctrls[i]);
}
});
}
};
})();
editText.init({
el: 'myArea',
controls: 'myControls',
controlTag: 'input',
controlInfo: 'title',
controlDelimit: '><',
clearSelect: 'clearSelection'
});
editText.init({
el: 'myArea2',
controls: 'myControls2',
controlTag: 'input',
controlInfo: 'title',
controlDelimit: '><',
clearSelect: 'clearSelection'
});
</script>
</head>
<body>
<form action="#">
<div>
<textarea id="myArea" rows=5 cols=40>The Slow Pink Fox Jumped Over the Quick Green Dog.</textarea><br>
<input type="reset" value="Reset"> <input id="clearSelection" type="button" value="DeSelect">
</div>
</form>
<div id="myControls">
<input type="button" title="<b></b>" value="B">
<input type="button" title="<i></i>" value="I">
<input type="button" title="<br>" value="BR">
</div>
<form action="#">
<div>
<textarea id="myArea2" rows=5 cols=40>Nothing Here to Look at Folks, Move Along . . .</textarea><br>
<input type="reset" value="Reset"> <input id="clearSelection" type="button" value="DeSelect">
</div>
</form>
<div id="myControls2">
<input type="button" title="<b></b>" value="B">
<input type="button" title="<i></i>" value="I">
<input type="button" title="<br>" value="BR">
</div>
</body>
</html>

Also, using ][ as delimiters probably won't work the way you think. Only >< gets split and used. If you want square brackets around your tags (as would be useful on a bulletin board or other system that uses tags like that), you should use a neutral character for the delimiter, like - say an undescore (_). Then for example your title could be:


<input type="button" title="_" value="B">

Though you could edit the script here (adding the highlighted):


controlsFront: function(el, cfg, area){
var t = el[cfg.controlInfo].split(cfg.controlDelimit);
if(cfg.controlDelimit === '><' && t.length === 2){
t[0] += '>';
t[1] = '<' + t[1];
}
else if(cfg.controlDelimit === '][' && t.length === 2){
t[0] += ']';
t[1] = '[' + t[1];
}
else if(t.length === 1){
t.unshift('');
}
this.saveCurRng(area);
this.insert(t[0], t[1]);
},

To allow for stuff like:


<input type="button" title="[b]" value="B">

james438
01-08-2010, 10:37 PM
editText.init({
el: 'myArea', // id of the textarea to init
controls: 'myControls', // id of the division holding the editing controls for this textarea
controlTag: 'input', // tagName used for the controls within that division
controlInfo: 'title', // attribute used within those tags to express what they will do
controlDelimit: '><' // delimiter used within that attribute to separate beginning and end tags
});

What if I wanted to use 'input' and 'a' tags?

jscheuer1
01-09-2010, 01:41 AM
editText.init({
el: 'myArea', // id of the textarea to init
controls: 'myControls', // id of the division holding the editing controls for this textarea
controlTag: 'input', // tagName used for the controls within that division
controlInfo: 'title', // attribute used within those tags to express what they will do
controlDelimit: '><' // delimiter used within that attribute to separate beginning and end tags
});

What if I wanted to use 'input' and 'a' tags?

Just to be clear, and I think I know the answer (guessing yes here) - but do you mean for the controlTag property?

If so, setting it to 'input', a hidden input could probably be used to execute the a tags via a little helper onclick function of the a tag, though a more fully integrated solution would be doable and preferable.

If not, then what?

james438
01-09-2010, 04:17 AM
yep. It looks like the input tag is more versatile than I was thinking. Here are the buttons I currently use now:


<input type="button" title="<b></b>" value="B">
<input type="button" title="<span class='o'></span>" value="color">
<input type="button" title="<i></i>" value="i">
<input type="button" title="&lt;a href=""></a>" value="link">
<input type="button" title="<ul></ul>" value="list">
<input type="button" title="<li>" value="li">
<input type="button" title="<div style='font-size:18px;text-align:center;'></div>" value="title">
<input type="button" title="CODE" value="CODE">
<input type="button" title="<span style='text-decoration:underline;'></span>" value="underline">
<input type="button" title="<div class='q'></div>" value="quote">
<input type="image" src="/images/pops/icon_smile.gif" alt="Submit" title=":)"> I am now going to add several more for the different smiles that are commonly seen. It may be easy to just type out : ) but this way I can see which ones are available and what they look like.

jscheuer1
01-09-2010, 05:00 AM
yep. It looks like the input tag is more versatile than I was thinking.

Good point. I hadn't considered that when I posted last, but of course you are correct. Does this mean that you've solved this to your satisfaction (guessing yes again)?

james438
01-09-2010, 05:05 AM
Well, yes. You pointed me in the right direction though ;)

In your script you seem to trim the leading whitespace. Is there a way to disable that. I tried looking for the term trim and/or \s, in your script, but with no luck. It could be that this is happening due to a default action of javascript.

jscheuer1
01-09-2010, 05:21 AM
Not that I recall, and not looking over the code. I'm at a bit of a loss though, what white space? Where and when? What browser?

james438
01-09-2010, 05:54 AM
I need to get in the habit of checking the browser versions.


<input type="image" src="/images/pops/icon_smile.gif" alt="Submit" title=" :)">works in Firefox and IE8, but not so much in Opera.
It operates in Opera as if it were:

<input type="image" src="/images/pops/icon_smile.gif" alt="Submit" title=":)">
the same is true with

<input type="image" src="/images/pops/icon_smile.gif" alt="Submit" title="&nbsp;:)">
No biggie. Opera is my browser of choice, but I feel it is more of a niche market browser. Do you think I should post it as a bug in the Opera forums?

jscheuer1
01-09-2010, 06:57 AM
Opera is also my browser of choice, and I think I see just what you mean now. This hack might serve:


controlsFront: function(el, cfg, area){
var t = el[cfg.controlInfo].split(cfg.controlDelimit);
if(window.opera && t.length === 1 && !/^<.*>$/.test(t[0])){
t = el.value.split(cfg.controlDelimit);
}
if(cfg.controlDelimit === '><' && t.length === 2){
t[0] += '>';
t[1] = '<' + t[1];
}
else if(t.length === 1){
t.unshift('');
}
this.saveCurRng(area);
this.insert(t[0], t[1]);
},

It will take (in Opera only) the value attribute (which Opera doesn't strip leading spaces from) rather than the configured controlInfo attribute (like title) for insertions that are not delimited and are not tags, example:


<input type="button" title=" :)" value=" :)">

will now behave as desired in Opera.

As long as you understand what is going on here, I believe this will solve your problem.

Any questions, feel free to ask.

james438
01-09-2010, 07:27 PM
What is the current version of your script?

Currently I use a version of the code you posted in post #25. My code looks like:


<br><textarea name="summary" cols=75 rows=25 id="myArea"></textarea><br><br>
<script type="text/javascript">
/* editText Script 2009 John Davenport Scheuer
as first seen in http://www.dynamicdrive.com/forums/
username: jscheuer1 - This Notice Must Remain for Legal Use
*/
var editText = {
init: function(){return;}
};
(function(){
if(!document.getElementById){
return;
}
editText = {
saveCurRng: (function(){return document.selection?
function(el){this.el = el; el.focus(); this.curRng = document.selection.createRange();}:
function(el){this.el = el, this.curRng = typeof el.selectionStart === 'number'?
el.value.substring(el.selectionStart, el.selectionEnd) : null;}
})(),
insert: (function(){return document.selection?
function(btag, etag){
this.el.focus();
if(!window.opera){
document.selection.empty();
}
this.curRng.text = btag + this.curRng.text + etag;
this.el.blur();
this.el.focus();
this.saveCurRng(this.el);
}:function(btag, etag){
if (typeof this.el.selectionStart === 'number'){
var el = this.el, startPos = el.selectionStart, endPos = el.selectionEnd,
l = [btag, this.curRng, etag].join('').length; el.focus();
el.value = [el.value.substring(0, startPos), btag, this.curRng, etag,
el.value.substring(endPos, el.value.length)].join('');
el.selectionStart = el.selectionEnd = startPos + l;
this.saveCurRng(el);
}
};
})(),
init: (function(){
return window.addEventListener? function(cfg){
window.addEventListener('load', function(){
var ctrls = document.getElementById(cfg.controls).getElementsByTagName(cfg.controlTag), i = 0,
area = document.getElementById(cfg.el);
area.addEventListener('change', function(){editText.saveCurRng(area);}, false);
for(i; i < ctrls.length; ++i){
ctrls[i].addEventListener('click', function(e){
var t = this[cfg.controlInfo].split(cfg.controlDelimit);
if(cfg.controlDelimit === '><' && t.length === 2){
t[0] += '>';
t[1] = '<' + t[1];
}
if(t.length === 1){
t.unshift('');
}
editText.saveCurRng(area);
editText.insert(t[0], t[1]);
e.preventDefault();
}, false);
}
}, false);
}:window.attachEvent? function(cfg){
window.attachEvent('onload', function(){
var ctrls = document.getElementById(cfg.controls).getElementsByTagName(cfg.controlTag), i = 0,
area = document.getElementById(cfg.el);
area.attachEvent('onchnage', function(){editText.saveCurRng(area);});
for(i; i < ctrls.length; ++i){
(function(el){
el.attachEvent('onclick', function(){
var t = el[cfg.controlInfo].split(cfg.controlDelimit);
if(cfg.controlDelimit === '><' && t.length === 2){
t[0] += '>';
t[1] = '<' + t[1];
}
if(t.length === 1){
t.unshift('');
}
editText.saveCurRng(area);
editText.insert(t[0], t[1]);
return false;
});
})(ctrls[i]);
}
});
}:function(){return;};
})()
};
})();
editText.init({
el: 'myArea',
controls: 'myControls',
controlTag: 'input',
controlInfo: 'title',
controlDelimit: '><'
});
</script>
<input type="reset" value="Reset"><br><br>
<div id="myControls">
<input type="button" title="<b></b>" value="B">
<input type="button" title="<span class='o'></span>" value="color">
<input type="button" title="<i></i>" value="i">
<input type="button" title="&lt;a href=""></a>" value="href">
<input type="button" title="<ul></ul>" value="&lt;ul>">
<input type="button" title="<li>" value="li"><br><br>
<input type="button" title="<div style='font-size:18px;text-align:center;'></div>" value="title">
<input type="button" title="CODE" value="CODE">
<input type="button" title="<span style='text-decoration:underline;'></span>" value="underline">
<input type="button" title="<div class='q'></div>" value="quote">
<input type="image" src="/images/pops/icon_smile.gif" alt="Submit" title=":)" style="background-color:<?php print $article_color; ?>;"/>
<input type="image" src="/images/pops/icon_confused.gif" alt="Submit" title=' :/' style="background-color:<?php print $article_color; ?>;"/>
<input type="image" src="/images/pops/icon_biggrin.gif" alt="Submit" title=":D" style="background-color:<?php print $article_color; ?>;"/>
<input type="image" src="/images/pops/icon_razz.gif" alt="Submit" title=":P" style="background-color:<?php print $article_color; ?>;"/>
<input type="image" src="/images/pops/icon_wink.gif" alt="Submit" title=";)" style="background-color:<?php print $article_color; ?>;"/>
<input type="image" src="/images/pops/icon_sad.gif" alt="Submit" title=":(" style="background-color:<?php print $article_color; ?>;"/>
</div>
<br>
class='floatimgleft'

I think the current version you are referencing is from post #33. When I updated it I basically just replaced my script with the script you posted just as you posted it, but was unable to get it to work. Here is what I have anyway:


<br><textarea name="summary" cols=75 rows=25 id="myArea"></textarea><br><br>
<script type="text/javascript">
/* editText Script 2009 John Davenport Scheuer
as first seen in http://www.dynamicdrive.com/forums/
username: jscheuer1 - This Notice Must Remain for Legal Use
*/
var editText = {
init: function(){return;}
};
(function(){
if(!document.getElementById){
return;
}
editText = {
saveCurRng: (function(){return document.selection?
function(el){this.el = el; el.focus(); this.curRng = document.selection.createRange();}:
function(el){this.el = el, this.curRng = typeof el.selectionStart === 'number'?
el.value.substring(el.selectionStart, el.selectionEnd) : null;}
})(),
insert: (function(){return document.selection?
function(btag, etag){
this.el.focus();
if(!window.opera){
document.selection.empty();
}
this.curRng.text = btag + this.curRng.text + etag;
this.el.blur();
this.el.focus();
}:function(btag, etag){
if (typeof this.el.selectionStart === 'number'){
var el = this.el, startPos = el.selectionStart, endPos = el.selectionEnd,
l = [btag, this.curRng, etag].join('').length; el.focus();
el.value = [el.value.substring(0, startPos), btag, this.curRng, etag,
el.value.substring(endPos, el.value.length)].join('');
el.selectionStart = el.selectionEnd = startPos + l;
}
};
})(),
controlsFront: function(el, cfg, area){
var t = el[cfg.controlInfo].split(cfg.controlDelimit);
if(cfg.controlDelimit === '><' && t.length === 2){
t[0] += '>';
t[1] = '<' + t[1];
}
else if(t.length === 1){
t.unshift('');
}
this.saveCurRng(area);
this.insert(t[0], t[1]);
},
addEvent: (function(){return window.addEventListener? function(el, ev, f){
el.addEventListener(ev, f, false);
}:window.attachEvent? function(el, ev, f){
el.attachEvent('on' + ev, f);
}:function(){return;};
})(),
init: function(cfg){
this.addEvent(window, 'load', function(){
var ctrls = document.getElementById(cfg.controls).getElementsByTagName(cfg.controlTag), i = 0,
area = document.getElementById(cfg.el);
editText.addEvent(area, 'change', function(){editText.saveCurRng(area);});
if(cfg.clearSelect){
editText.addEvent(document.getElementById(cfg.clearSelect), 'click', function(e){
area.value = area.value;
if(e && e.preventDefault){
e.preventDefault();
}
return false;
});
}
for(i; i < ctrls.length; ++i){
(function(el){
editText.addEvent(el, 'click', function(e){
editText.controlsFront(el, cfg, area);
if(e && e.preventDefault){
e.preventDefault();
}
return false;
});
})(ctrls[i]);
}
});
}
};
})();
editText.init({
el: 'myArea',
controls: 'myControls',
controlTag: 'input',
controlInfo: 'title',
controlDelimit: '><',
clearSelect: 'clearSelection'
});
editText.init({
el: 'myArea2',
controls: 'myControls2',
controlTag: 'input',
controlInfo: 'title',
controlDelimit: '><',
clearSelect: 'clearSelection'
});
</script>
<input type="reset" value="Reset"><br><br>
<div id="myControls">
<input type="button" title="<b></b>" value="B">
<input type="button" title="<span class='o'></span>" value="color">
<input type="button" title="<i></i>" value="i">
<input type="button" title="&lt;a href=""></a>" value="href">
<input type="button" title="<ul></ul>" value="&lt;ul>">
<input type="button" title="<li>" value="li"><br><br>
<input type="button" title="<div style='font-size:18px;text-align:center;'></div>" value="title">
<input type="button" title="CODE" value="CODE">
<input type="button" title="<span style='text-decoration:underline;'></span>" value="underline">
<input type="button" title="<div class='q'></div>" value="quote">
<input type="image" src="/images/pops/icon_smile.gif" alt="Submit" title=":)" style="background-color:<?php print $article_color; ?>;"/>
<input type="image" src="/images/pops/icon_confused.gif" alt="Submit" title=' :/' style="background-color:<?php print $article_color; ?>;"/>
<input type="image" src="/images/pops/icon_biggrin.gif" alt="Submit" title=":D" style="background-color:<?php print $article_color; ?>;"/>
<input type="image" src="/images/pops/icon_razz.gif" alt="Submit" title=":P" style="background-color:<?php print $article_color; ?>;"/>
<input type="image" src="/images/pops/icon_wink.gif" alt="Submit" title=";)" style="background-color:<?php print $article_color; ?>;"/>
<input type="image" src="/images/pops/icon_sad.gif" alt="Submit" title=":(" style="background-color:<?php print $article_color; ?>;"/>
</div>
<br>
class='floatimgleft'

If this is not the current version of your script, please let me know. Both are used in test.php pages.

james438
01-09-2010, 07:34 PM
Should this thread be split up and moved to the javascript forum?

jscheuer1
01-09-2010, 08:51 PM
Should this thread be split up and moved to the javascript forum?

Perhaps. Or the entire thread, if memory serves there is little if any real PHP in this thread. Anyways, here's a demo where it works in Opera here:


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript">
/* editText Script 2009 John Davenport Scheuer
as first seen in http://www.dynamicdrive.com/forums/
username: jscheuer1 - This Notice Must Remain for Legal Use
*/
var editText = {
init: function(){return;}
};
(function(){
if(!document.getElementById){
return;
}
editText = {
saveCurRng: (function(){return document.selection?
function(el){this.el = el; el.focus(); this.curRng = document.selection.createRange();}:
function(el){this.el = el, this.curRng = typeof el.selectionStart === 'number'?
el.value.substring(el.selectionStart, el.selectionEnd) : null;}
})(),
insert: (function(){return document.selection?
function(btag, etag){
this.el.focus();
if(!window.opera){
document.selection.empty();
}
this.curRng.text = btag + this.curRng.text + etag;
this.el.blur();
this.el.focus();
}:function(btag, etag){
if (typeof this.el.selectionStart === 'number'){
var el = this.el, startPos = el.selectionStart, endPos = el.selectionEnd,
l = [btag, this.curRng, etag].join('').length; el.focus();
el.value = [el.value.substring(0, startPos), btag, this.curRng, etag,
el.value.substring(endPos, el.value.length)].join('');
el.selectionStart = el.selectionEnd = startPos + l;
}
};
})(),
controlsFront: function(el, cfg, area){
var t = el[cfg.controlInfo].split(cfg.controlDelimit);
if(window.opera && t.length === 1 && !/^<.*>$/.test(t[0])){
t = el.value.split(cfg.controlDelimit);
}
if(cfg.controlDelimit === '><' && t.length === 2){
t[0] += '>';
t[1] = '<' + t[1];
}
else if(t.length === 1){
t.unshift('');
}
this.saveCurRng(area);
this.insert(t[0], t[1]);
},
addEvent: (function(){return window.addEventListener? function(el, ev, f){
el.addEventListener(ev, f, false);
}:window.attachEvent? function(el, ev, f){
el.attachEvent('on' + ev, f);
}:function(){return;};
})(),
init: function(cfg){
this.addEvent(window, 'load', function(){
var ctrls = document.getElementById(cfg.controls).getElementsByTagName(cfg.controlTag), i = 0,
area = document.getElementById(cfg.el);
editText.addEvent(area, 'change', function(){editText.saveCurRng(area);});
for(i; i < ctrls.length; ++i){
(function(el){
editText.addEvent(el, 'click', function(e){
editText.controlsFront(el, cfg, area);
if(e && e.preventDefault){
e.preventDefault();
}
return false;
});
})(ctrls[i]);
}
});
}
};
})();
editText.init({
el: 'myArea',
controls: 'myControls',
controlTag: 'input',
controlInfo: 'title',
controlDelimit: '><'
});
</script>
</head>
<body>
<form action="#">
<div>
<textarea id="myArea" rows=5 cols=40>The Slow Pink Fox Jumped Over the Quick Green Dog.</textarea><br>
<input type="reset" value="Reset">
</div>
</form>
<div id="myControls">
<input type="button" title="<b></b>" value="B">
<input type="button" title="<i></i>" value="I">
<input type="button" title="<br>" value="BR">
<input type="button" title=" :)" value=" :)">
</div>
</body>
</html>

james438
01-09-2010, 09:49 PM
Thanks. It all works great now. For completeness here are four "buttons" that currently I use. The first uses one word. The second and third are used for prepending and appending highlighted text. The last one uses an image.


<input type="button" title="CODE" value="CODE">
<input type="button" title="<span style='text-decoration:underline;'></span>" value="underline">
<input type="button" title="<div class='q'></div>" value="quote">
<input type="image" src="/images/pops/icon_smile.gif" title=":)" value=":)"/>

How can I make the text within a button bold and another italicized italicized?

Thanks again for your time and patience with me :).

jscheuer1
01-10-2010, 02:33 PM
For bold, give the button a style of font-weight: bold;

For italic, font-style: italic;

james438
01-11-2010, 02:43 AM
I should have looked that one up first before asking.


<input type="button" title="<b></b>" value="B" class="btnb"> works
<b><input type="button" title="<b></b>" value="B"></b> was not working
<span style="font-weight:bold;"><input type="button" title="<b></b>" value="B"></span> was not working
<input type="button" title="<b></b>" value="B" style="font-weight:bold;"> was not working (I probably had a typo or something with this one though)

either way it all works now. I can think of no more questions for this script and thanks for all of your help :)