それを利用して「リッチテキスト」を作成するプログラムを作りました。
JavaScriptが扱える人なら容易に機能を拡張することができます。
何気なく思いついて作ってみたけど、なかなかの拡張性で実用性が高そう。
画面はこんな感じです。

「html」「編集不可」「clickハンドラ設置」などのボタンの下のエリアはiframeです。
起動直後はiframe内部は自由に編集できる状態になっています。
画像をドラッグ移動させたい時など必要に応じてcontentEditableのtrue/falseを切り替えられます。
「html」ボタンを押すとメモ帳が起動して、編集内容に対応するHTMLソースが表示されます。

上記ソースを「拡張子:htm」などにして保存して

そのファイルを開くと、編集中の表示そのままのHTMLが表示されます。

ちなみに先ほどのメモ帳の画面で、中身を編集して上書き保存し、

メモ帳を閉じると編集プログラム側の表示に編集内容が反映されます。

以下、ソース
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<title>contentEditable</title> | |
<style> | |
html,body{width:100%;height:100%;} | |
.w-max{width:100%;} | |
.max{width:100%;height:100%;} | |
.of-auto{overflow:auto;} | |
.b1{border:solid 1px #000;} | |
.no_mp{margin:0;padding:0px;} | |
.bc{border-collapse:collapse;} | |
</style> | |
</head> | |
<body class=no_mp style="overflow:hidden;"> | |
<table class=max> | |
<tr height=1> | |
<td> | |
<select id=selDir></select> | |
<button id=btn追加>追加</button> | |
<button id=btn保存>保存</button> | |
<button id=btn削除>削除</button> | |
iframe用機能: | |
<button id=btnHTML>html</button> | |
<button id=btnEditable>編集可</button> | |
<button id=btnClickハンドラ>clickハンドラ設置</button> | |
</td> | |
</tr> | |
<tr><td><iframe id=ifrVIEW class="max" style="position:relative;left:-3px;"></iframe></td></tr> | |
<tr height=1> | |
<td> | |
<table id=tblElem class=max> | |
<tr><td>選択中エレメント用機能:<select id=selFun></select></td></tr> | |
<tr><td id=tdElem></td></tr> | |
</table> | |
</td> | |
</tr> | |
</table> | |
</body> | |
<script> | |
elem選択中 = null | |
ifrVIEW.document.body.contentEditable = true | |
ifrClickイベントハンドラ設置=function(){ | |
// iframe内に画像ファイルなどをD&Dするとイベントハンドラが消えてしまうので、再定義する方法が必要。 | |
ifrVIEW.document.body.onclick=function(){ | |
elem選択中 = ifrVIEW.window.event.target | |
選択中エレメント向け機能の実行() | |
} | |
} | |
ifrClickイベントハンドラ設置() | |
btnClickハンドラ.onclick = ifrClickイベントハンドラ設置 | |
btn追加.onclick=function(){ | |
var name=prompt('新しいデータの名前を入力してください','new name'), path=基準フォルダ+'/データ/'+name | |
if(!name){return} | |
if(!addデータdir(name)){return} | |
selDir更新(name) | |
selDir.onchange() | |
} | |
addデータdir=function(name){ | |
var path=基準フォルダ+'/データ/'+name | |
try{fs.CreateFolder(path)}catch(e){return alert('ファイルやフォルダの名前に使用できない文字が含まれています。\n\n'+name)} | |
Write(path+'/html.htm', '') | |
// エラー無く完了したらtrueを返す。 | |
return true | |
} | |
btn保存.onclick=function(){ Write(selOps(selDir).value+'/html.htm', ifrVIEW.document.body[iH]) } | |
btn削除.onclick=function(){ | |
var ops=selOps(selDir) | |
if(!confirm('['+ops.text+']を削除しますか?')){return} | |
fs.DeleteFolder(ops.value) | |
selDir.options.length==1 && addデータdir('new name') | |
selDir更新() | |
selDir.onchange() | |
} | |
selDir更新=function(selectName){ | |
var path=基準フォルダ+'/データ' | |
var arr=getDirList(path), ops=selDir.options | |
while(ops[0]){ops[0] = null} | |
for0L(arr, function(i, name){ | |
ops[i] = new Option(name, path+'/'+name) | |
if(name==selectName){ selDir[sI] = i } | |
}) | |
} | |
btnEditable.onclick=function(){ | |
if(this[iT]=='編集可'){ | |
this[iT] = '編集不可' | |
ifrVIEW.document.body.contentEditable = false | |
}else{ | |
this[iT] = '編集可' | |
ifrVIEW.document.body.contentEditable = true | |
} | |
} | |
btnHTML.onclick = function(){ | |
var pathTMP=gsf2+'/html'+(new Date()).getTime()+'.html', div=document.createElement('DIV') | |
Write(pathTMP, ifrVIEW.document.body[iH]) | |
document.body.insertBefore(div) | |
with(div.style){ | |
position = 'absolute' | |
top = '0px' | |
left = '0px' | |
width = '100%' | |
height = '100%' | |
} | |
div[iH] = '<table class=max><td style="text-align:center;background-color:rgba(220,220,220,0.9);">メモ帳を閉じると操作可能になります。</td></table>' | |
shell.run('notepad '+fun(pathTMP), 1, true) | |
div.removeNode(true) | |
if(!fs.FileExists(pathTMP)){return} | |
ifrVIEW.document.body[iH] = Read(pathTMP) | |
fs.DeleteFile(pathTMP) | |
elem選択中 = null | |
} | |
selDir.onchange = function(){ var si=this[sI]; 0 <= si ? ifrVIEW.document.body[iH] = Read(this.options[si].value+'/html.htm') : 0 } | |
selFun.onchange = function(){ elem選択中 && 選択中エレメント向け機能の実行() } | |
選択中エレメント向け機能の実行 = function(){ | |
var fun, path=selOps(selFun).value | |
eval('fun = '+Read(path+'/func.js')) | |
fun(elem選択中, tdElem, path) | |
} | |
onload = function(){ | |
/* | |
var arr=[] | |
forIn(tblElem.ownerDocument.parentWindow, function(name,v){arr.push(name)}) | |
Write(gsf2+'/aaa.txt',arr.sort().join('\r\n')) | |
shell.run('notepad '+gsf2+'/aaa.txt') | |
*/ | |
基準フォルダ = fs.GetParentFolderName(location.href.replace(/^file:/,'').replace(/^\/+([A-Z]:)/,'$1')).replace(/%20/g,' ') | |
var path=基準フォルダ+'/設定/viewエリア内の選択中エレメント向け機能' | |
var arr=getDirList(path), ops=selFun.options | |
for0L(arr, function(i, name){ ops[i] = new Option(name, path+'/'+name) }) | |
if(!fs.FolderExists(基準フォルダ+'/データ')){ | |
fs.CreateFolder(基準フォルダ+'/データ') | |
addデータdir('new name') | |
} | |
selDir更新() | |
selDir.onchange() | |
} | |
// 以下、基礎関数 | |
AXO = function(name){return new ActiveXObject(name)} | |
fs = AXO('Scripting.FileSystemObject') | |
shell = AXO('WScript.Shell') | |
gsf2 = fs.GetSpecialFolder(2) | |
Read = function(p){var o=fs.OpenTextFile(p), s=o.AtEndOfStream?'':o.ReadAll(); o.Close(); return s} | |
Write = function(path,v){with(fs.CreateTextFile(path)){Write(v);Close()}} | |
RAS = function(p){return Read(p).split('\r\n')} | |
for0L = function(arr,fun){for(var i=0,L=arr.length,res;i<L;i++){if(res=fun(i,arr[i])){return res}}} | |
forIn = function(obj,fun){var name,res; for(name in obj){if(res=fun(name, obj[name])){return res}}} | |
fun = function(path){return path.indexOf(' ')<0 ? path : ('"'+path+'"')} | |
selOps= function(sel){return sel.options[sel[sI]]} | |
getDirList = function(path, swFile){ | |
var pathTMP=gsf2+'/getDirList_'+(new Date()).getTime()+'.txt', arr | |
shell.Run('cmd /C dir /A'+(swFile?'-':'')+'D /B "'+path+'" > "'+pathTMP+'"' , 0 , true) | |
arr = fs.FileExists(pathTMP) ? RAS(pathTMP) : [] | |
arr.pop() | |
try{fs.DeleteFile(pathTMP)}catch(e){} | |
return arr | |
} | |
getFileList=function(path){return getDirList(path, true)} | |
getEBTN=function(elem, name){return elem.getElementsByTagName(name)} | |
iT='innerText', iH='innerHTML', PA='parentNode', FI='firstChild', CN='childNodes', NE='nextSibling', PR='previousSibling', sI='selectedIndex' | |
</script> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function(elem, td, path){ | |
td.innerHTML = '<span></span> <button>PA</button> <button>FI</button> <button>PR</button> <button>NE</button> <button>iT</button> <button>iH</button> <button>oH</button>' | |
var gEBTN=function(name){return td.getElementsByTagName(name)} | |
var span=gEBTN('span')[0] | |
var btns=gEBTN('button') | |
var func=function(elem){ | |
if(!elem){return alert('指定された関係のエレメントがありません')} | |
elem選択中 = elem | |
span.innerText = 'tagName:' + elem.tagName | |
} | |
func(elem選択中) | |
btns[0].onclick=function(){ func(elem選択中.parentNode) } | |
btns[1].onclick=function(){ func(elem選択中.firstChild) } | |
btns[2].onclick=function(){ func(elem選択中.previousSibling) } | |
btns[3].onclick=function(){ func(elem選択中. nextSibling) } | |
btns[4].onclick=function(){ confirm(elem選択中.innerText) } | |
btns[5].onclick=function(){ confirm(elem選択中.innerHTML) } | |
btns[6].onclick=function(){ confirm(elem選択中.outerHTML) } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function(elem, td, path){ | |
td.innerHTML = '<textarea class=max wrap=off style="height:100px;"></textarea>' | |
td.firstChild.value = elem.outerHTML | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function(elem, td, path){ | |
td.innerHTML = '<table class="bc w-max" border=1>'+ | |
'<tr><td width=1><span style="white-space:nowrap;">プロパティ名</span></td><td><input class=w-max></td></tr>'+ | |
'<tr><td>値</td><td><textarea class=max wrap=off style="height:100px;"></textarea></td></tr></table>' | |
var inp=getEBTN(td,'input')[0], ta=getEBTN(td,'textarea')[0] | |
var getP=function(elem, propStr){ | |
var arr=propStr.split('.'), obj=elem, name=arr.pop() | |
for0L(arr, function(i, key){ obj = obj[key] }) | |
return { | |
setP:function(v){ obj[name] = v }, | |
getP:function( ){ return obj[name] } | |
} | |
} | |
inp.onchange=function(){ if(inp.value){ ta.value = getP(elem, inp.value).getP() } } | |
ta .onchange=function(){ if(inp.value){ getP(elem, inp.value).setP( ta.value ) } } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function(elem, td, path){ | |
// elemはiframe内で最後にクリックされたエレメント, tdはこの機能のインターフェースを表示するためのエリア, pathはこのスクリプトファイルが入っているフォルダのPath | |
td[iH] = '<button>position:absoluteにする</button><button>position:relativeにする</button>' | |
td[FI].onclick=function(){ | |
elem.style.position = 'absolute' | |
elem.draggable = false | |
elem.onmousedown = function(){ | |
var win=elem.ownerDocument.parentWindow, e=win.event, x=e.x-elem.offsetLeft, y=e.y-elem.offsetTop | |
with(elem.ownerDocument.body){ | |
onmousemove = function(){ var e=win.event; with(elem.style){top=e.y-y; left=e.x-x} } | |
onmouseup = function(){ this.onmousemove = null } | |
} | |
} | |
} | |
td[CN][1].onclick=function(){ | |
elem.style.position = 'relative' | |
elem.onmousedown = null | |
} | |
} |
「設定/viewエリア内の選択中エレメント向け機能」フォルダ内にフォルダを追加すると

「選択中エレメント用機能:」のリストに表示されます。

上記機能はiframe内で最後にクリックした要素に対して動作します。
フォルダ内の「func.js」を編集すると動作内容を変更できます。
0 件のコメント:
コメントを投稿