Forum Moderators: open

Message Too Old, No Replies

Script creates unwanted whitespace

more a CSS issue, actually...

         

RonPK

12:43 am on Jul 29, 2006 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I made a little script that inserts an <ul> next to a <textarea> on an existing page. The ul is added by applying appendChild() to the parentNode of the textarea. A couple of style rules then position the ul nicely next to the textarea (it would default somewhere below the textarea).

So far so good. The thing is that somehow all this creates a lot of undesired whitespace below the texarea, and I can't figure out what's wrong. Your input would be much appreciated.

I've tried to explicitly set the height of the parent element, but that didn't help. I've also messed around with floating the textarea and the ul, to no avail.

If you want to see the script in action, just save it somewhere on your server and link to it (<script src="..."></script> ) from this boards Custom Code Insert Top¦Bottom (in Control Panel > System Preferences). Then hit 'post new topic' or 'post reply'. I find it to be quite handy ;)

Here is the code:


var ta;

window.onload = function () {
// identify the textarea. there is only one. quit if none is found.
ta = document.getElementsByTagName('textarea')[0];
if (!ta)
return;

// attach event handlers to the textarea
addOrAttach(ta, 'select', storeCaretPos);
addOrAttach(ta, 'click', storeCaretPos);
addOrAttach(ta, 'change', storeCaretPos);
addOrAttach(ta, 'keyup', storeCaretPos);
addOrAttach(ta, 'dblclick', storeCaretPos);
addOrAttach(ta, 'mouseup', storeCaretPos);

// create list with edit controls
var ul = document.createElement('ul');
ul.appendChild(createLI("addTags('b')", 'bold'));
ul.appendChild(createLI("addTags('i')", 'italic'));
ul.appendChild(createLI("addTags('small')", 'small'));
ul.appendChild(createLI("addTags('quote')", 'quote'));
ul.appendChild(createLI("addTags('code')", 'code'));
ul.appendChild(createLI("addTags('pre')", 'pre'));
ul.appendChild(createLI("addTags('fixed')", 'fixed'));
ul.appendChild(createLI("addTags('url')", 'link'));
ul.appendChild(createLI("addTags('ul')", 'u-list'));
ul.appendChild(createLI("addTags('ol')", 'o-list'));
ta.parentNode.appendChild(ul);

// position the edit controls to the right of the textarea
ul.style.position = 'relative';
ul.style.top = '-' + ta.offsetHeight + 'px';
ul.style.left = ta.offsetWidth + 10 + 'px';
ul.style.width = '100px';
ul.style.border = '1px solid #fff';
ul.style.margin = 0;
ul.style.fontFamily = 'Verdana, sans-serif';
ul.style.fontSize = '12px';
ul.style.listStyleType = 'none';
}

function createLI(clickhandler, txt) {
var li = document.createElement('li');
li.style.margin = '0 0 0.3em 1em';
var a = document.createElement('a');
a.href = 'javascript:' + clickhandler;
a.appendChild(document.createTextNode(txt));
li.appendChild(a);
return li;
}

// Remember the current position.
function storeCaretPos() {
// only for supporting browsers
if (typeof(ta.createTextRange)!= 'undefined')
ta.caretPos = document.selection.createRange().duplicate();
}

function addOrAttach(el, ev, hdlr) {
if (el.attachEvent)
el.attachEvent('on' + ev, hdlr);
// geckos don't really use the eventhandler, but we'll create it anyway.
else if (el.addEventListener)
el.addEventListener(ev, hdlr, false);
}


function addTags(tag) {
switch (tag) {
case 'url' : var url = prompt("Please enter the URL:", "http://");
if (url)
surroundText('[url=' + url + ']', '[/url]', ta);
break;
case 'ul' :
case 'ol' : replaceText('\n['+tag+']\n[li.]\n[li.]\n[\/'+tag+']\n', ta); break;
// note: replace li. by li
case 'code' :
case 'pre' : surroundText('\n['+tag+']', '[/'+tag+']\n', ta); break;
default : surroundText('['+tag+']', '[/'+tag+']', ta); break;
}
}


// edit methods: replaceText, surroundText
function replaceText(txt, ta) {
// Attempt to create a text range (IE).
if (typeof(ta.caretPos)!= 'undefined' && ta.createTextRange) {
var caretPos = ta.caretPos;
caretPos.text = / $/.test(caretPos.text)? txt + ' ' : txt;
caretPos.select();
}
// geckos & Opera
else if (typeof(ta.selectionStart)!= 'undefined') {
var begin = ta.value.substr(0, ta.selectionStart);
var end = ta.value.substr(ta.selectionEnd);
ta.value = begin + txt + end;
if (ta.setSelectionRange) {
ta.focus();
ta.setSelectionRange(begin.length + txt.length, begin.length + txt.length);
}
}
// else put them on the end.
else {
ta.value += txt;
ta.focus(ta.value.length - 1);
}
}

function surroundText(text1, text2, ta) {
// Can a text range be created (IE)?
if (typeof(ta.caretPos)!= 'undefined' && ta.createTextRange) {
var caretPos = ta.caretPos;
// remove the whitespace IE adds on dblclick
caretPos.text = / $/.test(caretPos.text)?
text1 + caretPos.text.trim() + text2 + ' '
: text1 + caretPos.text + text2;
caretPos.select();
}
// geckos & Opera
else if (typeof(ta.selectionStart)!= 'undefined') {
var newCursorPos = ta.selectionEnd + text1.length + text2.length;
var chars = ta.value.split('');
chars.splice(ta.selectionStart, 0, text1);
chars.splice(ta.selectionEnd+1, 0, text2);
ta.value = chars.join('');
if (ta.setSelectionRange) {
ta.focus();
ta.setSelectionRange(newCursorPos, newCursorPos);
}
}
// else put them on the end.
else {
ta.value += text1 + text2;
ta.focus(ta.value.length - 1);
}
}

String.prototype.trim = function() {
return this.replace(/(^\s+¦\s+$)/, '');
// note: don't forget to fix the broken pipe above
}

daveVk

8:06 am on Jul 29, 2006 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



For tracking problems like this I find, the "View generated source" option in firefox usefull, not sure what extension its in. If problem not obviously, you can cut and hack to narrow it down.

Dave

RonPK

8:38 am on Jul 29, 2006 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Yeah, the developer toolbar is a great tool. In this case, I can see that the list gets inserted after the textarea, as intended. But it doesn't tell me why there is such a huge margin below the textarea.

supermoi

8:28 pm on Jul 29, 2006 (gmt 0)

10+ Year Member



I tried your script and the problem is that both elements (the textarea and the ul) are both block-level elements. Therefore the browser calculates the height of the container to be the sum of the 2. By replacing the ul to a higher position inside the container, it makes it look like the space under it should not be there, where it's actually a perfectly normal behavior.
There's many ways around that I guess. The easiest would probably be to set a max-height (and a height for IE) to your container and make the overflow hidden. Otherwise your can screw around with the css properties by making elements inline and use floats.

RonPK

10:58 pm on Jul 31, 2006 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Thx supermoi, that indeed explains it.

I tried setting the height of the container and applying

overflow: hidden
, but that didn't work. I already had been messing with floats and
display: inline
: no luck there either. The easiest way turned out to be to give the list an absolute position and set the position of the container to relative. That makes it possible to set top and left relative to the containing td and not to the viewport (which would require some serious script to get the right values, cross-browser).

So, for the record, here are the first lines with styling rules for the list:

// position controls to the right of the textarea, by nesting absolute within relative 
ta.parentNode.style.position = 'relative';
ta.parentNode.style.display = 'block';
ul.style.position = 'absolute';
ul.style.top = 0;

supermoi

2:00 am on Aug 1, 2006 (gmt 0)

10+ Year Member



The overflow property does not seem to work inside a <td>, but you can use a <p> inside it to get the same effect.