?

Log in

No account? Create an account

Customize LiveJournal Post composer - Look, someone's on that tree

Jan. 15th, 2011

01:11 am - Customize LiveJournal Post composer

Previous Entry Share Next Entry

I have been developing advanced custom interfaces with JavaScript for some time now and while I still do not think that whole IDEs written in that language are ready for prime time, I do believe we should be able to extend the already present functionality for our fave web sites.

One easy way to do this is using 'user scripts'.

I use some custom classes in my blog in LiveJournal and there is no easy way to add divs with class names in the HTML editor. However it is fairly easy to add more buttons to the toolbar (I honestly do believe the empty space on the second row is left for users like me, who like to add more buttons!!!).

There are however some limitations when working with multiple iframes.

First of all nodes should either be created in the context of the iframe to which they will be added or created in outer context and imported. Other than that there is nothing special.

Sample code follows (assuming it is executed from 'top' context, however the function should actually be created in the context of the draft iframe to attach the event to the load event of the frame we are targeting, so have this in mind if you take the example code and intend to use it for your own custom buttons):

	var button_action = function(){
		var cDocument = document.getElementById('draft___Frame')
			.contentDocument.getElementById('xEditingArea')
			.childNodes[0].contentDocument;
		var cWindow = document.getElementById('draft___Frame')
			.contentDocument.getElementById('xEditingArea')
			.childNodes[0].contentWindow;


		var oSeclection = cWindow.getSelection();

		if (oSeclection.anchorNode !== oSeclection.focusNode ){
			var i, i1, i2, tmp;
			if (oSeclection.anchorNode === cDocument.body )
				i1 = oSeclection.anchorOffset;
			else {
				for (i=0; i< cDocument.body.childNodes.length; i++){
					if (cDocument.body.childNodes[i] ===
						 oSeclection.anchorNode){
						i1 = i;	
						break;	
					}
				}
			}
			if (oSeclection.focusNode === cDocument.body)
				i2 = oSeclection.focusOffset;
			else {
				for (i=0; i< cDocument.body.childNodes.length; i++){
					if (cDocument.body.childNodes[i] === 
						oSeclection.focusNode){
						i2 = i;		
						break;
					}
				}
			}
			if (i1 > i2) {
				i = i1;
				i1 = i2;
				i2 = i;
			}
			var docFragment = cDocument.createElement('div');
			docFragment.setAttribute('class','cod');
			for (i = i1; i <= i2; i++){
				docFragment.appendChild(cDocument.body.childNodes[i]
					.cloneNode(true));
			}
			for (i = i2; i >= i1; i--){
				cDocument.body.removeChild(cDocument.body.childNodes[i]);
			}
			i = cDocument.body.insertBefore(docFragment, cDocument.body
				.childNodes[i1]);
		}
		else {
			var i;
			for (i=0; i< cDocument.body.childNodes.length; i++){
				if (cDocument.body.childNodes[i] === oSeclection.anchorNode){
					break;	
				}
			}
			var docFragment = cDocument.createElement('div');
			docFragment.setAttribute('class','cod');
			docFragment
				.appendChild(cDocument.body.childNodes[i].cloneNode(true));
			cDocument.body.removeChild(cDocument.body.childNodes[i]);
			i = cDocument.body
				.insertBefore(docFragment, cDocument.body.childNodes[i]);
		}
	};


Notice that I do not want to separate textNodes but copy them as they are (because this is my use case). Probably the code can be shortened by applying better logic, however this is a late night quick and dirty approach and it works.

Now just add it to the new buttons you add to the draft frame and voilà!