From b6bf777ef977436472651727da4565e1ce04b0da Mon Sep 17 00:00:00 2001
From: Sam
Date: Thu, 5 Sep 2013 18:34:46 -0500
Subject: Switched registration form to no longer be modal, but instead it's
own page
Added validation of form using parsley.js
Added password strength indicator using zxcvbn
---
wqflask/wqflask/static/new/css/parsley.css | 20 +++++++++++
.../static/new/javascript/password_strength.coffee | 33 +++++++++++++++++
.../static/new/javascript/password_strength.js | 42 ++++++++++++++++++++++
.../wqflask/static/new/js_external/parsley.min.js | 35 ++++++++++++++++++
.../static/new/js_external/zxcvbn/.gitignore | 2 ++
5 files changed, 132 insertions(+)
create mode 100644 wqflask/wqflask/static/new/css/parsley.css
create mode 100644 wqflask/wqflask/static/new/javascript/password_strength.coffee
create mode 100644 wqflask/wqflask/static/new/javascript/password_strength.js
create mode 100644 wqflask/wqflask/static/new/js_external/parsley.min.js
create mode 100644 wqflask/wqflask/static/new/js_external/zxcvbn/.gitignore
(limited to 'wqflask')
diff --git a/wqflask/wqflask/static/new/css/parsley.css b/wqflask/wqflask/static/new/css/parsley.css
new file mode 100644
index 00000000..7d244579
--- /dev/null
+++ b/wqflask/wqflask/static/new/css/parsley.css
@@ -0,0 +1,20 @@
+/* Adapted from parsleyjs.org/documentation.html#parsleyclasses */
+
+input.parsley-success, textarea.parsley-success {
+ color: #468847 !important;
+ background-color: #DFF0D8 !important;
+ border: 1px solid #D6E9C6 !important;
+}
+input.parsley-error, textarea.parsley-error {
+ color: #B94A48 !important;
+ background-color: #F2DEDE !important;
+ border: 1px solid #EED3D7 !important;
+}
+ul.parsley-error-list {
+ font-size: 11px;
+ margin: 2px;
+ list-style-type:none;
+}
+ul.parsley-error-list li {
+ line-height: 11px;
+}
\ No newline at end of file
diff --git a/wqflask/wqflask/static/new/javascript/password_strength.coffee b/wqflask/wqflask/static/new/javascript/password_strength.coffee
new file mode 100644
index 00000000..0bee5836
--- /dev/null
+++ b/wqflask/wqflask/static/new/javascript/password_strength.coffee
@@ -0,0 +1,33 @@
+$ ->
+
+
+ $("#password").keyup ->
+ passtext = $(this).val()
+ result = zxcvbn(passtext)
+ if passtext.length < 6
+ $("#password_strength").html('')
+ $("#password_alert").fadeOut()
+ else
+ word = word_score(result.score)
+ crack_time = result.crack_time_display
+ if crack_time == "instant"
+ crack_time = "a second"
+ display = "This is #{word} password. It can be cracked in #{crack_time}."
+ $("#password_strength").html(display)
+ $("#password_alert").fadeIn()
+
+
+
+ word_score = (num_score) ->
+ num_score = parseInt(num_score)
+ console.log("num_score is:", num_score)
+ mapping =
+ 0: "a terrible"
+ 1: "a bad"
+ 2: "a mediocre"
+ 3: "a good"
+ 4: "an excellent"
+ console.log("mapping is:", mapping)
+ result = mapping[num_score]
+ console.log("result is:", result)
+ return result
\ No newline at end of file
diff --git a/wqflask/wqflask/static/new/javascript/password_strength.js b/wqflask/wqflask/static/new/javascript/password_strength.js
new file mode 100644
index 00000000..166e1125
--- /dev/null
+++ b/wqflask/wqflask/static/new/javascript/password_strength.js
@@ -0,0 +1,42 @@
+// Generated by CoffeeScript 1.6.1
+(function() {
+
+ $(function() {
+ var word_score;
+ $("#password").keyup(function() {
+ var crack_time, display, passtext, result, word;
+ passtext = $(this).val();
+ result = zxcvbn(passtext);
+ if (passtext.length < 6) {
+ $("#password_strength").html('');
+ return $("#password_alert").fadeOut();
+ } else {
+ word = word_score(result.score);
+ crack_time = result.crack_time_display;
+ if (crack_time === "instant") {
+ crack_time = "a second";
+ }
+ display = "This is " + word + " password. It can be cracked in " + crack_time + ".";
+ $("#password_strength").html(display);
+ return $("#password_alert").fadeIn();
+ }
+ });
+ return word_score = function(num_score) {
+ var mapping, result;
+ num_score = parseInt(num_score);
+ console.log("num_score is:", num_score);
+ mapping = {
+ 0: "a terrible",
+ 1: "a bad",
+ 2: "a mediocre",
+ 3: "a good",
+ 4: "an excellent"
+ };
+ console.log("mapping is:", mapping);
+ result = mapping[num_score];
+ console.log("result is:", result);
+ return result;
+ };
+ });
+
+}).call(this);
diff --git a/wqflask/wqflask/static/new/js_external/parsley.min.js b/wqflask/wqflask/static/new/js_external/parsley.min.js
new file mode 100644
index 00000000..ab85c683
--- /dev/null
+++ b/wqflask/wqflask/static/new/js_external/parsley.min.js
@@ -0,0 +1,35 @@
+/* Parsley dist/parsley.min.js build version 1.1.18 http://parsleyjs.org */
+!function(d){var h=function(a){this.messages={defaultMessage:"This value seems to be invalid.",type:{email:"This value should be a valid email.",url:"This value should be a valid url.",urlstrict:"This value should be a valid url.",number:"This value should be a valid number.",digits:"This value should be digits.",dateIso:"This value should be a valid date (YYYY-MM-DD).",alphanum:"This value should be alphanumeric.",phone:"This value should be a valid phone number."},notnull:"This value should not be null.",
+notblank:"This value should not be blank.",required:"This value is required.",regexp:"This value seems to be invalid.",min:"This value should be greater than or equal to %s.",max:"This value should be lower than or equal to %s.",range:"This value should be between %s and %s.",minlength:"This value is too short. It should have %s characters or more.",maxlength:"This value is too long. It should have %s characters or less.",rangelength:"This value length is invalid. It should be between %s and %s characters long.",
+mincheck:"You must select at least %s choices.",maxcheck:"You must select %s choices or less.",rangecheck:"You must select between %s and %s choices.",equalto:"This value should be the same."};this.init(a)};h.prototype={constructor:h,validators:{notnull:function(a){return 0=b},maxlength:function(a,b){return a.length<=b},rangelength:function(a,b){return this.minlength(a,b[0])&&this.maxlength(a,b[1])},
+min:function(a,b){return Number(a)>=b},max:function(a,b){return Number(a)<=b},range:function(a,b){return a>=b[0]&&a<=b[1]},equalto:function(a,b,c){c.options.validateIfUnchanged=!0;return a===d(b).val()},remote:function(a,b,c){var f={},g={};f[c.$element.attr("name")]=a;"undefined"!==typeof c.options.remoteDatatype&&(g={dataType:c.options.remoteDatatype});var m=function(a,b){"undefined"!==typeof b&&("undefined"!==typeof c.Validator.messages.remote&&b!==c.Validator.messages.remote)&&d(c.ulError+" .remote").remove();
+c.updtConstraint({name:"remote",valid:a},b);c.manageValidationResult()},n=function(a){if("object"===typeof a)return a;try{a=d.parseJSON(a)}catch(b){}return a},e=function(a){return"object"===typeof a&&null!==a?"undefined"!==typeof a.error?a.error:"undefined"!==typeof a.message?a.message:null:null};d.ajax(d.extend({},{url:b,data:f,type:c.options.remoteMethod||"GET",success:function(a){a=n(a);m(1===a||!0===a||"object"===typeof a&&null!==a&&"undefined"!==typeof a.success,e(a))},error:function(a){a=n(a);
+m(!1,e(a))}},g));return null},mincheck:function(a,b){return this.minlength(a,b)},maxcheck:function(a,b){return this.maxlength(a,b)},rangecheck:function(a,b){return this.rangelength(a,b)}},init:function(a){var b=a.validators;a=a.messages;for(var c in b)this.addValidator(c,b[c]);for(c in a)this.addMessage(c,a[c])},formatMesssage:function(a,b){if("object"===typeof b){for(var c in b)a=this.formatMesssage(a,b[c]);return a}return"string"===typeof a?a.replace(/%s/i,b):""},addValidator:function(a,b){this.validators[a]=
+b},addMessage:function(a,b,c){if("undefined"!==typeof c&&!0===c)this.messages.type[a]=b;else if("type"===a)for(var d in b)this.messages.type[d]=b[d];else this.messages[a]=b}};var j=function(a,b,c){this.options=b;this.Validator=new h(b);if("ParsleyFieldMultiple"===c)return this;this.init(a,c||"ParsleyField")};j.prototype={constructor:j,init:function(a,b){this.type=b;this.valid=!0;this.element=a;this.validatedOnce=!1;this.$element=d(a);this.val=this.$element.val();this.isRequired=!1;this.constraints=
+{};"undefined"===typeof this.isRadioOrCheckbox&&(this.isRadioOrCheckbox=!1,this.hash=this.generateHash(),this.errorClassHandler=this.options.errors.classHandler(a,this.isRadioOrCheckbox)||this.$element);this.ulErrorManagement();this.bindHtml5Constraints();this.addConstraints();this.hasConstraints()&&this.bindValidationEvents()},setParent:function(a){this.$parent=d(a)},getParent:function(){return this.$parent},bindHtml5Constraints:function(){if(this.$element.hasClass("required")||this.$element.prop("required"))this.options.required=
+!0;"undefined"!==typeof this.$element.attr("type")&&RegExp(this.$element.attr("type"),"i").test("email url number range")&&(this.options.type=this.$element.attr("type"),RegExp(this.options.type,"i").test("number range")&&(this.options.type="number","undefined"!==typeof this.$element.attr("min")&&this.$element.attr("min").length&&(this.options.min=this.$element.attr("min")),"undefined"!==typeof this.$element.attr("max")&&this.$element.attr("max").length&&(this.options.max=this.$element.attr("max"))));
+"string"===typeof this.$element.attr("pattern")&&this.$element.attr("pattern").length&&(this.options.regexp=this.$element.attr("pattern"))},addConstraints:function(){for(var a in this.options){var b={};b[a]=this.options[a];this.addConstraint(b,!0)}},addConstraint:function(a,b){for(var c in a)c=c.toLowerCase(),"function"===typeof this.Validator.validators[c]&&(this.constraints[c]={name:c,requirements:a[c],valid:null},"required"===c&&(this.isRequired=!0),this.addCustomConstraintMessage(c));"undefined"===
+typeof b&&this.bindValidationEvents()},updateConstraint:function(a,b){for(var c in a)this.updtConstraint({name:c,requirements:a[c],valid:null},b)},updtConstraint:function(a,b){this.constraints[a.name]=d.extend(!0,this.constraints[a.name],a);"string"===typeof b&&(this.Validator.messages[a.name]=b);this.bindValidationEvents()},removeConstraint:function(a){a=a.toLowerCase();delete this.constraints[a];"required"===a&&(this.isRequired=!1);this.hasConstraints()?this.bindValidationEvents():"ParsleyForm"===
+typeof this.getParent()?this.getParent().removeItem(this.$element):this.destroy()},addCustomConstraintMessage:function(a){var b=a+("type"===a&&"undefined"!==typeof this.options[a]?this.options[a].charAt(0).toUpperCase()+this.options[a].substr(1):"")+"Message";"undefined"!==typeof this.options[b]&&this.Validator.addMessage("type"===a?this.options[a]:a,this.options[b],"type"===a)},bindValidationEvents:function(){this.valid=null;this.$element.addClass("parsley-validated");this.$element.off("."+this.type);
+this.options.remote&&!/change/i.test(this.options.trigger)&&(this.options.trigger=!this.options.trigger?"change":" change");var a=(!this.options.trigger?"":this.options.trigger)+(/key/i.test(this.options.trigger)?"":" keyup");this.$element.is("select")&&(a+=/change/i.test(a)?"":" change");a=a.replace(/^\s+/g,"").replace(/\s+$/g,"");this.$element.on((a+" ").split(" ").join("."+this.type+" "),!1,d.proxy(this.eventValidation,this))},generateHash:function(){return"parsley-"+(Math.random()+"").substring(2)},
+getHash:function(){return this.hash},getVal:function(){return this.$element.data("value")||this.$element.val()},eventValidation:function(a){var b=this.getVal();if("keyup"===a.type&&!/keyup/i.test(this.options.trigger)&&!this.validatedOnce||"change"===a.type&&!/change/i.test(this.options.trigger)&&!this.validatedOnce||!this.isRadioOrCheckbox&&this.getLength(b)",errorElem:""},listeners:{onFieldValidate:function(){return!1},onFormSubmit:function(){},onFieldError:function(){},onFieldSuccess:function(){}}};
+d(window).on("load",function(){d('[data-validate="parsley"]').each(function(){d(this).parsley()})})}(window.jQuery||window.Zepto);
diff --git a/wqflask/wqflask/static/new/js_external/zxcvbn/.gitignore b/wqflask/wqflask/static/new/js_external/zxcvbn/.gitignore
new file mode 100644
index 00000000..af1b4bc3
--- /dev/null
+++ b/wqflask/wqflask/static/new/js_external/zxcvbn/.gitignore
@@ -0,0 +1,2 @@
+*~
+*.js
--
cgit v1.2.3