Skip to content

Instantly share code, notes, and snippets.

@jdorrance
Created October 22, 2013 15:20
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jdorrance/7102579 to your computer and use it in GitHub Desktop.
Save jdorrance/7102579 to your computer and use it in GitHub Desktop.
/**
* The <code>CQ.form.MultiFieldMultiField</code> class represents an editable list
* of form fields for editing multi value properties.
*
* @class CQ.form.MultiFieldMultiField
* @extends CQ.form.CompositeField
*/
CQ.form.MultiFieldMultiField = CQ.Ext.extend(CQ.form.CompositeField, {
/**
* @cfg {Object} fieldConfig
* The configuration options for the fields (optional).
*/
fieldConfig: null,
/**
* @cfg {Object} globalConfig
* The configuration options for the fields, to create a new field for the form.
*/
globalConfig: null,
/**
* Creates a new <code>CQ.form.MultiFieldMultiField</code>.
* @constructor
* @param {Object} config The config object
*/
constructor: function(config) {
var list = this;
if (!config.fieldConfig) {
config.fieldConfig = {};
}
if (!config.fieldConfig.xtype) {
config.fieldConfig.xtype = "textfield";
}
config.fieldConfig.name = config.name;
this.fieldConfig = config.fieldConfig;
var items = new Array();
if(config.readOnly) {
//if component is defined as readOnly, apply this to all items
config.fieldConfig.readOnly = true;
} else {
items.push({
"xtype":"button",
"cls": "cq-multifield-btn",
"text":"+",
"handler":function() {
list.addItem();
}
});
}
items.push({
"xtype":"hidden",
"name":config.name + CQ.Sling.DELETE_SUFFIX
});
config = CQ.Util.applyDefaults(config, {
"defaults":{
"xtype":"multifieldmultifielditem",
"name":config.name,
"fieldConfig":config.fieldConfig
},
"items":[
{
"xtype":"panel",
"border":false,
"bodyStyle":"padding:4px",
"items":items
}
]
});
CQ.form.MultiFieldMultiField.superclass.constructor.call(this,config);
if (this.defaults.fieldConfig.regex) {
// somehow regex get broken in this.defaults, so fix it
this.defaults.fieldConfig.regex = config.fieldConfig.regex;
}
this.addEvents(
/**
* @event change
* Fires when the value is changed.
* @param {CQ.form.MultiFieldMultiFieldNodes} this
* @param {Mixed} newValue The new value
* @param {Mixed} oldValue The original value
*/
"change"
);
this.findParentByType("panel").addListener("show", function() {
var tmp = this.findByType("multifieldmultifield");
var multifield = null;
if ( tmp.length > 0 ) multifield = tmp[0];
if (multifield != null) {
multifield.doLayout();
var itemsTmp = multifield.findByType("multifieldmultifielditem");
for ( var i = 0; i < itemsTmp.length; i ++ ) {
var item = itemsTmp[i];
if(item.fields) {
for (var j=0; j<item.fields.length; j++) {
if (item.fields[j]) {
if (item.fields[j].isXType("trigger")) {
if (item.fields[j].getWidth() > 15) {
item.fields[j].setWidth(item.fields[j].getWidth());
} else {
//arbitrary width value
item.fields[j].setWidth(134);
}
item.fields[j].wrap.setWidth(item.fields[j].getWidth()+"px");
}
}
}
}
}
}
/**/
});
},
/**
* Adds a new field to the widget.
* @param value The value of the field
*/
addItem: function(value) {
var index = this.items.getCount()-1;
var item = this.insert(index, {"nodeIndex": index});
this.findParentByType("form").getForm().add(item);
this.doLayout();
if (value) {
item.setValue(value);
}
},
/**
* Returns the data value.
* @return {String[]} value The field value
*/
getValue: function() {
var value = new Array();
this.items.each(function(item, index/*, length*/) {
if (item instanceof CQ.form.MultiFieldMultiField.Item) {
value[index] = item.getValue();
index++;
}
}, this);
return value;
},
/**
* Sets a data value into the field and validates it.
* @param {Mixed} value The value to set
*/
setValue: function(value) {
this.fireEvent("change", this, value, this.getValue());
var oldItems = this.items;
oldItems.each(function(item/*, index, length*/) {
if (item instanceof CQ.form.MultiFieldMultiField.Item) {
this.remove(item, true);
this.findParentByType("form").getForm().remove(item);
}
}, this);
this.doLayout();
if ((value != null) && (value != "")) {
if (value instanceof Array || CQ.Ext.isArray(value)) {
for (var i = 0; i < value.length; i++) {
var storedItem = value[i];
var valueString = null;
for (var key=0; key < this.fieldConfig.length;key++) {
if ( (this.fieldConfig[key]) && (this.fieldConfig[key].name) ) {
var fieldName = this.fieldConfig[key].name;
if (fieldName.indexOf("/") > -1) {
fieldName = fieldName.substring(fieldName.lastIndexOf("/")+1);
}
if (storedItem[fieldName]) {
if (valueString == null) {
valueString = storedItem[fieldName];
} else {
valueString = valueString + "|" + storedItem[fieldName];
}
} else {
if (valueString == null) {
valueString = "";
} else {
valueString = valueString + "|";
}
}
}
}
this.addItem(valueString);
}
} else {
this.addItem(value);
}
}
},
/**
/* ValidateValue function
/*
/* This validateValue enforces user to click on + initially when content is being first created.
/*
/* How to add validation: Add allowBlank="{Boolean}false" on the same level where
/* xtype="multifieldmultifield" is defined in dialog.xml
/*
/* Note: You still have to put allowBlank="{Boolean}false" on the fields under
/* multifield where you want to strictly enforce editors to provide values. If not provided
/* than users will click on + and this validation will skip.
/* EXAMPLE to add allowBlank on multifieldmultifield:
/*
/* <links
/* jcr:primaryType="cq:Widget"
/* fieldLabel="Links"
/* name="./links"
/* allowBlank="{Boolean}false"
/* xtype="multifieldmultifield">
/* <fieldConfig jcr:primaryType="cq:WidgetCollection">
/* <field1
/* jcr:primaryType="cq:Widget"
/* fieldLabel="Link Title"
/* name="linkTitle"
/* xtype="textfield"
/* allowBlank="{Boolean}false"
/* emptyText="Link Title"/>
/* </field1>
/* </fieldConfig>
/* </links>
/*
/*
*/
validateValue: function(value) {
if(this.allowBlank){
this.clearInvalid();
return true;
}else{
if(this.items.items.length > 1){
this.clearInvalid();
return true;
}
else{
this.markInvalid(this.blankText);
return false;
}
}
return true;
},
processRecord: function(record, path) {
var rows = new Array();
var index = 0;
var nodeName = this.getName().replace("./", "");
var node = record.get(nodeName);
for (var key in node) {
if (key != 'jcr:primaryType') {
//the nodes are saved in no particular order, so using the key (name) of the node
//to add to the right index of the array so they populate the form correctly
//the order can be maintained by adding isUpload ="true" to the dialog config
var nodePath = nodeName + "/" + key;
rows[key] = record.get(nodePath);
index++;
}
}
this.setValue(rows);
}
});
CQ.Ext.reg("multifieldmultifield", CQ.form.MultiFieldMultiField);
/**
* The <code>CQ.form.MultiFieldMultiField.Item</code> class represents an item in a
* <code>CQ.form.MultiFieldMultiField</code>. This class is not intended for direct use.
*
* @private
* @class CQ.form.MultiFieldMultiField.Item
* @extends CQ.Ext.Panel
*/
CQ.form.MultiFieldMultiField.Item = CQ.Ext.extend(CQ.form.MultiField.Item, {
mfConfig: null,
/**
* Creates a new <code>CQ.form.MultiFieldMultiField.Item</code>.
* @constructor
* @param {Object} config The config object
*/
constructor: function(config) {
var item = this;
mfConfig = config;
var index = config.nodeIndex;
this.fields = new Array();
var fieldIndex = 0;
for (var key = 0; key < config.fieldConfig.length;key++) {
var tempConfig = config.fieldConfig[key];
if ( (tempConfig) && (tempConfig.name) ) {
var fieldName = tempConfig.name;
if (fieldName.indexOf("./") > -1) {
fieldName = fieldName.substring(fieldName.lastIndexOf(['/']) + 1);
}
if (index != null) {
tempConfig.name = config.name + "/" + index + "/" + fieldName;
} else {
tempConfig.name = config.name + "/" + fieldName;
}
this.fields[fieldIndex] = CQ.Util.build(tempConfig, true);
fieldIndex++;
}
}
var items = new Array();
for (var i=0; i< this.fields.length; i++) {
items.push({
"xtype":"panel",
"border":false,
"items": this.fields[i]
});
}
if(!config.fieldConfig.readOnly) {
items.push({
"xtype":"panel",
"border":false,
"items":{
"xtype":"button",
"text":"Up",
"cls": "cq-multifield-btn",
"handler":function() {
var parent = item.ownerCt;
var index = parent.items.indexOf(item);
if (index > 0) {
item.reorder(parent.items.itemAt(index - 1));
}
}
}
});
items.push({
"xtype":"panel",
"border":false,
"items":{
"xtype":"button",
"text":"Down",
"cls": "cq-multifield-btn",
"handler":function() {
var parent = item.ownerCt;
var index = parent.items.indexOf(item);
if (index < parent.items.getCount() - 1) {
item.reorder(parent.items.itemAt(index + 1));
}
}
}
});
items.push({
"xtype":"panel",
"border":false,
"items":{
"xtype":"button",
"text":"-",
"cls": "cq-multifield-btn",
"handler":function() {
item.remove(item);
}
}
});
}
config = CQ.Util.applyDefaults(config, {
"layout":"table",
"border":false,
"layoutConfig":{
"columns": (this.fields.length + 3)
},
"defaults":{
"bodyStyle":"padding:3px"
},
"items":items
});
CQ.form.MultiField.Item.superclass.constructor.call(this, config);
if (config.value) {
this.setValue(config.value);
}
},
/**
* Reorders the item above the specified item.
* @param item The item to reorder above
*/
reorder: function(item) {
var vars = new Array();
for (var i=0; i<item.fields.length; i++) {
vars.push(item.fields[i].getValue());
}
for (var j=0; j<vars.length; j++) {
item.fields[j].setValue(this.fields[j].getValue());
this.fields[j].setValue(vars[j]);
}
},
remove: function(item) {
var parent = item.ownerCt;
var index = parent.items.indexOf(item);
if (index < parent.items.getCount() - 2) {
item.reorder(parent.items.itemAt(index + 1));
item.remove(parent.items.itemAt(index + 1));
} else {
parent.remove(item);
}
},
/**
* Returns the data value.
* @return {String} value The field value
*/
getValue: function() {
var value = null;
for (var i=0; i<this.fields.length; i++) {
if (i == 0) {
value = this.fields[0].getValue();
} else {
value = value + "|" + this.fields[i].getValue();
}
}
return value;
},
/**
* Sets a data value into the field and validates it.
* @param {String} value The value to set
*/
setValue: function(value) {
if (value) {
var values = value.split(["|"]);
for (var i=0; i<values.length; i++) {
this.fields[i].setValue(values[i]);
if (this.fields[i].isXType("trigger")) {
this.fields[i].wrap.setWidth(this.fields[i].width +"px");
}
}
}
},
validate: function() {
var isValid = true;
if(this.fields) {
for (var i=0; i<this.fields.length&&isValid; i++) {
if (this.fields[i]) {
isValid = this.fields[i].validate();
}
}
}
return isValid;
},
getName: function() {
if (mfConfig) {
return mfConfig.name;
} else {
return '';
}
}
});
CQ.Ext.reg("multifieldmultifielditem", CQ.form.MultiFieldMultiField.Item);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment