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 =
  {
    "&mdash; font &mdash;": '',
    "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 =
  {
    "&mdash; size &mdash;": "",
    "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 =
  {
    "&mdash; format &mdash;": "",
    "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 + -
显示快捷键?