htmlarea.js
来自「是个不错的文件代码,希望大家好好用,」· JavaScript 代码 · 共 1,974 行 · 第 1/5 页
JS
1,974 行
if ( typeof _editor_url == "string" )
{
// Leave exactly one backslash at the end of _editor_url
_editor_url = _editor_url.replace(/\x2f*$/, '/');
}
else
{
alert("WARNING: _editor_url is not set! You should set this variable to the editor files path; it should preferably be an absolute path, like in '/htmlarea/', but it can be relative if you prefer. Further we will try to load the editor files correctly but we'll probably fail.");
_editor_url = '';
}
// make sure we have a language
if ( typeof _editor_lang == "string" )
{
_editor_lang = _editor_lang.toLowerCase();
}
else
{
_editor_lang = "en";
}
// skin stylesheet to load
if ( typeof _editor_skin !== "string" )
{
_editor_skin = "";
}
var __htmlareas = [];
// browser identification
HTMLArea.agt = navigator.userAgent.toLowerCase();
HTMLArea.is_ie = ((HTMLArea.agt.indexOf("msie") != -1) && (HTMLArea.agt.indexOf("opera") == -1));
HTMLArea.is_opera = (HTMLArea.agt.indexOf("opera") != -1);
HTMLArea.is_mac = (HTMLArea.agt.indexOf("mac") != -1);
HTMLArea.is_mac_ie = (HTMLArea.is_ie && HTMLArea.is_mac);
HTMLArea.is_win_ie = (HTMLArea.is_ie && !HTMLArea.is_mac);
HTMLArea.is_gecko = (navigator.product == "Gecko");
// Creates a new HTMLArea object. Tries to replace the textarea with the given
// ID with it.
function HTMLArea(textarea, config)
{
if ( !textarea )
{
throw("Tried to create HTMLArea without textarea specified.");
}
if ( HTMLArea.checkSupportedBrowser() )
{
if ( typeof config == "undefined" )
{
this.config = new HTMLArea.Config();
}
else
{
this.config = config;
}
this._htmlArea = null;
if ( typeof textarea != 'object' )
{
textarea = HTMLArea.getElementById('textarea', textarea);
}
this._textArea = textarea;
// Before we modify anything, get the initial textarea size
this._initial_ta_size =
{
w: textarea.style.width ? textarea.style.width : ( textarea.offsetWidth ? ( textarea.offsetWidth + 'px' ) : ( textarea.cols + 'em') ),
h: textarea.style.height ? textarea.style.height : ( textarea.offsetHeight ? ( textarea.offsetHeight + 'px' ) : ( textarea.rows + 'em') )
};
// Create the loading message elements
if ( this.config.showLoading )
{
// Create and show the main loading message and the sub loading message for details of loading actions
// global element
var loading_message = document.createElement("div");
loading_message.id = "loading_" + textarea.name;
loading_message.className = "loading";
loading_message.innerHTML = "<img src='images/loading.gif' align='middle'> 正在载入编辑器...";
//alert("<img src='images/loading.gif'>loading....");
loading_message.style.width="160px";
loading_message.style.left = (HTMLArea.findPosX(textarea) + parseInt(this._initial_ta_size.w, 10) /2) + 'px';
loading_message.style.top = (HTMLArea.findPosY(textarea) + parseInt(this._initial_ta_size.h, 10) / 2) + 'px';
// main static message
document.body.appendChild(loading_message);
//this.setLoadingMessage("Constructing object");
}
this._editMode = "wysiwyg";
this.plugins = {};
this._timerToolbar = null;
this._timerUndo = null;
this._undoQueue = [this.config.undoSteps];
this._undoPos = -1;
this._customUndo = true;
this._mdoc = document; // cache the document, we need it in plugins
this.doctype = '';
this.__htmlarea_id_num = __htmlareas.length;
__htmlareas[this.__htmlarea_id_num] = this;
this._notifyListeners = {};
// Panels
var panels =
{
right:
{
on: true,
container: document.createElement('td'),
panels: []
},
left:
{
on: true,
container: document.createElement('td'),
panels: []
},
top:
{
on: true,
container: document.createElement('td'),
panels: []
},
bottom:
{
on: true,
container: document.createElement('td'),
panels: []
}
};
for ( var i in panels )
{
if(!panels[i].container) { continue; } // prevent iterating over wrong type
panels[i].div = panels[i].container; // legacy
panels[i].container.className = 'panels ' + i;
HTMLArea.freeLater(panels[i], 'container');
HTMLArea.freeLater(panels[i], 'div');
}
// finally store the variable
this._panels = panels;
HTMLArea.freeLater(this, '_textArea');
}
}
HTMLArea.onload = function() { };
HTMLArea.init = function() { HTMLArea.onload(); };
// cache some regexps
HTMLArea.RE_tagName = /(<\/|<)\s*([^ \t\n>]+)/ig;
HTMLArea.RE_doctype = /(<!doctype((.|\n)*?)>)\n?/i;
HTMLArea.RE_head = /<head>((.|\n)*?)<\/head>/i;
HTMLArea.RE_body = /<body[^>]*>((.|\n|\r|\t)*?)<\/body>/i;
HTMLArea.RE_Specials = /([\/\^$*+?.()|{}[\]])/g;
HTMLArea.RE_email = /[_a-zA-Z\d\-\.]{3,}@[_a-zA-Z\d\-]{2,}(\.[_a-zA-Z\d\-]{2,})+/i;
HTMLArea.RE_url = /(https?:\/\/)?(([a-z0-9_]+:[a-z0-9_]+@)?[a-z0-9_-]{2,}(\.[a-z0-9_-]{2,}){2,}(:[0-9]+)?(\/\S+)*)/i;
HTMLArea.Config = function(editor_type)
{
var cfg = this;
// Width and Height
// you may set these as follows
// width = 'auto' -- the width of the original textarea will be used
// width = 'toolbar' -- the width of the toolbar will be used
// width = '<css measure>' -- use any css measurement, eg width = '75%'
//
// height = 'auto' -- the height of the original textarea
// height = '<css measure>' -- any css measurement, eg height = '480px'
this.width = "auto";
this.height = "auto";
// the next parameter specifies whether the toolbar should be included
// in the size above, or are extra to it. If false then it's recommended
// to have explicit pixel sizes above (or on your textarea and have auto above)
this.sizeIncludesBars = true;
// the next parameter specifies whether the panels should be included
// in the size above, or are extra to it. If false then it's recommended
// to have explicit pixel sizes above (or on your textarea and have auto above)
this.sizeIncludesPanels = true;
// each of the panels has a dimension, for the left/right it's the width
// for the top/bottom it's the height.
//
// WARNING: PANEL DIMENSIONS MUST BE SPECIFIED AS PIXEL WIDTHS
this.panel_dimensions =
{
left: '200px', // Width
right: '200px',
top: '100px', // Height
bottom: '100px'
};
// enable creation of a status bar?
this.statusBar = true;
// intercept ^V and use the HTMLArea paste command
// If false, then passes ^V through to browser editor widget
this.htmlareaPaste = false;
this.mozParaHandler = 'best'; // set to 'built-in', 'dirty' or 'best'
// built-in: will (may) use 'br' instead of 'p' tags
// dirty : will use p and work good enough for the majority of cases,
// best : works the best, but it's about 12kb worth of javascript
// and will probably be slower than 'dirty'. This is the "EnterParagraphs"
// plugin from "hipikat", rolled in to be part of the core code
// maximum size of the undo queue
this.undoSteps = 10;
// the time interval at which undo samples are taken
this.undoTimeout = 1000; // 1/2 sec.
// set this to true if you want to explicitly right-justify when
// setting the text direction to right-to-left
this.changeJustifyWithDirection = false;
// if true then HTMLArea will retrieve the full HTML, starting with the
// <HTML> tag.
this.fullPage = false;
// style included in the iframe document
this.pageStyle = 'body { font-family: verdana,sans-serif,arial; font-size: 10pt;}.quote{margin:5px 20px;border:1px solid #CCCCCC;padding:5px; background:#F3F3F3;}';
// external stylesheets to load (REFERENCE THESE ABSOLUTELY)
this.pageStyleSheets = [];
// specify a base href for relative links
// this.baseHref = window.location.href.substring(0,window.location.href.lastIndexOf("/"))+'/';
this.baseHref =null;
// we can strip the base href out of relative links to leave them relative, reason for this
// especially if you don't specify a baseHref is that mozilla at least (& IE ?) will prefix
// the baseHref to any relative links to make them absolute, which isn't what you want most the time.
this.stripBaseHref = true;
// and we can strip the url of the editor page from named links (eg <a href="#top">...</a>)
// reason for this is that mozilla at least (and IE ?) prefixes location.href to any
// that don't have a url prefixing them
this.stripSelfNamedAnchors = true;
// sometimes high-ascii in links can cause problems for servers (basically they don't recognise them)
// so you can use this flag to ensure that all characters other than the normal ascii set (actually
// only ! through ~) are escaped in URLs to % codes
this.only7BitPrintablesInURLs = true;
// if you are putting the HTML written in Xinha into an email you might want it to be 7-bit
// characters only. This config option (off by default) will convert all characters consuming
// more than 7bits into UNICODE decimal entity references (actually it will convert anything
// below <space> (chr 20) except cr, lf and tab and above <tilde> (~, chr 7E))
this.sevenBitClean = false;
// sometimes we want to be able to replace some string in the html comng in and going out
// so that in the editor we use the "internal" string, and outside and in the source view
// we use the "external" string this is useful for say making special codes for
// your absolute links, your external string might be some special code, say "{server_url}"
// an you say that the internal represenattion of that should be http://your.server/
this.specialReplacements = {}; // { 'external_string' : 'internal_string' }
// set to true if you want Word code to be cleaned upon Paste
this.killWordOnPaste = true;
// enable the 'Target' field in the Make Link dialog
this.makeLinkShowsTarget = true;
// CharSet of the iframe, default is the charset of the document
this.charSet = HTMLArea.is_gecko ? document.characterSet : document.charset;
// URL-s
this.imgURL = "images/";
this.popupURL = "popups/";
// remove tags (these have to be a regexp, or null if this functionality is not desired)
this.htmlRemoveTags = null;
// Turning this on will turn all "linebreak" and "separator" items in your toolbar into soft-breaks,
// this means that if the items between that item and the next linebreak/separator can
// fit on the same line as that which came before then they will, otherwise they will
// float down to the next line.
// If you put a linebreak and separator next to each other, only the separator will
// take effect, this allows you to have one toolbar that works for both flowToolbars = true and false
// infact the toolbar below has been designed in this way, if flowToolbars is false then it will
// create explictly two lines (plus any others made by plugins) breaking at justifyleft, however if
// flowToolbars is false and your window is narrow enough then it will create more than one line
// even neater, if you resize the window the toolbars will reflow. Niiiice.
this.flowToolbars = false;
// set to true if you want the loading panel to show at startup
this.showLoading = true;
/** CUSTOMIZING THE TOOLBAR
* -------------------------
*
* It is recommended that you customize the toolbar contents in an
* external file (i.e. the one calling HTMLArea) and leave this one
* unchanged. That's because when we (InteractiveTools.com) release a
* new official version, it's less likely that you will have problems
* upgrading HTMLArea.
*/
if (editor_type==1){
this.toolbar =
[
["fontname","fontsize","space","bold","italic","underline",
"justifyleft","justifycenter","justifyright",
"separator","forecolor","hilitecolor",
"separator","createlink","insertimage","insertflash","insertmedia","insertemot",
"separator","htmlmode","showhelp","more_toolbar","linebreak"],
["formatblock","insertorderedlist","insertunorderedlist","outdent","indent","separator","selectall","killword","removeformat","toggleborders",
"separator","subscript","superscript","strikethrough","justifyfull","separator","inserttable","inserthorizontalrule","separator","print"],
(HTMLArea.is_gecko ? [] : ["saveas","cut","copy","paste","undo","redo"])
];
}else{
this.toolbar =
[
["bold","italic","underline",
"forecolor","hilitecolor","insertemot","insertimage","createlink",
"separator","undo","redo"],
];
}
this.fontname =
{
"— font —": '',
"Arial": 'arial,helvetica,sans-serif',
"Courier New": 'courier new,courier,monospace',
"Georgia": 'georgia,times new roman,times,serif',
"Tahoma": 'tahoma,arial,helvetica,sans-serif',
"Times New Roman": 'times new roman,times,serif',
"Verdana": 'verdana,arial,helvetica,sans-serif',
"impact": 'impact',
"WingDings": 'wingdings',
"黑体": "黑体",
"仿宋": "仿宋gb2312",
"楷体": "楷体gb2312",
"隶书": "隶书",
"幼圆": "幼圆"
};
this.fontsize =
{
"— size —": "",
"1 (8 pt)" : "1",
"2 (10 pt)": "2",
"3 (12 pt)": "3",
"4 (14 pt)": "4",
"5 (18 pt)": "5",
"6 (24 pt)": "6",
"7 (36 pt)": "7"
};
this.formatblock =
{
"— format —": "",
"Heading 1": "h1",
"Heading 2": "h2",
"Heading 3": "h3",
"Heading 4": "h4",
"Heading 5": "h5",
"Heading 6": "h6",
"Normal" : "p",
"Address" : "address",
"Formatted": "pre"
};
this.customSelects = {};
function cut_copy_paste(e, cmd, obj) { e.execCommand(cmd); }
this.debug = true;
this.URIs =
{
"blank": "popups/blank.html",
"link": "link.html",
"insert_image": "insert_image.html",
"insert_table": "insert_table.html",
"select_color": "select_color.html",
"help": "editor_help.html"
};
// ADDING CUSTOM BUTTONS: please read below!
// format of the btnList elements is "ID: [ ToolTip, Icon, Enabled in text mode?, ACTION ]"
// - ID: unique ID for the button. If the button calls document.execCommand
// it's wise to give it the same name as the called command.
// - ACTION: function that gets called when the button is clicked.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?