DOMEditor.js
Summary
No overview generated for 'DOMEditor.js'
var BaseEditor = new function()
{
this.edit =
this.oninput =
this.submit =
this.cancel =
this.onclick =
this.nav_next =
this.nav_previous = function(){return null};
var _init = function(instance)
{
this.context_enter = null;
this.context_cur = null;
this.base_style =
{
'font-family': '',
'line-height': 0,
'font-size': 0
}
this.char_width = 0;
this.line_height = 0;
this.cssText = '';
this.textarea_container = null;
this.textarea = null;
this.host_element_border_padding_left = 0;
this.host_element_border_padding_top = 0;
this.getInputHandler = function()
{
return function(event)
{
instance.oninput(event);
}
}
}
this.textarea_container_name = "textarea-container";
this.get_base_style = function(ele)
{
var
style = getComputedStyle(ele, null),
props = ['font-family', 'line-height', 'font-size'],
prop = null,
i = 0,
span = document.createElement('test-element'),
cssText = 'display:block;position:absolute;left:-100px;top:0;white-space:pre;';
for( ; prop = props[i]; i++)
{
this.base_style[prop] = style.getPropertyValue(prop);
cssText += prop +':' + this.base_style[prop] + ';';
}
span.textContent = '1234567890';
document.documentElement.appendChild(span);
span.style.cssText = cssText;
this.char_width = span.offsetWidth / 10;
this.base_style['line-height'] = ( this.line_height = span.offsetHeight ) + 'px';
document.documentElement.removeChild(span);
this.host_element_border_padding_left =
parseInt(style.getPropertyValue('padding-left')) +
parseInt(style.getPropertyValue('border-left-width'));
this.host_element_border_padding_top =
parseInt(style.getPropertyValue('padding-top')) +
parseInt(style.getPropertyValue('border-top-width'));
cssText = '';
for( prop in this.base_style )
{
cssText += prop +':' + this.base_style[prop] + ';';
}
this.textarea_container = document.createElement(this.textarea_container_name);
this.textarea = this.textarea_container.
appendChild(document.createElement('textarea-inner-container')).
appendChild(document.createElement('textarea'));
this.textarea.style.cssText = cssText;
this.textarea.oninput = this.getInputHandler();
}
this.__is_active = function(){return false};
this.__defineGetter__("is_active", function(){return this.__is_active()});
this.base_init = function(instance)
{
_init.apply(instance, [instance]);
}
}
var DOMAttrAndTextEditor = function(nav_filters)
{
this.base_init(this);
this.type = "dom-attr-text-editor";
this.textarea_container_name = "textarea-container-inline";
this.context_enter =
{
type: '',
rt_id: '',
obj_id:'',
text: '',
key: '',
value: '',
has_value: false,
is_new: false
}
this.context_cur =
{
type: '',
rt_id: '',
obj_id:'',
text: '',
key: '',
value: '',
has_value: false,
is_new: false
}
var crlf_encode = function(str)
{
return str.replace(/\r\n/g, "\\n");
}
this.edit = function(event, ref_ele)
{
var
ele = ref_ele || event.target,
parent_parent = null,
enter_state =
{
type: '',
rt_id: '',
obj_id:'',
text: '',
key: '',
value: '',
has_value: false
},
prop = '';
if( !this.base_style['font-size'] )
{
this.get_base_style(ele);
}
if( this.textarea_container.parentElement )
{
opera.postError("this.textarea_container.parentElement is not null in submit");
}
switch( enter_state.type = ele.nodeName )
{
case "key":
{
parent_parent = ele.parentElement.parentElement;
enter_state.rt_id = parent_parent.parentElement.getAttribute('rt-id')
|| parent_parent.parentElement.parentElement.getAttribute('rt-id');
enter_state.obj_id = parent_parent.getAttribute('ref-id');
enter_state.key = ele.textContent;
enter_state.has_value = ele.nextElementSibling && ele.nextElementSibling.nodeName == "value";
enter_state.value = enter_state.has_value
&& ele.nextElementSibling.textContent.replace(/^"|"$/g, "");
break;
}
case "value":
{
parent_parent = ele.parentElement.parentElement;
enter_state.rt_id = parent_parent.parentElement.getAttribute('rt-id')
|| parent_parent.parentElement.parentElement.getAttribute('rt-id');
enter_state.obj_id = parent_parent.getAttribute('ref-id');
enter_state.key =
ele.previousElementSibling
&& ele.previousElementSibling.nodeName == "key"
&& ele.previousElementSibling.textContent
|| "";
enter_state.value = ele.textContent.replace(/^"|"$/g, "");
break;
}
case "text":
{
parent_parent = ele.parentElement;
enter_state.rt_id = parent_parent.parentElement.getAttribute('rt-id')
|| parent_parent.parentElement.parentElement.getAttribute('rt-id');
enter_state.obj_id = ele.getAttribute('ref-id');
enter_state.text = ele.textContent;
break;
}
}
this.max_width = parseInt( getComputedStyle(parent_parent, null).getPropertyValue('width'));
if( enter_state.type == "value" )
{
this.textarea.value = ele.textContent.replace(/^"|"$/g, "");
ele.textContent = '"';
ele.appendChild(this.textarea_container);
ele.appendChild(document.createTextNode('"'));
}
else
{
this.textarea.value = ele.textContent;
ele.textContent = "";
ele.appendChild(this.textarea_container);
}
this.set_textarea_dimensions();
this.context_enter = enter_state;
for( prop in enter_state )
{
this.context_cur[prop] = enter_state[prop];
}
if( event )
{
this.textarea.focus();
}
this.textarea.selectionStart = 0;
this.textarea.selectionEnd = this.textarea.value.length;
}
this.oninput = function(event)
{
var
script = "",
state = this.context_cur;
if( this.textarea_container.parentElement )
{
this.set_textarea_dimensions();
switch(state.type)
{
case "key":
{
state.key = this.textarea.value
if(state.value)
{
script = 'node.setAttribute("' + crlf_encode(state.key) + '","' +
crlf_encode(state.value) + '")';
services['ecmascript-debugger'].eval(0, state.rt_id, '', '', script, ["node", state.obj_id]);
}
break;
}
case "value":
{
script = 'node.setAttribute("' + crlf_encode(state.key) + '","' +
crlf_encode(( state.value = this.textarea.value )) + '")';
services['ecmascript-debugger'].eval(0, state.rt_id, '', '', script, ["node", state.obj_id]);
break;
}
case "text":
{
script = 'node.nodeValue = "' + crlf_encode( state.text = this.textarea.value ) + '"';
services['ecmascript-debugger'].eval(0, state.rt_id, '', '', script, ["node", state.obj_id]);
break;
}
}
}
}
this.submit = function(check_value)
{
var
script = "",
state = this.context_cur,
nav_target = this.textarea_container.parentElement,
cur = null;
if( nav_target )
{
switch(state.type)
{
case "key":
{
if(state.key && ( !check_value || state.value ) )
{
dom_data.update(state);
nav_target.textContent = state.key;
}
else
{
nav_target = this.remove_attribute();
}
break;
}
case "value":
{
if(state.key && state.value)
{
dom_data.update(state);
nav_target.textContent = '"' + state.value+ '"';
}
else
{
nav_target = this.remove_attribute();
}
break;
}
case "text":
{
dom_data.update(state);
nav_target.textContent = state.text;
break;
}
}
}
return nav_target;
}
this.cancel = function()
{
var
script = "",
state = this.context_enter,
nav_target = null;
if( this.textarea_container.parentElement )
{
if(this.context_cur.is_new)
{
}
else
{
nav_target = this.textarea_container.parentElement;
switch(state.type)
{
case "key":
{
script = 'node.setAttribute("' + crlf_encode(state.key) + '","' + crlf_encode(state.value) + '")';
services['ecmascript-debugger'].eval(0, state.rt_id, '', '', script, ["node", state.obj_id]);
nav_target.textContent = state.key;
break;
}
case "value":
{
script = 'node.setAttribute("' + crlf_encode(state.key) + '","' + crlf_encode(state.value) + '")';
services['ecmascript-debugger'].eval(0, state.rt_id, '', '', script, ["node", state.obj_id]);
nav_target.textContent = '"' + state.value + '"';
break;
}
case "text":
{
script = 'node.nodeValue = "' + crlf_ecode(state.text) + '"';
services['ecmascript-debugger'].eval(0, state.rt_id, '', '', script, ["node", state.obj_id]);
nav_target.textContent = state.text;
break;
}
}
}
}
return nav_target;
}
this.nav_previous = function(event, action_id)
{
var
state = this.context_cur,
nav_target = this.textarea_container.parentElement,
nav_target_parent = nav_target.parentElement,
next = nav_target.previousElementSibling,
next_next = next && next.previousElementSibling,
submit_success = this.submit(true),
container = nav_target_parent.parentElement.parentElement;
switch(state.type)
{
case "key":
case "value":
{
( next && ( submit_success || next.parentElement ) )
|| ( next = next_next )
|| ( next = nav_target_parent.getPreviousWithFilter(container, nav_filters.attr_text) );
break;
}
case "text":
{
next = nav_target.getPreviousWithFilter(container, nav_filters.attr_text);
}
}
if( next )
{
if( next.nodeName == 'node' )
{
next.firstChild.splitText(next.firstChild.nodeValue.length - 1);
next = this.create_new_edit(next.firstChild);
}
else if( next.parentElement != nav_target_parent
&& next.nodeName == 'value'
&& next == next.parentElement.lastElementChild )
{
next = this.create_new_edit(next);
}
if(next)
{
this.edit({}, next);
}
}
return next;
}
this.nav_next = function(event, action_id)
{
var
state = this.context_cur,
nav_target = this.textarea_container.parentElement,
nav_target_parent = nav_target.parentElement,
next = nav_target.nextElementSibling,
next_next = next && next.nextElementSibling,
submit_success = this.submit(),
container = nav_target_parent.parentElement.parentElement;
switch(state.type)
{
case "key":
case "value":
{
( submit_success && ( next || ( next = this.create_new_edit(submit_success) ) ) )
|| ( next && next.parentElement ) || ( next = next_next )
|| ( next = nav_target_parent.getNextWithFilter(container, nav_filters.attr_text) );
break;
}
case "text":
{
next = nav_target.getNextWithFilter(container, nav_filters.attr_text);
}
}
if(next)
{
if( next.nodeName == 'node' )
{
next.firstChild.splitText(next.firstChild.nodeValue.length - 1);
next = this.create_new_edit(next.firstChild);
}
this.edit({}, next);
}
return next;
}
this.set_textarea_dimensions = function()
{
var
max_content_length =
Math.max.apply(null, this.textarea.value.split('\r\n').map(function(item){return item.length})),
width = this.char_width * ( max_content_length + 1 );
this.textarea.style.width = ( width < this.max_width ? width : this.max_width )+ "px";
this.textarea.style.height = this.textarea.scrollHeight + 'px';
}
this.create_new_edit = function(ref_node)
{
var
name = ref_node.nodeName,
parent = ref_node.parentNode,
cur = parent.insertBefore
(
document.createTextNode( name == 'key' && '=' || ' ' ), ref_node.nextSibling
);
return parent.insertBefore
(
document.createElement( name == 'key' && 'value' || 'key' ), cur.nextSibling
);
}
this.remove_attribute = function()
{
var
script = 'node.removeAttribute("' + this.context_enter.key + '")',
state = this.context_cur,
nav_target = this.textarea_container.parentElement,
nav_target_parent = nav_target.parentElement,
pair_target = nav_target.nodeName == 'key' && 'next' || 'previous',
check = nav_target.nodeName == 'key' && 'value' || 'key';
services['ecmascript-debugger'].eval(0, state.rt_id, '', '', script, ["node", state.obj_id]);
state.key = this.context_enter.key;
delete state.value;
dom_data.update(state);
nav_target.textContent = "";
cur = nav_target[pair_target + "ElementSibling"];
if( cur && cur.nodeName == check )
{
nav_target_parent.removeChild(cur);
}
cur = nav_target[pair_target + "Sibling"];
if( cur && /=/.test(cur.nodeValue) )
{
nav_target_parent.removeChild(cur);
}
cur = nav_target.previousSibling;
if( cur && / +/.test(cur.nodeValue) )
{
if(/^ +$/.test(cur.nodeValue))
{
nav_target_parent.removeChild(cur);
}
else
{
cur.nodeValue = cur.nodeValue.replace(/ +$/, '');
}
}
nav_target_parent.removeChild(nav_target);
nav_target_parent.normalize();
return null;
}
this.onclick = function(event)
{
event.preventDefault();
event.stopPropagation();
if(!this.textarea_container.contains(event.target))
{
this.submit(true);
return false;
}
return true;
}
}
DOMAttrAndTextEditor.prototype = BaseEditor;
Documentation generated by
JSDoc on Thu Oct 30 18:01:10 2008