I like Dojo richtext editor (
dojo.widget.Editor2
) mainly because of its "grow-as-you-write" feature. I believe the scrollbar in the browser window is enough for the user. In addition, it doesn't limit what HTML element we can make editable. Furthermore, while the javascript API to the editor has not completely matured yet as compared to, say, TinyMCE API, it was not too bad. Dojo seems to allow for more flexibility on what we can do to its widgets through javascript.For what I am trying to do, I have a button that is used to turn an innocuous HTML element into becoming editable. Example HTML fragment is given below:
<div style="float:left">
<button type="button" item="h1"
onclick="doEdit(this)">edit</button>
</div>
<div id="h1"><h1>Inlinely editable, yum!</h1></div>
<div style="float:left">
<button type="button" item="p1"
onclick="doEdit(this)">edit</button>
</div>
<div id="p1"><p>This is also editable</p></div>
<div style="float:left">
<button type="button" item="p2"
onclick="doEdit(this)">edit</button>
</div>
<div id="p2"><p>And this too.</p></div>
<div style="float:left">
<button type="button" item="p3"
onclick="doEdit(this)">edit</button>
</div>
<div id="p3"><p>And this too, yeah.</p></div>
Each button has a custom
item
attribute to point to the element to be edited (the <div>
next to it). When the button is clicked the doEdit
is called, its item
attribute is retrieved and the element it refers to is converted into a richtext editor. Note that if the editor has already been instantiated before, it is kept in variable last
. But first, we check whether we need to save the content from the last editor:
dojo.require("dojo.widget.Editor2");
var last;
function doEdit(button) {
var save, lastbutton;
if (last) {
if (changed(last)) save = confirm("Save?");
last.close(save);
if (save) {
// so call server to update. Use last.getEditorContent().
}
lastbutton = last.button;
lastbutton.innerHTML = "edit";
last.destroy();
last = null;
}
Since the Dojo richtext editor does not have a method to check whether its content has changed, a separate
changed
function has been written for that. If the content has changed, the user is asked whether or not she wants to save it. Ideally, the server will be called using some AJAX RPC to save it. Finally, the editor is transformed back to normal HTML element by closing and destroying it.Now if the button is the same button used to create the editor, we are done. If not, we need to create the editor:
if (lastbutton != button) {
var id = button.getAttribute("item");
var t = document.getElementById(id);
last = dojo.widget.createWidget(
"Editor2",
{
shareToolbar: false,
toolbarAlwaysVisible: false,
focusOnLoad: true,
closeOnSave: true
}, t);
last.button = button;
button.innerHTML = "close";
dojo.event.connect(last, "onLoad", onEdLoad);
}
}
Note that a custom property (
button
) has been added to the editor object to remember which button used to create it. And finally the onLoad
event for the editor is connected to the onEdLoad
. This is important if we have some initialization we need to do on the editor once it has fully been created. The editor seems to be created asynchronously.That is it. Below is the complete HTML file. Put it in your Dojo installation directory (where
dojo.js
) is:
<html>
<head>
<title>Dojo is cool</title>
<script type="text/javascript" src="dojo.js"></script>
<script type="text/javascript">
dojo.require("dojo.widget.Editor2");
var last;
function doEdit(button) {
var save, lastbutton;
if (last) {
if (changed(last)) save = confirm("Save?");
last.close(save);
if (save) {
// so call server to update. Use
// last.getEditorContent().
}
lastbutton = last.button;
lastbutton.innerHTML = "edit";
last.destroy();
last = null;
}
if (lastbutton != button) {
var id = button.getAttribute("item");
var t = document.getElementById(id);
last = dojo.widget.createWidget(
"Editor2",
{
shareToolbar: false,
toolbarAlwaysVisible: false,
focusOnLoad: true,
closeOnSave: true
}, t);
last.button = button;
button.innerHTML = "close";
dojo.event.connect(last, "onLoad", onEdLoad);
}
}
function onEdLoad() {
// now editor is completely loaded. Do whatever
// we want when editor is loaded here.
}
function changed(ed) {
return ed.editNode.innerHTML
!= last.savedContent.innerHTML;
}
</script>
</head>
<body>
<div style="float:left">
<button type="button" item="h1"
onclick="doEdit(this)">edit</button>
</div>
<div id="h1">
<h1>Inlinely editable, yum!</h1>
</div>
<div style="float:left">
<button type="button" item="p1"
onclick="doEdit(this)">edit</button>
</div>
<div id="p1">
<p>This is also editable</p>
</div>
<div style="float:left">
<button type="button" item="p2"
onclick="doEdit(this)">edit</button>
</div>
<div id="p2"><p>And this too.</p></div>
<div style="float:left">
<button type="button" item="p3"
onclick="doEdit(this)">edit</button>
</div>
<div id="p3"><p>And this too, yeah.</p></div>
</body>
</html>