Вход Регистрация
Файл: engine/template/module/editor/jquery.wysibb.js
Строк: 3312
<?php
/*! WysiBB v1.5.1 2014-03-26 
    Author: Vadim Dobroskok
 */
if (typeof (WBBLANG)=="undefined") {WBBLANG = {};}
WBBLANG['en'] = CURLANG = {
    
bold"Bold",
    
italic"Italic",
    
underline"Underline",
    
strike"Strike",
    
link"Link",
    
img"Insert image",
    
sup"Superscript",
    
sub"Subscript",
    
justifyleft"Align left",
    
justifycenter"Align center",
    
justifyright"Align right",
    
table"Insert table",
    
bullist"• Unordered list",
    
numlist"1. Ordered list",
    
quote"Quote",
    
offtop"Offtop",
    
code"Code",
    
spoiler"Spoiler",
    
fontcolor"Font color",
    
fontsize"Font size",
    
fontfamily"Font family",
    
fs_verysmall"Very small",
    
fs_small"Small",
    
fs_normal"Normal",
    
fs_big"Big",
    
fs_verybig"Very big",
    
smilebox"Insert emoticon",
    
video"Insert YouTube",
    
removeFormat:"Remove Format",
    
    
modal_link_title"Insert link",
    
modal_link_text"Display text",
    
modal_link_url"URL",
    
modal_email_text"Display email",
    
modal_email_url"Email",
    
modal_link_tab1"Insert URL",
    
    
modal_img_title"Insert image",
    
modal_img_tab1"Insert URL",
    
modal_img_tab2"Upload image",
    
modal_imgsrc_text"Enter image URL",
    
modal_img_btn"Choose file",
    
add_attach"Add Attachment",
    
    
modal_video_text"Enter the URL of the video",
    
    
close"Close",
    
save"Save",
    
cancel"Cancel",
    
remove"Delete",
    
    
validation_err"The entered data is invalid",
    
error_onupload"Error during file upload",
    
    
fileupload_text1"Drop file here",
    
fileupload_text2"or",
    
    
loading"Loading",
    
auto"Auto",
    
views"Views",
    
downloads"Downloads",
    
    
//smiles
    
sm1"Smile",
    
sm2"Laughter",
    
sm3"Wink",
    
sm4"Thank you",
    
sm5"Scold",
    
sm6"Shock",
    
sm7"Angry",
    
sm8"Pain",
    
sm9"Sick"
};
wbbdebug=true;
(function($) {
    
'use strict';
    $.
wysibb = function(txtArea,settings) {
        $(
txtArea).data("wbb",this);
        
        if (
settings && settings.deflang && typeof(WBBLANG[settings.deflang])!="undefined") {CURLANG WBBLANG[settings.deflang];}
        if (
settings && settings.lang && typeof(WBBLANG[settings.lang])!="undefined") {CURLANG WBBLANG[settings.lang];}
        
this.txtArea=txtArea;
        
this.$txtArea=$(txtArea);
        var 
id this.$txtArea.attr("id") || this.setUID(this.txtArea);
        
this.options = {
            
bbmode:                false,
            
onlyBBmode:            false,
            
themeName:            "default"
            
bodyClass:            "",
            
lang:                "ru",
            
tabInsert:            true,
//            toolbar:            false,
            //img upload config 
            
imgupload:            false,
            
img_uploadurl:        "/iupload.php",
            
img_maxwidth:        800,
            
img_maxheight:        800,
            
hotkeys:            true,
            
showHotkeys:        true,
            
autoresize:            true,
            
resize_maxheight:    800,
            
loadPageStyles:        true,
            
traceTextarea:        true,
//            direction:            "ltr",
            
smileConversion:    true,

            
//END img upload config 
            
buttons:             "bold,italic,underline,|,smilebox,|,strike,sup,sub,|,img,video,link,|,bullist,numlist,|,fontcolor,fontsize,fontfamily,|,justifyleft,justifycenter,justifyright,|,quote,code,table,removeFormat",
            
allButtons: {
                
bold : {
                    
titleCURLANG.bold,
                    
buttonHTML'<span class="fonticon ve-tlb-bold1">uE018</span>',
                    
excmd'bold',
                    
hotkey'ctrl+b',
                    
transform : {
                        
'<b>{SELTEXT}</b>':"[b]{SELTEXT}[/b]",
                        
'<strong>{SELTEXT}</strong>':"[b]{SELTEXT}[/b]"
                    
}
                },
                
italic : {
                    
titleCURLANG.italic,
                    
buttonHTML'<span class="fonticon ve-tlb-italic1">uE001</span>',
                    
excmd'italic',
                    
hotkey'ctrl+i',
                    
transform : {
                        
'<i>{SELTEXT}</i>':"[i]{SELTEXT}[/i]",
                        
'<em>{SELTEXT}</em>':"[i]{SELTEXT}[/i]"
                    
}
                },
                
underline : {
                    
titleCURLANG.underline,
                    
buttonHTML'<span class="fonticon ve-tlb-underline1">uE002</span>',
                    
excmd'underline',
                    
hotkey'ctrl+u',
                    
transform : {
                        
'<u>{SELTEXT}</u>':"[u]{SELTEXT}[/u]"
                    
}
                },
                
strike : {
                    
titleCURLANG.strike,
                    
buttonHTML'<span class="fonticon fi-stroke1 ve-tlb-strike1">uE003</span>',
                    
excmd'strikeThrough',
                    
transform : {
                        
'<strike>{SELTEXT}</strike>':"[s]{SELTEXT}[/s]",
                        
'<s>{SELTEXT}</s>':"[s]{SELTEXT}[/s]"
                    
}
                },
                
sup : {
                    
titleCURLANG.sup,
                    
buttonHTML'<span class="fonticon ve-tlb-sup1">uE005</span>',
                    
excmd'superscript',
                    
transform : {
                        
'<sup>{SELTEXT}</sup>':"[sup]{SELTEXT}[/sup]"
                    
}
                },
                
sub : {
                    
titleCURLANG.sub,
                    
buttonHTML'<span class="fonticon ve-tlb-sub1">uE004</span>',
                    
excmd'subscript',
                    
transform : {
                        
'<sub>{SELTEXT}</sub>':"[sub]{SELTEXT}[/sub]"
                    
}
                },
                
link : {
                    
titleCURLANG.link,
                    
buttonHTML'<span class="fonticon ve-tlb-link1">uE007</span>',
                    
hotkey'ctrl+shift+2',
                    
modal: {
                        
titleCURLANG.modal_link_title,
                        
width"500px",
                        
tabs: [
                            {
                                
input: [
                                    {
param"SELTEXT",title:CURLANG.modal_link_texttype"div"},
                                    {
param"URL",title:CURLANG.modal_link_url,validation'^http(s)?://'}
                                ]
                            }
                        ]
                    },
                    
transform : {
                        
'<a href="{URL}">{SELTEXT}</a>':"[url={URL}]{SELTEXT}[/url]",
                        
'<a href="{URL}">{URL}</a>':"[url]{URL}[/url]"
                    
}
                },
                
img : {
                    
titleCURLANG.img,
                    
buttonHTML'<span class="fonticon ve-tlb-img1">uE006</span>',
                    
hotkey'ctrl+shift+1',
                    
addWraptrue,
                    
modal: {
                        
titleCURLANG.modal_img_title,
                        
width"600px",
                        
tabs: [
                            {
                                
titleCURLANG.modal_img_tab1,
                                
input: [
                                    {
param"SRC",title:CURLANG.modal_imgsrc_text,validation'^http(s)?://.*?.(jpg|png|gif|jpeg)$'}
                                ]
                            }
                        ],
                        
onLoadthis.imgLoadModal
                    
},
                    
transform : {
                        
'<img src="{SRC}" />':"[img]{SRC}[/img]",
                        
'<img src="{SRC}" width="{WIDTH}" height="{HEIGHT}"/>':"[img width={WIDTH},height={HEIGHT}]{SRC}[/img]"
                    
}
                },
                
bullist : {
                    
titleCURLANG.bullist,
                    
buttonHTML'<span class="fonticon ve-tlb-list1">uE009</span>',
                    
excmd'insertUnorderedList',
                    
transform : {
                        
'<ul>{SELTEXT}</ul>':"[list]{SELTEXT}[/list]",
                        
'<li>{SELTEXT}</li>':"[*]{SELTEXT}[/*]"
                    
}
                },
                
numlist : {
                    
titleCURLANG.numlist,
                    
buttonHTML'<span class="fonticon ve-tlb-numlist1">uE00a</span>',
                    
excmd'insertOrderedList',
                    
transform : {
                        
'<ol>{SELTEXT}</ol>':"[list=1]{SELTEXT}[/list]",
                        
'<li>{SELTEXT}</li>':"[*]{SELTEXT}[/*]"
                    
}
                },
                
quote : {
                    
titleCURLANG.quote,
                    
buttonHTML'<span class="fonticon ve-tlb-quote1">uE00c</span>',
                    
hotkey'ctrl+shift+3',
                    
//subInsert: true,
                    
transform : { 
                        
'<blockquote>{SELTEXT}</blockquote>':"[quote]{SELTEXT}[/quote]"
                    
}
                },
                
offtop : {
                    
titleCURLANG.offtop,
                    
buttonText'offtop',
                    
transform : {
                        
'<span style="font-size:10px;color:#ccc">{SELTEXT}</span>':"[offtop]{SELTEXT}[/offtop]"
                    
}
                },
                
fontcolor: {
                    
type"colorpicker",
                    
titleCURLANG.fontcolor,
                    
excmd"foreColor",
                    
valueBBname"color",
                    
subInserttrue,
                    
colors"#000000,#444444,#666666,#999999,#b6b6b6,#cccccc,#d8d8d8,#efefef,#f4f4f4,#ffffff,-, 
                             #ff0000,#980000,#ff7700,#ffff00,#00ff00,#00ffff,#1e84cc,#0000ff,#9900ff,#ff00ff,-, 
                             #f4cccc,#dbb0a7,#fce5cd,#fff2cc,#d9ead3,#d0e0e3,#c9daf8,#cfe2f3,#d9d2e9,#ead1dc, 
                             #ea9999,#dd7e6b,#f9cb9c,#ffe599,#b6d7a8,#a2c4c9,#a4c2f4,#9fc5e8,#b4a7d6,#d5a6bd, 
                             #e06666,#cc4125,#f6b26b,#ffd966,#93c47d,#76a5af,#6d9eeb,#6fa8dc,#8e7cc3,#c27ba0, 
                             #cc0000,#a61c00,#e69138,#f1c232,#6aa84f,#45818e,#3c78d8,#3d85c6,#674ea7,#a64d79, 
                             #900000,#85200C,#B45F06,#BF9000,#38761D,#134F5C,#1155Cc,#0B5394,#351C75,#741B47, 
                             #660000,#5B0F00,#783F04,#7F6000,#274E13,#0C343D,#1C4587,#073763,#20124D,#4C1130"
,
                    
transform: {
                        
'<font color="{COLOR}">{SELTEXT}</font>':'[color={COLOR}]{SELTEXT}[/color]'
                    
}
                },

                
fontsize: {
                    
type'select',
                    
titleCURLANG.fontsize,
                    
options"fs_verysmall,fs_small,fs_normal,fs_big,fs_verybig"
                
},
                
fontfamily: {
                    
type'select',
                    
titleCURLANG.fontfamily,
                    
excmd'fontName',
                    
valueBBname"font",
                    
options: [
                        {
title"Arial",exvalue"Arial"},
                        {
title"Comic Sans MS",exvalue"Comic Sans MS"},
                        {
title"Courier New",exvalue"Courier New"},
                        {
title"Georgia",exvalue"Georgia"},
                        {
title"Lucida Sans Unicode",exvalue"Lucida Sans Unicode"},
                        {
title"Tahoma",exvalue"Tahoma"},
                        {
title"Times New Roman",exvalue"Times New Roman"},
                        {
title"Trebuchet MS",exvalue"Trebuchet MS"},
                        {
title"Verdana",exvalue"Verdana"}
                    ],
                    
transform: {
                        
'<font face="{FONT}">{SELTEXT}</font>':'[font={FONT}]{SELTEXT}[/font]'
                    
}
                },
                
smilebox: {
                    
type'smilebox',
                    
titleCURLANG.smilebox,
                    
buttonHTML'<span class="fonticon ve-tlb-smilebox1">uE00b</span>'
                
},
                
justifyleft: {
                    
titleCURLANG.justifyleft,
                    
buttonHTML'<span class="fonticon ve-tlb-textleft1">uE015</span>',
                    
groupkey'align',
                    
transform: {
                        
'<p style="text-align:left">{SELTEXT}</p>''[left]{SELTEXT}[/left]'
                    
}
                },
                
justifyright: {
                    
titleCURLANG.justifyright,
                    
buttonHTML'<span class="fonticon ve-tlb-textright1">uE016</span>',
                    
groupkey'align',
                    
transform: {
                        
'<p style="text-align:right">{SELTEXT}</p>''[right]{SELTEXT}[/right]'
                    
}
                },
                
justifycenter: {
                    
titleCURLANG.justifycenter,
                    
buttonHTML'<span class="fonticon ve-tlb-textcenter1">uE014</span>',
                    
groupkey'align',
                    
transform: {
                        
'<p style="text-align:center">{SELTEXT}</p>''[center]{SELTEXT}[/center]'
                    
}
                },
                
video: {
                    
titleCURLANG.video,
                    
buttonHTML'<span class="fonticon ve-tlb-video1">uE008</span>',
                    
modal: {
                        
titleCURLANG.video,
                        
width"600px",
                        
tabs: [
                            {
                                
titleCURLANG.video,
                                
input: [
                                    {
param"SRC",title:CURLANG.modal_video_text}
                                ]
                            }
                        ],
                        
onSubmit: function(cmd,opt,queryState) {
                            var 
url this.$modal.find('input[name="SRC"]').val();
                            if (
url) {
                                
url url.replace(/^s+/,"").replace(/s+$/,"");
                            }
                            var 
a;
                            if (
url.indexOf("youtu.be")!=-1) {
                                
url.match(/^http[s]*://youtu.be/([a-z0-9_-]+)/i);
                            
}else{
                                
url.match(/^http[s]*://www.youtube.com/watch?.*?v=([a-z0-9_-]+)/i);
                            
}
                            if (
&& a.length==2) {
                                var 
code a[1];
                                
this.insertAtCursor(this.getCodeByCommand(cmd,{src:code}));
                            }
                            
this.closeModal();
                            
this.updateUI();
                            return 
false;
                        }
                    },
                    
transform: {
                        
'<iframe src="http://www.youtube.com/embed/{SRC}" width="640" height="480" frameborder="0"></iframe>':'[video]{SRC}[/video]'
                    
}
                },
                
                
//select options
                
fs_verysmall: {
                    
titleCURLANG.fs_verysmall,
                    
buttonText"fs1",
                    
excmd'fontSize',
                    
exvalue"1",
                    
transform: {
                        
'<font size="1">{SELTEXT}</font>':'[size=50]{SELTEXT}[/size]'
                    
}
                },
                
fs_small: {
                    
titleCURLANG.fs_small,
                    
buttonText"fs2",
                    
excmd'fontSize',
                    
exvalue"2",
                    
transform: {
                        
'<font size="2">{SELTEXT}</font>':'[size=85]{SELTEXT}[/size]'
                    
}
                },
                
fs_normal: {
                    
titleCURLANG.fs_normal,
                    
buttonText"fs3",
                    
excmd'fontSize',
                    
exvalue"3",
                    
transform: {
                        
'<font size="3">{SELTEXT}</font>':'[size=100]{SELTEXT}[/size]'
                    
}
                },
                
fs_big: {
                    
titleCURLANG.fs_big,
                    
buttonText"fs4",
                    
excmd'fontSize',
                    
exvalue"4",
                    
transform: {
                        
'<font size="4">{SELTEXT}</font>':'[size=150]{SELTEXT}[/size]'
                    
}
                },
                
fs_verybig: {
                    
titleCURLANG.fs_verybig,
                    
buttonText"fs5",
                    
excmd'fontSize',
                    
exvalue"6",
                    
transform: {
                        
'<font size="6">{SELTEXT}</font>':'[size=200]{SELTEXT}[/size]'
                    
}
                },
                
                
removeformat: {
                    
titleCURLANG.removeFormat,
                    
buttonHTML'<span class="fonticon ve-tlb-removeformat1">uE00f</span>',
                    
excmd"removeFormat"
                
}
            },
            
systr: {
                
'<br/>':"n",
                
'<span class="wbbtab">{SELTEXT}</span>''   {SELTEXT}'
            
},
            
customRules: {
                
td: [["[td]{SELTEXT}[/td]",{seltext: {rgx:false,attr:false,sel:false}}]],
                
tr: [["[tr]{SELTEXT}[/tr]",{seltext: {rgx:false,attr:false,sel:false}}]],
                
table: [["[table]{SELTEXT}[/table]",{seltext: {rgx:false,attr:false,sel:false}}]]
                
//blockquote: [["   {SELTEXT}",{seltext: {rgx:false,attr:false,sel:false}}]]
            
},
            
smileList: [
                
//{title:CURLANG.sm1, img: '<img src="{themePrefix}{themeName}/img/smiles/sm1.png" class="sm">', bbcode:":)"},
            
],
            
attrWrap: ['src','color','href'//use becouse FF and IE change values for this attr, modify [attr] to _[attr]
        
}
        
        
//FIX for Opera. Wait while iframe loaded
        
this.inited=this.options.onlyBBmode;
        
        
//init css prefix, if not set
        
if (!this.options.themePrefix) {
            $(
'link').each($.proxy(function(idxel) {
                var 
sriptMatch = $(el).get(0).href.match(/(.*/)(.*)/wbbtheme.css.*$/);
                if (
sriptMatch !== null) {
                    
this.options.themeName sriptMatch[2];
                    
this.options.themePrefix sriptMatch[1];
                }
            },
this));
        }
        
        
//check for preset
        
if (typeof(WBBPRESET)!="undefined") {
            if (
WBBPRESET.allButtons) {
                
//clear transform
                
$.each(WBBPRESET.allButtons,$.proxy(function(k,v) {
                    if (
v.transform && this.options.allButtons[k]) {
                        
delete this.options.allButtons[k].transform;
                    }
                },
this));
            }
            $.
extend(true,this.options,WBBPRESET);
        } 
        
        if (
settings && settings.allButtons) {
            $.
each(settings.allButtons,$.proxy(function(k,v) {
                if (
v.transform && this.options.allButtons[k]) {
                    
delete this.options.allButtons[k].transform;
                }
            },
this));
        }
        $.
extend(true,this.options,settings);
        
this.init();
    }
    
    $.
wysibb.prototype = {
        
lastid 1,
        
init:    function() {
            $.
log("Init",this);
            
//check for mobile
            
this.isMobile = function(a) {(/android|avantgo|bada/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|meego.+mobile|midp|mmp|netfront|opera m(ob|in)i|palmos)?|phone|p(ixi|re)/|plucker|pocket|psp|series(4|6)0|symbian|treo|up.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a))}(navigator.userAgent||navigator.vendor||window.opera);
            
            
//use bbmode on mobile devices
            //this.isMobile = true; //TEMP
            
if (this.options.onlyBBmode===true) {this.options.bbmode=true;}
            
//create array of controls, for queryState
            
this.controllers = [];
            
            
//convert button string to array
            
this.options.buttons this.options.buttons.toLowerCase();
            
this.options.buttons this.options.buttons.split(",");
            
            
//init system transforms
            
this.options.allButtons["_systr"] = {};
            
this.options.allButtons["_systr"]["transform"]= this.options.systr;
            
            
this.smileFind();
            
this.initTransforms();
            
this.build();
            
this.initModal();
            if (
this.options.hotkeys===true && !this.isMobile) {
                
this.initHotkeys();
            }
            
            
//sort smiles
            
if (this.options.smileList && this.options.smileList.length>0) {
                
this.options.smileList.sort(function(a,b) {
                    return (
b.bbcode.length-a.bbcode.length);
                })
            }
            
            
this.$txtArea.parents("form").bind("submit",$.proxy(function() {
                
this.sync();
                return 
true;
            },
this)); 
            
            
            
//phpbb2
            
this.$txtArea.parents("form").find("input[id*='preview'],input[id*='submit'],input[class*='preview'],input[class*='submit'],input[name*='preview'],input[name*='submit']").bind("mousedown",$.proxy(function() {
                
this.sync();
                
setTimeout($.proxy(function() {
                    if (
this.options.bbmode===false) {
                        
this.$txtArea.removeAttr("wbbsync").val("");
                    }
                },
this),1000);
            },
this));
            
//end phpbb2
            
            
if (this.options.initCallback) {
                
this.options.initCallback.call(this);
            }
            
            $.
log(this);
            
        },
        
initTransforms: function() {
            $.
log("Create rules for transform HTML=>BB");
            var 
this.options;
            
//need to check for active buttons
            
if (!o.rules) {o.rules={};}
            if (!
o.groups) {o.groups={};} //use for groupkey, For example: justifyleft,justifyright,justifycenter. It is must replace each other.
            
var  btnlist o.buttons.slice();
            
            
//add system transform
            
btnlist.push("_systr");
            for (var 
bidx=0bidx<btnlist.lengthbidx++) {
                var 
ob o.allButtons[btnlist[bidx]];
                if (!
ob ) {continue;}
                
ob.en=true;
                
                
//check for simplebbcode
                
if (ob.simplebbcode && $.isArray(ob.simplebbcode) && ob.simplebbcode.length==2) {
                    
ob.bbcode ob.html ob.simplebbcode[0]+"{SELTEXT}"+ob.simplebbcode[1];
                    if (
ob.transformdelete ob.transform;
                    if (
ob.modal)  delete ob.modal;
                }
                
                
//add transforms to option list
                
if (ob.type=="select" && typeof(ob.options)=="string") {
                    var 
olist ob.options.split(",");
                    $.
each(olist,function(i,op) {
                        if ($.
inArray(op,btnlist)==-1) {
                            
btnlist.push(op);
                        }
                    });
                }
                if (
ob.transform && ob.skipRules!==true) {
                    var 
obtr = $.extend({},ob.transform);
                    
                    
/* if (ob.addWrap) {
                        //addWrap
                        $.log("needWrap");
                        for (var bhtml in obtr) {
                            var bbcode = ob.transform[bhtml];
                            var newhtml = '<span wbb="'+btnlist[bidx]+'">'+bhtml+'</span>';
                            obtr[newhtml] = bbcode;
                        }
                    } */
                    
                    
for (var bhtml in obtr) {
                        var 
orightml bhtml;
                        var 
bbcode obtr[bhtml];
                        
                        
//create root selector for isContain bbmode
                        
if (!ob.bbSelector) {ob.bbSelector=[];}
                        if ($.
inArray(bbcode,ob.bbSelector)==-1) {
                            
ob.bbSelector.push(bbcode);
                        }
                        if (
this.options.onlyBBmode===false) {
                        
                            
//wrap attributes 
                            
bhtml this.wrapAttrs(bhtml);
                            

                            var 
$bel = $(document.createElement('DIV')).append($(this.elFromString(bhtml,document)));
                            var 
rootSelector this.filterByNode($bel.children());
                            
                            
                            
//check if current rootSelector is exist, create unique selector for each transform (1.2.2)
                            
if (rootSelector=="div" || typeof(o.rules[rootSelector])!="undefined") {
                                
//create unique selector
                                
$.log("create unique selector: "+rootSelector);
                                
this.setUID($bel.children());
                                
rootSelector this.filterByNode($bel.children());
                                $.
log("New rootSelector: "+rootSelector);
                                
//replace transform with unique selector
                                
var nhtml2 $bel.html();
                                
nhtml2 this.unwrapAttrs(nhtml2);
                                var 
obhtml this.unwrapAttrs(bhtml);
                                
                                
                                
ob.transform[nhtml2]=bbcode;
                                
delete ob.transform[obhtml];
                                
                                
bhtml=nhtml2;
                                
orightml nhtml2;
                            }
                            
                            
//create root selector for isContain
                            
if (!ob.excmd) {
                                if (!
ob.rootSelector) {ob.rootSelector=[];}
                                
ob.rootSelector.push(rootSelector);
                            }
                            
                            
//check for rules on this rootSeletor
                            
if (typeof(o.rules[rootSelector])=="undefined") {
                                
o.rules[rootSelector]=[];
                            }
                            var 
crules={};
                            
                            if (
bhtml.match(/{S+?}/)) {
                                
$bel.find('*').each($.proxy(function(idx,el) {
                                    
//check attributes
                                    
                                    
var attributes this.getAttributeList(el);
                                    $.
each(attributes,$.proxy(function(iitem) {
                                        var 
attr = $(el).attr(item);
                                        if (
item.substr(0,1)=='_') {
                                            
item item.substr(1);
                                        }
                                        
                                        var 
attr.match(/{S+?}/g);
                                        if (
r) {
                                            for (var 
a=0a<r.lengtha++) {
                                                var 
rname r[a].substr(1,r[a].length-2);
                                                    
rname rname.replace(this.getValidationRGX(rname),"");
                                                var 
this.relFilterByNode(el,rootSelector);
                                                var 
regRepl = (attr!=r[a]) ? this.getRegexpReplace(attr,r[a]):false;
                                                
crules[rname.toLowerCase()]={sel:(p) ? $.trim(p):false,attr:item,rgx:regRepl}
                                            }
                                        }
                                    },
this));
                                    
                                    
//check for text
                                    
var  sl=[];
                                    if (!$(
el).is("iframe")) {
                                        $(
el).contents().filter(function() {return this.nodeType===3}).each($.proxy(function(i,rel) {
                                            var 
txt rel.textContent || rel.data;
                                            if (
typeof(txt)=="undefined") {return true;}
                                            var 
txt.match(/{S+?}/g)
                                            if (
r) {
                                                for (var 
a=0a<r.lengtha++) {    
                                                    var 
rname r[a].substr(1,r[a].length-2);
                                                        
rname rname.replace(this.getValidationRGX(rname),"");
                                                    var 
this.relFilterByNode(el,rootSelector);
                                                    var 
regRepl = (txt!=r[a]) ? this.getRegexpReplace(txt,r[a]):false;
                                                    var 
sel = (p) ? $.trim(p):false;
                                                    if ($.
inArray(sel,sl)>-|| $(rel).parent().contents().size()>1) {
                                                        
//has dublicate and not one children, need wrap
                                                        
var nel = $("<span>").html("{"+rname+"}");
                                                        
this.setUID(nel,"wbb");
                                                        var 
start = (txt.indexOf(rname)+rname.length)+1;
                                                        var 
after_txt txt.substr(start,txt.length-start);
                                                        
//create wrap element
                                                        
rel.data txt.substr(0,txt.indexOf(rname)-1);
                                                        $(
rel).after(this.elFromString(after_txt,document)).after(nel);
                                                        
                                                        
sel=((sel) ? sel+" ":"")+this.filterByNode(nel);
                                                        
regRepl=false;
                                                    }
                                                    
crules[rname.toLowerCase()]={sel:sel,attr:false,rgx:regRepl}
                                                    
sl[sl.length]=sel;
                                                }
                                            }
                                        },
this));
                                    }
                                    
sl=null;
                                    
                                    
                                },
this));
                                
                                var 
nbhtml $bel.html();
                                
//UnWrap attributes 
                                
nbhtml this.unwrapAttrs(nbhtml);
                                if (
orightml!=nbhtml) {
                                    
//if we modify html, replace it
                                    
delete ob.transform[orightml];
                                    
ob.transform[nbhtml]=bbcode;
                                    
bhtml=nbhtml;
                                }
                                
                            }
                            
o.rules[rootSelector].push([bbcode,crules]);
                            
                            
//check for onlyClearText
                            
if (ob.onlyClearText===true) {
                                if (!
this.cleartext) {this.cleartext={};}
                                
this.cleartext[rootSelector]=btnlist[bidx];
                            }
                            
                            
//check for groupkey
                            
if (ob.groupkey) {
                                if (!
o.groups[ob.groupkey]) {o.groups[ob.groupkey]=[]}
                                
o.groups[ob.groupkey].push(rootSelector);
                            }
                        }
                    }
                    
                    
//sort rootSelector
                    
if (ob.rootSelector) {
                        
this.sortArray(ob.rootSelector,-1);
                    }
                        
                    var 
htmll = $.map(ob.transform,function(bb,html) {return html}).sort(function(a,b) {
                            return ((
b[0] || "").length-(a[0] || "").length)
                    });
                    
ob.bbcode ob.transform[htmll[0]];
                    
ob.html htmll[0];
                }
            };
            
            
this.options.btnlist=btnlist//use for transforms, becouse select elements not present in buttons
            
            //add custom rules, for table,tr,td and other
            
$.extend(o.rules,this.options.customRules);
        
            
//smile rules
            
o.srules={};
            if (
this.options.smileList) {
                $.
each(o.smileList,$.proxy(function(i,sm) {
                    var 
$sm = $(this.strf(sm.img,o));
                    var 
this.filterByNode($sm);
                    
o.srules[f]=[sm.bbcode,sm.img];
                },
this));
            }
            
            
//sort transforms by bbcode length desc
            
for (var rootsel in o.rules) {
                
this.options.rules[rootsel].sort(function(a,b) {
                    return (
b[0].length-a[0].length)
                });
            }
            
            
//create rootsel list
            
this.rsellist = [];
            for (var 
rootsel in this.options.rules) {
                
this.rsellist.push(rootsel);
            }
            
this.sortArray(this.rsellist,-1);
        },
        
        
//BUILD
        
build: function() {
            $.
log("Build editor");
            
            
//this.$editor = $('<div class="wysibb">');
            
this.$editor = $('<div>').addClass("wysibb");
            
            if (
this.isMobile) {
                
this.$editor.addClass("wysibb-mobile");
            }
            
            
//set direction if defined
            
if (this.options.direction) {this.$editor.css("direction",this.options.direction)}
            
            
this.$editor.insertAfter(this.txtArea).append(this.txtArea);
            
            
this.startHeight this.$txtArea.outerHeight();
            
this.$txtArea.addClass("wysibb-texarea");
            
this.buildToolbar();
            
//Build iframe if needed
            
this.$txtArea.wrap('<div class="wysibb-text">');
            
            if (
this.options.onlyBBmode===false) {
                var 
height this.options.minheight || this.$txtArea.outerHeight();
                var 
maxheight this.options.resize_maxheight;
                var 
mheight = (this.options.autoresize===true) ? this.options.resize_maxheight:height;
                
this.$body = $(this.strf('<div class="wysibb-text-editor" style="max-height:{maxheight}px;min-height:{height}px"></div>',{maxheight:mheight,height:height})).insertAfter(this.$txtArea);
                
this.body this.$body[0];
                
this.$txtArea.hide();
                
                if (
height>32) {
                    
this.$toolbar.css("max-height",height);
                }
                
                $.
log("WysiBB loaded");
                
                
this.$body.addClass("wysibb-body").addClass(this.options.bodyClass);
                
                
//set direction if defined
                
if (this.options.direction) {this.$body.css("direction",this.options.direction)}
                
                
                if (
'contentEditable' in this.body) {
                    
this.body.contentEditable=true;
                    try{
                        
//fix for mfirefox
                        //document.execCommand('enableObjectResizing', false, 'false'); //disable image resizing
                        
document.execCommand('StyleWithCSS'falsefalse);
                        
//document.designMode = "on";
                        
this.$body.append("<span></span>");
                    }catch(
e) {}
                }else{
                    
//use onlybbmode
                    
this.options.onlyBBmode=this.options.bbmode=true;
                }
                
                
//check for exist content in textarea
                
if (this.txtArea.value.length>0) {
                    
this.txtAreaInitContent();
                }
                
                
                
//clear html on paste from external editors
                
this.$body.bind('keydown', $.proxy(function(e) {
                    if ((
e.which == 86 && (e.ctrlKey==true || e.metaKey==true)) || (e.which == 45 && (e.shiftKey==true || e.metaKey==true))) {
                        if (!
this.$pasteBlock) {
                            
this.saveRange();
                            
this.$pasteBlock = $(this.elFromString('<div style="opacity:0;" contenteditable="true">uFEFF</div>'));
                            
                            
this.$pasteBlock.appendTo(this.body);
                            
//if (!$.support.search?type=2) {this.$pasteBlock.focus();} //IE 7,8 FIX
                                
setTimeout($.proxy(function() {
                                    
this.clearPaste(this.$pasteBlock);
                                    var 
rdata '<span>'+this.$pasteBlock.html()+'</span>';
                                    
this.$body.attr("contentEditable","true");
                                    
this.$pasteBlock.blur().remove();
                                    
this.body.focus();

                                    if (
this.cleartext) {
                                        $.
log("Check if paste to clearText Block");
                                        if (
this.isInClearTextBlock()) {
                                            
rdata this.toBB(rdata).replace(/n/g,"<br/>").replace(/s{3}/g,'<span class="wbbtab"></span>');
                                        }
                                    }
                                    
rdata rdata.replace(/t/g,'<span class="wbbtab"></span>');
                                    
this.selectRange(this.lastRange);
                                    
this.insertAtCursor(rdata,false);
                                    
this.lastRange=false;
                                    
this.$pasteBlock=false;
                                }
                                ,
this), 1);
                            
this.selectNode(this.$pasteBlock[0]);
                        }
                        return 
true;
                    }
                },
this));
                
                
//insert BR on press enter
                
this.$body.bind('keydown',$.proxy(function(e) {
                    if (
e.which == 13) {
                        var 
isLi this.isContain(this.getSelectNode(),'li');
                        if (!
isLi) {
                            if (
e.preventDefault) {e.preventDefault();}
                            
this.checkForLastBR(this.getSelectNode());
                            
this.insertAtCursor('<br/>',false);
                        }
                    }
                },
this));
                
                
//tabInsert
                
if (this.options.tabInsert===true) {
                    
this.$body.bind('keydown', $.proxy(this.pressTab,this));
                }
                
                
//add event listeners
                
this.$body.bind('mouseup keyup',$.proxy(this.updateUI,this));
                
this.$body.bind('mousedown',$.proxy(function(e) {this.clearLastRange();this.checkForLastBR(e.target)},this));

                
//trace Textarea
                
if (this.options.traceTextarea===true) {
                    $(
document).bind("mousedown",$.proxy(this.traceTextareaEvent,this));
                    
this.$txtArea.val("");
                }

                
//attach hotkeys
                
if (this.options.hotkeys===true) {
                    
this.$body.bind('keydown',$.proxy(this.presskey,this));
                }
                
                
//smileConversion
                
if (this.options.smileConversion===true) {
                    
this.$body.bind('keyup',$.proxy(this.smileConversion,this));
                }

                
this.inited=true;

                
//create resize lines
                
if (this.options.autoresize===true) {
                    
this.$bresize = $(this.elFromString('<div class="bottom-resize-line"></div>')).appendTo(this.$editor)
                        .
wdrag({
                            
scope:this,
                            
axisYtrue,
                            
heightheight
                        
});
                }
                
                
this.imgListeners();
            }
            
            
            
//this.$editor.append('<span class="powered">Powered by <a href="http://www.wysibb.com" target="_blank">WysiBB<a/></span>');
            
            //add event listeners to textarea 
            
this.$txtArea.bind('mouseup keyup',$.proxy(function() {
                
clearTimeout(this.uitimer);
                
this.uitimer setTimeout($.proxy(this.updateUI,this),100);
            },
this));
            
            
//attach hotkeys
            
if (this.options.hotkeys===true) {
                $(
document).bind('keydown',$.proxy(this.presskey,this));
            }
        },
        
buildToolbar: function() {
            if (
this.options.toolbar === false) {return false;}
            
            
//this.$toolbar = $('<div class="wysibb-toolbar">').prependTo(this.$editor);
            
this.$toolbar = $('<div>').addClass("wysibb-toolbar").prependTo(this.$editor);
            
            var 
$btnContainer;
            $.
each(this.options.buttons,$.proxy(function(i,bn) {
                var 
opt this.options.allButtons[bn];
                if (
i==|| bn=="|" || bn=="-") {
                    if (
bn=="-") {
                        
this.$toolbar.append("<div>");
                    }
                    
$btnContainer = $('<div class="wysibb-toolbar-container">').appendTo(this.$toolbar);
                }
                if (
opt) {
                    if (
opt.type=="colorpicker") {
                        
this.buildColorpicker($btnContainer,bn,opt);
                    }else if (
opt.type=="table") {
                        
this.buildTablepicker($btnContainer,bn,opt);
                    }else if (
opt.type=="select") {
                        
this.buildSelect($btnContainer,bn,opt);
                    }else if (
opt.type=="smilebox") {
                        
this.buildSmilebox($btnContainer,bn,opt);
                    }else{
                        
this.buildButton($btnContainer,bn,opt);
                    }
                }
            },
this));
            
            
//fix for hide tooltip on quick mouse over
            
this.$toolbar.find(".btn-tooltip").hover(function () {$(this).parent().css("overflow","hidden")},function() {$(this).parent().css("overflow","visible")});
            
            
//build bbcode switch button
            //var $bbsw = $('<div class="wysibb-toolbar-container modeSwitch"><div class="wysibb-toolbar-btn" unselectable="on"><span class="btn-inner ve-tlb-bbcode" unselectable="on"></span></div></div>').appendTo(this.$toolbar);
            
var $bbsw = $(document.createElement('div')).addClass("wysibb-toolbar-container modeSwitch").html('<div class="wysibb-toolbar-btn mswitch" unselectable="on"><span class="btn-inner modesw" unselectable="on">BB</span></div>').appendTo(this.$toolbar);
            if (
this.options.bbmode==true) {$bbsw.children(".wysibb-toolbar-btn").addClass("on");}
            if (
this.options.onlyBBmode===false) {
                
$bbsw.children(".wysibb-toolbar-btn").click($.proxy(function(e) {
                    $(
e.currentTarget).toggleClass("on");
                    
this.modeSwitch();
                },
this));
            }
        },
        
buildButton: function(container,bn,opt) {
            if (
typeof(container)!="object") {
                
container this.$toolbar;
            }
            var 
btnHTML = (opt.buttonHTML) ? $(this.strf(opt.buttonHTML,this.options)).addClass("btn-inner") : this.strf('<span class="btn-inner btn-text">{text}</span>',{text:opt.buttonText.replace(/</g,"&lt;")});
            var 
hotkey = (this.options.hotkeys===true && this.options.showHotkeys===true && opt.hotkey) ? (' <span class="tthotkey">['+opt.hotkey+']</span>'):""
            
var $btn = $('<div class="wysibb-toolbar-btn wbb-'+bn+'">').appendTo(container).append(btnHTML).append(this.strf('<span class="btn-tooltip">{title}<ins/>{hotkey}</span>',{title:opt.title,hotkey:hotkey}));
            
            
//attach events
            
this.controllers.push($btn);
            
$btn.bind('queryState',$.proxy(function(e) {
                (
this.queryState(bn)) ? $(e.currentTarget).addClass("on"):$(e.currentTarget).removeClass("on");
            },
this));
            
$btn.mousedown($.proxy(function(e) {
                
e.preventDefault();
                
this.execCommand(bn,opt.exvalue || false);
                $(
e.currentTarget).trigger('queryState');
            },
this));
        },
        
buildColorpicker: function(container,bn,opt) {
            var 
$btn = $('<div class="wysibb-toolbar-btn wbb-dropdown wbb-cp">').appendTo(container).append('<div class="ve-tlb-colorpick"><span class="fonticon">uE010</span><span class="cp-line"></span></div><ins class="fonticon ar">uE011</ins>').append(this.strf('<span class="btn-tooltip">{title}<ins/></span>',{title:opt.title}));
            var 
$cpline $btn.find(".cp-line");
            
            var 
$dropblock = $('<div class="wbb-list">').appendTo($btn); 
            
$dropblock.append('<div class="nc">'+CURLANG.auto+'</div>');
            var 
colorlist = (opt.colors) ? opt.colors.split(","):[]; 
            for (var 
j=0j<colorlist.lengthj++) {
                
colorlist[j] = $.trim(colorlist[j]);
                if (
colorlist[j]=="-") { 
                    
//insert padding
                    
$dropblock.append('<span class="pl"></span>');
                }else{ 
                    
$dropblock.append(this.strf('<div class="sc" style="background:{color}" title="{color}"></div>',{color:colorlist[j]}));
                }
            }
            var 
basecolor = $(document.body).css("color");
            
//attach events
            
this.controllers.push($btn);
            
$btn.bind('queryState',$.proxy(function(e) {
                
//queryState
                
$cpline.css("background-color",basecolor);
                var 
this.queryState(bn,true);
                if (
r) {
                    
$cpline.css("background-color",(this.options.bbmode) ? r.color:r);
                    
$btn.find(".ve-tlb-colorpick span.fonticon").css("color",(this.options.bbmode) ? r.color:r);
                }
            },
this));
            
$btn.mousedown($.proxy(function(e) {
                
e.preventDefault();
                
this.dropdownclick(".wbb-cp",".wbb-list",e);
            },
this));
            
$btn.find(".sc").mousedown($.proxy(function(e) {
                
e.preventDefault();
                
this.selectLastRange();
                var 
= $(e.currentTarget).attr("title");
                
this.execCommand(bn,c);
                
$btn.trigger('queryState');
            },
this));
            
$btn.find(".nc").mousedown($.proxy(function(e) {
                
e.preventDefault();
                
this.selectLastRange();
                
this.execCommand(bn,basecolor);
                
$btn.trigger('queryState');
            },
this));
            
$btn.mousedown(function(e) { 
                if (
e.preventDefaulte.preventDefault();
            });
        },
        
buildTablepicker: function(container,bn,opt) {
            var 
$btn = $('<div class="wysibb-toolbar-btn wbb-dropdown wbb-tbl">').appendTo(container).append('<span class="btn-inner fonticon ve-tlb-table1">uE00e</span><ins class="fonticon ar">uE011</ins>').append(this.strf('<span class="btn-tooltip">{title}<ins/></span>',{title:opt.title}));
            
            var 
$listblock = $('<div class="wbb-list">').appendTo($btn);
            var 
$dropblock = $('<div>').css({"position":"relative","box-sizing":"border-box"}).appendTo($listblock);
            var 
rows opt.rows || 10;
            var 
cols opt.cols || 10;
            var 
allcount rows*cols;
            
$dropblock.css("height",(rows*opt.cellwidth+2)+"px");
            for (var 
j=1j<=colsj++) {
                for (var 
h=1h<=rowsh++) {
                    
//var html = this.strf('<div class="tbl-sel" style="width:{width}px;height:{height}px;z-index:{zindex}" title="{row},{col}"></div>',{width: (j*opt.cellwidth),height: (h*opt.cellwidth),zindex: --allcount,row:h,col:j});
                    
var html '<div class="tbl-sel" style="width:'+(j*100/cols)+'%;height:'+(h*100/rows)+'%;z-index:'+(--allcount)+'" title="'+h+','+j+'"></div>';
                    
$dropblock.append(html);
                }
            }
            
//this.debug("Attach event on: tbl-sel");
            
$btn.find(".tbl-sel").mousedown($.proxy(function(e) {
                
e.preventDefault();
                var 
= $(e.currentTarget).attr("title");
                var 
rc t.split(",");
                var 
code = (this.options.bbmode) ? '[table]':'<table class="wbb-table" cellspacing="5" cellpadding="0">';
                for (var 
i=1i<=rc[0]; i++) {
                    
code += (this.options.bbmode) ? ' [tr]n':'<tr>';
                    for (var 
j=1j<=rc[1]; j++) {
                        
code += (this.options.bbmode) ? '  [td][/td]n':'<td>uFEFF</td>';
                    }
                    
code += (this.options.bbmode) ? '[/tr]n':'</tr>';
                }
                
code += (this.options.bbmode) ? '[/table]':'</table>';
                
this.insertAtCursor(code);
            },
this));
            
//this.debug("END Attach event on: tbl-sel");
            
$btn.mousedown($.proxy(function(e) {
                
e.preventDefault();
                
this.dropdownclick(".wbb-tbl",".wbb-list",e);
            },
this));
            
        },
        
buildSelect: function(container,bn,opt) {
            var 
$btn = $('<div class="wysibb-toolbar-btn wbb-select wbb-'+bn+'">').appendTo(container).append(this.strf('<span class="val">{title}</span><ins class="fonticon sar">uE012</ins>',opt)).append(this.strf('<span class="btn-tooltip">{title}<ins/></span>',{title:opt.title}));  
            var 
$sblock = $('<div class="wbb-list">').appendTo($btn);
            var 
$sval $btn.find("span.val");
            
            var 
olist = ($.isArray(opt.options)) ? opt.options:opt.options.split(",");
            var 
$selectbox = (this.isMobile) ? $("<select>").addClass("wbb-selectbox"):"";
            for (var 
i=0i<olist.lengthi++) {
                var 
oname olist[i];
                if (
typeof(oname)=="string") {
                    var 
option this.options.allButtons[oname];
                    if (
option) {
                        
//$.log("create: "+oname); 
                        
if (option.html) {
                            $(
'<span>').addClass("option").attr("oid",oname).attr("cmdvalue",option.exvalue).appendTo($sblock).append(this.strf(option.html,{seltext:option.title}));
                        }else{
                            
$sblock.append(this.strf('<span class="option" oid="'+oname+'" cmdvalue="'+option.exvalue+'">{title}</span>',option));
                        }
                        
                        
//SelectBox for mobile devices
                        
if (this.isMobile) {
                            
$selectbox.append($('<option>').attr("oid",oname).attr("cmdvalue",option.exvalue).append(option.title));
                        }
                    }
                }else{
                    
//build option list from array
                    
var params = {
                        
seltextoname.title
                    
}
                    
params[opt.valueBBname]=oname.exvalue;
                    $(
'<span>').addClass("option").attr("oid",bn).attr("cmdvalue",oname.exvalue).appendTo($sblock).append(this.strf(opt.html,params));
                    
                    if (
this.isMobile) {$selectbox.append($('<option>').attr("oid",bn).attr("cmdvalue",oname.exvalue).append(oname.exvalue))}
                }
            }
            
//$sblock.append($selectbox);
            
if (this.isMobile) {
                
$selectbox.appendTo(container);
                
this.controllers.push($selectbox);
                
                
$selectbox.bind('queryState',$.proxy(function(e) {
                    
//queryState
                    
$selectbox.find("option").each($.proxy(function(i,el){
                        var 
$el = $(el);
                        var 
this.queryState($el.attr("oid"),true);
                        var 
cmdvalue $el.attr("cmdvalue");
                        if ((
cmdvalue && r==$el.attr("cmdvalue")) || (!cmdvalue && r)) {
                            
$el.prop("selected",true);
                            return 
false;
                        }
                    },
this));
                },
this));
                
                
$selectbox.change($.proxy(function(e) {
                    
e.preventDefault();
                    var 
$o =  $(e.currentTarget).find(":selected");
                    var 
oid $o.attr("oid");
                    var 
cmdvalue $o.attr("cmdvalue");
                    var 
opt this.options.allButtons[oid];
                    
this.execCommand(oid,opt.exvalue || cmdvalue || false);
                    $(
e.currentTarget).trigger('queryState');
                },
this));
                
            }
            
this.controllers.push($btn);
            
$btn.bind('queryState',$.proxy(function(e) {
                
//queryState
                
$sval.text(opt.title);
                
$btn.find(".option.selected").removeClass("selected");
                
$btn.find(".option").each($.proxy(function(i,el){
                    var 
$el = $(el);
                    var 
this.queryState($el.attr("oid"),true);
                    var 
cmdvalue $el.attr("cmdvalue");
                    if ((
cmdvalue && r==$el.attr("cmdvalue")) || (!cmdvalue && r)) {
                        
$sval.text($el.text());
                        
$el.addClass("selected");
                        return 
false;
                    }
                },
this));
            },
this));
            
$btn.mousedown($.proxy(function(e) {
                
e.preventDefault();
                
this.dropdownclick(".wbb-select",".wbb-list",e);
            },
this));
            
$btn.find(".option").mousedown($.proxy(function(e) {
                
e.preventDefault();
                var 
oid = $(e.currentTarget).attr("oid");
                var 
cmdvalue = $(e.currentTarget).attr("cmdvalue");
                var 
opt this.options.allButtons[oid];
                
this.execCommand(oid,opt.exvalue || cmdvalue || false);
                $(
e.currentTarget).trigger('queryState');
            },
this));
        },
        
buildSmilebox: function(container,bn,opt) {
            if (
this.options.smileList && this.options.smileList.length>0) {
                var 
$btnHTML = $(this.strf(opt.buttonHTML,opt)).addClass("btn-inner");
                var 
$btn = $('<div class="wysibb-toolbar-btn wbb-smilebox wbb-'+bn+'">').appendTo(container).append($btnHTML).append(this.strf('<span class="btn-tooltip">{title}<ins/></span>',{title:opt.title}));  
                var 
$sblock = $('<div class="wbb-list">').appendTo($btn);
                if ($.
isArray(this.options.smileList)) {
                    $.
each(this.options.smileList,$.proxy(function(i,sm){
                        $(
'<span>').addClass("smile").appendTo($sblock).append($(this.strf(sm.img,this.options)).attr("title",sm.title));
                    },
this));
                }
                
$btn.mousedown($.proxy(function(e) {
                    
e.preventDefault();
                    
this.dropdownclick(".wbb-smilebox",".wbb-list",e);
                },
this));
                
$btn.find('.smile').mousedown($.proxy(function(e) {
                    
e.preventDefault();
                    
//this.selectLastRange();
                    
this.insertAtCursor((this.options.bbmode) ? this.toBB($(e.currentTarget).html()):$($(e.currentTarget).html()));
                },
this))
            }
        },
        
updateUI: function(e) {
            if (!
|| ((e.which>=&& e.which<=46) || e.which>90 || e.type=="mouseup")) {
                $.
each(this.controllers,$.proxy(function(i,$btn) {
                    
$btn.trigger('queryState');
                },
this));
            }
            
            
//check for onlyClearText
            
this.disNonActiveButtons();
            
        },
        
initModal: function() {
            
this.$modal=$("#wbbmodal");
            if (
this.$modal.size()==0) {
                $.
log("Init modal");
                
this.$modal = $('<div>').attr("id","wbbmodal").prependTo(document.body)
                    .
html('<div class="wbbm"><div class="wbbm-title"><span class="wbbm-title-text"></span><span class="wbbclose" title="'+CURLANG.close+'">×</span></div><div class="wbbm-content"></div><div class="wbbm-bottom"><button id="wbbm-submit" class="wbb-button">'+CURLANG.save+'</button><button id="wbbm-cancel" class="wbb-cancel-button">'+CURLANG.cancel+'</button><button id="wbbm-remove" class="wbb-remove-button">'+CURLANG.remove+'</button></div></div>').hide();
                
                
this.$modal.find('#wbbm-cancel,.wbbclose').click($.proxy(this.closeModal,this));
                
this.$modal.bind('click',$.proxy(function(e) {
                    if ($(
e.target).parents(".wbbm").size()==0) {
                        
this.closeModal();
                    }
                },
this));
                
                $(
document).bind("keydown",$.proxy(this.escModal,this)); //ESC key close modal
            
}
        },
        
initHotkeys: function() {
            $.
log("initHotkeys");
            
this.hotkeys=[];
            var 
klist "0123456789       abcdefghijklmnopqrstuvwxyz";
            $.
each(this.options.allButtons,$.proxy(function(cmd,opt) {
                if (
opt.hotkey) {
                    var 
keys opt.hotkey.split("+");
                     if (
keys && keys.length>=2) {
                        var 
metasum=0;
                        var 
key keys.pop();
                        $.
each(keys,function(i,k) {
                            switch($.
trim(k.toLowerCase())) {
                                case 
"ctrl": {metasum+=1;break;}
                                case 
"shift": {metasum+=4;break;}
                                case 
"alt": {metasum+=7;break;}
                            }
                        })
                        
//$.log("metasum: "+metasum+" key: "+key+" code: "+(klist.indexOf(key)+48));
                        
if (metasum>0) {
                            if (!
this.hotkeys["m"+metasum]) {this.hotkeys["m"+metasum]=[];}
                            
this.hotkeys["m"+metasum]["k"+(klist.indexOf(key)+48)]=cmd;
                        }
                    }
                }
            },
this))
        },
        
presskey: function(e) {
            if (
e.ctrlKey==true || e.shiftKey==true || e.altKey==true) {
                var  
metasum = ((e.ctrlKey==true) ? 1:0)+((e.shiftKey==true) ? 4:0)+((e.altKey==true) ? 7:0);
                if (
this.hotkeys["m"+metasum] && this.hotkeys["m"+metasum]["k"+e.which]) {
                    
this.execCommand(this.hotkeys["m"+metasum]["k"+e.which],false);
                    
e.preventDefault();
                    return 
false;
                }
            }
        },
        
        
//COgdfMMAND FUNCTIONS
        
execCommand: function(command,value) {
            $.
log("execCommand: "+command);
            var 
opt this.options.allButtons[command];
            if (
opt.en!==true) {return false;}
            var 
queryState this.queryState(command,value);
            
            
//check for onlyClearText
            
var skipcmd this.isInClearTextBlock();
            if (
skipcmd && skipcmd!=command) {return;}
            
            
            if (
opt.excmd) {
                
//use NativeCommand
                
if (this.options.bbmode) {
                    $.
log("Native command in bbmode: "+command);
                    if (
queryState && opt.subInsert!=true) {
                        
//remove bbcode
                        
this.wbbRemoveCallback(command,value);
                    }else{
                        
//insert bbcode
                        
var = {};
                        if (
opt.valueBBname && value) {
                            
v[opt.valueBBname]=value;
                        }
                        
this.insertAtCursor(this.getBBCodeByCommand(command,v));
                    }
                }else{
                    
this.execNativeCommand(opt.excmd,value || false);
                }
            }else if (!
opt.cmd) {
                
//wbbCommand
                //this.wbbExecCommand(command,value,queryState,$.proxy(this.wbbInsertCallback,this),$.proxy(this.wbbRemoveCallback,this));
                
this.wbbExecCommand.call(this,command,value,queryState);
            }else{
                
//user custom command
                
opt.cmd.call(this,command,value,queryState);
            }
            
this.updateUI();
        },
        
queryState: function(command,withvalue) {
            var 
opt this.options.allButtons[command];
            if (
opt.en!==true) {return false;}
            
//if (opt.subInsert===true && opt.type!="colorpicker") {return false;}
            
if (this.options.bbmode) {
                
//bbmode
                
if (opt.bbSelector) {
                    for (var 
i=0i<opt.bbSelector.lengthi++) {
                        var 
this.isBBContain(opt.bbSelector[i]);
                        if (
b) {
                            return 
this.getParams(b,opt.bbSelector[i],b[1]);
                        }
                    }
                }
                return 
false;
            }else{
                if (
opt.excmd) {
                    
//native command
                    
if (withvalue) {
                        try {
                            
//Firefox fix
                            
var = (document.queryCommandValue(opt.excmd)+"").replace(/'/g,"");
                            if (opt.excmd=="foreColor") {
                                v = this.rgbToHex(v);
                            }
                            //return (v==value);
                            return v;
                        }catch(e) {return false;}
                    }else{
                        try { //Firefox fix, exception while get queryState for UnorderedList
                            if ((opt.excmd=="bold" || opt.excmd=="italic" || opt.excmd=="underline" || opt.excmd=="strikeThrough") && $(this.getSelectNode()).is("img")) { //Fix, when img selected
                                return false;
                            }else if (opt.excmd=="underline" && $(this.getSelectNode()).closest("a").size()>0) { //fix, when link select
                                return false;
                            }
                            return document.queryCommandState(opt.excmd);
                        }catch(e) {return false;}
                    }
                }else{
                    //custom command
                    if ($.isArray(opt.rootSelector)) {
                        for (var i=0; i<opt.rootSelector.length; i++) {
                            var n = this.isContain(this.getSelectNode(),opt.rootSelector[i]);
                            if (n) {
                                return this.getParams(n,opt.rootSelector[i]);
                            }
                        }
                    }
                    return false;
                }
            }
        },
        wbbExecCommand: function(command,value,queryState) { //default command for custom bbcodes
            $.log("wbbExecCommand");
            var opt = this.options.allButtons[command];
            if (opt) {
                if (opt.modal) {
                    if ($.isFunction(opt.modal)) {
                        //custom modal function
                        //opt.modal(command,opt.modal,queryState,new clbk(this));
                        opt.modal.call(this,command,opt.modal,queryState);
                    }else{
                        this.showModal.call(this,command,opt.modal,queryState);
                    }
                }else{
                    if (queryState && opt.subInsert!=true) {
                        //remove formatting
                        //removeCallback(command,value);
                        this.wbbRemoveCallback(command);
                    }else{
                        //insert format
                        if (opt.groupkey) {
                            var groupsel = this.options.groups[opt.groupkey];
                            if (groupsel) {
                                var snode = this.getSelectNode();
                                $.each(groupsel,$.proxy(function(i,sel) {
                                    var is = this.isContain(snode,sel);
                                    if (is) {
                                        var $sp = $('
<span>').html(is.innerHTML)
                                        var id = this.setUID($sp);
                                        $(is).replaceWith($sp);
                                        this.selectNode(this.$editor.find("#"+id)[0]);
                                        return false;
                                    }
                                },this));
                            }
                        }
                        this.wbbInsertCallback(command,value)
                    }
                }
            }
        },
        wbbInsertCallback: function(command,paramobj) {
            if (typeof(paramobj)!="object") {paramobj={}};
            $.log("wbbInsertCallback: "+command);
            var data = this.getCodeByCommand(command,paramobj);
            this.insertAtCursor(data);
            
            if (this.seltextID && data.indexOf(this.seltextID)!=-1) {
                var snode = this.$body.find("#"+this.seltextID)[0];
                this.selectNode(snode);
                $(snode).removeAttr("id");
                this.seltextID=false;
            }
        },
        wbbRemoveCallback: function(command,clear) {
            $.log("wbbRemoveCallback: "+command);
            var opt = this.options.allButtons[command];
            if (this.options.bbmode) {
                //bbmode
                //REMOVE BBCODE
                var pos = this.getCursorPosBB();
                var stextnum=0;
                $.each(opt.bbSelector,$.proxy(function(i,bbcode) {
                    var stext = bbcode.match(/{[sS]+?}/g);
                    $.each(stext,function(n,s) {
                        if (s.toLowerCase()=="{seltext}") {stextnum=n;return false}
                    });
                    var a = this.isBBContain(bbcode);
                    if (a) {
                        this.txtArea.value = this.txtArea.value.substr(0,a[1])+this.txtArea.value.substr(a[1],this.txtArea.value.length-a[1]).replace(a[0][0],(clear===true) ? '':a[0][stextnum+1]);
                        this.setCursorPosBB(a[1]);
                        return false;
                    }
                },this));
            }else{
                var node = this.getSelectNode();
                $.each(opt.rootSelector,$.proxy(function(i,s) {
                    //$.log("RS: "+s);
                    var root = this.isContain(node,s);
                    if (!root) {return true;}
                    var $root = $(root);
                    var cs = this.options.rules[s][0][1];
                    if ($root.is("span[wbb]") || !$root.is("span,font")) { //remove only blocks
                        if (clear===true || (!cs || !cs["seltext"])) {
                            this.setCursorByEl($root);
                            $root.remove();
                        }else{
                            if (cs && cs["seltext"] && cs["seltext"]["sel"]) {
                                var htmldata = $root.find(cs["seltext"]["sel"]).html();
                                if (opt.onlyClearText===true) {
                                    htmldata = this.getHTML(htmldata,true,true);
                                    htmldata = htmldata.replace(/&#123;/g,"{").replace(/&#125;/g,"}");
                                }
                                $root.replaceWith(htmldata);
                            }else{
                                var htmldata = $root.html();
                                if (opt.onlyClearText===true) {
                                    htmldata = this.getHTML(htmldata,true);
                                    htmldata = htmldata.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&#123;/g,"{").replace(/&#125;/g,"}");
                                }
                                $root.replaceWith(htmldata);
                            }
                        }
                        return false;
                    }else{
                        //span,font - extract select content from this span,font
                        var rng = this.getRange();
                        var shtml = this.getSelectText();
                        var rnode = this.getSelectNode();
                        if (shtml=="") {
                            shtml="uFEFF";
                        }else{
                            shtml = this.clearFromSubInsert(shtml,command);
                        }
                        var ins = this.elFromString(shtml);
                        
                        var before_rng = (window.getSelection) ? rng.cloneRange():this.body.createTextRange();
                        var after_rng = (window.getSelection) ? rng.cloneRange():this.body.createTextRange();

                        if (window.getSelection) {
                            this.insertAtCursor('
<span id="wbbdivide"></span>');
                            var div = $root.find('
span#wbbdivide').get(0);
                            
before_rng.setStart(root.firstChild,0);
                            
before_rng.setEndBefore(div);
                            
after_rng.setStartAfter(div);
                            
after_rng.setEndAfter(root.lastChild);
                        }else{
                            
before_rng.moveToElementText(root);
                            
after_rng.moveToElementText(root);
                            
before_rng.setEndPoint('EndToStart',rng);
                            
after_rng.setEndPoint('StartToEnd',rng);
                        }
                        var 
bf this.getSelectText(false,before_rng);
                        var 
af this.getSelectText(false,after_rng);
                        if (
af!="") {
                            var 
$af $root.clone().html(af);
                            
$root.after($af);
                        }
                        if (
clear!==true$root.after(ins); //insert select html
                        
if (window.getSelection) {
                            
$root.html(bf);
                            if (
clear!==truethis.selectNode(ins);
                        }else{
                            
$root.replaceWith(bf);
                        }
                        return 
false;
                    }
                },
this));
            }
        },
        
execNativeCommand: function(cmd,param) { 
            
//$.log("execNativeCommand: '"+cmd+"' : "+param); 
            
this.body.focus(); //set focus to frame body
            
if (cmd=="insertHTML" && !window.getSelection) { //IE does't support insertHTML
                
var = (this.lastRange) ? this.lastRange:document.selection.createRange(); //IE 7,8 range lost fix
                
r.pasteHTML(param);
                var 
txt = $('<div>').html(param).text(); //for ie selection inside block
                
var brsp txt.indexOf("uFEFF");
                if (
brsp>-1) {
                    
r.moveStart('character',(-1)*(txt.length-brsp));
                    
r.select();
                }
                
this.lastRange=false;
            }else if (
cmd=="insertHTML") { //fix webkit bug with insertHTML
                
var sel this.getSelection();
                var 
this.elFromString(param);
                var 
rng = (this.lastRange) ? this.lastRange:this.getRange();
                
rng.deleteContents();
                
rng.insertNode(e);
                
rng.collapse(false);
                
sel.removeAllRanges();
                
sel.addRange(rng);
            }else{
                if (
typeof param == "undefined") {param=false;}
                if (
this.lastRange) {
                    $.
log("Last range select");
                    
this.selectLastRange()
                }
                
document.execCommand(cmdfalseparam);
            }
            
        },
        
getCodeByCommand: function(command,paramobj) {
            return (
this.options.bbmode) ? this.getBBCodeByCommand(command,paramobj):this.getHTMLByCommand(command,paramobj);
        },
        
getBBCodeByCommand: function(command,params) {
            if (!
this.options.allButtons[command]) {return "";}
            if (
typeof(params)=="undefined") {params={};}
            
params this.keysToLower(params);
            if (!
params["seltext"]) {
                
//get selected text
                
params["seltext"] = this.getSelectText(true);
            }
            
            var 
bbcode this.options.allButtons[command].bbcode;
            
//bbcode = this.strf(bbcode,params);
            
bbcode bbcode.replace(/{(.*?)([.*?])*}/g,function(str,p,vrgx) {
                if (
vrgx) {
                    var 
vrgxp;
                    if (
vrgx) {
                        
vrgxp = new RegExp(vrgx+"+","i");
                    }
                    if (
typeof(params[p.toLowerCase()])!="undefined" && params[p.toLowerCase()].toString().match(vrgxp)===null) {
                        
//not valid value
                        
return "";
                    }
                }
                return (
typeof(params[p.toLowerCase()])=="undefined") ? "":params[p.toLowerCase()];
            });
            
            
//insert first with max params
            
var rbbcode=null,maxpcount=0;
            if (
this.options.allButtons[command].transform) {
                var 
tr=[];
                $.
each(this.options.allButtons[command].transform,function(html,bb) {
                    
tr.push(bb);
                });
                
tr=this.sortArray(tr,-1);
                $.
each(tr,function(i,v) {
                    var 
valid=true,pcount=0,pname={};;
                    
v.replace(/{(.*?)([.*?])*}/g,function(str,p,vrgx) {
                        var 
vrgxp;
                        
p.toLowerCase();
                        if (
vrgx) {
                            
vrgxp = new RegExp(vrgx+"+","i");
                        }
                        if (
typeof(params[p.toLowerCase()])=="undefined" || (vrgx && params[p.toLowerCase()].toString().match(vrgxp)===null)) {valid=false;};
                        if (
typeof(params[p])!="undefined" && !pname[p]) {pname[p]=1;pcount++;}
                        return (
typeof(params[p.toLowerCase()])=="undefined") ? "":params[p.toLowerCase()];
                    });
                    if (
valid && (pcount>maxpcount)) {rbbcode v;maxpcount=pcount;}
                });
            }
            return 
rbbcode || bbcode;
        },
        
getHTMLByCommand: function(command,params) {
            if (!
this.options.allButtons[command]) {return "";}
            
params this.keysToLower(params);
            if (
typeof(params)=="undefined") {params={};}
            if (!
params["seltext"]) {
                
//get selected text
                
params["seltext"] = this.getSelectText(false);
                
//$.log("seltext: '"+params["seltext"]+"'");
                
if (params["seltext"]=="") {params["seltext"]="uFEFF";}
                else{
                    
//clear selection from current command tags
                    
params["seltext"] = this.clearFromSubInsert(params["seltext"],command);
                    
                    
//toBB if params onlyClearText=true
                    
if (this.options.allButtons[command].onlyClearText===true) {
                        
params["seltext"] = this.toBB(params["seltext"]).replace(/</g,"&lt;").replace(/n/g,"<br/>").replace(/s{3}/g,'<span class="wbbtab"></span>'); 
                    }
                    
                }
            }
            
            var 
postsel="";
            
this.seltextID "wbbid_"+(++this.lastid);
            if (
command!="link" && command!="img") {
                
params["seltext"] = '<span id="'+this.seltextID+'">'+params["seltext"]+'</span>'//use for select seltext
            
}else{
                
postsel '<span id="'+this.seltextID+'">uFEFF</span>'
            
}
            var 
html this.options.allButtons[command].html;
            
html html.replace(/{(.*?)([.*?])*}/g,function(str,p,vrgx) {
                if (
vrgx) {
                    var 
vrgxp = new RegExp(vrgx+"+","i");
                    if (
typeof(params[p.toLowerCase()])!="undefined" && params[p.toLowerCase()].toString().match(vrgxp)===null) {
                        
//not valid value
                        
return "";
                    }
                }
                return (
typeof(params[p.toLowerCase()])=="undefined") ? "":params[p.toLowerCase()];
            });
            
            
//insert first with max params
            
var rhtml=null,maxpcount=0;
            if (
this.options.allButtons[command].transform) {
                var 
tr=[];
                $.
each(this.options.allButtons[command].transform,function(html,bb) {
                    
tr.push(html);
                });
                
tr=this.sortArray(tr,-1);
                $.
each(tr,function(i,v) {
                    var 
valid=truepcount=0,pname={};
                    
v.replace(/{(.*?)([.*?])*}/g,function(str,p,vrgx) {
                        var 
vrgxp;
                        
p.toLowerCase();
                        if (
vrgx) {
                            
vrgxp = new RegExp(vrgx+"+","i");
                        }
                        if (
typeof(params[p])=="undefined" || (vrgx && params[p].toString().match(vrgxp)===null)) {valid=false;};
                        if (
typeof(params[p])!="undefined" && !pname[p]) {pname[p]=1;pcount++;}
                        return (
typeof(params[p])=="undefined") ? "":params[p];
                    });
                    if (
valid && (pcount>maxpcount)) {rhtml v;maxpcount=pcount;}
                });
            }
            return (
rhtml || html)+postsel;
        },
        
        
//SELECTION FUNCTIONS
        
getSelection: function() {
            if (
window.getSelection) {
                return 
window.getSelection();
            }else if (
document.selection) {
                return (
this.options.bbmode) ? document.selection.createRange():document.selection.createRange();
            }
        },
        
getSelectText: function(fromTxtArea,range) {
            if (
fromTxtArea) {
                
//return select text from textarea
                
this.txtArea.focus();
                if(
'selectionStart' in this.txtArea) {
                    var 
this.txtArea.selectionEnd this.txtArea.selectionStart;
                    return 
this.txtArea.value.substr(this.txtArea.selectionStartl);
                }else{
                    
//IE
                    
var document.selection.createRange();
                    return 
r.text;
                }
            }else{
                
//return select html from body
                
this.body.focus();
                if (!
range)  {range=this.getRange()};
                if (
window.getSelection) {
                    
//w3c
                    
if (range) {
                        return $(
'<div>').append(range.cloneContents()).html();
                    }
                }else{
                    
//ie
                    
return range.htmlText;
                }
            }
            return 
"";
        },
        
getRange: function() {
            if (
window.getSelection) {
                var 
sel this.getSelection();
                if (
sel.getRangeAt && sel.rangeCount>0) {
                    return 
sel.getRangeAt(0);
                }else if (
sel.anchorNode) {
                    var 
range = (this.options.bbmode) ? document.createRange() : document.createRange();
                    
range.setStart (sel.anchorNodesel.anchorOffset);
                    
range.setEnd (sel.focusNodesel.focusOffset);
                    return 
range;
                }
            }else{
                return (
this.options.bbmode===true) ? document.selection.createRange():document.selection.createRange();
            }
        },
        
insertAtCursor: function(code,forceBBMode) {
            if (
typeof(code)!="string") {code = $("<div>").append(code).html();}
            if ((
this.options.bbmode && typeof(forceBBMode)=="undefined") || forceBBMode===true) {
                var 
clbb code.replace(/.*([/S+?])$/,"$1");
                var 
this.getCursorPosBB()+((code.indexOf(clbb)!=-&& code.match(/[.*]/)) ? code.indexOf(clbb):code.length);
                if (
document.selection) {
                    
//IE
                    
this.txtArea.focus();
                    
this.getSelection().text=code;
                }else if (
this.txtArea.selectionStart || this.txtArea.selectionStart == '0') {
                    
this.txtArea.value this.txtArea.value.substring(0this.txtArea.selectionStart) + code this.txtArea.value.substring(this.txtArea.selectionEndthis.txtArea.value.length);
                }
                if (
p<0) {p=0;}
                
this.setCursorPosBB(p);
            }else{
                
this.execNativeCommand("insertHTML",code);
                var 
node this.getSelectNode();
                if (!$(
node).closest("table,tr,td")) {
                    
this.splitPrevNext(node);
                }
            }
        },
        
getSelectNode: function(rng) {
            
this.body.focus();
            if (!
rng) {rng=this.getRange();}
            if (!
rng) {return this.$body;}
            
//return (window.getSelection) ? rng.commonAncestorContainer:rng.parentElement();
            
var sn = (window.getSelection) ? rng.commonAncestorContainer:rng.parentElement();
            if ($(
sn).is(".imgWrap")) {sn = $(sn).children("img")[0];}
            return 
sn;
        },
        
getCursorPosBB: function() {    
            var 
pos=0;
            if (
'selectionStart' in this.txtArea) {
                
pos this.txtArea.selectionStart;
            }else{
                
this.txtArea.focus();
                var 
this.getRange();
                var 
rt document.body.createTextRange();
                
rt.moveToElementText(this.txtArea);
                
rt.setEndPoint('EndToStart',r);
                
pos rt.text.length;
            }
            return 
pos;
        },
        
setCursorPosBB: function(pos) {
            if (
this.options.bbmode) {
                if (
window.getSelection) {
                    
this.txtArea.selectionStart=pos;
                    
this.txtArea.selectionEnd=pos;
                }else{
                    var 
range this.txtArea.createTextRange();
                    
range.collapse(true);
                    
range.move('character'pos);
                    
range.select();
                }
            }
        },
        
selectNode: function(node,rng) {
            if (!
rng) {rng this.getRange();}
            if (!
rng) {return;}
            if (
window.getSelection) {
                var 
sel this.getSelection();
                
rng.selectNodeContents(node)
                
sel.removeAllRanges();
                
sel.addRange(rng);
            }else{
                
rng.moveToElementText(node);
                
rng.select();
            }
        },
        
selectRange: function(rng) {
            if (
rng) {
                if (!
window.getSelection) {
                    
rng.select();
                }else{
                    var 
sel this.getSelection();
                    
sel.removeAllRanges();
                    
sel.addRange(rng);
                }
            }
        },
        
cloneRange: function(rng) {
            if (
rng) {
                if (!
window.getSelection) {
                    return 
rng.duplicate();
                }else{
                    return 
rng.cloneRange();
                }
            }
        },
        
getRangeClone: function() {
            return 
this.cloneRange(this.getRange());
        },
        
saveRange: function() {
            
this.setBodyFocus();
            
//this.lastRange=(this.options.bbmode) ? this.getCursorPosBB():this.getRangeClone();
            
this.lastRange=this.getRangeClone();
        },
        
selectLastRange: function() {
            if (
this.lastRange) {
                
this.body.focus();
                
this.selectRange(this.lastRange);
                
this.lastRange=false;
            }
        },
        
setBodyFocus: function() {
            $.
log("Set focus to WysiBB editor");
            if (
this.options.bbmode) {
                if (!
this.$txtArea.is(":focus")) {
                    
this.$txtArea.focus();
                }
            }else{
                if (!
this.$body.is(":focus")) {
                    
this.$body.focus();
                }
            }
        },
        
clearLastRange: function() {
            
this.lastRange=false;
        },
         
        
//TRANSFORM FUNCTIONS
        
filterByNode: function(node) {
            var 
$n = $(node);
            var 
tagName $n.get(0).tagName.toLowerCase();
            var 
filter=tagName;
            var 
attributes this.getAttributeList($n.get(0));
            $.
each(attributes, $.proxy(function(iitem) {
                var 
$n.attr(item);
                
/* $.log("v: "+v);
                if ($.inArray(item,this.options.attrWrap)!=-1) {
                    item = '_'+item;
                } */
                //$.log(item);
                
if (item.substr(0,1)=="_") {item=item.substr(1,item.length)}
                if (
&& !v.match(/{.*?}/)) {
                    
//$.log("I1: "+item);
                    
if (item=="style") {
                        var 
$n.attr(item);
                        var 
va v.split(";");
                        $.
each(va,function(i,f) {
                            if (
&& f.length>0) {
                                
filter+='['+item+'*="'+$.trim(f)+'"]';
                            }
                        });
                    }else{
                        
filter+='['+item+'="'+v+'"]';
                    }
                }else if (
&& item=="style") {
                    
//$.log("I2: "+item);
                    
var vf v.substr(0,v.indexOf("{"));
                    if (
vf && vf!="") {
                        var 
v.substr(0,v.indexOf("{"));
                        var 
va v.split(";");
                        $.
each(va,function(i,f) {
                            
filter+='['+item+'*="'+f+'"]';
                        });
                        
//filter+='['+item+'*="'+v.substr(0,v.indexOf("{"))+'"]';
                    
}
                }else{ 
//1.2.2
                    //$.log("I3: "+item);
                    
filter+='['+item+']';
                }
            },
this));
            
            
//index
            
var idx $n.parent().children(filter).index($n);
            if (
idx>0) {
                
filter+=":eq("+$n.index()+")";
            }
            return 
filter;
        },
        
relFilterByNode: function(node,stop) {
            var 
p="";
            $.
each(this.options.attrWrap,function(i,a) {
                
stop stop.replace('['+a,'[_'+a);
            });
            while (
node && node.tagName!="BODY" && !$(node).is(stop)) {
                
p=this.filterByNode(node)+" "+p;
                if (
node) {node node.parentNode;}
            }
            return 
p;
        },
        
getRegexpReplace: function(str,validname) {
            
str str.replace(/((|)|[|]|.|*|?|:|\)/g,"\$1"
                .
replace(/s+/g,"\s+")
                .
replace(validname.replace(/((|)|[|]|.|*|?|:|\)/g,"\$1"),"(.+)")
                .
replace(/{S+?}/g,".*");
            return (
str);
        },
        
getBBCode: function() {
            if (!
this.options.rules) {return this.$txtArea.val();}
            if (
this.options.bbmode) {return this.$txtArea.val();}
            
this.clearEmpty();
            
this.removeLastBodyBR();
            return 
this.toBB(this.$body.html());
        },
        
toBB: function(data) {
            if (!
data) {return "";};
            var 
$e = (typeof(data)=="string") ? $('<span>').html(data):$(data);
            
//remove last BR
            
$e.find("div,blockquote,p").each(function() {
                if (
this.nodeType!=&& this.lastChild && this.lastChild.tagName=="BR") {
                    $(
this.lastChild).remove();
                }
            })
            if (
$e.is("div,blockquote,p") && $e[0].nodeType!=&& $e[0].lastChild && $e[0].lastChild.tagName=="BR") {
                $(
$e[0].lastChild).remove();
            }
            
//END remove last BR
            
            //Remove BR
            
$e.find("ul > br, table > br, tr > br").remove();
            
//IE
            
            
var outbb="";
            
            
//transform smiles
            
$.each(this.options.srules,$.proxy(function(s,bb) {
                
$e.find(s).replaceWith(bb[0]);
            },
this));
            
            
$e.contents().each($.proxy(function(i,el) {
                var 
$el = $(el);
                if (
el.nodeType===3) {
                    
outbb+=el.data.replace(/n+/,"").replace(/t/g,"   ");
                }else{
                    
//process html tag
                    
var rpl,processed=false;

                    
//for (var rootsel in this.options.rules) {
                    
for (var j=0j<this.rsellist.lengthj++) {
                        var 
rootsel this.rsellist[j];
                        if (
$el && $el.is(rootsel)) {
                            
//it is root sel
                            
var rlist this.options.rules[rootsel];
                            for (var 
i=0i<rlist.lengthi++) {
                                var 
bbcode rlist[i][0];
                                var 
crules rlist[i][1];
                                var 
skip=false,keepElement=false,keepAttr=false;
                                if (!
$el.is("br")) {
                                    
bbcode bbcode.replace(/n/g,"<br>");
                                }
                                
bbcode bbcode.replace(/{(.*?)([.*?])*}/g,$.proxy(function(str,s,vrgx) {
                                    var 
crules[s.toLowerCase()];
                                    
//if (typeof(c)=="undefined") {$.log("Param: {"+s+"} not found in HTML representation.");skip=true;return s;}
                                    
if (typeof(c)=="undefined") {$.log("Param: {"+s+"} not found in HTML representation.");skip=true;}
                                    var 
$cel = (c.sel) ? $(el).find(c.sel):$(el);
                                    if (
c.attr && !$cel.attr(c.attr)) {skip=true;return s;} //skip if needed attribute not present, maybe other bbcode
                                    
var cont = (c.attr) ? $cel.attr(c.attr):$cel.html();
                                    if (
typeof(cont)=="undefined" || cont==null) {skip=true;return s;}
                                    var 
regexp c.rgx;
                                    
                                    
//style fix 
                                    
if (regexp && c.attr=="style" && regexp.substr(regexp.length-1,1)!=";") {
                                        
regexp+=";";
                                    }
                                    if (
c.attr=="style" && cont && cont.substr(cont.length-1,1)!=";") {cont+=";"}
                                    
//prepare regexp
                                    
var rgx = (regexp) ? new RegExp(regexp,""):false;
                                    if (
rgx) {
                                        if (
cont.match(rgx)) {
                                            var 
cont.match(rgx);
                                            if (
&& m.length==2) {
                                                
cont=m[1];
                                            }
                                        }else{
                                            
cont="";
                                        }
                                    }
                                    
                                    
//if it is style attr, then keep tag alive, remove this style
                                    
if (c.attr && skip===false) {
                                        if (
c.attr=="style") {
                                            
keepElement=true;
                                            var 
nstyle="";
                                            var 
c.rgx.replace(/^.*?/,"").replace(/.*$/,"").replace(/;$/,"");
                                            $(
$cel.attr("style").split(";")).each(function(idx,style) {
                                                if (
style && style!="") {
                                                    if (!
style.match(r)) {
                                                        
nstyle+=style+";";
                                                    }
                                                }
                                            });
                                            if (
nstyle=="") {
                                                
$cel.removeAttr("style");
                                            }else{
                                                
$cel.attr("style",nstyle);
                                            }
                                        }else if (
c.rgx===false){    
                                            
keepElement=true;
                                            
keepAttr=true;
                                            
$cel.removeAttr(c.attr);
                                        }
                                    }
                                    if (
$el.is('table,tr,td,font')) {keepElement=true;}
                                    
                                    return 
cont || "";
                                },
this));
                                if (
skip) {continue;}
                                if (
$el.is("img,br,hr")) {
                                    
//replace element
                                    
outbb+=bbcode;
                                    
$el=null;
                                    break;
                                }else{
                                    if (
keepElement && !$el.attr("notkeep")) {
                                        if (
$el.is("table,tr,td")) {
                                            
bbcode this.fixTableTransform(bbcode);
                                            
outbb+=this.toBB($('<span>').html(bbcode));
                                            
$el=null;
                                        }else{
                                            
$el.empty().html('<span>'+bbcode+'</span>');
                                        }
                                        
                                    }else{
                                        if (
$el.is("iframe")) {
                                            
outbb+=bbcode;
                                        }else{
                                            
$el.empty().html(bbcode);
                                            
outbb+=this.toBB($el);
                                            
$el=null;
                                            
                                        }
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    if (!
$el || $el.is("iframe,img")) {return true;}
                    
outbb+=this.toBB($el);
                }
            },
this));
            
            
outbb.replace(/uFEFF/g,"");
            return 
outbb;
        },
        
getHTML: function(bbdata,init,skiplt) {
            if (!
this.options.bbmode && !init) {return this.$body.html()}
            
            if (!
skiplt) {bbdata bbdata.replace(/</g,"&lt;").replace(/{/g,"&#123;").replace(/}/g,"&#125;");}
            
bbdata bbdata.replace(/[code]([sS]*?)[/code]/g,function(s) {
                
s.substr("[code]".length,s.length-"[code]".length-"[/code]".length).replace(/[/g,"&#91;").replace(/]/g,"&#93;");
                return 
"[code]"+s+"[/code]";
            });
            
            
            $.
each(this.options.btnlist,$.proxy(function(i,b){
                if (
b!="|" && b!="-") {
                    var 
find=true;
                    if (!
this.options.allButtons[b] || !this.options.allButtons[b].transform) {
                        return 
true;
                    }

                    $.
each(this.options.allButtons[b].transform,$.proxy(function(html,bb) {
                        
html html.replace(/n/g,""); //IE 7,8 FIX
                        
var a=[];
                        
bb bb.replace(/((|)|[|]|.|*|?|:|\|\)/g,"\$1");
                            
//.replace(/s/g,"\s");
                        
bb bb.replace(/{(.*?)(\[.*?\])*}/gi,$.proxy(function(str,s,vrgx) {
                            
a.push(s);
                            if (
vrgx) {
                                
//has validation regexp
                                
vrgx vrgx.replace(/\/g,"");
                                return 
"("+vrgx+"*?)";
                            }
                            return 
"([\s\S]*?)";
                        },
this));
                        var 
n=0,am;
                        while ((
am = (new RegExp(bb,"mgi")).exec(bbdata)) != null) {
                            if (
am) {
                                var 
r={};
                                $.
each(a,$.proxy(function(i,k) {
                                    
r[k]=am[i+1];
                                },
this));
                                var 
nhtml html;
                                
nhtml nhtml.replace(/{(.*?)([.*?])}/g,"{$1}");
                                
nhtml this.strf(nhtml,r);
                                
bbdata bbdata.replace(am[0],nhtml);
                            }
                        }
                    },
this));
                }
            },
this));
            
            
//transform system codes
            
$.each(this.options.systr,function(html,bb) {
                
bb bb.replace(/((|)|[|]|.|*|?|:|\|\)/g,"\$1")
                    .
replace(" ","\s");
                
bbdata bbdata.replace(new RegExp(bb,"g"),html);
            });
            
            
            var 
$wrap = $(this.elFromString("<div>"+bbdata+"</div>"));
            
//transform smiles
            /* $wrap.contents().filter(function() {return this.nodeType==3}).each($.proxy(smilerpl,this)).end().find("*").contents().filter(function() {return this.nodeType==3}).each($.proxy(smilerpl,this));
            
            function smilerpl(i,el) {
                var ndata = el.data;
                $.each(this.options.smileList,$.proxy(function(i,row) {
                    var fidx = ndata.indexOf(row.bbcode);
                    if (fidx!=-1) {
                        var afternode_txt = ndata.substring(fidx+row.bbcode.length,ndata.length);
                        var afternode = document.createTextNode(afternode_txt);
                        el.data = ndata = el.data.substr(0,fidx);
                        $(el).after(afternode).after(this.strf(row.img,this.options));
                    }
                },this));    
            } */
            
this.getHTMLSmiles($wrap);
            
//$wrap.contents().filter(function() {return this.nodeType==3}).each($.proxy(this,smileRPL,this));
            
            
return $wrap.html();
        },
        
getHTMLSmiles: function(rel) {
            $(
rel).contents().filter(function() {return this.nodeType==3}).each($.proxy(this.smileRPL,this));
        },
        
smileRPL: function(i,el) {
            var 
ndata el.data;
            $.
each(this.options.smileList,$.proxy(function(i,row) {
                var 
fidx ndata.indexOf(row.bbcode);
                if (
fidx!=-1) {
                    var 
afternode_txt ndata.substring(fidx+row.bbcode.length,ndata.length);
                    var 
afternode document.createTextNode(afternode_txt);
                    
el.data ndata el.data.substr(0,fidx);
                    $(
el).after(afternode).after(this.strf(row.img,this.options));
                    
this.getHTMLSmiles(el.parentNode);
                    return 
false;
                }
            
this.getHTMLSmiles(el);
            },
this));    
        },
        
//UTILS
        
setUID: function(el,attr) {
            var 
id "wbbid_"+(++this.lastid);
            if (
el) {
                $(
el).attr(attr || "id",id);
            }
            return 
id;
        },
        
keysToLower: function(o) {
            $.
each(o,function(k,v) {
                if (
k!=k.toLowerCase()) {
                    
delete o[k];
                    
o[k.toLowerCase()]=v;
                }
            });
            return 
o;
        },
        
strf: function(str,data) {
            
data this.keysToLower($.extend({},data));
            return 
str.replace(/{([w.]*)}/g, function (strkey) {key key.toLowerCase();var keys key.split("."), value data[keys.shift().toLowerCase()];$.each(keys, function () { value value[this]; }); return (value === null || value === undefined) ? "" value;});
        },
        
elFromString: function(str) {
            if (
str.indexOf("<")!=-&& str.indexOf(">")!=-1) {
                
//create tag
                
var wr document.createElement("SPAN");
                $(
wr).html(str);
                
this.setUID(wr,"wbb");
                return ($(
wr).contents().size()>1) ? wr:wr.firstChild;
            }else{
                
//create text node
                
return document.createTextNode(str);
            }
        },
        
isContain: function(node,sel) {
            while (
node && !$(node).hasClass("wysibb")) {
                if ($(
node).is(sel)) {return node};
                if (
node) {node node.parentNode;}
                else{return 
null;}
            }
        },
        
isBBContain: function(bbcode) {
            var 
pos=this.getCursorPosBB();
            var 
this.prepareRGX(bbcode);
            var 
bbrgx = new RegExp(b,"g");
            var 
a;
            var 
lastindex=0;
            while ((
a=bbrgx.exec(this.txtArea.value))!=null) {
                var 
this.txtArea.value.indexOf(a[0],lastindex);
                if (
pos>&& pos<(p+a[0].length)) {
                    return [
a,p];
                }
                
lastindex=p+1;
            }
        },
        
prepareRGX: function(r) {
            return 
r.replace(/([|]|)|(|.|*|?|:|||\)/g,"\$1").replace(/{.*?}/g,"([\s\S]*?)");
            
//return r.replace(/([^a-z0-9)/ig,"\$1").replace(/{.*?}/g,"([\s\S]*?)");
        
},
        
checkForLastBR: function(node) {
            if (!
node) {$node this.body;} 
            if (
node.nodeType==3) {node=node.parentNode;}
            var 
$node = $(node);
            if (
$node.is("span[id*='wbbid']")) {$node $node.parent();}
            if (
this.options.bbmode===false && $node.is('div,blockquote,code') && $node.contents().size()>0) {
                var 
$node[0].lastChild;
                if (!
|| (&& l.tagName!="BR")) {$node.append("<br/>");}
            }
            if (
this.$body.contents().size()>&& this.body.lastChild.tagName!="BR") {
                
this.$body.append('<br/>');
            }
        },
        
getAttributeList: function(el) {
            var 
a=[];
            $.
each(el.attributes,function(i,attr) {
                if (
attr.specified) {
                    
a.push(attr.name);
                }
            });
            return 
a;
        },
        
clearFromSubInsert: function(html,cmd) {
            if (
this.options.allButtons[cmd] && this.options.allButtons[cmd].rootSelector) {
                var 
$wr = $('<div>').html(html);
                $.
each(this.options.allButtons[cmd].rootSelector,$.proxy(function(i,s) {
                    var 
seltext=false;
                    if (
typeof(this.options.rules[s][0][1]["seltext"])!="undefined") {
                        
seltext this.options.rules[s][0][1]["seltext"]["sel"];
                    }
                    var 
res=true;
                    
$wr.find("*").each(function() { //work with find("*") and "is", becouse in ie7-8 find is case sensitive
                        
if ($(this).is(s)) {
                            if (
seltext && seltext["sel"]) {
                                $(
this).replaceWith($(this).find(seltext["sel"].toLowerCase()).html());
                            }else{
                                $(
this).replaceWith($(this).html());
                            }
                            
res=false;
                        }
                    });
                    return 
res;
                },
this));
                return 
$wr.html();
            }
            return 
html;
        },
        
splitPrevNext: function(node) {
            if (
node.nodeType==3) {node node.parentNode};
            var 
this.filterByNode(node).replace(/:eq.*$/g,"");
            if ($(
node.nextSibling).is(f)) {
                $(
node).append($(node.nextSibling).html());
                $(
node.nextSibling).remove();
            }
            if ($(
node.previousSibling).is(f)) {
                $(
node).prepend($(node.previousSibling).html());
                $(
node.previousSibling).remove();
            }
        },
        
modeSwitch: function() {
            if (
this.options.bbmode) {
                
//to HTML
                
this.$body.html(this.getHTML(this.$txtArea.val()));
                
this.$txtArea.hide().removeAttr("wbbsync").val("");
                
this.$body.css("min-height",this.$txtArea.height()).show().focus();
            }else{
                
//to bbcode
                
this.$txtArea.val(this.getBBCode()).css("min-height",this.$body.height());
                
this.$body.hide();
                
this.$txtArea.show().focus();
            }
            
this.options.bbmode=!this.options.bbmode;
        },
        
clearEmpty: function () {
            
this.$body.children().filter(emptyFilter).remove();
            function 
emptyFilter() {
                if (!$(
this).is("span,font,a,b,i,u,s")) {
                    
//clear empty only for span,font
                    
return false;
                }
                if (!$(
this).hasClass("wbbtab") && $.trim($(this).html()).length==0) {
                    return 
true;
                }else if ($(
this).children().size()>0) {
                    $(
this).children().filter(emptyFilter).remove();
                    if ($(
this).html().length==&& this.tagName!="BODY") {
                        return 
true;
                    }
                }
            }
        },
        
dropdownclick: function(bsel,tsel,e) {
            
//this.body.focus();
            
var $btn = $(e.currentTarget).closest(bsel);
            if (
$btn.hasClass("dis")) {return;}
            if (
$btn.attr("wbbshow")) {
                
//hide dropdown
                
$btn.removeAttr("wbbshow");
                $(
document).unbind("mousedown",this.dropdownhandler);
                if (
document) {
                    $(
document).unbind("mousedown",this.dropdownhandler);
                }
                
this.lastRange=false;
                
            }else{
                
this.saveRange();
                
this.$editor.find("*[wbbshow]").each(function(i,el) {
                    $(
el).removeClass("on").find($(el).attr("wbbshow")).hide().end().removeAttr("wbbshow");
                })
                
$btn.attr("wbbshow",tsel);
                $(
document.body).bind("mousedown",$.proxy(function(evt) {this.dropdownhandler($btn,bsel,tsel,evt)},this));
                if (
this.$body) {
                    
this.$body.bind("mousedown",$.proxy(function(evt) {this.dropdownhandler($btn,bsel,tsel,evt)},this));
                }
            }
            
$btn.find(tsel).toggle();
            
$btn.toggleClass("on");
        },
        
dropdownhandler: function($btn,bsel,tsel,e) {
            if ($(
e.target).parents(bsel).size()==0) {
                
$btn.removeClass("on").find(tsel).hide();
                $(
document).unbind('mousedown',this.dropdownhandler);
                if (
this.$body) {
                    
this.$body.unbind('mousedown',this.dropdownhandler);
                }
            }
        },
        
rgbToHex: function(rgb) {
            if (
rgb.substr(01)=='#') {return rgb;}
            
//if (rgb.indexOf("rgb")==-1) {return rgb;}
            
if (rgb.indexOf("rgb")==-1) {
                
//IE
                
var color=parseInt(rgb);
                
color = ((color 0x0000ff) << 16) | (color 0x00ff00) | ((color 0xff0000) >>> 16);
                return 
'#'+color.toString(16);
            }
            var 
digits = /(.*?)rgb((d+),s*(d+),s*(d+))/.exec(rgb);
            return 
"#"+this.dec2hex(parseInt(digits[2]))+this.dec2hex(parseInt(digits[3]))+this.dec2hex(parseInt(digits[4])); 
        },
        
dec2hex: function(d) {
            if(
d>15) {
                return 
d.toString(16);
            }else{
                return 
"0"+d.toString(16);
            }
        },
        
sync: function() {
            if (
this.options.bbmode) {
                
this.$body.html(this.getHTML(this.txtArea.value,true));
            }else{
                
this.$txtArea.attr("wbbsync",1).val(this.getBBCode());
            }
        },
        
clearPaste: function(el) {
            var 
$block = $(el);
            
//NEW 
            
$.each(this.options.rules,$.proxy(function(s,ar) {
                var 
$sf $block.find(s).attr("wbbkeep",1);
                if (
$sf.size()>0) {
                    var 
s2 ar[0][1];
                    $.
each(s2,function(i,v) {
                        if (
v.sel) {
                            
$sf.find(v.sel).attr("wbbkeep",1);
                        }
                    });
                }
            },
this));
            
$block.find("*[wbbkeep!='1']").each($.proxy(function(i,el) {
                var 
$this = $(el);
                if (
$this.is('div,p') && ($this.children().size()==|| el.lastChild.tagName!="BR")) {
                    
$this.after("<br/>");
                }
            },
this));
            
$block.find("*[wbbkeep]").removeAttr("wbbkeep").removeAttr("style");
            $.
log($block.html());
            
//$.log("BBCODE: "+this.toBB($block.clone(true)));
            
$block.html(this.getHTML(this.toBB($block),true));
            $.
log($block.html());
            
            
//OLD
            /* $.each(this.options.rules,$.proxy(function(s,bb) {
                $block.find(s).attr("wbbkeep",1);
            },this));
            
            //replace div and p without last br to html()+br
            $block.find("*[wbbkeep!='1']").each($.proxy(function(i,el) {
                var $this = $(el);
                if ($this.is('div,p') && ($this.children().size()==0 || el.lastChild.tagName!="BR")) {
                    $this.after("<br/>").after($this.contents()).remove();
                }else{
                    $this.after($this.contents()).remove();
                }
            },this));
            $block.find("*[wbbkeep]").removeAttr("wbbkeep").removeAttr("style"); */
        
},
        
sortArray: function(ar,asc) {
            
ar.sort(function(a,b) {
                return (
a.length-b.length)*(asc || 1);
            });
            return 
ar;
        },
        
smileFind: function() {
            if (
this.options.smilefind) {
                var 
$smlist = $(this.options.smilefind).find('img[alt]');
                if (
$smlist.size()>0) {
                    
this.options.smileList=[];
                    
$smlist.each($.proxy(function(i,el) {
                        var 
$el=$(el);
                        
this.options.smileList.push({title:$el.attr("title"),bbcode:$el.attr("alt"),img:$el.removeAttr("alt").removeAttr("title")[0].outerHTML});
                    },
this));
                }
            }
        },
        
destroy: function() {
            
this.$editor.replaceWith(this.$txtArea);
            
this.$txtArea.removeClass("wysibb-texarea").show();
            
this.$modal.remove();
            
this.$txtArea.data("wbb",null);
        },
        
pressTab: function(e) {
            if (
&& e.which == 9) {
                
//insert tab
                
if (e.preventDefault) {e.preventDefault();}
                if (
this.options.bbmode) {
                    
this.insertAtCursor('   ',false);
                }else{
                    
this.insertAtCursor('<span class="wbbtab">uFEFF</span>',false);
                    
//this.execNativeCommand("indent",false); 
                
}
            }
        },
        
removeLastBodyBR: function() {
            if (
this.body.lastChild && this.body.lastChild.nodeType!=&& this.body.lastChild.tagName=="BR") {
                
this.body.removeChild(this.body.lastChild);
                
this.removeLastBodyBR();
            }
        },
        
traceTextareaEvent: function(e) {
            if ($(
e.target).closest("div.wysibb").size()==0) {
                if ($(
document.activeElement).is("div.wysibb-body")) {
                    
this.saveRange();
                }
                
setTimeout($.proxy(function() {
                    var 
data this.$txtArea.val();
                    if (
this.options.bbmode===false && data!="" && $(e.target).closest("div.wysibb").size()==&& !this.$txtArea.attr("wbbsync")) {
                        
this.selectLastRange();
                        
this.insertAtCursor(this.getHTML(data,true));
                        
this.$txtArea.val("");
                    }
                    if ($(
document.activeElement).is("div.wysibb-body")) {
                        
this.lastRange=false;
                    }
                },
this),100);
            }
        },
        
txtAreaInitContent: function() {
            
//$.log(this.txtArea.value);
            
this.$body.html(this.getHTML(this.txtArea.value,true));
        },
        
getValidationRGX: function(s) {
            if (
s.match(/[S+]/)) {
                return 
s.replace(/.*(\*[S+]).*/,"$1");
            }
            return 
"";
        },
        
smileConversion: function() {
            if (
this.options.smileList && this.options.smileList.length>0) {
                var 
snode this.getSelectNode();
                if (
snode.nodeType==3) {
                    var 
ndata snode.data;
                    if (
ndata.length>=&& !this.isInClearTextBlock(snode) && $(snode).parents("a").size()==0) {
                        $.
each(this.options.srules,$.proxy(function(i,sar) {
                            var 
smbb sar[0];
                            var 
fidx ndata.indexOf(smbb);
                            if (
fidx!=-1) {
                                var 
afternode_txt ndata.substring(fidx+smbb.length,ndata.length);
                                var 
afternode document.createTextNode(afternode_txt);
                                var 
afternode_cursor document.createElement("SPAN");
                                
snode.data snode.data.substr(0,fidx);
                                $(
snode).after(afternode).after(afternode_cursor).after(this.strf(sar[1],this.options));
                                
this.selectNode(afternode_cursor);
                                return 
false;
                            }
                        },
this));
                    }
                }
            }
        },
        
isInClearTextBlock: function() {
            if (
this.cleartext) {
                var 
find=false;
                $.
each(this.cleartext,$.proxy(function(sel,command) {
                    if (
this.queryState(command)) {
                        
find=command;
                        return 
false;
                    }
                },
this))
                return 
find;
            }
            return 
false;
        },
        
wrapAttrs: function(html) {
            $.
each(this.options.attrWrap,function(i,a) {
                
html html.replace(a+'="','_'+a+'="');
            });
            return 
html;
        },
        
unwrapAttrs: function(html) {
            $.
each(this.options.attrWrap,function(i,a) {
                
html html.replace('_'+a+'="',a+'="');
            });
            return 
html;
        },
        
disNonActiveButtons: function() {
            if (
this.isInClearTextBlock()) {
                
this.$toolbar.find(".wysibb-toolbar-btn:not(.on,.mswitch)").addClass("dis");
            }else{
                
this.$toolbar.find(".wysibb-toolbar-btn.dis").removeClass("dis");
            }
        },
        
setCursorByEl: function(el) {
            var 
sl document.createTextNode("uFEFF");
            $(
el).after(sl);
            
this.selectNode(sl);
        },
        
        
//img listeners
        
imgListeners: function() {
            $(
document).on("mousedown",$.proxy(this.imgEventHandler,this));
        },
        
imgEventHandler: function(e) {
            var 
$e = $(e.target);
            if (
this.hasWrapedImage && ($e.closest(".wbb-img,#wbbmodal").size()==|| $e.hasClass("wbb-cancel-button"))) {
                
this.$body.find(".imgWrap ").each(function() {
                    $.
log("Removed imgWrap block");
                    $(
this).replaceWith($(this).find("img"));
                })
                
this.hasWrapedImage false;
                
this.updateUI();
            }
            
            if (
$e.is("img") && $e.closest(".wysibb-body").size()>0) {
                
$e.wrap("<span class='imgWrap'></span>");
                
this.hasWrapedImage $e;
                
this.$body.focus();
                
this.selectNode($e.parent()[0]);
            }
        },
        
        
//MODAL WINDOW
        
showModal: function(cmd,opt,queryState) {
            $.
log("showModal: "+cmd);
            
this.saveRange();
            var 
$cont this.$modal.find(".wbbm-content").html("");
            var 
$wbbm this.$modal.find(".wbbm").removeClass("hastabs");
            
this.$modal.find("span.wbbm-title-text").html(opt.title);
            if (
opt.tabs && opt.tabs.length>1) {
                
//has tabs, create
                
$wbbm.addClass("hastabs");
                var 
$ul = $('<div class="wbbm-tablist">').appendTo($cont).append("<ul>").children("ul");
                $.
each(opt.tabs,$.proxy(function(i,row) {
                    if (
i==0) {row['on']="on"}
                    
$ul.append(this.strf('<li class="{on}" onClick="$(this).parent().find('.on').removeClass('on');$(this).addClass('on');$(this).parents('.wbbm-content').find('.tab-cont').hide();$(this).parents('.wbbm-content').find('.tab'+i+'').show()">{title}</li>',row));
                    
                },
this))
            }
            if (
opt.width) {
                
$wbbm.css("width",opt.width);
            }
            var 
$cnt = $('<div class="wbbm-cont">').appendTo($cont);
            if (
queryState) {
                
$wbbm.find('#wbbm-remove').show();
            }else{
                
$wbbm.find('#wbbm-remove').hide();
            }
            $.
each(opt.tabs,$.proxy(function(i,r) {
                var 
$c = $('<div>').addClass("tab-cont tab"+i).attr("tid",i).appendTo($cnt);
                if (
i>0) {$c.hide();} 
                if (
r.html) {
                    
$c.html(this.strf(r.html,this.options));
                }else{
                    $.
each(r.input,$.proxy(function(j,inp) {
                        
inp["value"]=queryState[inp.param.toLowerCase()];
                        if (
inp.param.toLowerCase()=="seltext" && (!inp["value"] || inp["value"]=="")) {
                            
inp["value"] = this.getSelectText(this.options.bbmode);
                        }
                        if (
inp["value"] && inp["value"].indexOf("<span id='wbbid")==&& $(inp["value"]).is("span[id*='wbbid']")) {
                            
inp["value"] = $(inp["value"]).html();
                        }
                        if (
inp.type && inp.type=="div") {
                            
//div input, support wysiwyg input
                            
$c.append(this.strf('<div class="wbbm-inp-row"><label>{title}</label><div class="inp-text div-modal-text" contenteditable="true" name="{param}">{value}</div></div>',inp));
                        }else{
                            
//default input
                            
$c.append(this.strf('<div class="wbbm-inp-row"><label>{title}</label><input class="inp-text modal-text" type="text" name="{param}" value="{value}"/></div>',inp));
                        }
                        
                        
                    },
this));
                }
            },
this));
            
            
//this.lastRange=this.getRange();
            
            
if ($.isFunction(opt.onLoad)) {
                
opt.onLoad.call(this,cmd,opt,queryState);
            }
            
            
$wbbm.find('#wbbm-submit').click($.proxy(function() {
                
                if ($.
isFunction(opt.onSubmit)) { //custom submit function, if return false, then don't process our function
                    
var opt.onSubmit.call(this,cmd,opt,queryState);
                    if (
r===false) {return;}
                }
                var 
params={};
                var 
valid=true;
                
this.$modal.find(".wbbm-inperr").remove();
                
this.$modal.find(".wbbm-brdred").removeClass("wbbm-brdred");
                
//$.each(this.$modal.find(".tab-cont:visible input"),$.proxy(function(i,el) {
                
$.each(this.$modal.find(".tab-cont:visible .inp-text"),$.proxy(function(i,el) {
                    var 
tid = $(el).parents(".tab-cont").attr("tid");
                    var 
pname = $(el).attr("name").toLowerCase();
                    var 
pval="";
                    if ($(
el).is("input,textrea,select")) {
                        
pval = $(el).val();
                    }else{
                        
pval = $(el).html();
                    }
                    var 
validation opt.tabs[tid]["input"][i]["validation"];
                    if (
typeof(validation)!="undefined") {
                        if (!
pval.match(new RegExp(validation,"i"))) {
                            
valid=false;
                            $(
el).after('<span class="wbbm-inperr">'+CURLANG.validation_err+'</span>').addClass("wbbm-brdred");
                        }
                    }
                    
params[pname]=pval;
                },
this));
                if (
valid) {
                    $.
log("Last range: "+this.lastRange);
                    
this.selectLastRange();
                    
//insert callback
                    
if (queryState) {
                        
this.wbbRemoveCallback(cmd,true);
                    }
                    
this.wbbInsertCallback(cmd,params);
                    
//END insert callback
                    
                    
this.closeModal();
                    
this.updateUI();
                }
            },
this));
            
$wbbm.find('#wbbm-remove').click($.proxy(function() {
                
//clbk.remove();
                
this.selectLastRange();
                
this.wbbRemoveCallback(cmd); //remove callback
                
this.closeModal();
                
this.updateUI();
            },
this));
            
            $(
document.body).css("overflow","hidden"); //lock the screen, remove scroll on body
            
if ($("body").height() > $(window).height()) { //if body has scroll, add padding-right 18px
                
$(document.body).css("padding-right","18px");
            }
            
this.$modal.show();
            
//if (window.getSelection) 
            
if (this.isMobile) {
                
$wbbm.css("margin-top","10px");
            }else{
                
$wbbm.css("margin-top",($(window).height()-$wbbm.outerHeight())/3+"px");
            }
            
//setTimeout($.proxy(function() {this.$modal.find("input:visible")[0].focus()},this),10);
            
setTimeout($.proxy(function() {this.$modal.find(".inp-text:visible")[0].focus()},this),10);
        },
        
escModal: function(e) {
            if (
e.which==27) {this.closeModal();}
        },
        
closeModal: function() {
            $(
document.body).css("overflow","auto").css("padding-right","0").unbind("keyup",this.escModal); //ESC key close modal;
            
this.$modal.find('#wbbm-submit,#wbbm-remove').unbind('click');
            
this.$modal.hide();
            
this.lastRange=false;
            return 
this;
        },
        
getParams: function(src,s,offset) {
            var 
params={};
            if (
this.options.bbmode) {
                
//bbmode
                
var stext s.match(/{[sS]+?}/g);
                
this.prepareRGX(s);
                var 
rgx = new RegExp(s,"g");
                var 
val this.txtArea.value;
                if (
offset>0) {
                    
val val.substr(offset,val.length-offset);
                }
                var 
rgx.exec(val);
                if (
a) {
                    $.
each(stext,function(i,n) {
                        
params[n.replace(/{|}/g,"").replace(/"/g,"'").toLowerCase()] = a[i+1];
                    });
                }
            }else{
                var rules = this.options.rules[s][0][1];
                $.each(rules,$.proxy(function(k,v) {
                    var value="";
                    var $v = (v.sel!==false) ? value=$(src).find(v.sel):$(src);
                    if (v.attr!==false) {
                        value=$v.attr(v.attr);
                    }else{
                        value=$v.html();
                    }
                    if (value) {
                        if (v.rgx!==false) {
                            var m = value.match(new RegExp(v.rgx));
                            if (m && m.length==2) {
                                value = m[1];
                            }
                        }
                        params[k]=value.replace(/"/g,"'");
                    }
                },this))
            }
            return params;
        },
        
         
        //imgUploader
        imgLoadModal: function() {
            $.log("
imgLoadModal");
            if (this.options.imgupload===true) {
                this.
$modal.find("#imguploader").dragfileupload({
                    
urlthis.strf(this.options.img_uploadurl,this.options),
                    
extraParams: {
                        
maxwidththis.options.img_maxwidth,
                        
maxheightthis.options.img_maxheight
                    
},
                    
themePrefixthis.options.themePrefix,
                    
themeNamethis.options.themeName,
                    
success: $.proxy(function(data) {
                        
this.$txtArea.insertImage(data.image_link,data.thumb_link);
                        
                        
this.closeModal();
                        
this.updateUI();
                    },
this)
                });
                
                
this.$modal.find("#fileupl").bind("change",function() {
                    $(
"#fupform").submit();
                });
                
this.$modal.find("#fupform").bind("submit",$.proxy(function(e) {
                    $(
e.target).parents("#imguploader").hide().after('<div class="loader"><img src="'+this.options.themePrefix+'/'+this.options.themeName+'/img/loader.gif" /><br/><span>'+CURLANG.loading+'</span></div>').parent().css("text-align","center");
                },
this))
                
            }else{
                
this.$modal.find(".hastabs").removeClass("hastabs");
                
this.$modal.find("#imguploader").parents(".tab-cont").remove();
                
this.$modal.find(".wbbm-tablist").remove();
            }
        },
        
imgSubmitModal: function() {
            $.
log("imgSubmitModal");
        },
        
//DEBUG
        
printObjectInIE: function(obj) {
            try{
            $.
log(JSON.stringify(obj));
            }catch(
e) {}
        },
        
checkFilter: function(node,filter) {
            $.
log("node: "+$(node).get(0).outerHTML+" filter: "+filter+" res: "+$(node).is(filter.toLowerCase()));
        },
        
debug: function(msg) {
            if (
this.options.debug===true) {
                var 
time = (new Date()).getTime();
                if (
typeof(console)!="undefined") {
                    
console.log((time-this.startTime)+" ms: "+msg);
                }else{
                    $(
"#exlog").append('<p>'+(time-this.startTime)+" ms: "+msg+'</p>');  
                }
                
this.startTime=time;
            }
        },
        
        
//Browser fixes
        
isChrome: function() {
            return (
window.chrome) ? true:false;
        },
        
fixTableTransform: function(html) {
            if (!
html) {return "";}
            if ($.
inArray("table",this.options.buttons)==-1) {
                return 
html.replace(/<(/*?(table|tr|td|tbody))[^>]*>/ig,"");
            }else{
                return html.replace(/<(/*?(table|tr|td))[^>]*>/ig,"[$1]".toLowerCase()).replace(/</*tbody[^>]*>/ig,"");
            }
        }
    }
    
    $.log = function(msg) {
        if (typeof(wbbdebug)!="undefined" && wbbdebug===true) {
            if (typeof(console)!="undefined") {
                console.log(msg);
            }else{
                $("#exlog").append('<p>'+msg+'</p>');  
            }
        }
    }
    $.fn.wysibb = function(settings) {
        return this.each(function() {
            var data = $(this).data("wbb");
            if (!data) {
                new $.wysibb(this, settings);
            }
        });
    }
    $.fn.wdrag = function(opt) {
        if (!opt.scope) {opt.scope=this;}
        var start={x:0,y:0, height: 0};
        var drag;
        opt.scope.drag_mousedown = function(e) {
            e.preventDefault();
            start = {
                x: e.pageX,
                y: e.pageY,
                height: opt.height,
                sheight: opt.scope.$body.height()
            }
            drag=true;
            $(document).bind("mousemove",$.proxy(opt.scope.drag_mousemove,this));
            $(this).addClass("drag");
        };
        opt.scope.drag_mouseup = function(e) {
            if (drag===true) {
                e.preventDefault();
                $(document).unbind("mousemove",opt.scope.drag_mousemove);
                $(this).removeClass("drag");
                drag=false;
            }
        };
        opt.scope.drag_mousemove = function(e) {
            e.preventDefault();
            var axisX=0,axisY=0;
            if (opt.axisX) {
                axisX = e.pageX-start.x;
            }
            if (opt.axisY) {
                axisY = e.pageY-start.y;
            }
            if (axisY!=0) {
                var nheight = start.sheight+axisY;
                if (nheight>start.height && nheight<=opt.scope.options.resize_maxheight) {
                    if (opt.scope.options.bbmode==true) {
                        opt.scope.$txtArea.css((opt.scope.options.autoresize===true) ? "min-height":"height",nheight+"px");
                    }else{
                        opt.scope.$body.css((opt.scope.options.autoresize===true) ? "min-height":"height",nheight+"px");
                    }
                }
            }
        };

        
        $(this).bind("mousedown",opt.scope.drag_mousedown);
        $(document).bind("mouseup",$.proxy(opt.scope.drag_mouseup,this));
    },
    
    //API
    $.fn.getDoc = function() {
        return this.data('wbb').doc;
    }
    $.fn.getSelectText = function(fromTextArea) {
        return this.data('wbb').getSelectText(fromTextArea);
    }
    $.fn.bbcode = function(data) {
        if (typeof(data)!="undefined") {
            if (this.data('wbb').options.bbmode) {
                this.data('wbb').$txtArea.val(data);
            }else{
                this.data('wbb').$body.html(this.data("wbb").getHTML(data));
            }
            return this;
        }else{
            return this.data('wbb').getBBCode();
        }
    }
    $.fn.htmlcode = function(data) {
        if (!this.data('wbb').options.onlyBBMode && this.data('wbb').inited===true) {
            if (typeof(data)!="undefined") {
                this.data('wbb').$body.html(data);
                return this;
            }else{
                return this.data('wbb').getHTML(this.data('wbb').$txtArea.val());
            }
        }
    }
    $.fn.getBBCode = function() {
        return this.data('wbb').getBBCode();
    }
    $.fn.getHTML = function() {
        var wbb = this.data('wbb');
        return wbb.getHTML(wbb.$txtArea.val());
    }
    $.fn.getHTMLByCommand = function(command,params) {
        return this.data("wbb").getHTMLByCommand(command,params);
    }
    $.fn.getBBCodeByCommand = function(command,params) {
        return this.data("wbb").getBBCodeByCommand(command,params);
    }
    $.fn.insertAtCursor = function(data,forceBBMode) {
        this.data("wbb").insertAtCursor(data,forceBBMode);
        return this.data("wbb");
    }
    $.fn.execCommand = function(command,value) {
        this.data("wbb").execCommand(command,value);
        return this.data("wbb");
    }
    $.fn.insertImage = function(imgurl,thumburl) {
        var editor = this.data("wbb");
        var code = (thumburl) ? editor.getCodeByCommand('link',{url:imgurl,seltext: editor.getCodeByCommand('img',{src:thumburl})}): editor.getCodeByCommand('img',{src:imgurl});
        this.insertAtCursor(code);
        return editor;
    }
    $.fn.sync = function() {
        this.data("wbb").sync();
        return this.data("wbb");
    }
    $.fn.destroy = function() {
        this.data("wbb").destroy();
    }
    
    
    $.fn.queryState = function(command) {
        return this.data("wbb").queryState(command);
    }
})(jQuery);


//Drag&Drop file uploader
(function($) {
    'use strict';
    
    $.fn.dragfileupload = function(options) {        
        return this.each(function() { 
            var upl = new FileUpload(this, options);
            upl.init();
        });
    }; 
    
    function FileUpload(e, options) {
        this.$block=$(e);
        
        this.opt = $.extend({
            url: false,
            success: false,
            extraParams: false,
            fileParam: 'img',
            validation: '.(jpg|png|gif|jpeg)$',
            
            t1: CURLANG.fileupload_text1,
            t2: CURLANG.fileupload_text2
        },options);
    }
    
    FileUpload.prototype = {
        init: function() {
            if (window.FormData != null) {
                this.$block.addClass("drag");
                this.$block.prepend('<div class="p2">'+this.opt.t2+'</div>');
                this.$block.prepend('<div class="p">'+this.opt.t1+'</div>');
                
                this.$block.bind('dragover', function() {$(this).addClass('dragover');return false;});
                this.$block.bind('dragleave', function() {$(this).removeClass('dragover');return false;});
                
                //upload progress
                var uploadProgress = $.proxy(function(e) { 
                    var p = parseInt(e.loaded/e.total*100, 10);
                    this.$loader.children("span").text(CURLANG.loading+': '+ p+'%');
                    
                }, this);
                var xhr = jQuery.ajaxSettings.xhr(); 
                if (xhr.upload) {
                    xhr.upload.addEventListener('progress', uploadProgress, false);
                }
                this.$block[0].ondrop = $.proxy(function(e) {
                    e.preventDefault();
                    this.$block.removeClass('dragover');
                    var ufile = e.dataTransfer.files[0];
                    if (this.opt.validation && !ufile.name.match(new RegExp(this.opt.validation))) {
                        this.error(CURLANG.validation_err);
                        return false;
                    }
                    var fData = new FormData();
                    fData.append(this.opt.fileParam, ufile);
                    
                    if (this.opt.extraParams) { //check for extraParams to upload
                        $.each(this.opt.extraParams,function(k,v) {
                            fData.append(k, v);
                        });
                    }
                    
                    this.$loader = $('<div class="loader"><img src="'+this.opt.themePrefix+'/'+this.opt.themeName+'/img/loader.gif" /><br/><span>'+CURLANG.loading+'</span></div>');
                    this.$block.html(this.$loader);
                    
                    $.ajax({
                        type: 'POST',
                        url: this.opt.url,
                        data: fData,
                        processData: false,
                        contentType: false,
                        xhr: function() {return xhr},
                        dataType: 'json',
                        success: $.proxy(function(data) {
                            if (data && data.status==1) {
                                this.opt.success(data); 
                            }else{
                                this.error(data.msg || CURLANG.error_onupload);
                            }
                        },this),
                        error: $.proxy(function (xhr, txt, thr) {this.error(CURLANG.error_onupload)},this)
                    });
                },this);
                
            }
        },
        error: function(msg) {
            this.$block.find(".upl-error").remove().end().append('<span class="upl-error">'+msg+'</span>').addClass("wbbm-brdred");
        }
    }
})(jQuery);
?>
Онлайн: 1
Реклама