From 7eef07f0caade5abc1ab1db0ee42e841dcbc1396 Mon Sep 17 00:00:00 2001
From: virusdefender <1670873886@qq.com>
Date: Sat, 15 Aug 2015 20:38:53 +0800
Subject: [PATCH 1/8] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AF=B9=E5=88=A4?=
=?UTF-8?q?=E9=A2=98=E8=B6=85=E6=97=B6=E7=9A=84=E6=8F=90=E7=A4=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
static/src/js/app/oj/problem/problem.js | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/static/src/js/app/oj/problem/problem.js b/static/src/js/app/oj/problem/problem.js
index 8e107bb..5b23c75 100644
--- a/static/src/js/app/oj/problem/problem.js
+++ b/static/src/js/app/oj/problem/problem.js
@@ -53,7 +53,14 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert"], function ($, codeMirro
return html;
}
+ var counter = 0;
+
function getResult() {
+ if(counter++ > 10){
+ hideLoading();
+ bsAlert("抱歉,服务器可能出现了故障,请稍后到我的提交列表中查看");
+ return;
+ }
$.ajax({
url: "/api/submission/?submission_id=" + submissionId,
method: "get",
@@ -85,7 +92,7 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert"], function ($, codeMirro
showLoading();
if(!code.trim()){
- bs_alert("请填写代码!");
+ bsAlert("请填写代码!");
hideLoading();
return false;
}
From 7e16a9feb88023a03363aee5be552a2f15b825fc Mon Sep 17 00:00:00 2001
From: virusdefender <1670873886@qq.com>
Date: Sat, 15 Aug 2015 20:40:54 +0800
Subject: [PATCH 2/8] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20waiting=20=E7=8A=B6?=
=?UTF-8?q?=E6=80=81=E4=B8=8B=E9=A2=9C=E8=89=B2=E9=94=99=E8=AF=AF=E7=9A=84?=
=?UTF-8?q?=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
utils/templatetags/submission.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/utils/templatetags/submission.py b/utils/templatetags/submission.py
index a1b30eb..86dd2d5 100644
--- a/utils/templatetags/submission.py
+++ b/utils/templatetags/submission.py
@@ -27,7 +27,7 @@ def translate_language(value):
def translate_result_class(value):
if value == 0:
return "success"
- elif value == "8":
+ elif value == 8:
return "info"
return "danger"
From a6bd787b86bdc96ef1a65558403a4956bfd98e86 Mon Sep 17 00:00:00 2001
From: virusdefender <1670873886@qq.com>
Date: Sat, 15 Aug 2015 23:46:25 +0800
Subject: [PATCH 3/8] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20celery=20=E9=85=8D?=
=?UTF-8?q?=E7=BD=AE=E6=96=87=E4=BB=B6=E6=A0=BC=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
judge/judger_controller/celery.py | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/judge/judger_controller/celery.py b/judge/judger_controller/celery.py
index 6befedf..5b90bdb 100644
--- a/judge/judger_controller/celery.py
+++ b/judge/judger_controller/celery.py
@@ -3,8 +3,7 @@ from __future__ import absolute_import
from celery import Celery
from .settings import redis_config
-app = Celery("judge", broker="redis://" +
- redis_config["host"] + ":" +
- str(redis_config["port"]) +
- "/" + str(redis_config["db"]),
+app = Celery("judge", broker='redis://%s:%s/%s' % (redis_config["host"], redis_config["port"], redis_config["db"]),
include=["judge.judger_controller.tasks"])
+
+Celery().conf.update(CELERY_ACCEPT_CONTENT = ['json'])
\ No newline at end of file
From 884d3ff980fceead968f64ed6c94782b222cfc68 Mon Sep 17 00:00:00 2001
From: virusdefender <1670873886@qq.com>
Date: Sat, 15 Aug 2015 23:46:40 +0800
Subject: [PATCH 4/8] =?UTF-8?q?=E9=81=BF=E5=85=8D=E7=A1=AC=E7=BC=96?=
=?UTF-8?q?=E7=A0=81=E7=BD=91=E7=AB=99=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
template/oj_base.html | 6 +++---
utils/templatetags/website_info.py | 8 ++++++++
2 files changed, 11 insertions(+), 3 deletions(-)
create mode 100644 utils/templatetags/website_info.py
diff --git a/template/oj_base.html b/template/oj_base.html
index fd8321b..082cad5 100644
--- a/template/oj_base.html
+++ b/template/oj_base.html
@@ -16,7 +16,7 @@
{% block css_block %}{% endblock %}
-
+{% load website_info %}
@@ -38,7 +38,7 @@
- qduoj
+ {% show_website_info "website_name" %}
@@ -88,7 +88,7 @@
{% block js_block %}{% endblock %}
diff --git a/utils/templatetags/website_info.py b/utils/templatetags/website_info.py
new file mode 100644
index 0000000..e071b2e
--- /dev/null
+++ b/utils/templatetags/website_info.py
@@ -0,0 +1,8 @@
+# coding=utf-8
+from django import template
+register = template.Library()
+
+
+@register.simple_tag
+def show_website_info(name):
+ return {"website_name": "qduoj", "website_footer": u"青岛大学创新实验室"}[name]
From d5ab12bb322d1f6bb4ffa72956ad32fe89e0194c Mon Sep 17 00:00:00 2001
From: virusdefender <1670873886@qq.com>
Date: Sat, 15 Aug 2015 23:46:52 +0800
Subject: [PATCH 5/8] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81?=
=?UTF-8?q?=E6=A0=BC=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
utils/templatetags/submission.py | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/utils/templatetags/submission.py b/utils/templatetags/submission.py
index 86dd2d5..12bf267 100644
--- a/utils/templatetags/submission.py
+++ b/utils/templatetags/submission.py
@@ -1,4 +1,5 @@
# coding=utf-8
+from django import template
def translate_result(value):
@@ -32,9 +33,6 @@ def translate_result_class(value):
return "danger"
-from django import template
-
-
register = template.Library()
register.filter("translate_result", translate_result)
register.filter("translate_id", translate_id)
From a36268bcc812352d53d85a7f0f760a3fde8e1615 Mon Sep 17 00:00:00 2001
From: virusdefender <1670873886@qq.com>
Date: Sun, 16 Aug 2015 08:47:03 +0800
Subject: [PATCH 6/8] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=85=8D=E7=BD=AE?=
=?UTF-8?q?=E9=A1=B9=E7=9B=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
judge/judger_controller/settings.py | 2 +-
oj/local_settings.py | 2 +-
utils/templatetags/website_info.py | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/judge/judger_controller/settings.py b/judge/judger_controller/settings.py
index 7964832..2c69d80 100644
--- a/judge/judger_controller/settings.py
+++ b/judge/judger_controller/settings.py
@@ -1,6 +1,6 @@
# coding=utf-8
redis_config = {
- "host": "121.42.196.141",
+ "host": "121.42.32.129",
"port": 6379,
"db": 0
}
diff --git a/oj/local_settings.py b/oj/local_settings.py
index 7963e7a..2d84f67 100644
--- a/oj/local_settings.py
+++ b/oj/local_settings.py
@@ -18,7 +18,7 @@ DATABASES = {
# 这是web 服务器连接到mongodb 的地址
MONGODB = {
- 'HOST': '121.42.196.141',
+ 'HOST': '121.42.32.129',
'USERNAME': 'root',
'PASSWORD': 'root',
'PORT': 27017
diff --git a/utils/templatetags/website_info.py b/utils/templatetags/website_info.py
index e071b2e..85b6c23 100644
--- a/utils/templatetags/website_info.py
+++ b/utils/templatetags/website_info.py
@@ -5,4 +5,4 @@ register = template.Library()
@register.simple_tag
def show_website_info(name):
- return {"website_name": "qduoj", "website_footer": u"青岛大学创新实验室"}[name]
+ return {"website_name": "qduoj", "website_footer": u"青岛大学信息工程学院 创新实验室"}[name]
From 83ad1e9f3c4a4f004b298a824ff12c996ce2b6d6 Mon Sep 17 00:00:00 2001
From: virusdefender <1670873886@qq.com>
Date: Sun, 16 Aug 2015 12:14:56 +0800
Subject: [PATCH 7/8] =?UTF-8?q?=E6=9B=BF=E6=8D=A2=E6=8E=89=E5=95=86?=
=?UTF-8?q?=E4=B8=9A=E7=89=88=E7=9A=84=20formvalidation?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
account/serializers.py | 2 +-
.../src/js/app/oj/account/change_password.js | 85 ++---
static/src/js/app/oj/account/login.js | 32 +-
static/src/js/app/oj/account/register.js | 85 +----
static/src/js/config.js | 4 +-
static/src/js/lib/validator/validator.js | 325 ++++++++++++++++++
template/oj/account/change_password.html | 15 +-
template/oj/account/login.html | 7 +-
template/oj/account/register.html | 16 +-
9 files changed, 387 insertions(+), 184 deletions(-)
create mode 100644 static/src/js/lib/validator/validator.js
diff --git a/account/serializers.py b/account/serializers.py
index 358ced7..9a43457 100644
--- a/account/serializers.py
+++ b/account/serializers.py
@@ -26,7 +26,7 @@ class UserRegisterSerializer(serializers.Serializer):
class UserChangePasswordSerializer(serializers.Serializer):
username = serializers.CharField(max_length=30)
- old_password = serializers.CharField(max_length=30, min_length=6)
+ old_password = serializers.CharField()
new_password = serializers.CharField(max_length=30, min_length=6)
diff --git a/static/src/js/app/oj/account/change_password.js b/static/src/js/app/oj/account/change_password.js
index 8129fb1..ba88f5f 100644
--- a/static/src/js/app/oj/account/change_password.js
+++ b/static/src/js/app/oj/account/change_password.js
@@ -1,68 +1,25 @@
-require(["jquery", "bsAlert", "csrfToken", "formValidation"], function ($, bsAlert, csrfTokenHeader) {
- $("#change_password-form").formValidation({
- framework: "bootstrap",
- fields: {
- username: {
- validators: {
- notEmpty: {
- message: "请填写用户名"
- }
- }
- },
- password: {
- validators: {
- notEmpty: {
- message: "请填写旧密码"
- }
- }
- },
- new_password: {
- validators: {
- notEmpty: {
- message: "请填写新密码"
- },
- stringLength: {
- min: 6,
- max: 30,
- message: '密码长度必须在6到30位之间'
- }
- },
- onSuccess: function (e, data) {
- data.fv.revalidateField('confirm_password');
- }
- },
- confirm_password: {
- validators: {
- notEmpty: {
- message: "请填写确认密码"
- },
- confirm: {
- original: $("#new_password"),
- message: "两次输入的密码必须一致"
- }
- }
+require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, csrfTokenHeader) {
+
+ $('form').validator().on('submit', function (e) {
+ e.preventDefault();
+ var username = $("#username").val();
+ var newPassword = $("#new_password ").val();
+ var password = $("#password").val();
+ $.ajax({
+ beforeSend: csrfTokenHeader,
+ url: "/api/change_password/",
+ data: {username: username, new_password: newPassword, old_password: password},
+ dataType: "json",
+ method: "post",
+ success: function (data) {
+ if (!data.code) {
+ window.location.href = "/login/";
+ }
+ else {
+ bsAlert(data.data);
}
}
- }
- ).on('success.form.fv', function (e) {
- e.preventDefault();
- var username = $("#username").val();
- var newPassword = $("#new_password ").val();
- var password = $("#password").val();
- $.ajax({
- beforeSend: csrfTokenHeader,
- url: "/api/change_password/",
- data: {username: username, new_password: newPassword, old_password: password},
- dataType: "json",
- method: "post",
- success: function (data) {
- if (!data.code) {
- window.location.href = "/login/";
- }
- else {
- bsAlert(data.data);
- }
- }
- })
});
+ return false;
+ });
});
\ No newline at end of file
diff --git a/static/src/js/app/oj/account/login.js b/static/src/js/app/oj/account/login.js
index ca84975..5ef83b9 100644
--- a/static/src/js/app/oj/account/login.js
+++ b/static/src/js/app/oj/account/login.js
@@ -1,26 +1,6 @@
-require(["jquery", "bsAlert", "csrfToken", "formValidation"], function ($, bsAlert, csrfTokenHeader) {
- $("#login-form")
- .formValidation({
- framework: "bootstrap",
- fields: {
- username: {
- validators: {
- notEmpty: {
- message: "请填写用户名"
- }
- }
- },
- password: {
- validators: {
- notEmpty: {
- message: "请填写密码"
- }
- }
- }
- }
- }
- ).on('success.form.fv', function (e) {
- e.preventDefault();
+require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, csrfTokenHeader) {
+ $('form').validator().on('submit', function (e) {
+ if (!e.isDefaultPrevented()) {
var username = $("#username").val();
var password = $("#password").val();
$.ajax({
@@ -38,6 +18,8 @@ require(["jquery", "bsAlert", "csrfToken", "formValidation"], function ($, bsAle
}
}
- })
- });
+ });
+ return false;
+ }
+ })
});
\ No newline at end of file
diff --git a/static/src/js/app/oj/account/register.js b/static/src/js/app/oj/account/register.js
index bd00fb8..9537fdb 100644
--- a/static/src/js/app/oj/account/register.js
+++ b/static/src/js/app/oj/account/register.js
@@ -1,83 +1,12 @@
-require(["jquery", "bsAlert", "csrfToken", "validation"], function ($, bsAlert, csrfTokenHeader) {
- $("#register-form")
- .formValidation({
- framework: "bootstrap",
- fields: {
- username: {
- validators: {
- notEmpty: {
- message: "请填写用户名"
- },
- stringLength: {
- min: 3,
- max: 30,
- message: '用户名长度必须在3到30位之间'
- },
- remote: {
- message: "用户名已存在",
- url: "/api/username_check/",
- field: 'username'
- }
- }
- },
- password: {
- validators: {
- notEmpty: {
- message: "请填写密码"
- },
- stringLength: {
- min: 6,
- max: 30,
- message: '密码长度必须在6到30位之间'
- }
- },
- onSuccess: function (e, data) {
- data.fv.revalidateField('confirm_password');
- }
- },
- real_name: {
- validators: {
- notEmpty: {
- message: "请填写真实姓名"
- }
- }
- },
- confirm_password: {
- validators: {
- notEmpty: {
- message: "请填写确认密码"
- },
- confirm: {
- original: $("#password"),
- message: "两次输入的密码必须一致"
- }
- }
- },
- email: {
- validators: {
- notEmpty: {
- message: "请填写电子邮箱邮箱地址"
- },
- emailAddress: {
- message: "请填写有效的邮箱地址"
- },
- remote: {
- message: "您已经注册过了",
- url: "/api/email_check/",
- field: 'email'
- }
- }
- }
- }
- }
- ).on('success.form.fv', function (e) {
- e.preventDefault();
+require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, csrfTokenHeader) {
+ $('form').validator().on('submit', function (e) {
+ if (!e.isDefaultPrevented()) {
var username = $("#username").val();
var realName = $("#real_name").val();
var password = $("#password").val();
var email = $("#email").val();
$.ajax({
- beforeSend: csrfHeader,
+ beforeSend: csrfTokenHeader,
url: "/api/register/",
data: {username: username, real_name: realName, password: password, email: email},
dataType: "json",
@@ -90,6 +19,8 @@ require(["jquery", "bsAlert", "csrfToken", "validation"], function ($, bsAlert,
bsAlert(data.data);
}
}
- })
- });
+ });
+ return false;
+ }
+ })
});
\ No newline at end of file
diff --git a/static/src/js/config.js b/static/src/js/config.js
index d74fcdd..8b14e0e 100644
--- a/static/src/js/config.js
+++ b/static/src/js/config.js
@@ -19,6 +19,7 @@ var require = {
jqueryUI: "lib/jqueryUI/jquery-ui",
bootstrap: "lib/bootstrap/bootstrap",
datetimePicker: "lib/datetime_picker/bootstrap-datetimepicker.zh-CN",
+ validator: "lib/validator/validator",
// ------ 下面写的都不要直接用,而是使用上面的封装版本 ------
@@ -55,6 +56,7 @@ var require = {
shim: {
bootstrap: {deps: ["jquery"]},
_datetimePicker: {dep: ["jquery"]},
- datetimePicker: {deps: ["_datetimePicker"]}
+ datetimePicker: {deps: ["_datetimePicker"]},
+ validator: ["jquery"]
}
};
\ No newline at end of file
diff --git a/static/src/js/lib/validator/validator.js b/static/src/js/lib/validator/validator.js
new file mode 100644
index 0000000..687d983
--- /dev/null
+++ b/static/src/js/lib/validator/validator.js
@@ -0,0 +1,325 @@
+/* ========================================================================
+ * Bootstrap (plugin): validator.js v0.9.0
+ * ========================================================================
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Cina Saffary.
+ * Made by @1000hz in the style of Bootstrap 3 era @fat
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // VALIDATOR CLASS DEFINITION
+ // ==========================
+
+ var Validator = function (element, options) {
+ this.$element = $(element)
+ this.options = options
+
+ options.errors = $.extend({}, Validator.DEFAULTS.errors, options.errors)
+
+ for (var custom in options.custom) {
+ if (!options.errors[custom]) throw new Error('Missing default error message for custom validator: ' + custom)
+ }
+
+ $.extend(Validator.VALIDATORS, options.custom)
+
+ this.$element.attr('novalidate', true) // disable automatic native validation
+ this.toggleSubmit()
+
+ this.$element.on('input.bs.validator change.bs.validator focusout.bs.validator', $.proxy(this.validateInput, this))
+ this.$element.on('submit.bs.validator', $.proxy(this.onSubmit, this))
+
+ this.$element.find('[data-match]').each(function () {
+ var $this = $(this)
+ var target = $this.data('match')
+
+ $(target).on('input.bs.validator', function (e) {
+ $this.val() && $this.trigger('input.bs.validator')
+ })
+ })
+ }
+
+ Validator.INPUT_SELECTOR = ':input:not([type="submit"], button):enabled:visible'
+
+ Validator.DEFAULTS = {
+ delay: 500,
+ html: false,
+ disable: true,
+ custom: {},
+ errors: {
+ match: 'Does not match',
+ minlength: 'Not long enough'
+ },
+ feedback: {
+ success: 'glyphicon-ok',
+ error: 'glyphicon-remove'
+ }
+ }
+
+ Validator.VALIDATORS = {
+ 'native': function ($el) {
+ var el = $el[0]
+ return el.checkValidity ? el.checkValidity() : true
+ },
+ 'match': function ($el) {
+ var target = $el.data('match')
+ return !$el.val() || $el.val() === $(target).val()
+ },
+ 'minlength': function ($el) {
+ var minlength = $el.data('minlength')
+ return !$el.val() || $el.val().length >= minlength
+ }
+ }
+
+ Validator.prototype.validateInput = function (e) {
+ var $el = $(e.target)
+ var prevErrors = $el.data('bs.validator.errors')
+ var errors
+
+ if ($el.is('[type="radio"]')) $el = this.$element.find('input[name="' + $el.attr('name') + '"]')
+
+ this.$element.trigger(e = $.Event('validate.bs.validator', {relatedTarget: $el[0]}))
+
+ if (e.isDefaultPrevented()) return
+
+ var self = this
+
+ this.runValidators($el).done(function (errors) {
+ $el.data('bs.validator.errors', errors)
+
+ errors.length ? self.showErrors($el) : self.clearErrors($el)
+
+ if (!prevErrors || errors.toString() !== prevErrors.toString()) {
+ e = errors.length
+ ? $.Event('invalid.bs.validator', {relatedTarget: $el[0], detail: errors})
+ : $.Event('valid.bs.validator', {relatedTarget: $el[0], detail: prevErrors})
+
+ self.$element.trigger(e)
+ }
+
+ self.toggleSubmit()
+
+ self.$element.trigger($.Event('validated.bs.validator', {relatedTarget: $el[0]}))
+ })
+ }
+
+
+ Validator.prototype.runValidators = function ($el) {
+ var errors = []
+ var deferred = $.Deferred()
+ var options = this.options
+
+ $el.data('bs.validator.deferred') && $el.data('bs.validator.deferred').reject()
+ $el.data('bs.validator.deferred', deferred)
+
+ function getErrorMessage(key) {
+ return $el.data(key + '-error')
+ || $el.data('error')
+ || key == 'native' && $el[0].validationMessage
+ || options.errors[key]
+ }
+
+ $.each(Validator.VALIDATORS, $.proxy(function (key, validator) {
+ if (($el.data(key) || key == 'native') && !validator.call(this, $el)) {
+ var error = getErrorMessage(key)
+ !~errors.indexOf(error) && errors.push(error)
+ }
+ }, this))
+
+ if (!errors.length && $el.val() && $el.data('remote')) {
+ this.defer($el, function () {
+ var data = {}
+ data[$el.attr('name')] = $el.val()
+ $.get($el.data('remote'), data)
+ .fail(function (jqXHR, textStatus, error) { errors.push(getErrorMessage('remote') || error) })
+ .always(function () { deferred.resolve(errors)})
+ })
+ } else deferred.resolve(errors)
+
+ return deferred.promise()
+ }
+
+ Validator.prototype.validate = function () {
+ var delay = this.options.delay
+
+ this.options.delay = 0
+ this.$element.find(Validator.INPUT_SELECTOR).trigger('input.bs.validator')
+ this.options.delay = delay
+
+ return this
+ }
+
+ Validator.prototype.showErrors = function ($el) {
+ var method = this.options.html ? 'html' : 'text'
+
+ this.defer($el, function () {
+ var $group = $el.closest('.form-group')
+ var $block = $group.find('.help-block.with-errors')
+ var $feedback = $group.find('.form-control-feedback')
+ var errors = $el.data('bs.validator.errors')
+
+ if (!errors.length) return
+
+ errors = $('')
+ .addClass('list-unstyled')
+ .append($.map(errors, function (error) { return $('')[method](error) }))
+
+ $block.data('bs.validator.originalContent') === undefined && $block.data('bs.validator.originalContent', $block.html())
+ $block.empty().append(errors)
+ $group.addClass('has-error')
+
+ $feedback.length
+ && $feedback.removeClass(this.options.feedback.success)
+ && $feedback.addClass(this.options.feedback.error)
+ && $group.removeClass('has-success')
+ })
+ }
+
+ Validator.prototype.clearErrors = function ($el) {
+ var $group = $el.closest('.form-group')
+ var $block = $group.find('.help-block.with-errors')
+ var $feedback = $group.find('.form-control-feedback')
+
+ $block.html($block.data('bs.validator.originalContent'))
+ $group.removeClass('has-error')
+
+ $feedback.length
+ && $feedback.removeClass(this.options.feedback.error)
+ && $feedback.addClass(this.options.feedback.success)
+ && $group.addClass('has-success')
+ }
+
+ Validator.prototype.hasErrors = function () {
+ function fieldErrors() {
+ return !!($(this).data('bs.validator.errors') || []).length
+ }
+
+ return !!this.$element.find(Validator.INPUT_SELECTOR).filter(fieldErrors).length
+ }
+
+ Validator.prototype.isIncomplete = function () {
+ function fieldIncomplete() {
+ return this.type === 'checkbox' ? !this.checked :
+ this.type === 'radio' ? !$('[name="' + this.name + '"]:checked').length :
+ $.trim(this.value) === ''
+ }
+
+ return !!this.$element.find(Validator.INPUT_SELECTOR).filter('[required]').filter(fieldIncomplete).length
+ }
+
+ Validator.prototype.onSubmit = function (e) {
+ this.validate()
+ if (this.isIncomplete() || this.hasErrors()) e.preventDefault()
+ }
+
+ Validator.prototype.toggleSubmit = function () {
+ if(!this.options.disable) return
+
+ var $btn = $('button[type="submit"], input[type="submit"]')
+ .filter('[form="' + this.$element.attr('id') + '"]')
+ .add(this.$element.find('input[type="submit"], button[type="submit"]'))
+
+ $btn.toggleClass('disabled', this.isIncomplete() || this.hasErrors())
+ }
+
+ Validator.prototype.defer = function ($el, callback) {
+ callback = $.proxy(callback, this)
+ if (!this.options.delay) return callback()
+ window.clearTimeout($el.data('bs.validator.timeout'))
+ $el.data('bs.validator.timeout', window.setTimeout(callback, this.options.delay))
+ }
+
+ Validator.prototype.destroy = function () {
+ this.$element
+ .removeAttr('novalidate')
+ .removeData('bs.validator')
+ .off('.bs.validator')
+
+ this.$element.find(Validator.INPUT_SELECTOR)
+ .off('.bs.validator')
+ .removeData(['bs.validator.errors', 'bs.validator.deferred'])
+ .each(function () {
+ var $this = $(this)
+ var timeout = $this.data('bs.validator.timeout')
+ window.clearTimeout(timeout) && $this.removeData('bs.validator.timeout')
+ })
+
+ this.$element.find('.help-block.with-errors').each(function () {
+ var $this = $(this)
+ var originalContent = $this.data('bs.validator.originalContent')
+
+ $this
+ .removeData('bs.validator.originalContent')
+ .html(originalContent)
+ })
+
+ this.$element.find('input[type="submit"], button[type="submit"]').removeClass('disabled')
+
+ this.$element.find('.has-error').removeClass('has-error')
+
+ return this
+ }
+
+ // VALIDATOR PLUGIN DEFINITION
+ // ===========================
+
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var options = $.extend({}, Validator.DEFAULTS, $this.data(), typeof option == 'object' && option)
+ var data = $this.data('bs.validator')
+
+ if (!data && option == 'destroy') return
+ if (!data) $this.data('bs.validator', (data = new Validator(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.validator
+
+ $.fn.validator = Plugin
+ $.fn.validator.Constructor = Validator
+
+
+ // VALIDATOR NO CONFLICT
+ // =====================
+
+ $.fn.validator.noConflict = function () {
+ $.fn.validator = old
+ return this
+ }
+
+
+ // VALIDATOR DATA-API
+ // ==================
+
+ $(window).on('load', function () {
+ $('form[data-toggle="validator"]').each(function () {
+ var $form = $(this)
+ Plugin.call($form, $form.data())
+ })
+ })
+
+}(jQuery);
diff --git a/template/oj/account/change_password.html b/template/oj/account/change_password.html
index 1e6a5cb..039cb73 100644
--- a/template/oj/account/change_password.html
+++ b/template/oj/account/change_password.html
@@ -7,22 +7,23 @@