From ce41118086d9956fd2d364b3c86983859616aceb Mon Sep 17 00:00:00 2001 From: Scott Baker Date: Tue, 25 Nov 2014 17:15:21 -0800 Subject: [PATCH] rudimentary validation in xoslib --- planetstack/core/xoslib/dashboards/test.html | 1 + .../xoslib/dashboards/xosAdminDashboard.html | 1 + .../xoslib/dashboards/xosAdminWholePage.html | 1 + .../core/xoslib/static/css/xosAdminSite.css | 5 ++++ .../xoslib/static/js/xoslib/xos-backbone.js | 19 +++++++++++++ .../core/xoslib/static/js/xoslib/xos-util.js | 16 +++++++++++ .../core/xoslib/static/js/xoslib/xosHelper.js | 27 ++++++++++++++++++- 7 files changed, 69 insertions(+), 1 deletion(-) diff --git a/planetstack/core/xoslib/dashboards/test.html b/planetstack/core/xoslib/dashboards/test.html index 27b0b8d..e6faf3a 100644 --- a/planetstack/core/xoslib/dashboards/test.html +++ b/planetstack/core/xoslib/dashboards/test.html @@ -9,6 +9,7 @@ + diff --git a/planetstack/core/xoslib/dashboards/xosAdminDashboard.html b/planetstack/core/xoslib/dashboards/xosAdminDashboard.html index 8011884..1544d9f 100644 --- a/planetstack/core/xoslib/dashboards/xosAdminDashboard.html +++ b/planetstack/core/xoslib/dashboards/xosAdminDashboard.html @@ -11,6 +11,7 @@ + diff --git a/planetstack/core/xoslib/dashboards/xosAdminWholePage.html b/planetstack/core/xoslib/dashboards/xosAdminWholePage.html index 4af6093..8aaa8c1 100644 --- a/planetstack/core/xoslib/dashboards/xosAdminWholePage.html +++ b/planetstack/core/xoslib/dashboards/xosAdminWholePage.html @@ -11,6 +11,7 @@ + diff --git a/planetstack/core/xoslib/static/css/xosAdminSite.css b/planetstack/core/xoslib/static/css/xosAdminSite.css index f09bbcf..ad9eb47 100644 --- a/planetstack/core/xoslib/static/css/xosAdminSite.css +++ b/planetstack/core/xoslib/static/css/xosAdminSite.css @@ -66,6 +66,11 @@ text-decoration:none; } +.help-inline.error { + color: red; + font-weight: bold; +} + /* these are for the inline list and detail titles */ .xos-list-title { diff --git a/planetstack/core/xoslib/static/js/xoslib/xos-backbone.js b/planetstack/core/xoslib/static/js/xoslib/xos-backbone.js index bbf13a4..a04fd8f 100644 --- a/planetstack/core/xoslib/static/js/xoslib/xos-backbone.js +++ b/planetstack/core/xoslib/static/js/xoslib/xos-backbone.js @@ -68,6 +68,21 @@ if (! window.XOSLIB_LOADED ) { } } return res; + }, + + validate: function(attrs, options) { + errors = {}; + _.each(this.validators, function(validatorList, fieldName) { + _.each(validatorList, function(validator) { + if (fieldName in attrs) { + validatorResult = validateField(validator, attrs[fieldName]) + if (validatorResult != true) { + errors[fieldName] = validatorResult; + } + } + }); + }); + return errors; } }); @@ -287,6 +302,10 @@ if (! window.XOSLIB_LOADED ) { modelAttrs["defaults"] = xosdefaults[modelName]; } + if (xosvalidators && xosvalidators[modelName]) { + modelAttrs["validators"] = xosvalidators[modelName]; + } + lib[modelName] = XOSModel.extend(modelAttrs); collectionAttrs["model"] = lib[modelName]; diff --git a/planetstack/core/xoslib/static/js/xoslib/xos-util.js b/planetstack/core/xoslib/static/js/xoslib/xos-util.js index 79ce0f8..bebc44a 100644 --- a/planetstack/core/xoslib/static/js/xoslib/xos-util.js +++ b/planetstack/core/xoslib/static/js/xoslib/xos-util.js @@ -21,3 +21,19 @@ function limitTableRows(tableSelector, maxRows) { wrapper.style.height = height + "px"; } } + +function validateField(validatorName, value) { + switch (validatorName) { + case "notBlank": + if ((value==undefined) || (value=="")) { + return "can not be blank"; + } + break; + case "isUrl": + if (! /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value)) { + return "must be a valid url"; + } + break; + } + return true; +} diff --git a/planetstack/core/xoslib/static/js/xoslib/xosHelper.js b/planetstack/core/xoslib/static/js/xoslib/xosHelper.js index 8fa27a6..30835c7 100644 --- a/planetstack/core/xoslib/static/js/xoslib/xosHelper.js +++ b/planetstack/core/xoslib/static/js/xoslib/xosHelper.js @@ -264,10 +264,22 @@ XOSDetailView = Marionette.ItemView.extend({ save: function() { this.app.hideError(); - var infoMsgId = this.app.showInformational( {what: "save " + model.modelName + " " + model.attributes.humanReadableName, status: "", statusText: "in progress..."} ); var data = Backbone.Syphon.serialize(this); var that = this; var isNew = !this.model.id; + + /* although model.validate() is called automatically by + model.save, we call it ourselves, so we can throw up our + validation error before creating the infoMsg in the log + */ + errors = this.model.validate(data); + if (errors) { + this.onFormDataInvalid(errors); + return; + } + + var infoMsgId = this.app.showInformational( {what: "save " + model.modelName + " " + model.attributes.humanReadableName, status: "", statusText: "in progress..."} ); + this.model.save(data, {error: function(model, result, xhr) { that.saveError(model,result,xhr,infoMsgId);}, success: function(model, result, xhr) { that.saveSuccess(model,result,xhr,infoMsgId);}}); if (isNew) { @@ -356,6 +368,19 @@ XOSDetailView = Marionette.ItemView.extend({ this.tabClick('#xos-nav-detail', 'detail'); }, + onFormDataInvalid: function(errors) { + var self=this; + var markErrors = function(value, key) { + console.log("name='" + key + "'"); + var $inputElement = self.$el.find("[name='" + key + "']"); + var $inputContainer = $inputElement.parent(); + $inputContainer.find(".help-inline").remove(); + var $errorEl = $("", {class: "help-inline error", text: value}); + $inputContainer.append($errorEl).addClass("error"); + } + _.each(errors, markErrors); + }, + }); /* XOSItemView -- 2.43.0