mirror of
https://github.com/silverstripe/silverstripe-userforms.git
synced 2024-10-22 17:05:42 +02:00
556 lines
15 KiB
JavaScript
Executable File
556 lines
15 KiB
JavaScript
Executable File
FieldEditor = Class.create();
|
|
FieldEditor.applyTo('div.FieldEditor');
|
|
FieldEditor.prototype = {
|
|
initialize: function() {
|
|
FieldEditorField.applyToChildren(this, 'div.EditableFormField');
|
|
FieldEditorHeadingField.applyToChildren(this, 'div.EditableFormHeading');
|
|
FieldEditorRadioField.applyToChildren(this, 'div.EditableRadioField');
|
|
FieldEditorCheckboxGroupField.applyToChildren(this, 'div.EditableCheckboxGroupField');
|
|
FieldEditorDropdown.applyToChildren(this, 'div.EditableDropdown');
|
|
FieldEditorEmailField.applyToChildren(this, 'div.EditableEmailField');
|
|
FieldEditorTextField.applyToChildren(this, 'div.EditableTextField');
|
|
|
|
if( !Element.hasClassName( this, 'readonly' ) ) {
|
|
Sortable.create('Fields_fields', {tag: 'div', handle:'handle'});
|
|
$('Form_EditForm').observeMethod('BeforeSave', this.beforeSave.bind(this));
|
|
}
|
|
|
|
},
|
|
sortFields: function() {
|
|
var fieldEditor = $('Fields_fields');
|
|
|
|
if(fieldEditor) {
|
|
|
|
var i, j, div, field, editables = fieldEditor.childNodes;
|
|
|
|
for( i = 0; div = editables[i]; i++ ) {
|
|
var fields = div.getElementsByTagName('input');
|
|
/*fields[fields.length - 1].value = i;*/
|
|
for( j = 0; field = fields.item(j); j++ ) {
|
|
if( field.name == div.id + '[Sort]' ) {
|
|
field.value = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
beforeSave: function() {
|
|
var fieldEditor = $('Fields_fields');
|
|
|
|
if(fieldEditor) {
|
|
this.sortFields();
|
|
|
|
var children = $('Fields_fields').childNodes;
|
|
|
|
for( var i = 0; i < children.length; ++i ) {
|
|
var child = children[i];
|
|
|
|
if( child.beforeSave )
|
|
child.beforeSave();
|
|
}
|
|
}
|
|
},
|
|
deleteOption: function( optionToRemove ) {
|
|
this.getElementsByTagName('div')[0].removeChild( optionToRemove );
|
|
}
|
|
}
|
|
|
|
FieldEditorField = Class.create();
|
|
|
|
FieldEditorField.prototype = {
|
|
initialize: function() {
|
|
var fieldInfoDiv = this.findDescendant( 'div', 'FieldInfo' );
|
|
|
|
this.titleField = this.findDescendant( 'input', 'text', element );
|
|
|
|
this.titleField.onchange = this.changeTitle.bind(this);
|
|
this.titleField.onblur = this.changeTitle.bind(this);
|
|
this.titleField.onfocus = this.focusTitle.bind(this);
|
|
|
|
this.titleField.onchange();
|
|
|
|
var links = fieldInfoDiv.getElementsByTagName('a');
|
|
this.toggler = this.findDescendant( 'a', 'toggler' );
|
|
this.fieldInfo = this.getElementsByTagName('div')[0];
|
|
|
|
|
|
this.toggler.onclick = this.toggle.bind(this);
|
|
this.extraOptions = this.getExtraOptions();
|
|
this.visible = false;
|
|
this.deleteButton = this.findDescendant('a', 'delete');
|
|
|
|
//this.style.height = "auto";
|
|
|
|
if( this.deleteButton )
|
|
this.deleteButton.onclick = this.confirmDelete.bind(this);
|
|
},
|
|
toggle: function() {
|
|
// this.parentNode.autoSize();
|
|
|
|
if( this.visible )
|
|
this.hide();
|
|
else
|
|
this.show();
|
|
|
|
this.fieldInfo.style.display = 'block';
|
|
|
|
return false;
|
|
},
|
|
show: function() {
|
|
/*this.style.height = "";
|
|
this.style.overflow = "";*/
|
|
|
|
if( this.selectedOption )
|
|
this.selectedOption.checked = true;
|
|
|
|
this.visible = true;
|
|
// var extraOptions = this.getExtraOptions();
|
|
// if( this.extraOptions )
|
|
this.extraOptions.style.display = 'block';
|
|
},
|
|
hide: function() {
|
|
|
|
this.visible = false;
|
|
// var extraOptions = this.getExtraOptions();
|
|
//if( this.extraOptions )
|
|
this.extraOptions.style.display = 'none';
|
|
},
|
|
getExtraOptions: function() {
|
|
var extraOptions = this.findDescendant('div', 'ExtraOptions');
|
|
|
|
if( extraOptions.parentNode != this )
|
|
alert("Found extra options but not this parent (" + this.id + ")");
|
|
|
|
return extraOptions;
|
|
},
|
|
confirmDelete: function() {
|
|
if( confirm( 'Are you sure you want to delete this field from the form?' ) )
|
|
this.parentNode.parentNode.deleteOption( this );
|
|
|
|
return false;
|
|
},
|
|
findDescendant: function( tag, clsName, element ) {
|
|
|
|
if( !element )
|
|
element = this;
|
|
|
|
var descendants = element.getElementsByTagName(tag);
|
|
|
|
for( var i = 0; i < descendants.length; i++ ) {
|
|
var el = descendants[i];
|
|
// alert(el.tagName + ' ' + el.className);
|
|
|
|
if( tag.toUpperCase() == el.tagName && el.className.indexOf( clsName ) != -1 )
|
|
return el;
|
|
}
|
|
|
|
return null;
|
|
},
|
|
focusTitle: function() {
|
|
if( this.titleField && this.titleField.value == this.titleField.title )
|
|
this.titleField.value = '';
|
|
},
|
|
changeTitle: function() {
|
|
if( this.titleField && this.titleField.value == '' )
|
|
this.titleField.value = this.titleField.title;
|
|
}
|
|
}
|
|
|
|
FieldEditorHeadingField = Class.extend('FieldEditorField');
|
|
|
|
FieldEditorHeadingField.prototype = {
|
|
initialize: function() {
|
|
this.FieldEditorField.initialize();
|
|
}
|
|
}
|
|
|
|
FieldEditorEmailField = Class.extend('FieldEditorField');
|
|
|
|
|
|
FieldEditorEmailField.prototype = {
|
|
initialize: function() {
|
|
this.extraOptions = this.getExtraOptions();
|
|
this.defaultText = this.getDefaultText();
|
|
|
|
this.FieldEditorField.initialize();
|
|
},
|
|
getDefaultText: function() {
|
|
var defaultField = this.getDefaultField();
|
|
if(defaultField) {
|
|
var j, nestedChild, nestedChildren = defaultField.childNodes;
|
|
for( j=0; nestedChild = nestedChildren[j]; j++) {
|
|
if (nestedChild.className == 'defaultText' )
|
|
{
|
|
return nestedChild;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
getDefaultField: function() {
|
|
|
|
var i, child, children = this.getElementsByTagName('div');
|
|
for( i = 0; child = children[i]; i++){
|
|
if(child.className == 'FieldDefault'){
|
|
return child;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
FieldEditorTextField = Class.extend('FieldEditorField');
|
|
FieldEditorTextField.prototype = {
|
|
initialize: function() {
|
|
this.FieldEditorField.initialize();
|
|
this.defaultText = this.getDefaultText();
|
|
this.numRows = this.extraOptions.getElementsByTagName('input')[3];
|
|
if(this.numRows) {
|
|
this.numRows.onchange = this.changedRows.bind(this);
|
|
this.oldNumRows = eval(this.numRows.value);
|
|
}
|
|
|
|
},
|
|
changedRows: function() {
|
|
var newNumRows = eval(this.numRows.value);
|
|
|
|
// TODO Show that the field is actually longer than 5 rows
|
|
if( newNumRows > 5 )
|
|
newNumRows == 5;
|
|
|
|
if( this.oldNumRows == newNumRows )
|
|
return;
|
|
|
|
if( newNumRows < 1 )
|
|
newNumRows = 1;
|
|
|
|
// resize/convert the textarea
|
|
var newType = '';
|
|
|
|
if( newNumRows == 1 )
|
|
newType = 'input';
|
|
else
|
|
newType = 'textarea'
|
|
|
|
var newDefaultText = document.createElement(newType);
|
|
newDefaultText.className = this.defaultText.className;
|
|
newDefaultText.value = this.defaultText.value;
|
|
newDefaultText.id = this.defaultText.id;
|
|
newDefaultText.name = this.defaultText.name;
|
|
|
|
if( newDefaultText.rows )
|
|
newDefaultText.rows = newNumRows;
|
|
|
|
//Does not work any more
|
|
//this.replaceChild( newDefaultText, this.defaultText );
|
|
|
|
//instead, using the following code
|
|
var defaultField = this.getDefaultField();
|
|
defaultField.replaceChild(newDefaultText, this.defaultText);
|
|
|
|
//keep other codes.
|
|
this.defaultText = newDefaultText;
|
|
this.oldNumRows = newNumRows;
|
|
},
|
|
getDefaultText: function() {
|
|
var defaultField = this.getDefaultField();
|
|
|
|
if(defaultField) {
|
|
var j, nestedChild, nestedChildren = defaultField.childNodes;
|
|
for( j=0; nestedChild = nestedChildren[j]; j++) {
|
|
|
|
if (nestedChild.className == 'defaultText' )
|
|
{
|
|
return nestedChild;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
getDefaultField: function() {
|
|
var i, child, children = this.getElementsByTagName('div');
|
|
for( i = 0; child = children[i]; i++){
|
|
if(child.className == 'FieldDefault'){
|
|
return child.getElementsByTagName('div')[0];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This should extend FieldEditorField
|
|
*/
|
|
FieldEditorRadioField = Class.extend('FieldEditorField');
|
|
|
|
FieldEditorRadioField.prototype = {
|
|
initialize: function() {
|
|
this.FieldEditorField.initialize();
|
|
|
|
this.hiddenFields = this.findDescendant( 'div', 'hidden' );
|
|
|
|
var dropdownBox = this.findDescendant( 'div', 'EditableDropdownBox' );
|
|
|
|
this.optionList = dropdownBox.getElementsByTagName('ul')[0];
|
|
var options = this.optionList.getElementsByTagName('li');
|
|
|
|
if( options && options.length > 0 ) {
|
|
this.addOptionField = options[options.length - 1];
|
|
|
|
if( typeof this.addOptionField != 'undefined' && this.addOptionField.className != "AddDropdownOption" )
|
|
this.addOptionField = null;
|
|
|
|
// bind each option's delete link
|
|
for( var i = 0; i < options.length - 1; i++ ) {
|
|
var option = options[i];
|
|
|
|
var links = option.getElementsByTagName('a');
|
|
|
|
links[0].onclick = this.removeOption.bindAsEventListener(this);
|
|
}
|
|
}
|
|
|
|
// Bind method to add option at the bottom of the list
|
|
if( this.addOptionField ) {
|
|
this.addOptionLink = this.addOptionField.getElementsByTagName('a')[0];
|
|
this.addOptionTitle = this.addOptionField.getElementsByTagName('input')[0];
|
|
this.addOptionLink.onclick = this.addOption.bind(this);
|
|
}
|
|
|
|
if( !Element.hasClassName( $('Fields'), 'readonly' ) ) {
|
|
Sortable.create(this.optionList.id,{handle:'handle',tag:'li',only:'EditableFormFieldOption'});
|
|
}
|
|
this.FieldEditorField.initialize();
|
|
|
|
// find the Delete field
|
|
var hiddenFields = this.getElementsByTagName('input');
|
|
|
|
for( var i = 0; i < hiddenFields.length; i++ ) {
|
|
var field = hiddenFields[i];
|
|
if( field.name.indexOf('[Deleted\]' ) != -1 )
|
|
this.deletedOptions = field;
|
|
}
|
|
|
|
this.selectedOption = null;
|
|
|
|
$('Form_EditForm').observeMethod('BeforeSave', this.beforeSave.bind(this));
|
|
},
|
|
firstElement: function( el ) {
|
|
|
|
var node = el.firstChild;
|
|
|
|
while( !node.tagName )
|
|
node = node.nextSibling;
|
|
|
|
return node;
|
|
},
|
|
createOption: function( title, id, selected ) {
|
|
var templateNode = this.firstElement( this.hiddenFields );
|
|
var newOptionNode = templateNode.cloneNode( true );
|
|
|
|
var newNodeChildren = newOptionNode.childNodes;
|
|
|
|
for( var i = 0; i < newNodeChildren.length; i++ ) {
|
|
|
|
var child = newNodeChildren[i];
|
|
|
|
if( !child.tagName )
|
|
continue;
|
|
|
|
// input elements
|
|
if( child.tagName.toLowerCase() == 'input' ) {
|
|
|
|
if( child.className == 'text' ) {
|
|
child.name = this.id + '[' + id + '][Title]';
|
|
child.value = title;
|
|
} else if( child.type == 'checkbox' )
|
|
child.name = this.id + '[' + id + '][Default]';
|
|
else if( child.type == 'radio' ) {
|
|
child.value = id;
|
|
} else if( child.type == 'hidden' ) {
|
|
child.name = this.id + '[' + id + '][Sort]';
|
|
child.value = -1;
|
|
}
|
|
} else if ( child.tagName.toLowerCase() == 'a' ) {
|
|
child.onclick = this.removeOption.bindAsEventListener(this);
|
|
}
|
|
}
|
|
|
|
this.optionList.insertBefore( newOptionNode, this.addOptionField );
|
|
},
|
|
removeOption: function( event ) {
|
|
|
|
var target = event.srcElement;
|
|
|
|
if( !target )
|
|
target = event.target;
|
|
|
|
var entry = target.parentNode.parentNode;
|
|
var id = entry.id;
|
|
|
|
if( !id.match( '/^[0-9]+$/' ) ) {
|
|
if( this.deletedOptions.value )
|
|
this.deletedOptions.value += ',';
|
|
|
|
this.deletedOptions.value += id;
|
|
}
|
|
|
|
// remove the child from the options
|
|
this.optionList.removeChild( entry );
|
|
|
|
// remove the child from the dropdown
|
|
/*for( var i = 0; i < this.dropdown.length; i++ ) {
|
|
if( this.dropdown.options[i].text == title ) {
|
|
this.dropdown.remove(i);
|
|
return false;
|
|
}
|
|
}*/
|
|
|
|
if( !Element.hasClassName( $('Fields'), 'readonly' ) )
|
|
Sortable.create(this.optionList.id,{handle:'handle',tag:'li',only:'EditableFormFieldOption'});
|
|
|
|
// return false so it doesn't follow the link
|
|
return false;
|
|
},
|
|
addOption: function() {
|
|
if( this.addOptionTitle.value.length == 0 )
|
|
return false;
|
|
|
|
// The IDs come from the database and are the ID of the actual record
|
|
// client-side, we will need a unique identifier that can be differentiated
|
|
// from the actual database IDs, unless we just drop all records and
|
|
// recreate them
|
|
var newID = '_' + this.optionList.childNodes.length;
|
|
|
|
this.createOption( this.addOptionTitle.value, newID, this.optionList.childNodes.length == 0 );
|
|
|
|
if( !Element.hasClassName( $('Fields'), 'readonly' ) )
|
|
Sortable.create(this.optionList.id,{handle:'handle',tag:'li',only:'EditableFormFieldOption'});
|
|
|
|
this.addOptionTitle.value = '';
|
|
|
|
return false;
|
|
},
|
|
beforeSave: function() {
|
|
this.sortOptions();
|
|
},
|
|
sortOptions: function() {
|
|
var inputTags = this.optionList.getElementsByTagName('input');
|
|
|
|
var i,item,sort=0;
|
|
for(i=0;item=inputTags[i];i++) {
|
|
if(item.name.match(/\[Sort\]$/) ) {
|
|
item.value = sort++;
|
|
}
|
|
}
|
|
},
|
|
selectOption: function(newOption) {
|
|
|
|
if( this.selectedOption )
|
|
this.selectedOption.checked = false;
|
|
|
|
newOption.checked = true;
|
|
this.selectedOption = newOption;
|
|
},
|
|
selectOptionEvent: function(event) {
|
|
if(event.srcElement)
|
|
this.selectOption(event.srcElement);
|
|
else
|
|
this.selectOption(event.target);
|
|
},
|
|
updateOption: function( prefix, tempID, newID, newSort ) {
|
|
var options = this.optionList.childNodes;
|
|
|
|
for( var i = 0; i < options.length; i++ ) {
|
|
var option = options[i];
|
|
|
|
var fields = option.getElementsByTagName('input');
|
|
|
|
for( var j = 0; j < fields.length; j++ ) {
|
|
var field = fields[j];
|
|
|
|
var oldPrefix = prefix + '[' + tempID + ']';
|
|
var newPrefix = prefix + '[' + newID + ']';
|
|
|
|
if( field.name.indexOf( oldPrefix ) == 0 ) {
|
|
|
|
if( field.name.match( /\[Sort\]$/ ) )
|
|
field.value = newSort;
|
|
|
|
// rename the field
|
|
field.name = newPrefix + field.name.substring( oldPrefix.length );
|
|
|
|
} else if( field.name == prefix + '[Default]' ) {
|
|
field.value = newID;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FieldEditorCheckboxGroupField = Class.extend('FieldEditorRadioField');
|
|
|
|
FieldEditorDropdown = Class.extend('FieldEditorRadioField');
|
|
|
|
Behaviour.register(
|
|
{
|
|
'div.FieldEditor ul.Menu li a': {
|
|
|
|
|
|
urlForFieldMethod: function(methodName) {
|
|
return this.ownerForm().action + '/field/Fields/' + methodName + '?NewID=' + this.numNewFields;
|
|
},
|
|
ownerForm: function() {
|
|
var f = this.parentNode;
|
|
while(f && f.tagName.toLowerCase() != 'form') f = f.parentNode;
|
|
return f;
|
|
},
|
|
|
|
onclick: function() {
|
|
// get the ID of the field editor here
|
|
|
|
if( Element.hasClassName( $('Fields'), 'readonly' ) )
|
|
return false;
|
|
|
|
action = this.urlForFieldMethod("addfield") + "&Type=" + this.id + ($('SecurityID') ? '&SecurityID=' + $('SecurityID').value : '');;
|
|
|
|
statusMessage('Adding new field' );
|
|
|
|
new Ajax.Request(action, {
|
|
method: 'get',
|
|
onFailure: reportError,
|
|
onSuccess: this.appendNewField.bind(this)
|
|
});
|
|
|
|
return false;
|
|
},
|
|
|
|
appendNewField: function(response) {
|
|
this.numNewFields++;
|
|
|
|
var el = document.createElement('div');
|
|
el.innerHTML = response.responseText;
|
|
|
|
var i=0;
|
|
while(!el.childNodes[i].tagName) i++;
|
|
var newField = el.childNodes[i];
|
|
$('Fields_fields').appendChild(newField);
|
|
|
|
// Behaviour.debug();
|
|
if(newField) {
|
|
Behaviour.apply(newField,true);
|
|
FieldEditor.applyTo('div.FieldEditor');
|
|
}
|
|
|
|
// do we want to make sorting explicit?
|
|
Sortable.create('Fields_fields', {tag: 'div', handle:'handle'});
|
|
|
|
statusMessage('Added new field','good');
|
|
}
|
|
}
|
|
}
|
|
);
|
|
|
|
function reportError(request){
|
|
// More complex error for developers
|
|
statusMessage(request.responseText,'bad');
|
|
|
|
}
|