this.initEl(el);
}
Roo.form.BasicForm.superclass.constructor.call(this);
+
+ Roo.form.BasicForm.popover.apply();
};
Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
* @cfg {Boolean} fileUpload
* Set to true if this form is a file upload.
*/
+
/**
* @cfg {Object} baseParams
* Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
*/
+ /**
+
/**
* @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
*/
* element by passing it or its id or mask the form itself by passing in true.
* @type Mixed
*/
- waitMsgTarget : undefined,
+ waitMsgTarget : false,
+
+ /**
+ * @type Boolean
+ */
+ disableMask : false,
+
+ /**
+ * @cfg {Boolean} errorMask Should the form be masked (and the active element highlighted on error - default false
+ */
+ errorMask : false,
+
+ /**
+ * @cfg {Number} maskOffset space around form element to mask if there is an error Default 100
+ */
+ maskOffset : 100,
// private
initEl : function(el){
*/
isValid : function(){
var valid = true;
+ var target = false;
this.items.each(function(f){
- if(!f.validate()){
- valid = false;
- }
+ if(f.validate()){
+ return;
+ }
+
+ valid = false;
+
+ if(!target && f.el.isVisible(true)){
+ target = f;
+ }
});
+
+ if(this.errorMask && !valid){
+ Roo.form.BasicForm.popover.mask(this, target);
+ }
+
return valid;
},
-
/**
- * Returns true if any fields in this form have changed since their original load.
+ * Returns array of invalid form fields.
+ * @return Array
+ */
+
+ invalidFields : function()
+ {
+ var ret = [];
+ this.items.each(function(f){
+ if(f.validate()){
+ return;
+ }
+ ret.push(f);
+
+ });
+
+ return ret;
+ },
+
+
+ /**
+ * DEPRICATED Returns true if any fields in this form have changed since their original load.
* @return Boolean
*/
isDirty : function(){
});
return dirty;
},
-
+
+ /**
+ * Returns true if any fields in this form have changed since their original load. (New version)
+ * @return Boolean
+ */
+
+ hasChanged : function()
+ {
+ var dirty = false;
+ this.items.each(function(f){
+ if(f.hasChanged()){
+ dirty = true;
+ return false;
+ }
+ });
+ return dirty;
+
+ },
+ /**
+ * Resets all hasChanged to 'false' -
+ * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
+ * So hasChanged storage is only to be used for this purpose
+ * @return Boolean
+ */
+ resetHasChanged : function()
+ {
+ this.items.each(function(f){
+ f.resetHasChanged();
+ });
+
+ },
+
+
/**
* Performs a predefined action (submit or load) or custom actions you define on this form.
* @param {String} actionName The name of the action type
// private
beforeAction : function(action){
var o = action.options;
- if(o.waitMsg){
+
+ if(!this.disableMask) {
if(this.waitMsgTarget === true){
- this.el.mask(o.waitMsg, 'x-mask-loading');
+ this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
}else if(this.waitMsgTarget){
this.waitMsgTarget = Roo.get(this.waitMsgTarget);
- this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
- }else{
- Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
+ this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
+ }else {
+ Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
}
}
+
+
},
// private
afterAction : function(action, success){
this.activeAction = null;
var o = action.options;
- if(o.waitMsg){
+
+ if(!this.disableMask) {
if(this.waitMsgTarget === true){
this.el.unmask();
}else if(this.waitMsgTarget){
Roo.MessageBox.hide();
}
}
+
if(success){
if(o.reset){
this.reset();
}
Roo.callback(o.success, o.scope, [this, action]);
this.fireEvent('actioncomplete', this, action);
+
}else{
+
+ // failure condition..
+ // we have a scenario where updates need confirming.
+ // eg. if a locking scenario exists..
+ // we look for { errors : { needs_confirm : true }} in the response.
+ if (
+ (typeof(action.result) != 'undefined') &&
+ (typeof(action.result.errors) != 'undefined') &&
+ (typeof(action.result.errors.needs_confirm) != 'undefined')
+ ){
+ var _t = this;
+ Roo.MessageBox.confirm(
+ "Change requires confirmation",
+ action.result.errorMsg,
+ function(r) {
+ if (r != 'yes') {
+ return;
+ }
+ _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
+ }
+
+ );
+
+
+
+ return;
+ }
+
Roo.callback(o.failure, o.scope, [this, action]);
+ // show an error message if no failed handler is set..
+ if (!this.hasListener('actionfailed')) {
+ Roo.MessageBox.alert("Error",
+ (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
+ action.result.errorMsg :
+ "Saving Failed, please check your entries or try again"
+ );
+ }
+
this.fireEvent('actionfailed', this, action);
}
+
},
/**
* @param {Roo.form.Form} form to add.
*
*/
- addForm : function(form){
+ addForm : function(form)
+ {
+ if (this.childForms.indexOf(form) > -1) {
+ // already added..
+ return;
+ }
this.childForms.push(form);
+ var n = '';
Roo.each(form.allItems, function (fe) {
- if (this.findField(fe.name)) { // already added..
+ n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
+ if (this.findField(n)) { // already added..
return;
}
var add = new Roo.form.Hidden({
- name : fe.name
+ name : n
});
- add.render();
- this.add( new Roo.form.Hidden({
- name : fe.name
- }));
+ add.render(this.el);
+
+ this.add( add );
}, this);
},
for(id in values){
if(typeof values[id] != 'function' && (field = this.findField(id))){
+
+
+
if (field.setFromData &&
field.valueField &&
field.displayField &&
sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
field.setFromData(sd);
+ } else if (field.inputType && field.inputType == 'radio') {
+
+ field.setValue(values[id]);
} else {
field.setValue(values[id]);
}
}
}
}
-
+ this.resetHasChanged();
+
+
Roo.each(this.childForms || [], function (f) {
f.setValues(values);
+ f.resetHasChanged();
});
return this;
},
-
+
/**
* Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
* they are returned as an array.
- * @param {Boolean} asString
+ * @param {Boolean} asString (def)
* @return {Object}
*/
- getValues : function(asString){
+ getValues : function(asString)
+ {
if (this.childForms) {
// copy values from the child forms
Roo.each(this.childForms, function (f) {
- if (f.allFields) {
- Roo.each(f.allFields, function (e) {
- if (e.name && e.getValue && this.findField(e.name)) {
- this.findField(e.name).setValue(e.getValue());
- }
- });
- }
+ this.setValues(f.getFieldValues()); // get the full set of data, as we might be copying comboboxes from external into this one.
}, this);
}
+ // use formdata
+ if (typeof(FormData) != 'undefined' && asString !== true) {
+ // this relies on a 'recent' version of chrome apparently...
+ try {
+ var fd = (new FormData(this.el.dom)).entries();
+ var ret = {};
+ var ent = fd.next();
+ while (!ent.done) {
+ ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
+ ent = fd.next();
+ };
+ return ret;
+ } catch(e) {
+
+ }
+
+ }
var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
}
return Roo.urlDecode(fs);
},
+
+ /**
+ * Returns the fields in this form as an object with key/value pairs.
+ * This differs from getValues as it calls getValue on each child item, rather than using dom data.
+ * Normally this will not return readOnly data
+ * @param {Boolean} with_readonly return readonly field data.
+ * @return {Object}
+ */
+ getFieldValues : function(with_readonly)
+ {
+ if (this.childForms) {
+ // copy values from the child forms
+ // should this call getFieldValues - probably not as we do not currently copy
+ // hidden fields when we generate..
+ Roo.each(this.childForms, function (f) {
+ this.setValues(f.getFieldValues());
+ }, this);
+ }
+
+ var ret = {};
+ this.items.each(function(f){
+
+ if (f.readOnly && with_readonly !== true) {
+ return; // skip read only values. - this is in theory to stop 'old' values being copied over new ones
+ // if a subform contains a copy of them.
+ // if you have subforms with the same editable data, you will need to copy the data back
+ // and forth.
+ }
+
+ if (!f.getName()) {
+ return;
+ }
+ var v = f.getValue();
+ if (f.inputType =='radio') {
+ if (typeof(ret[f.getName()]) == 'undefined') {
+ ret[f.getName()] = ''; // empty..
+ }
+
+ if (!f.el.dom.checked) {
+ return;
+
+ }
+ v = f.el.dom.value;
+
+ }
+
+ // not sure if this supported any more..
+ if ((typeof(v) == 'object') && f.getRawValue) {
+ v = f.getRawValue() ; // dates..
+ }
+ // combo boxes where name != hiddenName...
+ if (f.name != f.getName()) {
+ ret[f.name] = f.getRawValue();
+ }
+ ret[f.getName()] = v;
+ });
+
+ return ret;
+ },
/**
* Clears all invalid messages in this form.
Roo.each(this.childForms || [], function (f) {
f.reset();
});
-
+ this.resetHasChanged();
return this;
},
});
// back compat
-Roo.BasicForm = Roo.form.BasicForm;
\ No newline at end of file
+Roo.BasicForm = Roo.form.BasicForm;
+
+Roo.apply(Roo.form.BasicForm, {
+
+ popover : {
+
+ padding : 5,
+
+ isApplied : false,
+
+ isMasked : false,
+
+ form : false,
+
+ target : false,
+
+ intervalID : false,
+
+ maskEl : false,
+
+ apply : function()
+ {
+ if(this.isApplied){
+ return;
+ }
+
+ this.maskEl = {
+ top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
+ left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
+ bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
+ right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
+ };
+
+ this.maskEl.top.enableDisplayMode("block");
+ this.maskEl.left.enableDisplayMode("block");
+ this.maskEl.bottom.enableDisplayMode("block");
+ this.maskEl.right.enableDisplayMode("block");
+
+ Roo.get(document.body).on('click', function(){
+ this.unmask();
+ }, this);
+
+ Roo.get(document.body).on('touchstart', function(){
+ this.unmask();
+ }, this);
+
+ this.isApplied = true
+ },
+
+ mask : function(form, target)
+ {
+ this.form = form;
+
+ this.target = target;
+
+ if(!this.form.errorMask || !target.el){
+ return;
+ }
+
+ var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
+
+ var ot = this.target.el.calcOffsetsTo(scrollable);
+
+ var scrollTo = ot[1] - this.form.maskOffset;
+
+ scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
+
+ scrollable.scrollTo('top', scrollTo);
+
+ var el = this.target.wrap || this.target.el;
+
+ var box = el.getBox();
+
+ this.maskEl.top.setStyle('position', 'absolute');
+ this.maskEl.top.setStyle('z-index', 10000);
+ this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
+ this.maskEl.top.setLeft(0);
+ this.maskEl.top.setTop(0);
+ this.maskEl.top.show();
+
+ this.maskEl.left.setStyle('position', 'absolute');
+ this.maskEl.left.setStyle('z-index', 10000);
+ this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
+ this.maskEl.left.setLeft(0);
+ this.maskEl.left.setTop(box.y - this.padding);
+ this.maskEl.left.show();
+
+ this.maskEl.bottom.setStyle('position', 'absolute');
+ this.maskEl.bottom.setStyle('z-index', 10000);
+ this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
+ this.maskEl.bottom.setLeft(0);
+ this.maskEl.bottom.setTop(box.bottom + this.padding);
+ this.maskEl.bottom.show();
+
+ this.maskEl.right.setStyle('position', 'absolute');
+ this.maskEl.right.setStyle('z-index', 10000);
+ this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
+ this.maskEl.right.setLeft(box.right + this.padding);
+ this.maskEl.right.setTop(box.y - this.padding);
+ this.maskEl.right.show();
+
+ this.intervalID = window.setInterval(function() {
+ Roo.form.BasicForm.popover.unmask();
+ }, 10000);
+
+ window.onwheel = function(){ return false;};
+
+ (function(){ this.isMasked = true; }).defer(500, this);
+
+ },
+
+ unmask : function()
+ {
+ if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
+ return;
+ }
+
+ this.maskEl.top.setStyle('position', 'absolute');
+ this.maskEl.top.setSize(0, 0).setXY([0, 0]);
+ this.maskEl.top.hide();
+
+ this.maskEl.left.setStyle('position', 'absolute');
+ this.maskEl.left.setSize(0, 0).setXY([0, 0]);
+ this.maskEl.left.hide();
+
+ this.maskEl.bottom.setStyle('position', 'absolute');
+ this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
+ this.maskEl.bottom.hide();
+
+ this.maskEl.right.setStyle('position', 'absolute');
+ this.maskEl.right.setSize(0, 0).setXY([0, 0]);
+ this.maskEl.right.hide();
+
+ window.onwheel = function(){ return true;};
+
+ if(this.intervalID){
+ window.clearInterval(this.intervalID);
+ this.intervalID = false;
+ }
+
+ this.isMasked = false;
+
+ }
+
+ }
+
+});
\ No newline at end of file