blob: 1eb1ccd1bb45cab01b951d9a30c1aa975fe052c5 [file] [log] [blame]
/** CSS Picker Plugin by Justin Rovang
*
* For full documentation, please see
* http://bitbucket.org/rovangju/xinha_csspicker/wiki/Home
*
* SAMPLE CONFIG:
*
* You can configure the appearance of the item/style list using the following CSS classes:
* .CSSPickerOption (Normal state)
* .CSSPickerOptionOver (Mouse-over state, typically border change)
* .CSSPickerOptionActive (Indicator for active classes under the selection/carat)
*
* Keys are CSS Class names
* wrapper: tag to wrap selected text with
* name: friendly name to display in panel with that class style applied to it.
*
* Sample config:
* CSSPicker.cssList = {
* 'xinhaDashedBox' : { 'wrapper':'div', 'name':'Breakout box' }
* 'xinhaMiniHeadline' : { 'wrapper':'div', 'name':'Sub-headline' }
* }
*
*/
function CSSPicker(editor, args) {
this.editor = editor;
var CSSPicker = this;
}
CSSPicker._pluginInfo = {
name : "CSSPicker",
version : "2008-12-01",
author : "Justin Rovang"
}
CSSPicker.prototype.onGenerateOnce = function() {
var editor = this.editor;
var CSSPicker = this;
editor._cssPicker = editor.addPanel("right");
this.main = document.createElement("div");
editor._cssPicker.style.backgroundColor='#dee5f8';
editor._cssPicker.appendChild(this.main);
Xinha.freeLater(this,"main");
editor.showPanel(editor._cssPicker);
}
CSSPicker.prototype.onUpdateToolbar = function() {
if(this.editor._cssPicker) {
if(this._timeoutID) window.clearTimeout(this._timeoutID);
var e = this.editor;
this._timeoutID = window.setTimeout(function() { e._gen(); }, 250); //1000 = 1sec / 500=.5sec / 250=.25sec
}
}
Xinha.prototype.listStyles = function(s) {
var editor = this;
var mySel = this.getSelection();
var myRange;
if(Xinha.is_ie) {
myRange = this.saveSelection();//mySel;
mySel = this.createRange(mySel).text;
}
var d = document.createElement("div");
d.className='CSSPickerOption';
/* If our carat is within an active class, highlight it */
var toggleState = editor.getStyleInfo(s);
if(toggleState) Xinha._addClass(d, 'CSSPickerOptionActive');
d.align='center';
// v-- Avoid lc_parse_strings.php
d.innerHTML='<'+'div class="'+s+'">'+CSSPicker.cssList[s].name+'</div>';
d.onclick = function() {
editor.wrapStyle(s, mySel, myRange, CSSPicker.cssList[s].wrapper);
return false;
};
Xinha._addEvent(d, 'mouseover', function(ev) {
Xinha._addClass(d, 'CSSPickerOptionOver');
});
Xinha._addEvent(d, 'mouseout', function(ev) {
Xinha._removeClass(d, 'CSSPickerOptionOver');
});
return d;
}
Xinha.prototype._gen = function() {
this.plugins.CSSPicker.instance.main.innerHTML='';
for(var s in CSSPicker.cssList) {
this.plugins.CSSPicker.instance.main.appendChild(this.listStyles(s));
}
return true;
}
/*
(string) s: style name
(string) sel: selection text
(object) myRange: selection object
(string) sWrapper: wrapper tag (e.g.: div, span)
*/
Xinha.prototype.wrapStyle = function(s, sel, myRange, sWrapper) {
if(!sWrapper) sWrapper="div";
sWrapper=sWrapper.toLowerCase();
/* The reason for these next lines is that we want the user to be able to place
* their cursor below the new div element. Otherwise they can't which makes
* placing anything after a div wrapper difficult/almost impossible. */
var divBreak='';
if(sWrapper=="div") divBreak='<br/>';
var editor=this;
this.focusEditor();
if(Xinha.is_ie) this.restoreSelection(myRange);
/*
* First - Get parent elements and see if the style is already applied.
*/
var toggleState = editor.getStyleInfo(s);
if(!toggleState) {
/* Create a new wrapper when:
* 1. Selected text has no 'snug' wrapper around it already.
* 2. If it does have a 'snug' wrapper, only append to the className if it's of the same type (span or div)
*/
if(sel == '') sel = '&nbsp;'; //We insert this if the selection is empty, making it easier for carat placement via click
this.insertHTML("<"+sWrapper+" class='"+s+"'>"+sel+"</"+sWrapper+">"+divBreak);
/* Modify the 'snug' wrapper if the above conditions are not met for a new element: */
}
else {
/* 1. If the current ancestor has -just- this classname. It should be removed.
* 2. If it has more than one class, it should be removed from the list of the parents
*/
Xinha._removeClass(toggleState, s);
}
return true;
}
Xinha.prototype.getStyleInfo = function(sClassToProbe) {
var editor = this;
var aList = this.getAllAncestors();
var a,s;
if(aList) aList.pop(); //We don't want the body element to show up in this list.
if(aList.length > 0) {
for(var o in aList){
a = aList[o];
/* Instead of break down and rebuild the array for this search, we're going
* to do some string trickery...
* // NOTE: THIS MAY BE PRONE TO PARTIAL MATCHES. SOLUTION IS TO ADD A SPACE PREPEND
*/
if(a.className) {
s = a.className.trim()+' ';
if(s.toLowerCase().match(sClassToProbe.toLowerCase()+' ')) {
return a;
}
}
}
}
return false;
}