Analisis Kode Sumber Fckeditor (i) Analisis Anotasi Cina dari FCKEDITOR.js telah mempelajari kode sumber FCKEDITOR dalam beberapa hari terakhir (FCKEDITOR adalah editor web dengan berbagai aplikasi dalam jaringan). Saya perlu berterima kasih kepada Nileaderblog untuk terjemahannya yang sulit.
Saya mencari hampir semua internet, dan tampaknya saya telah menjelaskan banyak hal tentang file fckconfig.js, tetapi informasi tentang file fck inti fckeditor.js hampir 0.
Oleh karena itu, saya menghabiskan sepanjang hari memeras pasta gigi untuk mengomentari file inti fckeditor.js, fckeditor.js, untuk referensi oleh netizen yang juga belajar fckeditor.
Mengingat bahwa level penulis terbatas, di sini, silakan tunjukkan poin yang tidak pantas dalam komentar saya untuk menghindari menyesatkan orang lain. Terima kasih.
Disarankan untuk menyalinnya ke IDE Anda atau
Catatan: Artikel ini didasarkan pada fckeditor2.6.5
Untuk informasi yang lebih otoritatif, silakan merujuk ke Panduan Pengembang Resmi FCK
Salinan kode adalah sebagai berikut:
/**
*
**********Hak cipta***************
*-------- Dianotasi oleh Nileader ----
*---- Versi 1.00 2009-10-18 ----
*---- Setelah disalin, ditandai http://www.nileader.cn
*
* Kelas fckeditor dijelaskan oleh nileader
* @param {Object} Instancename Nama unik editor (setara dengan ID) adalah parameter yang belum diselamatkan.
* Lebar, Tinggi, Toolbarset, Nilai adalah semua parameter opsional
*/
var fckeditor = fungsi (instancename, lebar, tinggi, toolbarset, nilai)
{
// Properti dasar editor Catatan: Hal -hal ini diutamakan daripada konfigurasi di fckconfig.js
this.instancename = instancename; // Nama unik editor (setara dengan ID) (harus dimiliki!)
this.width = lebar || '100%'; // Lebar 100% secara default
this.height = tinggi || '200'; // Lebar 200 secara default
this.toolbarset = toolbarset || 'Default'; // Nama Set Alat, Nilai Default Default
this.value = value || ''; // Inisialisasi kode HTML editor, nilai default kosong
// jalur root default ketika editor diinisialisasi adalah menulis fck. Semua jalur yang digunakan default ke / fckeditor / dari direktori fckeditor.basepath.
this.basePath = fckeditor.basepath;
this.checkbrowser = true; // Apakah akan memeriksa kompatibilitas browser sebelum menampilkan editor, default benar
this.displayErrors = true; // Apakah itu ditampilkan dengan kesalahan, standarnya benar
this.config = objek baru ();
// acara
this.onError = null; // Fungsi (Sumber, Errornumber, Errordescription) Fungsi Penanganan Kesalahan Kustom
}
Fckeditor.basePath = '/fckeditor/'; // Direktori Root Default FCK
Fckeditor.minheight = 200; // Batas tinggi dan lebar
Fckeditor.minwidth = 750;
Fckeditor.prototype.version = '2.6.5'; // Nomor Versi
Fckeditor.prototype.versionBuild = '23959';
/**
* Call createHTML () untuk menghasilkan kode HTML editor dan output editor pada halaman
*/
Fckeditor.prototype.create = function ()
{
// Memanggil metode createHTML ()
document.write (this.createHtml ());
}
/**
* @return shtml kode html digunakan untuk menghasilkan editor
*/
Fckeditor.prototype.createHtml = function ()
{
// Periksa apakah ada nama instancen, tidak ada kode HTML yang akan dihasilkan
if (! this.instancename || this.instancename.length == 0)
{
this._throwerror (701, 'Anda harus menentukan nama instance.');
kembali '' ;
}
// Kembalikan nilai fungsi
var shtml = '';
/*
* Saat browser pengguna memenuhi beberapa browser yang telah ditetapkan,
* Menghasilkan kotak teks dengan id = this.instancename name = this.instancename, penyimpanan konten de facto
*/
if (! this.checkbrowser || this._isCompatibleBrowser ())
{
// Letakkan input ini setelah nilai awal FCK lolos
shtml + = '<input type = hidden id =' + this.instancename + 'name =' + this.instancename + 'value =' + this._htmlencode (this.value) + 'style = display: none style = display: none />';
// menghasilkan input tersembunyi untuk menempatkan konten di ini.config
shtml += this._getConfightMl ();
// kode untuk menghasilkan iframe editor
shtml += this._getiframeHtml ();
}
/**
* Jika browser pengguna tidak kompatibel dengan browser FCK default
* Hanya tekstara tradisional yang dapat ditemukan
*/
kalau tidak
{
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 + = '<name textarea =' + this.instancename +
'Baris = 4 cols = 40 style = lebar:' + swidth +
'; tinggi:' + sheight;
if (this.tabindex)
shtml + = 'tabIndex =' + this.tabIndex;
shtml += '>' +
this._htmlencode (this.value) +
'<// textarea>';
}
mengembalikan SHTML;
}
/**
* Gunakan editor untuk mengganti kotak teks yang sesuai
*/
Fckeditor.prototype.replacetextArea = function ()
{
// Jika Anda sudah memiliki tag ID = this.instancename ___ frame, kembalikan langsung
if (document.geteLementById (this.instancename + '___frame'))
kembali ;
// Saat browser pengguna memenuhi beberapa browser yang telah ditetapkan
if (! this.checkbrowser || this._isCompatibleBrowser ())
{
// Kita harus memeriksa elemen terlebih dahulu menggunakan ID dan kemudian namanya.
// Dapatkan tag html id = this.instancename
var OtexTarea = document.getElementById (this.instancename);
// Dapatkan semua tag nama = this.instancename
var colelementsbyname = document.getElementsbyname (this.instancename);
var i = 0;
/*
* Mempertimbangkan bahwa penamaan tag HTML pengguna tidak distandarisasi, catatan berikut dibuat untuk menentukan bahwa penulis mengacu pada pengguna menggunakan name = this.instancename dalam tag TextArea.
* Name = this.instancename juga digunakan pada tag lain di halaman yang sama
*/
while (Otextarea || i == 0)
{
// bepergian sampai tag tekstara nama = this.instancename ditemukan dan ditugaskan ke Otextarea
if (OtExTarea && OtexTarea.tagname.tolowercase () == 'TextAreA')
merusak;
OTEXTAREA = colelementsbyname [i ++];
}
// Jika tidak ada tag dengan ID atau nama ini.instancename, kotak kesalahan muncul
if (! Otextarea)
{
Peringatan ('Kesalahan: TextArea dengan ID atau nama diatur ke' + this.instancename + 'tidak ditemukan');
kembali ;
}
/*
* Setelah mengonfirmasi bahwa tag TextArea dengan name = this.instancename ada, tetapkan kode editor untuk itu
*/
OtexTarea.Style.Display = 'None';
// Jika urutan kunci tab didefinisikan pada halaman untuk tag TextArea tersebut, tetapkan ke ini. TABINDEX untuk digunakan nanti
if (Otextarea.tabindex)
this.tabIndex = OtexTarea.tabIndex;
this._inserthTmlBefore (this._getConfightMl (), OtexTarea);
this._inserthtmlBefore (this._getiframehtml (), OtextAreA);
}
}
/**
* Masukkan kode HTML di depan tag halaman yang ditentukan
* @param {objek} kode html yang akan dimasukkan
* @param {objek} tag halaman yang ditentukan (objek)
*/
Fckeditor.prototype._inserthtmlBefore = function (html, elemen)
{
if (element.insertAdJacentHtml) // yaitu metode insertAdJacentHtml pribadi
element.insertAdJacentHtml ('sebelum BBEGIN', html);
else // browser non -e
{
var oranye = document.createrange ();
oranye.setStartBefore (elemen);
var ofragment = oranye.createContextualFragment (html);
element.parentnode.insertbefore (ofRagment, elemen);
}
}
/*
* Menghasilkan domain tersembunyi dengan mengedit this.config [].
* Misalnya:
* this.config ['nileader'] = 1104, this.config ['leaderni'] = nichao ...
* Lalu, sconfig = ... & nileader = 1104 & leaderni = nichao…
* Tentu saja, pada akhirnya, Sconfig akan dikonversi menjadi persentase pengkodean oleh fungsi komponen encodeuric dan dimasukkan ke dalam input tersembunyi
*/
Fckeditor.prototype._getConfightMl = function ()
{
var sconfig = '';
untuk (var o di ini.config)
{
if (sconfig.length> 0) sconfig += '&';
// Fungsi Encodeuricomponent dikonversi menjadi penyandian persentase
sconfig + = encodeuricomponent (o) + '=' + encodeuricomponent (this.config [o]);
}
return '<input type = hidden id =' + this.instancename + '___config value =' + sconfig + 'style = display: none style = display: none />';
}
/*
* Hasilkan html iframe. Di sini melibatkan penentuan SRC
*/
Fckeditor.prototype._getiframeHtml = function ()
{
var sfile = 'fckeditor.html';
// Kasing Khusus, jendela tempat fckedito berada tidak tertanam di browser
mencoba
{
if ((/fcksource = true/i) .test (window.top.location.search))
sfile = 'fckeditor.original.html';
}
Catch (e) { /* Abaikan pengecualian ini. Sering kali, jendela tempat fckedito berada tertanam di browser. */}
/*
* Satu hal yang perlu diperhatikan di sini:
* Bagaimana cara kerja iframe: Saat iframe dalam keadaan edit yang dapat diedit, halaman tempat src sebenarnya diedit
* Ini slink untuk memasukkannya ke dalam tag iframe
*/
// slink apakah halaman de facto ini, mulai dari direktori root fck, misalnya, slink =/fckeditor/editor/fckeditor.html? Instancename = nileader & toolbar = nileadersbar
var slink = this.basePath + 'editor/' + sfile + '? instancename =' + encodeuricomponent (this.instancename);
if (this.toolbarset)
slink + = '& toolbar =' + this.toolbarset;
// Hasilkan kode HTML nyata untuk mengedit iframer, tentu saja, taruh src = slink
var html = '<iframe id =' + this.instancename +
'___Frame src =' + slink +
'src =' + slink +
'width =' + this.width +
'height =' + this.height;
// Jika pesanan traversal menggunakan tombol tab diatur, lalu tetapkan ke iframe
if (this.tabindex)
html + = 'tabIndex =' + this.tabIndex;
html += 'frameborder = 0 scrolling = no> </iframe>';
mengembalikan html;
}
/*
* Periksa apakah bowser pengguna adalah default FCK
* Metode ini hanyalah perusahaan FK yang mengejar oo, tidak berarti
*/
Fckeditor.prototype._iscompatibleBrowser = function ()
{
return fckeditor_isCompatibleBrowser ();
}
/**
* Kesalahan dilemparkan
* @param {objek} nomor kesalahan errornumber
* @param {object} errordescription kesalahan ikhtisar
*/
Fckeditor.prototype._throwerror = function (errornumber, errordescription)
{
this.errornumber = errornumber;
this.errordescription = errordescription;
// Apakah itu ditampilkan dengan kesalahan, standarnya benar
if (this.displayErrors)
{// Cetak Nomor Kesalahan dan Ikhtisar Kesalahan
document.write ('<div style = warna: #ff0000 style = warna: #ff0000>');
document.write ('[kesalahan fckeditor' + this.errornumber + ':' + this.errordescription + ']');
document.write ('</div>');
}
// OnError apakah fungsi penanganan kesalahan disesuaikan, jika didefinisikan, itu akan ditangani olehnya
if (typeof (this.onError) == 'function')
this.onError (ini, errornumber, errordescription);
}
/**
* Escape Text
* @param {objek} teks yang harus diloloskan
* @return string teks setelah melarikan diri
*/
Fckeditor.prototype._htmlencode = fungsi (teks)
{
if (typeof (teks)! = string)
text = text.toString ();
// gantikan semua & <> dalam string dengan karakter pelarian yang sesuai
text = text.replace (
/&/g, &). Ganti (
// g,). Replace (
/</g, <). Ganti (
/>/g,>);
mengembalikan teks;
}
;(fungsi()
{
// Tetapkan elemen TextArea pada halaman ke variabel editor
var TexTareatoEditor = Function (TextArea)
{
editor var = fckEditor baru (TextArea.name);
editor.width = Math.max (TextArea.OffsetWidth, fckeditor.minwidth);
editor.height = math.max (textarea.offsetheight, fckeditor.minheight);
editor kembali;
}
/**
* Ganti semua elemen <TextArea> yang tersedia dalam dokumen dengan fckeditor
* instance.
*
* // Ganti semua elemen <TextArea> di halaman.
* Fckeditor.replaceallTextArAseas ();
*
* // Ganti semua <TextArea class = MyClassName> elemen di halaman.
* Fckeditor.replacealltextArdaeas ('myclassname');
*
* // Secara selektif mengganti elemen <TextArea>, berdasarkan pernyataan khusus.
* Fckeditor.replacealltextArdaeas (function (textarea, editor)
* {
* // kode khusus untuk mengevaluasi ganti, mengembalikan false jika itu
* // Tidak boleh dilakukan.
* // Ini juga melewati parameter editor, sehingga pengembang bisa
* // Sesuaikan instance.
*});
*/
Fckeditor.replacealltextArdaeas = function ()
{
// Dapatkan semua elemen TextArea
var textareas = document.geteLementsbyTagname ('textarea');
untuk (var i = 0; i <textareas.length; i ++)
{
editor var = null;
var textarea = textareas [i];
var name = textarea.name;
// Atribut nama harus ada.
if (! name || name.length == 0)
melanjutkan ;
if (typeof argumen [0] == 'string')
{
// Nama kelas TexTarea dapat dilewati sebagai fungsinya
// parameter.
var classregex = regexp baru ('(?:^|)' + argumen [0] + '(?: $ |)');
if (! classregex.test (textarea.classname))
melanjutkan ;
}
lain jika (typeof argumen [0] == 'fungsi')
{
// Fungsi pernyataan dapat dilewati sebagai parameter fungsi.
// Itu harus secara eksplisit mengembalikan false untuk mengabaikan <pesifik TextArea>.
editor = TexTareatoEditor (TextArea);
if (argumen [0] (textarea, editor) === false)
melanjutkan ;
}
if (! Editor)
editor = TexTareatoEditor (TextArea);
editor.replacetextArea ();
}
}
}) ();
/**
* Mendeteksi kompatibilitas browser
* Menggunakan beberapa informasi yang dikembalikan oleh objek Navigator, ini menentukan bahwa browser mengembalikan informasi termasuk nama kode browser, nama browser, bahasa versi browser dan informasi lainnya dan huruf kecil
* Misalnya:
* Mozilla/4.0 (kompatibel; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322)
*
* Saat menilai IE browser, kompilasi bersyarat yang didukung setelah menggunakan IE4.0 ditambahkan.
* Karena hanya didukung oleh IE, properti ini tidak didukung di browser standar W3C. Oleh karena itu, IE dinilai dengan tepat dengan menggunakan fitur ini
*/
fungsi fckeditor_iscompatibleBrowser ()
{
var sagent = navigator.useragent.tolowercase ();
// browser saat ini adalah Internet Explorer 5.5+
// Gunakan kompilasi bersyarat untuk menilai IE di IE,/*@cc_on!@*/False ==! false == true,
// Jika itu adalah browser non -e, abaikan saja,/*@cc_on!@*/False == false
if ( /*@cc_on!@* /false && sagent.indexof (mac) == -1) // bukan apple mac os
{
var sbrowserVersion = navigator.appversion.match (/msie (./..)/) media];
return (sbrowserVersion> = 5.5);
}
// Gecko (Opera 9 mencoba berperilaku seperti tokek pada saat ini).
// Deteksi apakah itu Browser Opera 9
if (navigator.product == gecko && navigator.productsub> = 20030210 &&! (typeof (opera) == 'objek' && opera.posterror))))
Kembali Benar;
// opera 9.50+
if (window.opera && window.opera.version && parsefloat (window.opera.version ())> = 9.5)
Kembali Benar;
// Adobe Air
// diperiksa sebelum safari karena udara memiliki editor teks kaya webkit
// Fitur dari Safari 3.0.4, tetapi versi yang dilaporkan adalah 420.
if (sagent.indexof ('adobeair/')! = -1)
return (sagent.match (/adobeair // (/d+)/) [1]> = 1); // build harus setidaknya v1
// Safari 3+
if (sagent.indexof ('applewebkit/')! = -1)
return (sagent.match (/applewebkit // (/d+)/) [1]> = 522); // build harus minimal 522 (v3)
mengembalikan false;
}