Javascript development Article 3 Development of iframe Rich Text Editor

Source: Internet
Author: User

Record the problems encountered. The TinyMCE editor used to write this article is very powerful, but it is third-party, and the project also considers this. It is not convenient to do something customized.
1. Determine the style of the element (or selected part) at the cursor position. When the cursor position changes, update the style of the corresponding button in the toolbar. Under what circumstances will the cursor position change? It is the keyboard direction key and mouse click, so the keyboard event and mouse event are judged to execute the cursor movement processing.
A. Get the cursor position or selected element: First getSelection, create range. Then obtain the element. After obtaining the element, you can obtain the style, tagName, and so on. Perform more operations and run the Code: Copy codeThe Code is as follows: <! Doctype html public "-// W3C // dtd html 4.01 Transitional // EN">
<Html>
<Head>
<Title> </title>
<Meta http-equiv = "Content-Type" content = "text/html; charset = UTF-8">
<Style type = "text/css">
P {width: 600px; text-align: left; text-indent: 2em; line-height: 20px; font-size: 12px}
Textarea {width: 600px; height: 100px; font-size: 12px; overflow: auto}
</Style>
</Head>
<Body>
<Span style = "display: block; height: 150px; font-size: 12px; line-height: 150%"> Information </span>
<Script type = "text/javascript">
Function createEditor (){
Var iframe = document. createElement ('iframe ');
Iframe. id = 'iframe ';
Iframe. frameBorder = 1;
Iframe. width = 400;
Iframe. height = 200;
Document. body. appendChild (iframe );
Return iframe;
}
Var bind = function (element, eventType, fn, useCapture ){
UseCapture = useCapture | false;
If (arguments. length <3 ){
Return true
};
If (window. addEventListener ){
Element. addEventListener (eventType, fn, useCapture );
} Else {
Element. attachEvent ('on' + eventType, fn, useCapture );
}
}
// From situ zhengmei
Var css = document. defaultView? Function (el, style ){
Return document. defaultView. getComputedStyle (el, null). getPropertyValue (style)
}: Function (el, style ){
Style = style. replace (/\-(\ w)/g, function ($, $1 ){
Return $1. toUpperCase ();
});
Return el. currentStyle [style];
}
Function bindEditor (){
Var iframe = createEditor ();
Var ifr_win = iframe. contentWindow;
Var ifr_doc = ifr_win.document;

Var editorContent = '<span style = "font-family:; font-weight: bold; "> A, 4, 4, 4, and 4 </span> big <span style =" font-style: italic; text-decoration: underline; "> four major plans </span>: <span style =" font-style: italic; color: # ff0000; "> doubles sass </span> master ';
Ifr_doc.designMode = 'on'; // editable
Ifr_doc.contentEditable = true;
Ifr_doc.open ();
Ifr_doc.writeln ('Ifr_doc.close ();

Var getRange = function (){
Var range = window. getSelection? Ifr_win.getSelection (): ifr_win.document.selection;
If (! Range ){
Return {
Node: null,
Range: null,
Text: null
};
}
Range = range. createRange? Range. createRange (): range. getRangeAt (0 );
Var text = window. getSelection? Range: range. text;
Var rangeNode = null;
If (range. commonAncestorContainer ){
RangeNode = range. commonAncestorContainer;
} Else {
If (range. parentElement) rangeNode = range. parentElement ();
}
Return {
Node: rangeNode,
Range: range,
Text: text
}
}
Var info = document. getElementsByTagName ('span ') [0];
Var getStyle = function (node ){
// Console. log (node)
Var html = '';
Html + = '<span style = "font-family:' + css (node, 'font-family ') +'"> font: '+ css (node, 'font-family ') +' </span> <br/> ';
Html + = '<span style = "color:' + css (node, 'color') + '"> color:' + css (node, 'color ') + '</span> <br/> ';
Html + = '<span style = "font-style:' + css (node, 'font-style') + '"> italic:' + css (node, 'font-style') + '</span> <br/> ';
Html + = '<span style = "font-weight:' + css (node, 'font-weight ') +'"> bold: '+ css (node, 'font-weight ') +' </span> <br/> ';
Html + = '<span style = "text-decoration:' + css (node, 'text-decoration') + '"> underline:' + css (node, 'text-recoration') + '</span> <br/> ';
Html + = 'tagname: '+ node. tagName +', style: '+ node. getAttribute ('style') +' <br/> ';

Info. innerHTML = html;
}
// Execute when the cursor position changes
Var onselectionchange = function (event ){
Var e = event | window. event;
If (! E. keyCode) e. keyCode = e. which;
// Move the cursor with the direction key to obtain the dom of the cursor position
If (e. keyCode >=37 & e. keyCode <= 40) | e. type = "click "){

Var node = getRange (). node; // get the cursor position Element
If (node! = Null ){
While (node. nodeType! = 1 ){
Node = node. parentNode;
}
GetStyle (node );
}
}
}

Bind (ifr_doc, 'click', onselectionchange, false );
Bind (ifr_doc, 'keylow', onselectionchange, false );
}
Window. onload = function (){
BindEditor ();
}
</Script>
</Body>
</Html>

2. ie cannot maintain the cursor position. This is a problem when adding hyperlinks. When the cursor moves other text fields without the browser's built-in input box, ie will lose the selected part, the link cannot be added to the selected part. The solution is to use getBookmark and moveToBookmark of range, and then bind onbeforedeactivate (getBookmark) and onactivate (moveTo) to the document of iframe ), the general meaning of these two events is that they are activated and deactivated. After an event is added, you do not have to save lastRang or set bookmark elsewhere, so that ie can automatically hold the cursor position like other browsers.Copy codeThe Code is as follows: if (Util. browser. msie ){
Util.bind(this.E.ifr_win.doc ument, "beforedeactivate", function (){
Var Rng = _ self. getRange (). range;
_ Self. rangeBookMark = Rng. getBookmark ();
});
Util.bind(this.E.ifr_win.doc ument, "activate", function (){
Var Rng = _ self. getRange (). range;
Rng. moveToBookmark (_ self. rangeBookMark );
Rng. select ();
_ Self. rangeBookMark = null;
});
}

3. Cancel and redo in ie. If an external iframe window exists, or the html undo or redo function is modified. It can only be classified as ie bug .... Maybe ie does not distinguish the iframe from the document on the page, so they can undo and redo the mixed morality.
As follows:Copy codeThe Code is as follows: <! Doctype html public "-// W3C // dtd html 4.01 Transitional // EN">
<Html>
<Head>
<Title> </title>
<Meta http-equiv = "Content-Type" content = "text/html; charset = UTF-8">
<Style type = "text/css">
P {width: 600px; text-align: left; text-indent: 2em; line-height: 20px; font-size: 12px}
Textarea {width: 600px; height: 100px; font-size: 12px; overflow: auto}
</Style>
</Head>
<Body>
<Span style = "display: block; height: 150px; font-size: 12px; line-height: 150%"> Information </span>
<Div id = "J_tool">
<Input type = "button" command = "Undo" value = "unselectable =" on "/>
<Input type = "button" command = "Redo" value = "Redo" unselectable = "on"/>
<Input type = "button" command = "Bold" value = "Bold" unselectable = "on"/>
<Input type = "button" command = "Italic" value = "Italic" unselectable = "on"/>
</Div>
<Br/>
<Input type = "button" onclick = "changeLayout ()" value = "click it, ie cannot be undone or redone."/>
<Br/>
<Script type = "text/javascript">
Function changeLayout (){
Var popwin = document. getElementById ('popwin ');
If (! Popwin ){
Popwin = document. createElement ('div ');
Popwin. id = 'popwin ';
Popwin.style.css Text = 'display: none; width: 300px; height: 150px; background-color: # ccc; position: absolute; left: 0; top: 0px; text-align: center; line-height: 150px ;';
Popwin. innerHTML = 'changed layoud rendering, ie will not be able to undo or redo ';
Document. body. appendChild (popwin );
Popwin. onclick = function () {this. style. display = 'none '};
}
Popwin. style. display = popwin. style. display = 'none '? 'Block': 'none ';
}
Function createEditor (){
Var iframe = document. createElement ('iframe ');
Iframe. id = 'iframe ';
Iframe. frameBorder = 1;
Iframe. width = 400;
Iframe. height = 200;
Document. body. appendChild (iframe );
Return iframe;
}
Var bind = function (element, eventType, fn, useCapture ){
UseCapture = useCapture | false;
If (arguments. length <3 ){
Return true
};
If (window. addEventListener ){
Element. addEventListener (eventType, fn, useCapture );
} Else {
Element. attachEvent ('on' + eventType, fn, useCapture );
}
}
// From situ zhengmei
Var css = document. defaultView? Function (el, style ){
Return document. defaultView. getComputedStyle (el, null). getPropertyValue (style)
}: Function (el, style ){
Style = style. replace (/\-(\ w)/g, function ($, $1 ){
Return $1. toUpperCase ();
});
Return el. currentStyle [style];
}
Function bindEditor (){
Var iframe = createEditor ();
Var ifr_win = iframe. contentWindow;
Var ifr_doc = ifr_win.document;
Var editorContent = '<span style = "font-family:; font-weight: bold; "> A, 4, 4, 4, and 4 </span> big <span style =" font-style: italic; text-decoration: underline; "> four major plans </span>: <span style =" font-style: italic; color: # ff0000; "> doubles sass </span> master ';
Ifr_doc.designMode = 'on'; // editable
Ifr_doc.contentEditable = true;
Ifr_doc.open ();
Ifr_doc.writeln ('Ifr_doc.close ();
Var getRange = function (){
Var range = window. getSelection? Ifr_win.getSelection (): ifr_win.document.selection;
If (! Range ){
Return {
Node: null,
Range: null,
Text: null
};
}
Range = range. createRange? Range. createRange (): range. getRangeAt (0 );
Var text = window. getSelection? Range: range. text;
Var rangeNode = null;
If (range. commonAncestorContainer ){
RangeNode = range. commonAncestorContainer;
} Else {
If (range. parentElement) rangeNode = range. parentElement ();
}
Return {
Node: rangeNode,
Range: range,
Text: text
}
}
Var info = document. getElementsByTagName ('span ') [0];
Var getStyle = function (node ){
// Console. log (node)
Var html = '';
Html + = '<span style = "font-family:' + css (node, 'font-family ') +'"> font: '+ css (node, 'font-family ') +' </span> <br/> ';
Html + = '<span style = "color:' + css (node, 'color') + '"> color:' + css (node, 'color ') + '</span> <br/> ';
Html + = '<span style = "font-style:' + css (node, 'font-style') + '"> italic:' + css (node, 'font-style') + '</span> <br/> ';
Html + = '<span style = "font-weight:' + css (node, 'font-weight ') +'"> bold: '+ css (node, 'font-weight ') +' </span> <br/> ';
Html + = '<span style = "text-decoration:' + css (node, 'text-decoration') + '"> underline:' + css (node, 'text-recoration') + '</span> <br/> ';
Html + = 'tagname: '+ node. tagName +', style: '+ node. getAttribute ('style') +' <br/> ';
Info. innerHTML = html;
}
// Execute when the cursor position changes
Var onselectionchange = function (event ){
Var e = event | window. event;
If (! E. keyCode) e. keyCode = e. which;
// Move the cursor with the direction key to obtain the dom of the cursor position
If (e. keyCode >=37 & e. keyCode <= 40) | e. type = "click "){
Var node = getRange (). node; // get the cursor position Element
If (node! = Null ){
While (node. nodeType! = 1 ){
Node = node. parentNode;
}
GetStyle (node );
}
}
}
Bind (ifr_doc, 'click', onselectionchange, false );
Bind (ifr_doc, 'keylow', onselectionchange, false );
Bind (document. getElementById ('J _ tool'), 'click', function (event ){
Event = event | window. event;
Var target = event. srcElement | event.tar get;
Var command = target. getAttribute ('command ');
Var param = target. getAttribute ('param') | '';
Ifr_doc.execCommand (command, false, param );
Return false;
})
}
Window. onload = function (){
BindEditor ();
}
</Script>
</Body>
</Html>

How can this problem be solved? You can only rely on javascript to simulate undo and redo it. There are still a lot of resources in the network, so we will not detail them here

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.