Análise do código fonte do FCKeditor (i) Análise de anotação chinesa do FCKeditor.js estuda o código -fonte do FCKeditor nos últimos dias (o FCKeditor é um editor da Web com uma ampla gama de aplicativos na rede). Preciso agradecer ao NileaderBlog por sua dura tradução.
Eu pesquisei quase toda a Internet e parece que expliquei muito sobre o arquivo fckconfig.js, mas as informações sobre o principal arquivo fck do fckeditor.js são quase 0.
Portanto, passei um dia inteiro apertando creme dental para comentar o arquivo principal fckeditor.js, fckeditor.js, para referência de internautas que também aprendem o FCKeditor.
Dado que o nível do autor é limitado, aqui, aponte os pontos inadequados em meus comentários para evitar enganar os outros. Obrigado.
É recomendável copiá -lo para o seu IDE ou
Nota: Este artigo é baseado no fckeditor2.6.5
Para obter informações mais autorizadas, consulte o Guia de desenvolvedores oficiais da FCK
A cópia do código é a seguinte:
/**
*
********** Copyright *****************
*-------- anotado por Nileader ----
*---- Versão 1.00 2009-10-18 ----
*---- Uma vez copiado, marcado http://www.nileader.cn
*
* FCKEDITOR CLASS
* @param {objeto} InstanceName O nome exclusivo do editor (equivalente ao ID) é um parâmetro não salvo.
* Largura, altura, barro de ferramentas, valor são todos parâmetros opcionais
*/
var fckeditor = function (InstanceName, Width, Height, Toolbarset, Valor)
{
// Propriedades básicas do editor Nota: Essas coisas têm precedência sobre a configuração em fckconfig.js
this.instanceName = InstanceName; // O nome exclusivo do editor (equivalente ao id) (deve ter!)
this.width = width || '100%'; // a largura é 100% por padrão
this.Height = altura || '200'; // a largura é 200 por padrão
this.ToolBarset = ToolBarSet || 'Padrão'; // o nome do conjunto de ferramentas, o valor padrão é padrão
this.value = valor || ''; // inicialize o código HTML do editor, o valor padrão está vazio
// O caminho raiz padrão quando o editor é inicializado é escrever FCK. Todos os caminhos utilizados são padronizados para / fckeditor / do diretório fckeditor.basepath.
this.basepath = fckeditor.basepath;
this.checkbrowser = true; // Se você deve verificar a compatibilidade do navegador antes de exibir o editor, o padrão é verdadeiro
this.displayerrors = true; // Quer seja exibido com erros, o padrão é verdadeiro
this.config = new Object ();
// eventos
this.onerror = null; // função (fonte, errornumber, errordescription) função de manuseio de erros personalizada
}
Fckeditor.basepath = '/fckeditor/'; // diretório raiz padrão do FCK
Fckeditor.minHeight = 200; // Os limites de altura e largura
Fckeditor.MinWidth = 750;
Fckeditor.prototype.version = '2.6.5'; // Número da versão
Fckeditor.prototype.versionBuild = '23959';
/**
* Ligue para CreateHtml () para gerar o código HTML do editor e produzir o editor na página
*/
Fckeditor.prototype.create = function ()
{
// chamando o método createhtml ()
document.write (this.createhtml ());
}
/**
* @return shtml html código usado para gerar o editor
*/
Fckeditor.prototype.createhtml = function ()
{
// Verifique se houver um nome de instância, nenhum código HTML será gerado
if (! this.instanceName || this.instanceName.length == 0)
{
this._throwerRor (701, 'você deve especificar um nome de instância.');
retornar '' ;
}
// Valor de retorno da função
var shtml = '';
/*
* Quando o navegador do usuário atende a vários navegadores predefinidos,
* Gerar uma caixa de texto com id = this.instanceName name = this.instanceName, o armazenamento de conteúdo de fato
*/
if (! this.checkbrowser || this._iscompatibleBrowser ())
{
// Coloque esta entrada após a escape do valor inicial do FCK
shtml + = '<tipo de entrada = oculto id =' + this.instanceName + 'name =' + this.instanceName + 'value =' + this._htmlencode (this.value) + 'style = display: None Style = Display: Nenhum />';
// Gere uma entrada oculta para colocar o conteúdo neste.config
shtml += this._getConfightMl ();
// Código para gerar o iframe do editor
shtml += this._getiframehtml ();
}
/**
* Se o navegador do usuário não for compatível com os navegadores FCK padrão
* Somente os textaras tradicionais podem ser encontrados
*/
outro
{
var swidth = this.width.toString (). IndexOf ('%')> 0? this.width: this.width + 'px';
var sheight = this.Height.toString (). IndexOf ('%')> 0? this.Height: this.Height + 'PX';
shtml + = '<texttarea name =' + this.instanceName +
'linhas = 4 cols = 40 estilo = largura:' + swidth +
'; altura:' + Sheight;
if (this.tabindex)
shtml + = 'tabindex =' + this.tabindex;
shtml += '>' +
this._htmlencode (this.value) +
'<// textarea>';
}
retornar shtml;
}
/**
* Use o editor para substituir a caixa de texto correspondente
*/
Fckeditor.prototype.replaceTextarea = function ()
{
// Se você já possui o ID da tag = this.instancename ___ quadro, retorne diretamente
if (document.getElementById (this.instanceName + '___frame')))
retornar ;
// Quando o navegador do usuário atende a vários navegadores predefinidos
if (! this.checkbrowser || this._iscompatibleBrowser ())
{
// Devemos verificar os elementos primeiro usando o ID e depois o nome.
// Obtenha a tag html de id = this.instanceName
var otextarea = document.getElementById (this.instanceName);
// Obtenha todas as tags do nome = this.instanceName
var colElementsByName = document.getElementsByName (this.instancename);
var i = 0;
/*
* Considerando que a nomeação da tag HTML do usuário não é padronizada, o registro a seguir é feito para determinar que o autor se refere ao usuário usando nome = this.instanceName na tag textarea.
* Nome = this.instanceName também é usado em outras tags na mesma página
*/
while (otextea || i == 0)
{
// Viaje até que a tag textarea do nome = this.instanceName é encontrada e designada para otextea
if (otextarea && otextarea.tagname.tolowercase () == 'textarea')
quebrar;
otextarea = colelementsByName [i ++];
}
// Se não houver tag com id ou nome deste.instanceName, uma caixa de erro aparece
if (! Otextariaa)
{
Alert ('Erro: o textarea com identificação ou nome definido como' + this.instanceName + 'não foi encontrado');
retornar ;
}
/*
* Depois de confirmar que a tag textarea com nome = this.instanceName existe, atribua o código do editor a ele
*/
otextarea.style.display = 'nenhum';
// Se a chave da tecla da guia for definida na página para tais tags textarea, atribua -a a este.tabindex para uso posterior
if (otextarea.tabindex)
this.tabindex = otextarea.tabindex;
this._inserthtmlbe antes (this._getConfightMl (), otextarea);
this._inserthtmlBe antes (this._getIframehtml (), otextarea);
}
}
/**
* Insira o código HTML na frente da tag de página especificada
* @param {objeto} código html a ser inserido
* @param {objeto} tag especificada de página (objeto)
*/
Fckeditor.prototype._inserthtmlbefore = function (html, elemento)
{
if (element.insertadjacenthtml) // oue privado insertadjacenthtml método
Element.Insertadjacenthtml ('antes deBegin', html);
else // navegador que não
{
var Orange = document.Createrange ();
Orange.SetstartBefore (elemento);
var ofRagment = Orange.createContextualFragment (html);
element.ParentNode.insertBefore (Offragment, Element);
}
}
/*
* Gere um domínio oculto editando this.config [].
* Por exemplo:
* this.config ['nileader'] = 1104, this.config ['Leaderni'] = nichao ...
* Então, sconfig =… & nileader = 1104 & leaderni = nichao…
* Claro, no final, o SCONFIG será convertido em uma codificação percentual pela função Encodeuricomponent e colocada em uma entrada oculta
*/
Fckeditor.prototype._getConfightMl = function ()
{
var sconfig = '';
para (var o neste.config)
{
if (sconfig.length> 0) sconfig += '&';
// A função codeuricomponent é convertida em codificação percentual
sconfig + = codeuricomponent (o) + '=' + codeuricomponent (this.config [o]);
}
return '<type de entrada = oculto id =' + this.instanceName + '___config value =' + sconfig + 'style = display: nenhum estilo = display: nenhum />';
}
/*
* Gere o html do iframe. Aqui envolve a determinação do SRC
*/
Fckeditor.prototype._getiframehtml = function ()
{
var sfile = 'fckeditor.html';
// Case especial, a janela onde o fckedito está localizado não está incorporado no navegador
tentar
{
if ((/fcksource = true/i) .test (window.top.location.search))
sfile = 'fckeditor.original.html';
}
Catch (e) { /* Ignore esta exceção. Muitas vezes, a janela onde o fckedito está localizada é incorporada no navegador. */}
/*
* Uma coisa a observar aqui:
* Como o iframe funciona: Quando o iframe está em estado editável, a página em que o SRC é realmente editado
* Aqui está um slink para colocá -lo na tag iframe
*/
// Slink é esta página de fato, começando no diretório raiz de fck, por exemplo, slink =/fckeditor/editor/fckeditor.html?
var slink = this.basepath + 'editor/' + sfile + '? Instancename =' + Encodeuricomponent (this.instanceName);
if (this.toolbarset)
slink + = '& ToolBar =' + this.toolbarset;
// gerar um código HTML real para editar iframer, é claro, coloque src = slink
var html = '<iframe id =' + this.instanceName +
'___Frame src =' + slink +
'src =' + slink +
'largura =' + this.width +
'altura =' + this.Height;
// Se a ordem de travessia usando a tecla TAB for definida, atribua -a ao iframe
if (this.tabindex)
html + = 'tabindex =' + this.tabindex;
html += 'frameBorder = 0 rolagem = não> </frame>';
retornar html;
}
/*
* Verifique se o Bowser do usuário é o padrão do FCK
* Este método é apenas uma empresa FK perseguindo oo, sem sentido
*/
Fckeditor.prototype._iscompatibleBrowser = function ()
{
retornar fckeditor_iscompatibleBrowser ();
}
/**
* Erro lançado
* @param {objeto} ErrorNumber Número de erro
* @param {object} errorDescription. Visão geral do erro
*/
Fckeditor.prototype._throwerRor = function (errornumber, errorDescription)
{
this.errorNumber = errorNumber;
this.errorDescription = errorDescription;
// Quer seja exibido com erros, o padrão é verdadeiro
if (this.displayerrors)
{// Imprima o número do erro e a visão geral do erro
document.write ('<div estilo = cor: #ff0000 style = cor: #ff0000>');
document.write ('[fckeditor error' + this.errorNumber + ':' + this.errorDescription + ']');
document.write ('</div>');
}
// onError se a função de manuseio de erros é personalizada, se definida, será tratada por ela
if (typeof (this.onerror) == 'função')
this.onerror (isto, errornumber, errordescription);
}
/**
* Escape texto
* @param {objeto} texto a ser escapado
* @return string text após fuga
*/
Fckeditor.prototype._htmlencode = function (texto)
{
if (typeof (text)! = string)
text = text.toString ();
// Substitua tudo & <> na string pelos caracteres de fuga correspondentes
texto = text.replace (
/&/g, &). Substitua (
// g,) .replace (
/</g, <). Substitua (
/>/g,>);
Retornar texto;
}
;(função()
{
// atribui o elemento textarea na página à variável do editor
var textareatoeditor = função (textarea)
{
VAR Editor = new FCKeditor (textarea.name);
editor.width = Math.max (textarea.offsetWidth, fckeditor.minwidth);
editor.Height = Math.max (textarea.offsethight, fckeditor.minhight);
Editor de retorno;
}
/**
* Substitua todos os elementos <sexttarea> disponíveis no documento pelo FCKeditor
* instâncias.
*
* // Substitua todos os elementos <sexttarea> na página.
* Fckeditor.ReplaceallTextareas ();
*
* // Substitua todos os elementos <textarea classes = myclassName> na página.
* Fckeditor.ReplaceallTextareas ('MyClassName');
*
* // Substitua seletivamente os elementos <Textarea>, com base em asserções personalizadas.
* Fckeditor.ReplaceallTextareas (função (texttarea, editor)
* {
* // Código personalizado para avaliar a substituição, retornando false se ele
* // não deve ser feito.
* // também passa o parâmetro do editor, para que o desenvolvedor possa
* // Personalize a instância.
*});
*/
Fckeditor.ReplaceallTextareas = function ()
{
// Obtenha todos os elementos de textarea
var textareas = document.getElementsByTagName ('textarea');
for (var i = 0; i <textareas.length; i ++)
{
VAR Editor = NULL;
var textarea = textareas [i];
var name = textarea.name;
// o atributo de nome deve existir.
if (! nome || name.length == 0)
continuar ;
if (typeof argumentos [0] == 'string')
{
// O nome da classe textarea pode ser passado como a função
// parâmetro.
var ClassRegex = novo regexp ('(?:^|)' + argumentos [0] + '(?: $ |)');
if (! ClassRegex.test (textarea.className))
continuar ;
}
caso contrário, if (typeof argumentos [0] == 'função')
{
// Uma função de asserção pode ser passada como parâmetro de função.
// Deve retornar explicitamente false para ignorar uma <sexttarea> específica.
editor = textareatoeditor (textarea);
if (argumentos [0] (textarea, editor) === false)
continuar ;
}
if (! Editor)
editor = textareatoeditor (textarea);
editor.ReplaceTextarea ();
}
}
}) ();
/**
* Detectar a compatibilidade do navegador
* Usando algumas informações Sagent retornadas pelo objeto Navigator, ele determina que o navegador retorna informações, incluindo o nome do código do navegador, nome do navegador, idioma da versão do navegador e outras informações e minúsculas
* Por exemplo:
* mozilla/4.0 (compatível; msie 6.0; Windows nt 5.2; sv1; .net clr 1.1.4322)
*
* Ao julgar o navegador do IE, a compilação condicional suportada após o uso do IE4.0 é adicionada.
* Como é suportado apenas pelo IE, essa propriedade não é suportada nos navegadores padrão W3C. Portanto, o IE é julgado adequadamente usando este recurso
*/
função fckeditor_iscompatibleBrowser ()
{
var sagent = Navigator.UserAgent.TolowerCase ();
// O navegador atual é o Internet Explorer 5.5+
// Use a compilação condicional para julgar o IE no IE,/*@cc_on!@*/False ==! false == verdadeiro,
// Se for um navegador que não
if ( /*@cc_on!@* /false && sagent.indexof (mac) == -1) // Não Apple Mac OS
{
var sbrowsServersion = Navigator.AppVersion.Match (/msie (./..)/):1];
return (sbrowsServersão> = 5.5);
}
// Gecko (Opera 9 tenta se comportar como uma bibola neste momento).
// Detecção seja o Opera 9 navegador
if (Navigator.Product == Gecko && Navigator.productsub> = 20030210 &&! (Typeof (Opera) == 'Object' && opera.posterror))
retornar true;
// Opera 9.50+
if (window.opera && window.opera.version && parsefloat (window.opera.version ())> = 9.5)
retornar true;
// Adobe Air
// verificado antes do Safari porque o AIR tem o editor de texto rico em webkit
// Recursos do Safari 3.0.4, mas a versão relatada é 420.
if (sagent.indexof ('adobeair/')! = -1)
return (sagent.match (/adobeair // (/d+)/) [1]> = 1); // A construção deve ser pelo menos v1
// Safari 3+
if (sagent.indexof ('Applewebkit/')! = -1)
return (sagent.match (/Applewebkit // (/d+)/) [1]> = 522); // A construção deve ser pelo menos 522 (v3)
retornar falso;
}