📄 htmlarea.js
字号:
/*--------------------------------------:noTabs=true:tabSize=2:indentSize=2:--
-- Xinha (is not htmlArea) - http://xinha.gogo.co.nz/
--
-- Use of Xinha is granted by the terms of the htmlArea License (based on
-- BSD license) please read license.txt in this package for details.
--
-- Xinha was originally based on work by Mihai Bazon which is:
-- Copyright (c) 2003-2004 dynarch.com.
-- Copyright (c) 2002-2003 interactivetools.com, inc.
-- This copyright notice MUST stay intact for use.
--
-- Developers - Coding Style:
-- For the sake of not committing needlessly conflicting changes,
--
-- * New code to be indented with 2 spaces ("soft tab").
-- * New code preferably uses BSD-Style Bracing
-- if(foo)
-- {
-- bar();
-- }
-- * Don't change brace styles unless you're working on the non BSD-Style
-- area (so we don't get spurious changes in line numbering).
-- * Don't change indentation unless you're working on the badly indented
-- area (so we don't get spurious changes of large blocks of code).
-- * Jedit is the recommended editor, a comment of this format should be
-- included in the top 10 lines of the file (see the embedded edit mode)
--
-- $HeadURL: http://svn.xinha.python-hosting.com/trunk/htmlarea.js $
-- $LastChangedDate: 2006-01-19 02:10:25 +0100 (Thu, 19 Jan 2006) $
-- $LastChangedRevision: 461 $
-- $LastChangedBy: mokhet $
--------------------------------------------------------------------------*/
HTMLArea.version =
{
'Release' : 'Trunk',
'Head' : '$HeadURL: http://svn.xinha.python-hosting.com/trunk/htmlarea.js $'.replace(/^[^:]*: (.*) \$$/, '$1'),
'Date' : '$LastChangedDate: 2006-01-19 02:10:25 +0100 (Thu, 19 Jan 2006) $'.replace(/^[^:]*: ([0-9-]*) ([0-9:]*) ([+0-9]*) \((.*)\) \$/, '$4 $2 $3'),
'Revision' : '$LastChangedRevision: 461 $'.replace(/^[^:]*: (.*) \$$/, '$1'),
'RevisionBy': '$LastChangedBy: mokhet $'.replace(/^[^:]*: (.*) \$$/, '$1')
};
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'))
};
this._editMode = "wysiwyg";
this.plugins = {};
this._timerToolbar = null;
this._timerUndo = null;
this._undoQueue = new Array(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 = this._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');
}
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-z0-9_]{3,}@[a-z0-9_-]{2,}(\.[a-z0-9_-]{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 () {
var cfg = this;
this.version = HTMLArea.version.Revision;
// 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 = 20;
// the time interval at which undo samples are taken
this.undoTimeout = 500; // 1/2 sec.
// 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 = "";
// external stylesheets to load (REFERENCE THESE ABSOLUTELY)
this.pageStyleSheets = [ ];
// specify a base href for relative links
// [JR 21-02-2006]
// Set baseHref to hostname + protocol for relative links
var locationref = window.location.href;
var hostposition = locationref.indexOf(window.location.host);
var protocol = locationref.substring(0,hostposition);
this.baseHref = protocol + window.location.host;
// 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 = 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.
*/
this.toolbar =
[
["popupeditor"],
["separator","formatblock","fontname","fontsize","bold","italic","underline","strikethrough"],
["separator","forecolor","hilitecolor","textindicator"],
["separator","subscript","superscript"],
["linebreak","separator","justifyleft","justifycenter","justifyright","justifyfull"],
["separator","insertorderedlist","insertunorderedlist","outdent","indent"],
["separator","inserthorizontalrule","createlink","insertimage","inserttable"],
["separator","undo","redo","selectall","print"], (HTMLArea.is_gecko ? [] : ["cut","copy","paste","overwrite","saveas"]),
["separator","killword","clearfonts","removeformat","toggleborders","splitblock","lefttoright", "righttoleft"],
["separator","htmlmode","showhelp","about"]
];
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'
};
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 = {};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -