Forked from: itozyun's 非designModeなWYSIWYGエディターの試作 View Diff (1) forked: 非designModeなWYSIWYGエディターの試作 november26 Follow 2016-02-13 07:43:48 License: MIT License Fork0 Fav0 View447 Play Stop Reload Fullscreen Smart Phone Readme JavaScript 388 lines HTML 10 lines CSS 49 lines forked: 非designModeなWYSIWYGエディターの試作 jQuery v1.6.2 // forked from itozyun's "非designModeなWYSIWYGエディターの試作" http://jsdo.it/itozyun/3HO1 /* * * author: * itozyun (http://twitter.com/itozyun) * http://outcloud.blogspot.com/ * * origin: * KAWAGUCHI Yoshihiro (http://twitter.com/#!/kawagooch) * designModeを使わないWYSIWYGエディターの試作 * http://d.hatena.ne.jp/kawagooch/20101206/1291644876 */ var miceditor = ( function(){ var inputStrLen = 0, keypressed = false, isImeOff = true, jqCursor, jqEditArea, log, EDIT_AREA_ID = 'edit_area', BOX_SIZE_GETTTER = document.getElementById( 'getCursorBoxWidth'); function getRange(){ var range, selected = false; if( document.selection){ range = document.selection.createRange(); selected = range.text.length !== 0; } else if( window.getSelection().rangeCount !== 0) { range = window.getSelection().getRangeAt(0); selected = range.startOffset !== range.endOffset; } return { selected: selected, surroundContents: function( elm){ if( !range) return; if ( document.selection) { elm.innerHTML = elm.text; range.pasteHTML( elm.outerHTML); // TODO:カーソル移動 } else { range.surroundContents( elm); $( elm).after( jqCursor); } } }; } function keydown(e){ var parent = this.parentNode, prev = this.previousSibling, next = this.nextSibling, val = this.value || ''; switch (e.keyCode) { case 8: // delete key val.length === 0 && deleteKey( this); break; case 13: // enter key val.length === 0 && parent.insertBefore( document.createElement('BR'), this); break; case 37: // left key moveLeft(this, prev); break; case 38: // up key moveUp(this, prev); break; case 39: // right key moveRight(this, next, false) break; case 40: // down key moveDown(this, next); break; default: break; } focusCursorBox(); return true; } function keyup(e){ var thisObj = $(this), str = thisObj.val(); if(( isImeOff === true && keypressed === true && str.charCodeAt(0) < 127) || e.keyCode === 13 || (e.ctrlKey === true && e.keyCode === 86)){ // && str.length === 1 insertText( this); } !$.browser.mozilla && jqCursor.css('width', getCursorBoxWidth()); jqCursor.focus(); keypressed = false; } function keypress(e){ keypressed = true; } function click(e){ if( getRange().selected === true) return true; var left = e.clientX, top = e.clientY - jqCursor.height(), fix = false; jqEditArea.children( 'br').each(function(){ $(this).before(jqCursor); if (jqCursor.offset().top > top) { fix = true; return false; } return true; }); fix === false && jqEditArea.append(jqCursor); while (jqCursor.offset().left > left && moveLeft(jqCursor.get(0), jqCursor.get(0).previousSibling)) { } focusCursorBox(); return true; } function write(){ isImeOff = true; insertText( this); setTimeout(function(){ jqCursor.val('').css('width', getCursorBoxWidth()); }, 0); } function insertText( _this){ var str = _this.value || '', prevElm = _this.previousSibling; _this.value = ''; if( prevElm && prevElm.nodeType === 3){ prevElm.nodeValue = prevElm.nodeValue + str; } else { _this.parentNode.insertBefore( document.createTextNode( str), _this); } } function deleteKey( _this){ var prev = _this.previousSibling, parent = _this.parentNode; if( prev){ del( prev) === false && deleteKey( _this); } else if( parent.id !== EDIT_AREA_ID){ parent.parentNode.insertBefore( _this, parent); parent.childNodes.length === 0 && parent.parentNode.removeChild( parent); // dom cleaner deleteKey( _this); } function del( prev){ if( prev == null) return false; if( prev.nodeType === 3) { var text = prev.data, l = text.length; l > 1 ? prev.data = text.substring( 0, l -1) : prev.parentNode.removeChild( prev); return l !== 0; } else if( prev.nodeType === 1){ if( prev.nodeName === 'BR'){ prev.parentNode.removeChild( prev); return true; } var result = del( prev.lastChild); result === true ? prev.childNodes.length === 0 && prev.parentNode.removeChild( prev) : prev.parentNode.removeChild( prev); return result; } // ?? return true; } } function moveLeft(thisObj, prev){ var parent = thisObj.parentNode; if (prev == null) { if( parent.id !== EDIT_AREA_ID) { $(parent).before(thisObj); moveLeft(thisObj, thisObj.previousSibling); return true; } else { return false; } } if (prev.nodeType === 3) { var text = prev.data, l = text.length; if ( l === 0) { $(prev).remove(); moveLeft(thisObj, thisObj.previousSibling); return true; } else { var nextNode = thisObj.nextSibling; if( l === 1){ if( nextNode && nextNode.nodeType === 3){ nextNode.nodeValue = text + nextNode.nodeValue; $( prev).remove(); } else { nextNode ? parent.insertBefore( prev, nextNode) : parent.appendChild( prev); } } else { var str = text.substring( l -1); if( nextNode && nextNode.nodeType === 3){ nextNode.nodeValue = str + nextNode.nodeValue; } else { var t = document.createTextNode( str); nextNode ? parent.insertBefore( t, nextNode) : parent.appendChild( t); } prev.nodeValue = text.substring( 0, l -1); } } } else if (prev.nodeType === 1) { var last = prev.lastChild; if (!last) { prev.nodeName !== 'BR' ? parent.removeChild( prev) : parent.insertBefore( thisObj, prev); return true; } prev.appendChild( thisObj); moveLeft( thisObj, last); } return true; } function moveRight(thisObj, next, brStop){ var parent = thisObj.parentNode; if( next == null) { if( parent.id !== EDIT_AREA_ID) { $(parent).after(thisObj); moveRight(thisObj, thisObj.nextSibling, brStop); return true; } else { return false; } } if( next.nodeType === 3) { var text = next.data, l = text.length; if ( l === 0) { $(next).remove(); moveRight(thisObj, thisObj.nextSibling, brStop); return true; } else { var prevNode = thisObj.previousSibling; if ( l === 1) { if( prevNode && prevNode.nodeType === 3){ prevNode.nodeValue = prevNode.nodeValue + text; $( next).remove(); } else { parent.insertBefore( next, thisObj); } } else { var str = text.substring(0, 1); if( prevNode && prevNode.nodeType === 3){ prevNode.nodeValue = prevNode.nodeValue + str; } else { parent.insertBefore( document.createTextNode( str), thisObj); } next.nodeValue = text.substring(1); } } } else if (next.nodeType === 1) { if( brStop === true && next.nodeName === 'BR') { return false; } var first = next.firstChild; if (!first) { next.nodeName !== 'BR' ? parent.removeChild( next) : next.nextSibling ? parent.insertBefore( thisObj, next.nextSibling) : parent.appendChild( thisObj); return true; } next.insertBefore( thisObj, first); moveRight(thisObj, first, brStop); } return true; } function moveUp(thisObj, prev){ var nowLeft = startLeft = thisObj.offsetLeft; nowTop = startTop = thisObj.offsetTop; while (nowTop >= startTop && moveLeft(thisObj, prev) === true) { prev = thisObj.previousSibling; nowTop = thisObj.offsetTop; } prev = thisObj.previousSibling; nowLeft = thisObj.offsetLeft; while (nowLeft > startLeft && moveLeft(thisObj, prev) === true) { prev = thisObj.previousSibling; nowLeft = thisObj.offsetLeft; } } function moveDown(thisObj, next){ var nowLeft = startLeft = thisObj.offsetLeft, nowTop = startTop = thisObj.offsetTop; while ( nowTop <= startTop && moveRight(thisObj, next, false) === true) { next = thisObj.nextSibling; nowTop = thisObj.offsetTop; } next = thisObj.nextSibling; nowLeft = thisObj.offsetLeft; while (nowLeft < startLeft && moveRight(thisObj, next, true) === true) { next = thisObj.nextSibling; nowLeft = thisObj.offsetLeft; } } function getCursorBoxWidth(){ var span = BOX_SIZE_GETTTER; span.innerHTML = jqCursor.val(); var width = $(span).width(); span.innerHTML = ''; return width === 0 ? 20 : width + 23; } function focusCursorBox(){ $.browser.msie ? setTimeout( function(){jqCursor.focus();}, 1) : jqCursor.focus(); } return { init : function(){ jqCursor = $('#cursor').bind('keydown', keydown); if ($.browser.msie && $.browser.version < 8) { jqCursor.bind('keypress', keydown); } log = $( '#log').html( 'ready'); jqCursor.bind('keyup', keyup) .bind('keypress', keypress) .bind('compositionstart', function(e){ isImeOff = false; }).bind('compositionend', write).focus(); jqEditArea = $('#' +EDIT_AREA_ID).bind('click', click); ( $.browser.mozilla || navigator.userAgent.indexOf('iPhone;') >= 0) && ( function(){ setInterval( function(){ var len = jqCursor.val().length; if (inputStrLen !== len) { inputStrLen = len; jqCursor.css( 'width', getCursorBoxWidth()).val( jqCursor.val()); } }, 100); })(); delete miceditor.init; }, link: function (){ var range = getRange(), a = document.createElement("a"); a.href = $('#url').val(); if ( range.selected === false) { var parent = jqCursor.get(0).parentNode; $(parent).is('a') ? $(parent).after(jqCursor) : jqCursor.wrap(a); } else { range.surroundContents(a); } jqCursor.focus(); return true; }, span: function (className){ var range = getRange(), span = document.createElement('span'); $(span).addClass(className); if( range.selected === false) { var parent = jqCursor.get(0).parentNode; $(parent).is('span.' + className) ? $(parent).after(jqCursor) : jqCursor.wrap(span); } else { range.surroundContents(span); } jqCursor.focus(); return true; } } })(); $(document).ready( miceditor.init); <input id="url" type="text" value="http://"> <input type="button" onclick="miceditor.link();" value="リンク">| <button type="button" onclick="miceditor.span('red');"><span class="red">紅</span></button>| <button type="button" onclick="miceditor.span('blue');"><span class="blue">蒼</span></button>| <button type="button" onclick="miceditor.span('green');"><span class="green">翠</span></button>| <button type="button" onclick="miceditor.span('new');"><span class="new">NEW</span></button> <div id="edit_area" class="edit_area"><input type="text" id="cursor" class="cursor"></div> <div class="edit_area" style="visibility:hidden;"><span id="getCursorBoxWidth"></span></div> <p id="log"></p> forked: 非designModeなWYSIWYGエディターの試作 .red { font-weight:bold; color:red; } .blue { font-weight:bold; color:blue; } .green { font-weight:bold; color:green; } .new { background-color: red; color: white; border : 1px solid gray; padding: 2px; border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px; -moz-box-shadow: 2px 2px 5px rgba(0,0,0,0.7); -webkit-box-shadow: 2px 2px 5px rgba(0,0,0,0.7); } #edit_area { border: 1px solid black; width: 400px; height: 300px; } .edit_area { font-size: medium; line-height: 1.6em; white-space: pre-wrap; font-family: monospace; word-wrap: break-word; } .cursor { width: 20px; font-size: 100%; font-family: monospace; margin: 0 -20px 0 0; background: #ccf; *background: none; border: 0; outline: 0; } .btn { cursor: pointer; } // forked from itozyun's "非designModeなWYSIWYGエディターの試作" http://jsdo.it/itozyun/3HO1 /* * * author: * itozyun (http://twitter.com/itozyun) * http://outcloud.blogspot.com/ * * origin: * KAWAGUCHI Yoshihiro (http://twitter.com/#!/kawagooch) * designModeを使わないWYSIWYGエディターの試作 * http://d.hatena.ne.jp/kawagooch/20101206/1291644876 */ var miceditor = ( function(){ var inputStrLen = 0, keypressed = false, isImeOff = true, jqCursor, jqEditArea, log, EDIT_AREA_ID = 'edit_area', BOX_SIZE_GETTTER = document.getElementById( 'getCursorBoxWidth'); function getRange(){ var range, selected = false; if( document.selection){ range = document.selection.createRange(); selected = range.text.length !== 0; } else if( window.getSelection().rangeCount !== 0) { range = window.getSelection().getRangeAt(0); selected = range.startOffset !== range.endOffset; } return { selected: selected, surroundContents: function( elm){ if( !range) return; if ( document.selection) { elm.innerHTML = elm.text; range.pasteHTML( elm.outerHTML); // TODO:カーソル移動 } else { range.surroundContents( elm); $( elm).after( jqCursor); } } }; } function keydown(e){ var parent = this.parentNode, prev = this.previousSibling, next = this.nextSibling, val = this.value || ''; switch (e.keyCode) { case 8: // delete key val.length === 0 && deleteKey( this); break; case 13: // enter key val.length === 0 && parent.insertBefore( document.createElement('BR'), this); break; case 37: // left key moveLeft(this, prev); break; case 38: // up key moveUp(this, prev); break; case 39: // right key moveRight(this, next, false) break; case 40: // down key moveDown(this, next); break; default: break; } focusCursorBox(); return true; } function keyup(e){ var thisObj = $(this), str = thisObj.val(); if(( isImeOff === true && keypressed === true && str.charCodeAt(0) < 127) || e.keyCode === 13 || (e.ctrlKey === true && e.keyCode === 86)){ // && str.length === 1 insertText( this); } !$.browser.mozilla && jqCursor.css('width', getCursorBoxWidth()); jqCursor.focus(); keypressed = false; } function keypress(e){ keypressed = true; } function click(e){ if( getRange().selected === true) return true; var left = e.clientX, top = e.clientY - jqCursor.height(), fix = false; jqEditArea.children( 'br').each(function(){ $(this).before(jqCursor); if (jqCursor.offset().top > top) { fix = true; return false; } return true; }); fix === false && jqEditArea.append(jqCursor); while (jqCursor.offset().left > left && moveLeft(jqCursor.get(0), jqCursor.get(0).previousSibling)) { } focusCursorBox(); return true; } function write(){ isImeOff = true; insertText( this); setTimeout(function(){ jqCursor.val('').css('width', getCursorBoxWidth()); }, 0); } function insertText( _this){ var str = _this.value || '', prevElm = _this.previousSibling; _this.value = ''; if( prevElm && prevElm.nodeType === 3){ prevElm.nodeValue = prevElm.nodeValue + str; } else { _this.parentNode.insertBefore( document.createTextNode( str), _this); } } function deleteKey( _this){ var prev = _this.previousSibling, parent = _this.parentNode; if( prev){ del( prev) === false && deleteKey( _this); } else if( parent.id !== EDIT_AREA_ID){ parent.parentNode.insertBefore( _this, parent); parent.childNodes.length === 0 && parent.parentNode.removeChild( parent); // dom cleaner deleteKey( _this); } function del( prev){ if( prev == null) return false; if( prev.nodeType === 3) { var text = prev.data, l = text.length; l > 1 ? prev.data = text.substring( 0, l -1) : prev.parentNode.removeChild( prev); return l !== 0; } else if( prev.nodeType === 1){ if( prev.nodeName === 'BR'){ prev.parentNode.removeChild( prev); return true; } var result = del( prev.lastChild); result === true ? prev.childNodes.length === 0 && prev.parentNode.removeChild( prev) : prev.parentNode.removeChild( prev); return result; } // ?? return true; } } function moveLeft(thisObj, prev){ var parent = thisObj.parentNode; if (prev == null) { if( parent.id !== EDIT_AREA_ID) { $(parent).before(thisObj); moveLeft(thisObj, thisObj.previousSibling); return true; } else { return false; } } if (prev.nodeType === 3) { var text = prev.data, l = text.length; if ( l === 0) { $(prev).remove(); moveLeft(thisObj, thisObj.previousSibling); return true; } else { var nextNode = thisObj.nextSibling; if( l === 1){ if( nextNode && nextNode.nodeType === 3){ nextNode.nodeValue = text + nextNode.nodeValue; $( prev).remove(); } else { nextNode ? parent.insertBefore( prev, nextNode) : parent.appendChild( prev); } } else { var str = text.substring( l -1); if( nextNode && nextNode.nodeType === 3){ nextNode.nodeValue = str + nextNode.nodeValue; } else { var t = document.createTextNode( str); nextNode ? parent.insertBefore( t, nextNode) : parent.appendChild( t); } prev.nodeValue = text.substring( 0, l -1); } } } else if (prev.nodeType === 1) { var last = prev.lastChild; if (!last) { prev.nodeName !== 'BR' ? parent.removeChild( prev) : parent.insertBefore( thisObj, prev); return true; } prev.appendChild( thisObj); moveLeft( thisObj, last); } return true; } function moveRight(thisObj, next, brStop){ var parent = thisObj.parentNode; if( next == null) { if( parent.id !== EDIT_AREA_ID) { $(parent).after(thisObj); moveRight(thisObj, thisObj.nextSibling, brStop); return true; } else { return false; } } if( next.nodeType === 3) { var text = next.data, l = text.length; if ( l === 0) { $(next).remove(); moveRight(thisObj, thisObj.nextSibling, brStop); return true; } else { var prevNode = thisObj.previousSibling; if ( l === 1) { if( prevNode && prevNode.nodeType === 3){ prevNode.nodeValue = prevNode.nodeValue + text; $( next).remove(); } else { parent.insertBefore( next, thisObj); } } else { var str = text.substring(0, 1); if( prevNode && prevNode.nodeType === 3){ prevNode.nodeValue = prevNode.nodeValue + str; } else { parent.insertBefore( document.createTextNode( str), thisObj); } next.nodeValue = text.substring(1); } } } else if (next.nodeType === 1) { if( brStop === true && next.nodeName === 'BR') { return false; } var first = next.firstChild; if (!first) { next.nodeName !== 'BR' ? parent.removeChild( next) : next.nextSibling ? parent.insertBefore( thisObj, next.nextSibling) : parent.appendChild( thisObj); return true; } next.insertBefore( thisObj, first); moveRight(thisObj, first, brStop); } return true; } function moveUp(thisObj, prev){ var nowLeft = startLeft = thisObj.offsetLeft; nowTop = startTop = thisObj.offsetTop; while (nowTop >= startTop && moveLeft(thisObj, prev) === true) { prev = thisObj.previousSibling; nowTop = thisObj.offsetTop; } prev = thisObj.previousSibling; nowLeft = thisObj.offsetLeft; while (nowLeft > startLeft && moveLeft(thisObj, prev) === true) { prev = thisObj.previousSibling; nowLeft = thisObj.offsetLeft; } } function moveDown(thisObj, next){ var nowLeft = startLeft = thisObj.offsetLeft, nowTop = startTop = thisObj.offsetTop; while ( nowTop <= startTop && moveRight(thisObj, next, false) === true) { next = thisObj.nextSibling; nowTop = thisObj.offsetTop; } next = thisObj.nextSibling; nowLeft = thisObj.offsetLeft; while (nowLeft < startLeft && moveRight(thisObj, next, true) === true) { next = thisObj.nextSibling; nowLeft = thisObj.offsetLeft; } } function getCursorBoxWidth(){ var span = BOX_SIZE_GETTTER; span.innerHTML = jqCursor.val(); var width = $(span).width(); span.innerHTML = ''; return width === 0 ? 20 : width + 23; } function focusCursorBox(){ $.browser.msie ? setTimeout( function(){jqCursor.focus();}, 1) : jqCursor.focus(); } return { init : function(){ jqCursor = $('#cursor').bind('keydown', keydown); if ($.browser.msie && $.browser.version < 8) { jqCursor.bind('keypress', keydown); } log = $( '#log').html( 'ready'); jqCursor.bind('keyup', keyup) .bind('keypress', keypress) .bind('compositionstart', function(e){ isImeOff = false; }).bind('compositionend', write).focus(); jqEditArea = $('#' +EDIT_AREA_ID).bind('click', click); ( $.browser.mozilla || navigator.userAgent.indexOf('iPhone;') >= 0) && ( function(){ setInterval( function(){ var len = jqCursor.val().length; if (inputStrLen !== len) { inputStrLen = len; jqCursor.css( 'width', getCursorBoxWidth()).val( jqCursor.val()); } }, 100); })(); delete miceditor.init; }, link: function (){ var range = getRange(), a = document.createElement("a"); a.href = $('#url').val(); if ( range.selected === false) { var parent = jqCursor.get(0).parentNode; $(parent).is('a') ? $(parent).after(jqCursor) : jqCursor.wrap(a); } else { range.surroundContents(a); } jqCursor.focus(); return true; }, span: function (className){ var range = getRange(), span = document.createElement('span'); $(span).addClass(className); if( range.selected === false) { var parent = jqCursor.get(0).parentNode; $(parent).is('span.' + className) ? $(parent).after(jqCursor) : jqCursor.wrap(span); } else { range.surroundContents(span); } jqCursor.focus(); return true; } } })(); $(document).ready( miceditor.init); <input id="url" type="text" value="http://"> <input type="button" onclick="miceditor.link();" value="リンク">| <button type="button" onclick="miceditor.span('red');"><span class="red">紅</span></button>| <button type="button" onclick="miceditor.span('blue');"><span class="blue">蒼</span></button>| <button type="button" onclick="miceditor.span('green');"><span class="green">翠</span></button>| <button type="button" onclick="miceditor.span('new');"><span class="new">NEW</span></button> <div id="edit_area" class="edit_area"><input type="text" id="cursor" class="cursor"></div> <div class="edit_area" style="visibility:hidden;"><span id="getCursorBoxWidth"></span></div> <p id="log"></p> .red { font-weight:bold; color:red; } .blue { font-weight:bold; color:blue; } .green { font-weight:bold; color:green; } .new { background-color: red; color: white; border : 1px solid gray; padding: 2px; border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px; -moz-box-shadow: 2px 2px 5px rgba(0,0,0,0.7); -webkit-box-shadow: 2px 2px 5px rgba(0,0,0,0.7); } #edit_area { border: 1px solid black; width: 400px; height: 300px; } .edit_area { font-size: medium; line-height: 1.6em; white-space: pre-wrap; font-family: monospace; word-wrap: break-word; } .cursor { width: 20px; font-size: 100%; font-family: monospace; margin: 0 -20px 0 0; background: #ccf; *background: none; border: 0; outline: 0; } .btn { cursor: pointer; } use an iframe compat browser, deer Play on jsdo.it games Author Share ブログに埋め込む QR Tag Download Complete! Description What kind of game? Control Device Smartphone Controllerjsdo.it WebSocket Controller» Mouse Keyboard Touch Device Fullscreen Activated Inactivated jsdo.it games から削除する Submit Author november26 Tweet Default Panel Auto play Screenshot Readme JavaScript HTML CSS Size Width: px Height: px code <script type="text/javascript" src="http://jsdo.it/blogparts/6V6N/js"></script> editor WYSIWYG, Discussion Questions on this code? Tags WYSIWYG, editor