form handling of f.options, f.regex, f.listable, f.rearchable
This commit is contained in:
@@ -12,6 +12,10 @@
|
|||||||
$.error('web2py.js has already been loaded!');
|
$.error('web2py.js has already been loaded!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var FORMDATA_IS_SUPPORTED = typeof(FormData) !== 'undefined';
|
||||||
|
var animateIn = 'fadeIn';
|
||||||
|
// var animateIn = 'slideDown';
|
||||||
|
|
||||||
String.prototype.reverse = function () {
|
String.prototype.reverse = function () {
|
||||||
return this.split('').reverse().join('');
|
return this.split('').reverse().join('');
|
||||||
};
|
};
|
||||||
@@ -178,7 +182,7 @@
|
|||||||
},
|
},
|
||||||
/* manage errors in forms */
|
/* manage errors in forms */
|
||||||
manage_errors: function (target) {
|
manage_errors: function (target) {
|
||||||
$('div.error', target).hide().slideDown('slow');
|
$('div.error', target).hide()[animateIn]('slow');
|
||||||
},
|
},
|
||||||
after_ajax: function (xhr) {
|
after_ajax: function (xhr) {
|
||||||
/* called whenever an ajax request completes */
|
/* called whenever an ajax request completes */
|
||||||
@@ -263,13 +267,17 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
/* help preventing double form submission for normal form (not LOADed) */
|
/* help preventing double form submission for normal form (not LOADed) */
|
||||||
$(doc).on('submit', 'form', function () {
|
$(doc).on('submit', 'form', function (e) {
|
||||||
var submit_button = $(this).find(web2py.formInputClickSelector);
|
var submit_buttons = $(this).find(web2py.formInputClickSelector);
|
||||||
web2py.disableElement(submit_button);
|
submit_buttons.each(function() {
|
||||||
|
web2py.disableElement($(this));
|
||||||
|
})
|
||||||
/* safeguard in case the form doesn't trigger a refresh,
|
/* safeguard in case the form doesn't trigger a refresh,
|
||||||
see https://github.com/web2py/web2py/issues/1100 */
|
see https://github.com/web2py/web2py/issues/1100 */
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
web2py.enableElement(submit_button);
|
submit_buttons.each(function() {
|
||||||
|
web2py.enableElement($(this));
|
||||||
|
});
|
||||||
}, 5000);
|
}, 5000);
|
||||||
});
|
});
|
||||||
doc.ajaxSuccess(function (e, xhr) {
|
doc.ajaxSuccess(function (e, xhr) {
|
||||||
@@ -320,7 +328,15 @@
|
|||||||
form.submit(function (e) {
|
form.submit(function (e) {
|
||||||
web2py.disableElement(form.find(web2py.formInputClickSelector));
|
web2py.disableElement(form.find(web2py.formInputClickSelector));
|
||||||
web2py.hide_flash();
|
web2py.hide_flash();
|
||||||
web2py.ajax_page('post', url, form.serialize(), target, form);
|
|
||||||
|
var formData;
|
||||||
|
if (FORMDATA_IS_SUPPORTED) {
|
||||||
|
formData = new FormData(form[0]); // Allows file uploads.
|
||||||
|
} else {
|
||||||
|
formData = form.serialize(); // Fallback for older browsers.
|
||||||
|
}
|
||||||
|
web2py.ajax_page('post', url, formData, target, form);
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
form.on('click', web2py.formInputClickSelector, function (e) {
|
form.on('click', web2py.formInputClickSelector, function (e) {
|
||||||
@@ -339,11 +355,18 @@
|
|||||||
if (web2py.isUndefined(element)) element = $(document);
|
if (web2py.isUndefined(element)) element = $(document);
|
||||||
/* if target is not there, fill it with something that there isn't in the page*/
|
/* if target is not there, fill it with something that there isn't in the page*/
|
||||||
if (web2py.isUndefined(target) || target === '') target = 'w2p_none';
|
if (web2py.isUndefined(target) || target === '') target = 'w2p_none';
|
||||||
|
|
||||||
|
/* processData and contentType must be set to false when passing a FormData
|
||||||
|
object to jQuery.ajax. */
|
||||||
|
var isFormData = Object.prototype.toString.call(data) === '[object FormData]';
|
||||||
|
var contentType = isFormData ? false : 'application/x-www-form-urlencoded; charset=UTF-8';
|
||||||
if (web2py.fire(element, 'ajax:before', null, target)) { /*test a usecase, should stop here if returns false */
|
if (web2py.fire(element, 'ajax:before', null, target)) { /*test a usecase, should stop here if returns false */
|
||||||
$.ajax({
|
$.ajax({
|
||||||
'type': method,
|
'type': method,
|
||||||
'url': action,
|
'url': action,
|
||||||
'data': data,
|
'data': data,
|
||||||
|
'processData': !isFormData,
|
||||||
|
'contentType': contentType,
|
||||||
'beforeSend': function (xhr, settings) {
|
'beforeSend': function (xhr, settings) {
|
||||||
xhr.setRequestHeader('web2py-component-location', document.location);
|
xhr.setRequestHeader('web2py-component-location', document.location);
|
||||||
xhr.setRequestHeader('web2py-component-element', target);
|
xhr.setRequestHeader('web2py-component-element', target);
|
||||||
@@ -595,7 +618,7 @@
|
|||||||
var flash = $('.w2p_flash');
|
var flash = $('.w2p_flash');
|
||||||
web2py.hide_flash();
|
web2py.hide_flash();
|
||||||
flash.html(message).addClass(status);
|
flash.html(message).addClass(status);
|
||||||
if (flash.html()) flash.append('<span id="closeflash"> × </span>').slideDown();
|
if (flash.html()) flash.append('<span id="closeflash"> × </span>')[animateIn]();
|
||||||
},
|
},
|
||||||
hide_flash: function () {
|
hide_flash: function () {
|
||||||
$('.w2p_flash').fadeOut(0).html('');
|
$('.w2p_flash').fadeOut(0).html('');
|
||||||
@@ -609,7 +632,7 @@
|
|||||||
for (var k = 0; k < triggers[id].length; k++) {
|
for (var k = 0; k < triggers[id].length; k++) {
|
||||||
var dep = $('#' + triggers[id][k], target);
|
var dep = $('#' + triggers[id][k], target);
|
||||||
var tr = $('#' + triggers[id][k] + '__row', target);
|
var tr = $('#' + triggers[id][k] + '__row', target);
|
||||||
if (t.is(dep.attr('data-show-if'))) tr.slideDown();
|
if (t.is(dep.attr('data-show-if'))) tr[animateIn]();
|
||||||
else tr.hide();
|
else tr.hide();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -699,8 +722,9 @@
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
/* Disables form elements:
|
/* Disables form elements:
|
||||||
|
- Does not disable elements with 'data-w2p_disable' attribute
|
||||||
- Caches element value in 'w2p_enable_with' data store
|
- Caches element value in 'w2p_enable_with' data store
|
||||||
- Replaces element text with value of 'data-disable-with' attribute
|
- Replaces element text with value of 'data-w2p_disable_with' attribute
|
||||||
- Sets disabled property to true
|
- Sets disabled property to true
|
||||||
*/
|
*/
|
||||||
disableFormElements: function (form) {
|
disableFormElements: function (form) {
|
||||||
@@ -712,13 +736,15 @@
|
|||||||
if (!web2py.isUndefined(disable)) {
|
if (!web2py.isUndefined(disable)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (web2py.isUndefined(disable_with)) {
|
if (!element.is(':file')) { // Altering file input values is not allowed.
|
||||||
element.data('w2p_disable_with', element[method]());
|
if (web2py.isUndefined(disable_with)) {
|
||||||
|
element.data('w2p_disable_with', element[method]());
|
||||||
|
}
|
||||||
|
if (web2py.isUndefined(element.data('w2p_enable_with'))) {
|
||||||
|
element.data('w2p_enable_with', element[method]());
|
||||||
|
}
|
||||||
|
element[method](element.data('w2p_disable_with'));
|
||||||
}
|
}
|
||||||
if (web2py.isUndefined(element.data('w2p_enable_with'))) {
|
|
||||||
element.data('w2p_enable_with', element[method]());
|
|
||||||
}
|
|
||||||
element[method](element.data('w2p_disable_with'));
|
|
||||||
element.prop('disabled', true);
|
element.prop('disabled', true);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -799,4 +825,4 @@ web2py_event_handlers = jQuery.web2py.event_handlers;
|
|||||||
web2py_trap_link = jQuery.web2py.trap_link;
|
web2py_trap_link = jQuery.web2py.trap_link;
|
||||||
web2py_calc_entropy = jQuery.web2py.calc_entropy;
|
web2py_calc_entropy = jQuery.web2py.calc_entropy;
|
||||||
*/
|
*/
|
||||||
/* compatibility code - end*/
|
/* compatibility code - end*/
|
||||||
|
|||||||
@@ -12,6 +12,10 @@
|
|||||||
$.error('web2py.js has already been loaded!');
|
$.error('web2py.js has already been loaded!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var FORMDATA_IS_SUPPORTED = typeof(FormData) !== 'undefined';
|
||||||
|
var animateIn = 'fadeIn';
|
||||||
|
// var animateIn = 'slideDown';
|
||||||
|
|
||||||
String.prototype.reverse = function () {
|
String.prototype.reverse = function () {
|
||||||
return this.split('').reverse().join('');
|
return this.split('').reverse().join('');
|
||||||
};
|
};
|
||||||
@@ -178,7 +182,7 @@
|
|||||||
},
|
},
|
||||||
/* manage errors in forms */
|
/* manage errors in forms */
|
||||||
manage_errors: function (target) {
|
manage_errors: function (target) {
|
||||||
$('div.error', target).hide().slideDown('slow');
|
$('div.error', target).hide()[animateIn]('slow');
|
||||||
},
|
},
|
||||||
after_ajax: function (xhr) {
|
after_ajax: function (xhr) {
|
||||||
/* called whenever an ajax request completes */
|
/* called whenever an ajax request completes */
|
||||||
@@ -263,13 +267,17 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
/* help preventing double form submission for normal form (not LOADed) */
|
/* help preventing double form submission for normal form (not LOADed) */
|
||||||
$(doc).on('submit', 'form', function () {
|
$(doc).on('submit', 'form', function (e) {
|
||||||
var submit_button = $(this).find(web2py.formInputClickSelector);
|
var submit_buttons = $(this).find(web2py.formInputClickSelector);
|
||||||
web2py.disableElement(submit_button);
|
submit_buttons.each(function() {
|
||||||
|
web2py.disableElement($(this));
|
||||||
|
})
|
||||||
/* safeguard in case the form doesn't trigger a refresh,
|
/* safeguard in case the form doesn't trigger a refresh,
|
||||||
see https://github.com/web2py/web2py/issues/1100 */
|
see https://github.com/web2py/web2py/issues/1100 */
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
web2py.enableElement(submit_button);
|
submit_buttons.each(function() {
|
||||||
|
web2py.enableElement($(this));
|
||||||
|
});
|
||||||
}, 5000);
|
}, 5000);
|
||||||
});
|
});
|
||||||
doc.ajaxSuccess(function (e, xhr) {
|
doc.ajaxSuccess(function (e, xhr) {
|
||||||
@@ -320,7 +328,15 @@
|
|||||||
form.submit(function (e) {
|
form.submit(function (e) {
|
||||||
web2py.disableElement(form.find(web2py.formInputClickSelector));
|
web2py.disableElement(form.find(web2py.formInputClickSelector));
|
||||||
web2py.hide_flash();
|
web2py.hide_flash();
|
||||||
web2py.ajax_page('post', url, form.serialize(), target, form);
|
|
||||||
|
var formData;
|
||||||
|
if (FORMDATA_IS_SUPPORTED) {
|
||||||
|
formData = new FormData(form[0]); // Allows file uploads.
|
||||||
|
} else {
|
||||||
|
formData = form.serialize(); // Fallback for older browsers.
|
||||||
|
}
|
||||||
|
web2py.ajax_page('post', url, formData, target, form);
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
form.on('click', web2py.formInputClickSelector, function (e) {
|
form.on('click', web2py.formInputClickSelector, function (e) {
|
||||||
@@ -339,11 +355,18 @@
|
|||||||
if (web2py.isUndefined(element)) element = $(document);
|
if (web2py.isUndefined(element)) element = $(document);
|
||||||
/* if target is not there, fill it with something that there isn't in the page*/
|
/* if target is not there, fill it with something that there isn't in the page*/
|
||||||
if (web2py.isUndefined(target) || target === '') target = 'w2p_none';
|
if (web2py.isUndefined(target) || target === '') target = 'w2p_none';
|
||||||
|
|
||||||
|
/* processData and contentType must be set to false when passing a FormData
|
||||||
|
object to jQuery.ajax. */
|
||||||
|
var isFormData = Object.prototype.toString.call(data) === '[object FormData]';
|
||||||
|
var contentType = isFormData ? false : 'application/x-www-form-urlencoded; charset=UTF-8';
|
||||||
if (web2py.fire(element, 'ajax:before', null, target)) { /*test a usecase, should stop here if returns false */
|
if (web2py.fire(element, 'ajax:before', null, target)) { /*test a usecase, should stop here if returns false */
|
||||||
$.ajax({
|
$.ajax({
|
||||||
'type': method,
|
'type': method,
|
||||||
'url': action,
|
'url': action,
|
||||||
'data': data,
|
'data': data,
|
||||||
|
'processData': !isFormData,
|
||||||
|
'contentType': contentType,
|
||||||
'beforeSend': function (xhr, settings) {
|
'beforeSend': function (xhr, settings) {
|
||||||
xhr.setRequestHeader('web2py-component-location', document.location);
|
xhr.setRequestHeader('web2py-component-location', document.location);
|
||||||
xhr.setRequestHeader('web2py-component-element', target);
|
xhr.setRequestHeader('web2py-component-element', target);
|
||||||
@@ -595,7 +618,7 @@
|
|||||||
var flash = $('.w2p_flash');
|
var flash = $('.w2p_flash');
|
||||||
web2py.hide_flash();
|
web2py.hide_flash();
|
||||||
flash.html(message).addClass(status);
|
flash.html(message).addClass(status);
|
||||||
if (flash.html()) flash.append('<span id="closeflash"> × </span>').slideDown();
|
if (flash.html()) flash.append('<span id="closeflash"> × </span>')[animateIn]();
|
||||||
},
|
},
|
||||||
hide_flash: function () {
|
hide_flash: function () {
|
||||||
$('.w2p_flash').fadeOut(0).html('');
|
$('.w2p_flash').fadeOut(0).html('');
|
||||||
@@ -609,7 +632,7 @@
|
|||||||
for (var k = 0; k < triggers[id].length; k++) {
|
for (var k = 0; k < triggers[id].length; k++) {
|
||||||
var dep = $('#' + triggers[id][k], target);
|
var dep = $('#' + triggers[id][k], target);
|
||||||
var tr = $('#' + triggers[id][k] + '__row', target);
|
var tr = $('#' + triggers[id][k] + '__row', target);
|
||||||
if (t.is(dep.attr('data-show-if'))) tr.slideDown();
|
if (t.is(dep.attr('data-show-if'))) tr[animateIn]();
|
||||||
else tr.hide();
|
else tr.hide();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -699,8 +722,9 @@
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
/* Disables form elements:
|
/* Disables form elements:
|
||||||
|
- Does not disable elements with 'data-w2p_disable' attribute
|
||||||
- Caches element value in 'w2p_enable_with' data store
|
- Caches element value in 'w2p_enable_with' data store
|
||||||
- Replaces element text with value of 'data-disable-with' attribute
|
- Replaces element text with value of 'data-w2p_disable_with' attribute
|
||||||
- Sets disabled property to true
|
- Sets disabled property to true
|
||||||
*/
|
*/
|
||||||
disableFormElements: function (form) {
|
disableFormElements: function (form) {
|
||||||
@@ -712,13 +736,15 @@
|
|||||||
if (!web2py.isUndefined(disable)) {
|
if (!web2py.isUndefined(disable)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (web2py.isUndefined(disable_with)) {
|
if (!element.is(':file')) { // Altering file input values is not allowed.
|
||||||
element.data('w2p_disable_with', element[method]());
|
if (web2py.isUndefined(disable_with)) {
|
||||||
|
element.data('w2p_disable_with', element[method]());
|
||||||
|
}
|
||||||
|
if (web2py.isUndefined(element.data('w2p_enable_with'))) {
|
||||||
|
element.data('w2p_enable_with', element[method]());
|
||||||
|
}
|
||||||
|
element[method](element.data('w2p_disable_with'));
|
||||||
}
|
}
|
||||||
if (web2py.isUndefined(element.data('w2p_enable_with'))) {
|
|
||||||
element.data('w2p_enable_with', element[method]());
|
|
||||||
}
|
|
||||||
element[method](element.data('w2p_disable_with'));
|
|
||||||
element.prop('disabled', true);
|
element.prop('disabled', true);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -799,4 +825,4 @@ web2py_event_handlers = jQuery.web2py.event_handlers;
|
|||||||
web2py_trap_link = jQuery.web2py.trap_link;
|
web2py_trap_link = jQuery.web2py.trap_link;
|
||||||
web2py_calc_entropy = jQuery.web2py.calc_entropy;
|
web2py_calc_entropy = jQuery.web2py.calc_entropy;
|
||||||
*/
|
*/
|
||||||
/* compatibility code - end*/
|
/* compatibility code - end*/
|
||||||
|
|||||||
+14
-9
@@ -50,6 +50,10 @@ def _default_validators(db, field):
|
|||||||
requires.append(validators.IS_TIME())
|
requires.append(validators.IS_TIME())
|
||||||
elif field_type == 'datetime':
|
elif field_type == 'datetime':
|
||||||
requires.append(validators.IS_DATETIME())
|
requires.append(validators.IS_DATETIME())
|
||||||
|
elif field.options is not None:
|
||||||
|
requires = IS_IN_SET(field.options, multiple=field_type.startswith('list:'))
|
||||||
|
elif field.regex and not requires:
|
||||||
|
requires = IS_REGEX(regex)
|
||||||
elif db and field_type.startswith('reference') and \
|
elif db and field_type.startswith('reference') and \
|
||||||
field_type.find('.') < 0 and \
|
field_type.find('.') < 0 and \
|
||||||
field_type[10:] in db.tables:
|
field_type[10:] in db.tables:
|
||||||
@@ -76,16 +80,17 @@ def _default_validators(db, field):
|
|||||||
requires._and = validators.IS_NOT_IN_DB(db, field)
|
requires._and = validators.IS_NOT_IN_DB(db, field)
|
||||||
if not field.notnull:
|
if not field.notnull:
|
||||||
requires = validators.IS_EMPTY_OR(requires)
|
requires = validators.IS_EMPTY_OR(requires)
|
||||||
return requires
|
return requires
|
||||||
# does not get here for reference and list:reference
|
# does not get here for reference and list:reference
|
||||||
if field.unique:
|
if isinstance(requires, list):
|
||||||
requires.insert(0, validators.IS_NOT_IN_DB(db, field))
|
if field.unique:
|
||||||
excluded_fields = ['string', 'upload', 'text', 'password', 'boolean']
|
requires.insert(0, validators.IS_NOT_IN_DB(db, field))
|
||||||
if (field.notnull or field.unique) and field_type not in excluded_fields:
|
excluded_fields = ['string', 'upload', 'text', 'password', 'boolean']
|
||||||
requires.insert(0, validators.IS_NOT_EMPTY())
|
if (field.notnull or field.unique) and field_type not in excluded_fields:
|
||||||
elif not field.notnull and not field.unique and requires:
|
requires.insert(0, validators.IS_NOT_EMPTY())
|
||||||
requires[0] = \
|
elif not field.notnull and not field.unique and requires:
|
||||||
validators.IS_EMPTY_OR(requires[0], null='' if field.type in ('string', 'text', 'password') else None)
|
null = null='' if field.type in ('string', 'text', 'password') else None
|
||||||
|
requires[0] = validators.IS_EMPTY_OR(requires[0], null=null)
|
||||||
return requires
|
return requires
|
||||||
|
|
||||||
DAL.serializers = {'json': custom_json, 'xml': xml}
|
DAL.serializers = {'json': custom_json, 'xml': xml}
|
||||||
|
|||||||
+1
-1
Submodule gluon/packages/dal updated: 35dd4fc6f8...d8631f683c
+4
-4
@@ -2348,12 +2348,12 @@ class SQLFORM(FORM):
|
|||||||
for k, f in iteritems(table):
|
for k, f in iteritems(table):
|
||||||
if isinstance(f, Field.Virtual):
|
if isinstance(f, Field.Virtual):
|
||||||
f.tablename = table._tablename
|
f.tablename = table._tablename
|
||||||
columns = [f for f in fields if f.tablename in tablenames]
|
columns = [f for f in fields if f.tablename in tablenames and f.listable]
|
||||||
else:
|
else:
|
||||||
fields = []
|
fields = []
|
||||||
columns = []
|
columns = []
|
||||||
filter1 = lambda f: isinstance(f, Field) and (f.type!='blob' or showblobs)
|
filter1 = lambda f: isinstance(f, Field) and (f.type!='blob' or showblobs)
|
||||||
filter2 = lambda f: isinstance(f, Field) and f.readable
|
filter2 = lambda f: isinstance(f, Field) and f.readable and f.listable
|
||||||
for table in tables:
|
for table in tables:
|
||||||
fields += filter(filter1, table)
|
fields += filter(filter1, table)
|
||||||
columns += filter(filter2, table)
|
columns += filter(filter2, table)
|
||||||
@@ -2571,8 +2571,8 @@ class SQLFORM(FORM):
|
|||||||
try:
|
try:
|
||||||
# the query should be constructed using searchable
|
# the query should be constructed using searchable
|
||||||
# fields but not virtual fields
|
# fields but not virtual fields
|
||||||
sfields = reduce(lambda a, b: a + b,
|
is_searchable = lambda f: f.readable and not isinstance(f, Field.Virtual) and f.searchable
|
||||||
[[f for f in t if f.readable and not isinstance(f, Field.Virtual)] for t in tables])
|
sfields = reduce(lambda a, b: a + b, [filter(is_searchable, t) for t in tables])
|
||||||
# use custom_query using searchable
|
# use custom_query using searchable
|
||||||
if callable(searchable):
|
if callable(searchable):
|
||||||
dbset = dbset(searchable(sfields, keywords))
|
dbset = dbset(searchable(sfields, keywords))
|
||||||
|
|||||||
Reference in New Issue
Block a user