Merge pull request #1 from eshengsky/master

同步代码
This commit is contained in:
振云 (Percy)
2018-08-30 16:40:01 +08:00
committed by GitHub
455 changed files with 102570 additions and 2770 deletions

View File

@@ -1,3 +0,0 @@
{
"directory": "public/libs"
}

7
.gitignore vendored
View File

@@ -1,5 +1,4 @@
node_modules/ node_modules
*.log *.log
public/libs .idea
.idea/ .vscode
.gitignore

174
README.md
View File

@@ -1,116 +1,148 @@
# iBlog2 # iBlog2
基于 Node.js 的个人开源博客系统,采用响应式布局,支持移动设备直接访问,功能全面,美观大方。 基于 Node.js 的开源个人开源博客系统,采用响应式布局,支持手机访问,功能全面,美观大方。
_不仅仅是博客,更是 Demo_,适合新人入门学习的完整项目。 **不仅仅是博客,更是 Demo**适合新人入门学习的完整项目。
基于 ASP.NET 的版本请点击[这里](https://github.com/eshengsky/iBlog/) (基于 ASP.NET 的版本[这里](https://github.com/eshengsky/iBlog/))
## 在线实例 ## 在线实例
个人博客 [http://www.skysun.name/](http://www.skysun.name/) 我的博客 [http://139.196.22.226/](http://139.196.22.226/)
## 分支说明 ## [noginx](https://github.com/eshengsky/noginx)
当前项目分为 [master](https://github.com/eshengsky/iBlog2/tree/master) 分支和 [Jade-template](https://github.com/eshengsky/iBlog2/tree/Jade-template) 分支,唯一的区别在于 master 分支使用的是我自己写的 [Saker](https://github.com/eshengsky/saker) 模板引擎Jade-template 分支使用的 [Jade](https://pugjs.org/) 模板引擎 [noginx](https://github.com/eshengsky/noginx) 是基于 Node.js 的 HTTP 及反向代理服务器(类似 nginx如果你有多台 iBlog2 服务器实例,你可以使用 [noginx](https://github.com/eshengsky/noginx) 进行代理转发和负载均衡
## [Wiki](https://github.com/eshengsky/iBlog2/wiki) ## [Wiki](https://github.com/eshengsky/iBlog2/wiki)
整理了 iBlog2 中涉及 Node.js 及部分前端技术的基本功能与知识点,适合新手学习、备查。 整理了 iBlog2 中涉及 Node.js 及部分前端技术的知识点,适合新手学习、备查。
## 功能模块 ## 功能模块
#### 博客 * 文章列表
* 文章列表页 * 支持搜索
* 文章详细页 * 创新的竖向分页
* 文章详情
#### 留言 * 自动生成目录
#### 关于 * 支持评论 (基于[畅言](http://changyan.kuaizhan.com/))
#### 后台管理 * 留言
* 网站统计 * 关于
* 博客管理 - 新的文章 * 后台管理
* 博客管理 - 分类管理 * 网站统计
* 博客管理 - 文章管理 * 博客管理 - 新的文章 (支持 UEditor 和 Markdown 编辑器)
* 评论管理 * 博客管理 - 分类管理
* 留言管理 * 博客管理 - 文章管理
* 关于管理 * 评论管理
* 缓存管理 * 留言管理
* 异常管理 * 关于管理
* 系统设置 * 缓存管理
* 异常管理
* 系统设置
## 技术构成 ## 技术构成
* 服务端 [Node.js](https://nodejs.org/) * 服务端 [Node.js](https://nodejs.org/)
* web框架 [Express 4](http://expressjs.com/) * web框架 [Express 4](http://expressjs.com/)
* 模板引擎 [Saker](https://github.com/eshengsky/saker) (master分支) / [Jade](https://pugjs.org/) (Jade-template分支) * 模板引擎 [Pug](https://pugjs.org/)
* JS库 [jQuery](http://jquery.com/) * JS库 [jQuery](http://jquery.com/)
* UI库 [Bootstrap 3](http://getbootstrap.com/) * UI库 [Bootstrap 3](http://getbootstrap.com/)
* Web字体 [Font Awesome](https://fontawesome.com/)
* 持久化 [MongoDB](https://www.mongodb.org/) * 持久化 [MongoDB](https://www.mongodb.org/)
* 缓存可选 [Redis](http://redis.io/) * 缓存(可选) [Redis](http://redis.io/)
* 日志 [winston](https://github.com/winstonjs/winston/) * 日志 [winston](https://github.com/winstonjs/winston/)
* 多语言 [i18n](https://github.com/mashpie/i18n-node)
* 身份验证 [Passport](http://www.passportjs.org/)
## 快速开始 ## 快速开始
#### 准备条件 #### 准备条件
安装最新版[Node.js](https://nodejs.org/en/download/)、[bower](http://bower.io/)、[MongoDB](https://www.mongodb.org/downloads/)、[Redis](http://redis.io/download/)(可选)。 安装 [Node.js](https://nodejs.org/en/download/) (v6 以上版本)、[MongoDB](https://www.mongodb.org/downloads/)、[Redis](http://redis.io/download/)(可选)。
如果使用Windows平台可以去[https://github.com/MSOpenTech/redis/releases](https://github.com/MSOpenTech/redis/releases)下载安装Redis 如果使用Windows平台可以去[https://github.com/MSOpenTech/redis/releases](https://github.com/MSOpenTech/redis/releases)下载安装Redis
#### 安装依赖 #### 安装依赖
* 服务端依赖
```Shell ```Shell
$ npm install $ npm install
``` ```
* 客户端依赖
```Shell
$ bower install
```
#### 参数配置
根据实际情况修改 config.json 配置文件DbPath 是 MongoDB 路径Redis 是缓存配置Redis.Active 表示是否启用Redis缓存默认不开启Redis.Host 表示 Redis 服务器 ip 地址Redis.Port 表示 Redis 端口号。
```JSON
{
"DbPath": "mongodb://localhost/iBlog2",
"Redis": {
"Active": false,
"Host": "127.0.0.1",
"Port": 6379
}
}
```
后台管理员账号信息在 config/account.json 中配置,默认管理员账号 admin ,密码 123456 ,密码需[md5加密](http://md5jiami.51240.com/)存储。
```JSON
{
"Id": "1",
"UserName": "admin",
"Password": "e10adc3949ba59abbe56e057f20f883e"
}
```
在 "后台管理-系统设置" 页面中,支持以可视化方式配置其余参数。
#### 启动站点 #### 启动站点
*注意对于node v4及以下版本需要添加 --harmony-proxies 参数。*
* 方式1普通模式启动
```Shell ```Shell
$ node ./bin/www $ node bin/www
```
* 方式2快速启动
```Shell
$ npm start
```
* 方式3守护进程启动
_守护进程能够发挥多核CPU性能并在出现异常退出后延迟30秒自动重启工作进程。_
```Shell
$ node daemon.js
``` ```
打开浏览器,访问 [http://localhost:3000/](http://localhost:3000) 打开浏览器,访问 [http://localhost:3000/](http://localhost:3000)
#### Enjoy it! :smile: #### Enjoy it! :smile:
## 配置说明
### 系统配置
根据实际情况修改 `/config.json` 配置文件,修改后需要重启服务器。参数说明:
##### ssl
Object 类型SSL 安全设置。
##### ssl.enable
Boolean 类型,是否创建 HTTPS 站点。
##### ssl.key
String 类型,私钥文件路径。
##### ssl.cert
String 类型,证书文件路径。
##### mongoUrl
String 类型MongoDB 连接字符串。
##### redis
Object 类型Redis 缓存设置。
##### redis.enable
Boolean 类型,是否启用缓存功能。
##### redis.host
String 类型Redis 服务器host。
##### redis.port
Number 类型Redis 服务器端口号。
### 用户配置
后台管理员账号信息在 `/config/account.json` 中配置,修改后需要重启服务器。参数说明:
##### Id
String 类型,管理员账号唯一标识。
##### UserName
String 类型,管理员账号用户名。
##### Password
String 类型,管理员账号密码,必须是 md5 加密后的字符串。
### 站点配置
以管理员身份登录后台 [http://localhost:3000/admin](http://localhost:3000/admin) ,在系统设置页面,支持以可视化方式配置相关参数,修改参数后不需要重启。
## 关于缓存 ## 关于缓存
文章分类、文章列表、文章详细等都作了缓存处理,若想使修改立即可见,需要在"后台管理-缓存管理"页面手动清除缓存。
如果开启了缓存功能,在缓存有效期内,文章分类、文章列表、文章详细等数据都将从缓存中获取,若想使修改立即可见,你需要在 "后台管理 - 缓存管理" 页面手动清除相关缓存。
## 线上部署 ## 线上部署
推荐使用 [pm2](https://github.com/Unitech/pm2) 进行线上Node.js的进程管理和持久运行。
#### 安装 #### 使用守护进程
iBlog2 自带的守护进程能够利用多核 CPU 性能,并在出现异常退出后自动重启服务。
```Shell
$ NODE_ENV=production node daemon.js
```
#### 使用PM2
推荐使用 [pm2](https://github.com/Unitech/pm2) 进行 Node.js 的进程管理和持久运行,其基本原理与上述守护进程一致。
##### 安装
```Shell ```Shell
$ npm install -g pm2 $ npm install -g pm2
``` ```
#### 使用 ##### 启动
```Shell ```Shell
$ pm2 start ./bin/www $ NODE_ENV=production pm2 start bin/www -i 0
``` ```
#### 使用noginx
[noginx](https://github.com/eshengsky/noginx) 是基于 Node.js 的 HTTP 及反向代理服务器(类似 nginx如果你有多台 iBlog2 服务器实例,你可以使用 [noginx](https://github.com/eshengsky/noginx) 进行代理转发和负载均衡。
## 贡献者们 ## 贡献者们
感谢给 iBlog2 项目贡献代码的朋友,感谢他们的支持,详情[点击这里](https://github.com/eshengsky/iBlog2/graphs/contributors)。 感谢给 iBlog2 项目贡献代码的朋友,感谢他们的支持,详情 [点击这里](https://github.com/eshengsky/iBlog2/graphs/contributors)。
## 许可协议 ## 许可协议
The MIT License (MIT) The MIT License (MIT)

120
app.js
View File

@@ -1,41 +1,63 @@
var express = require('express'); const express = require('express');
var path = require('path'); const path = require('path');
var favicon = require('serve-favicon'); const favicon = require('serve-favicon');
var morgan = require('morgan'); const cookieParser = require('cookie-parser');
var cookieParser = require('cookie-parser'); const session = require('express-session');
var session = require('express-session'); const bodyParser = require('body-parser');
var bodyParser = require('body-parser'); const helmet = require('helmet');
var route = require('./routes/index'); const route = require('./routes/index');
var blog = require('./routes/blog'); const blog = require('./routes/blog');
var misc = require('./routes/misc'); const misc = require('./routes/misc');
var auth = require('./routes/auth'); const auth = require('./routes/auth');
var admin = require('./routes/admin'); const admin = require('./routes/admin');
var locale = require('./routes/locale'); const locale = require('./routes/locale');
var ue = require('./routes/ue'); const ue = require('./routes/ue');
var logger = require('./utility/logger'); const logger = require('./utility/logger');
var passport = require('passport'); const passport = require('passport');
var i18n = require('./models/i18n'); const i18n = require('./models/i18n');
var saker = require('saker'); const app = express();
saker.config({
defaultLayout: './shared/layout.html', /**
partialViewDir: './views/shared/' * 记录未捕获异常
*/
process.on('uncaughtException', err => {
logger.errLogger(err);
}); });
var app = express();
// view engine setup /**
app.engine('html', saker.renderView); * 记录未处理的Promise失败
*/
process.on('unhandledRejection', reason => {
logger.errLogger(err);
});
// 设置模板引擎
app.set('views', path.join(__dirname, 'views')); app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'html'); app.set('view engine', 'pug');
// uncomment after placing your favicon in /public // 增加安全性头部
app.use(helmet());
// 记录所有请求
app.use((req, res, next) => {
logger.info(`${req.method.toUpperCase()}: ${req.protocol}://${req.get('Host')}${req.originalUrl}`);
next();
});
// 网站 Icon
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(morgan('dev'));
// parse body
app.use(bodyParser.json()); app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false})); app.use(bodyParser.urlencoded({ extended: false }));
// parse cookie
app.use(cookieParser()); app.use(cookieParser());
// i18n init parses req for language headers, cookies, etc.
// 多语言
app.use(i18n.init); app.use(i18n.init);
// 设置 Session
app.use(session({ app.use(session({
secret: 'iblog-exp-session', secret: 'iblog-exp-session',
cookie: { cookie: {
@@ -44,36 +66,44 @@ app.use(session({
resave: false, resave: false,
saveUninitialized: false saveUninitialized: false
})); }));
app.use(express.static(path.join(__dirname, 'public')));
app.use(passport.initialize()); app.use(passport.initialize());
app.use(passport.session()); app.use(passport.session());
// 静态文件
app.use('/static', express.static(path.join(__dirname, 'public')));
app.use('/static', express.static(path.join(__dirname, 'node_modules')));
// 前台站点路由,无需登录
app.use('/', route); app.use('/', route);
app.use('/', locale); app.use('/', locale);
app.use('/', misc); app.use('/', misc);
app.use('/', auth); app.use('/', auth);
app.use('/blog', blog); app.use('/blog', blog);
app.use('/admin', require('connect-ensure-login').ensureLoggedIn('/login'), admin);
app.use('/ue/controller', ue); app.use('/ue/controller', ue);
// 后台站点路由,需要身份验证
app.use('/admin', require('connect-ensure-login')
.ensureLoggedIn('/login'), admin);
// catch 404 and forward to error handler // 捕获 404
app.use(function (req, res, next) { app.use((req, res) => {
var err = new Error(); const err = new Error('Not Found!');
err.status = 404; err.status = 404;
next(err); logger.errLogger(err, req);
res.status(404).render('./shared/error', {
code: 404,
message: res.__('error.404_1')
});
}); });
// error handlers // 捕获 500
app.use(function (err, req, res, next) { app.use((err, req, res) => {
var code = err.status || 500, let code = err.status || 500;
message = code === 404 ? res.__('error.404_1') : res.__('error.404_2'); err.status = code;
res.status(code); logger.errLogger(err, req);
logger.errLogger(req, err); res.status(code).render('./shared/error', {
res.render('./shared/error', { code,
code: code, message: res.__('error.404_2')
message: message
}); });
}); });

130
bin/www
View File

@@ -1,90 +1,68 @@
#!/usr/bin/env node const app = require('../app');
const ssl = require('../config.json').ssl;
const logger = require('../utility/logger');
/** const port = normalizePort(process.env.PORT || '3000');
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('iBlog:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port); app.set('port', port);
/** let server;
* Create HTTP server. if (ssl.enable) {
*/ // 创建 HTTPS
const https = require('https');
var server = http.createServer(app); const fs = require('fs');
try {
/** const privateKey = fs.readFileSync(ssl.key, 'utf8');
* Listen on provided port, on all network interfaces. const certificate = fs.readFileSync(ssl.cert, 'utf8');
*/ server = https.createServer({
key: privateKey,
server.listen(port); cert: certificate
}, app);
} catch (err) {
logger.error('未能成功读取SSL私钥或证书文件Error:', err);
process.exit(1);
}
} else {
// 创建 HTTP
const http = require('http');
server = http.createServer(app);
}
server.listen(port, () => {
logger.info('iBlog2 listening on port', port, 'with pid', process.pid);
});
server.on('error', onError); server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) { function normalizePort(val) {
var port = parseInt(val, 10); const port = parseInt(val, 10);
if (isNaN(port)) {
return val;
}
if (isNaN(port)) { if (port >= 0) {
// named pipe return port;
return val; }
}
if (port >= 0) { return false;
// port number
return port;
}
return false;
} }
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) { function onError(error) {
if (error.syscall !== 'listen') { if (error.syscall !== 'listen') {
throw error; throw error;
} }
var bind = typeof port === 'string' const bind = typeof port === 'string' ?
? 'Pipe ' + port `Pipe ${port}` :
: 'Port ' + port; `Port ${port}`;
// handle specific listen errors with friendly messages switch (error.code) {
switch (error.code) { case 'EACCES':
case 'EACCES': console.error(`${bind} requires elevated privileges`);
console.error(bind + ' requires elevated privileges'); process.exit(1);
process.exit(1); break;
break; case 'EADDRINUSE':
case 'EADDRINUSE': console.error(`${bind} is already in use`);
console.error(bind + ' is already in use'); process.exit(1);
process.exit(1); break;
break; default:
default: throw error;
throw error; }
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
} }

View File

@@ -1,48 +0,0 @@
{
"name": "iBlog2",
"description": "",
"main": "",
"authors": [
"Sky <eshengsky@163.com>"
],
"license": "MIT",
"moduleType": [],
"homepage": "https://github.com/eshengsky/iBlog2",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"public/libs",
"test",
"tests"
],
"dependencies": {
"jquery": "2.2.1",
"bootstrap": "~3.3.6",
"font-awesome": "~4.5.0",
"fuelux": "~3.14.1",
"malihu-custom-scrollbar-plugin": "~3.1.3",
"jquery-qrcode": "https://github.com/lrsjng/jquery-qrcode.git#~0.12.0",
"lightbox2": "^2.8.2",
"scrollNav": "^2.6.0",
"sweetalert": "^1.1.3",
"jQuery-cycleText": "https://github.com/eshengsky/jQuery-cycleText.git",
"ace-builds": "^1.2.3",
"wookmark": "wookmark-jquery#^2.0.1",
"devbridge-autocomplete": "^1.2.24",
"animate.css": "^3.5.1",
"metisMenu": "^2.4.0",
"blueimp-file-upload": "fileupload#^9.11.2",
"bootstrap-table": "^1.10.0",
"lodash": "^4.2.1",
"form.validation": "*",
"jquery-sortable": "^0.9.13",
"js-md5": "^2.1.0",
"codemirror": "^5.11.0",
"switchery": "^0.8.1",
"supersized": "*"
},
"resolutions": {
"jquery": "2.2.1"
}
}

View File

@@ -1,8 +1,13 @@
{ {
"DbPath": "mongodb://localhost/iBlog2", "ssl": {
"Redis": { "enable": false,
"Active": false, "key": "/iBlog2/ssl/iblog2.key",
"Host": "127.0.0.1", "cert": "/iBlog2/ssl/iblog2.crt"
"Port": 6379 },
} "mongoUrl": "mongodb://localhost/iBlog2",
"redis": {
"enable": false,
"host": "127.0.0.1",
"port": 6379
}
} }

View File

@@ -1,10 +1,9 @@
{ {
"FirstLine": "第一行文本", "FirstLine": "第一行文本",
"SecondLine": "第二行文本", "SecondLine": "第二行文本",
"PhotoPath": "/images/zhr.jpg", "PhotoPath": "/static/images/zhr.jpg",
"ThirdLine": "第三行文本", "ThirdLine": "第三行文本",
"Profile": "个人简介", "Profile": "个人简介",
"Wechat": "微信号", "Github": "http://baidu.com",
"QrcodePath": "",
"Email": "Email地址" "Email": "Email地址"
} }

View File

@@ -2,17 +2,18 @@
"SiteName": "iBlog", "SiteName": "iBlog",
"SiteDomain": "www.example.com", "SiteDomain": "www.example.com",
"RecordNo": "浙ICP备XXX号", "RecordNo": "浙ICP备XXX号",
"LogoPath": "/images/zhr.jpg", "LogoPath": "/static/images/zhr.jpg",
"PageSize": "10", "PageSize": "10",
"ExpandMenu": "false", "ExpandMenu": "true",
"Editor": "",
"CacheExpired": "300", "CacheExpired": "300",
"TranslateKey": "", "TranslateKey": "y2RIaF6RifHnJeD1Szzw",
"EnableStatistics": "true", "EnableStatistics": "true",
"StatisticsId": "", "StatisticsId": "646bc927e37fe4c5c0e6e7c2d37fcb2c",
"EnableShare": "true", "EnableShare": "true",
"JiaThisId": "", "JiaThisId": "",
"ShowComments": "true", "ShowComments": "true",
"ShowGuestbook": "true", "ShowGuestbook": "true",
"ChangyanId": "", "ChangyanId": "cyrUoGjWj",
"ChangyanConf": "" "ChangyanConf": "prod_c77d5188bc137c8d9181720d02506ab6"
} }

View File

@@ -1,28 +1,31 @@
var cluster = require('cluster'); const cluster = require('cluster');
var numCPUs = require('os').cpus().length; const numCPUs = require('os')
.cpus()
.length;
if (cluster.isMaster) { if (cluster.isMaster) {
var worker; let worker;
//遍历CPU核心数
for (var i = 0; i < numCPUs; i++) { // 遍历CPU核心数
//生成新的工作进程运行主模块 for (let i = 0; i < numCPUs; i++) {
// 生成新的工作进程运行主模块
worker = cluster.fork(); worker = cluster.fork();
console.log('worker%d 正在运行...', worker.process.pid); console.log(`worker${worker.process.pid} 正在运行...`);
} }
} else { } else {
//运行主模块 // 运行主模块
require('./bin/www'); require('./bin/www');
} }
//监听退出事件 // 监听退出事件
cluster.on('exit', function (worker, code, signal) { cluster.on('exit', (worker, code, signal) => {
if (code !== 0) { if (code !== 0) {
console.error('worker%d 异常退出(%s30s后尝试重启...', worker.process.pid, signal || code); console.error(`worker${worker.process.pid} 异常退出(${signal || code}5s后尝试重启...`);
setTimeout(function () { setTimeout(() => {
var new_worker = cluster.fork(); const new_worker = cluster.fork();
console.log('worker%d 正在运行...', new_worker.process.pid); console.log(`worker${new_worker.process.pid} 正在运行...`);
},30000); }, 5000);
} else { } else {
console.log('worker%d 正常退出!', worker.process.pid); console.log(`worker${worker.process.pid} 正常退出!`);
} }
}); });

View File

@@ -54,8 +54,7 @@
"small_screen": "Small Screen Mode" "small_screen": "Small Screen Mode"
}, },
"about": { "about": {
"wechat": "WeChat", "github": "Github",
"qr_code": "QR Code",
"email": "Email" "email": "Email"
}, },
"blog": { "blog": {
@@ -88,7 +87,7 @@
"line_2": "Line 2", "line_2": "Line 2",
"line_3": "Line 3, use '|' to change line. Using Jade Engine", "line_3": "Line 3, use '|' to change line. Using Jade Engine",
"self_intro": "Self Intro", "self_intro": "Self Intro",
"wechat": "WeChat", "github": "Github",
"email": "Email", "email": "Email",
"save": "Save" "save": "Save"
}, },
@@ -204,7 +203,8 @@
"message_service": "友言", "message_service": "友言",
"message_id": "友言uid", "message_id": "友言uid",
"message_id_placeholder": "apply uid", "message_id_placeholder": "apply uid",
"save": "Save" "save": "Save",
"editor": "Default Editor"
} }
} }
} }

View File

@@ -1,5 +1,5 @@
{ {
"language": "English", "language": "En",
"lang-code": "en-US", "lang-code": "en-US",
"error": { "error": {
"404_1": "请求的页面已失联~系统已自动记录该错误。", "404_1": "请求的页面已失联~系统已自动记录该错误。",
@@ -54,8 +54,7 @@
"small_screen": "手机访问该页面" "small_screen": "手机访问该页面"
}, },
"about": { "about": {
"wechat": "微信", "github": "Github",
"qr_code": "二维码",
"email": "邮箱" "email": "邮箱"
}, },
"blog": { "blog": {
@@ -88,7 +87,7 @@
"line_2": "第二行文本", "line_2": "第二行文本",
"line_3": "第三行文本,支持用 | 分割切换显示", "line_3": "第三行文本,支持用 | 分割切换显示",
"self_intro": "个人简介", "self_intro": "个人简介",
"wechat": "微信号", "github": "Github地址",
"email": "Email地址", "email": "Email地址",
"save": "保存修改" "save": "保存修改"
}, },
@@ -204,7 +203,8 @@
"message_service": "友言", "message_service": "友言",
"message_id": "友言uid", "message_id": "友言uid",
"message_id_placeholder": "申请的uid", "message_id_placeholder": "申请的uid",
"save": "保存修改" "save": "保存修改",
"editor": "默认文章编辑器"
} }
} }
} }

View File

@@ -1,16 +1,19 @@
var db = require('./db'), const db = require('./db');
mongoose = db.mongoose, const mongoose = db.mongoose;
base = db.base; const base = db.base;
var categorySchema = base.extend({ const categorySchema = base.extend({
//分类名称 // 分类名称
CateName: {type: String}, CateName: { type: String },
//分类别名
Alias: {type: String}, // 分类别名
//图标地址 Alias: { type: String },
Img: {type: String},
//链接地址 // 图标地址
Link: {type: String} Img: { type: String },
// 链接地址
Link: { type: String }
}); });
exports.CategoryModel = mongoose.model('category', categorySchema, 'category'); exports.CategoryModel = mongoose.model('category', categorySchema, 'category');

View File

@@ -1,24 +1,27 @@
var dbPath = require('../config').DbPath; const dbPath = require('../config')
// var dbPath = process.env.MONGOLAB_URI; .mongoUrl;
var mongoose = require('mongoose'); const mongoose = require('mongoose');
var extend = require('mongoose-schema-extend'); const extend = require('mongoose-schema-extend');
var i18n = require('./i18n'); const i18n = require('./i18n');
// use custom mongodb url or localhost // use custom mongodb url or localhost
mongoose.connect(dbPath || "mongodb://localhost/blogrift"); mongoose.connect(dbPath || 'mongodb://localhost/blogrift');
var db = mongoose.connection; const db = mongoose.connection;
db.on('error', function (err) { db.on('error', err => {
console.error(i18n.__('error.db_1') + err); console.error(i18n.__('error.db_1') + err);
process.exit(1); process.exit(1);
}); });
exports.mongoose = mongoose; exports.mongoose = mongoose;
//基础Schema // 基础Schema
var base = new mongoose.Schema({ const base = new mongoose.Schema({
//唯一键 // 唯一键
_id: {type: String, unique: true}, _id: { type: String, unique: true },
//创建时间
CreateTime: {type: Date}, // 创建时间
//修改时间 CreateTime: { type: Date },
ModifyTime: {type: Date}
// 修改时间
ModifyTime: { type: Date }
}); });
exports.base = base; exports.base = base;

View File

@@ -1,23 +1,27 @@
var i18n = require('i18n'); const i18n = require('i18n');
// multi language support // multi language support
i18n.configure({ i18n.configure({
// setup some locales - other locales default to en silently // setup some locales - other locales default to en silently
locales: ['zh-CN', 'en-US'], locales: ['zh-CN', 'en-US'],
// sets a custom cookie name to parse locale settings from // sets a custom cookie name to parse locale settings from
cookie: 'locale', cookie: 'locale',
// query parameter to switch locale (ie. /home?locale=en) - defaults to NULL
queryParameter: 'locale',
// you may alter a site wide default locale
defaultLocale: 'en-US',
// enable object notation in order to use nested translation
objectNotation: true,
// sync locale information accros all files - defaults to false
syncFiles: false,
// where to store json files - defaults to './locales' // query parameter to switch locale (ie. /home?locale=en) - defaults to NULL
directory: __dirname + '/../language' queryParameter: 'locale',
// you may alter a site wide default locale
defaultLocale: 'zh-CN',
// enable object notation in order to use nested translation
objectNotation: true,
// sync locale information accros all files - defaults to false
syncFiles: false,
// where to store json files - defaults to './locales'
directory: `${__dirname}/../language`
}); });
module.exports = i18n; module.exports = i18n;

View File

@@ -1,17 +1,21 @@
var db = require('./db'), const db = require('./db');
mongoose = db.mongoose; const mongoose = db.mongoose;
var logSchema = new mongoose.Schema({ const logSchema = new mongoose.Schema({
//唯一键 // 唯一键
_id: {type: mongoose.Schema.Types.ObjectId}, _id: { type: mongoose.Schema.Types.ObjectId },
//异常信息
message: {type: String}, // 异常信息
//记录时间 message: { type: String },
timestamp: {type: Date},
//级别 // 记录时间
level: {type: String}, timestamp: { type: Date },
//详细信息
meta: {type: mongoose.Schema.Types.Mixed} // 级别
level: { type: String },
// 详细信息
meta: { type: mongoose.Schema.Types.Mixed }
}); });
exports.LogModel = mongoose.model('log', logSchema, 'log'); exports.LogModel = mongoose.model('log', logSchema, 'log');

View File

@@ -1,30 +1,43 @@
var db = require('./db'), const db = require('./db');
mongoose = db.mongoose, const mongoose = db.mongoose;
base = db.base; const base = db.base;
var postSchema = base.extend({ const postSchema = base.extend({
//标题 // 标题
Title: {type: String}, Title: { type: String },
//文章别名
Alias: {type: String}, // 文章别名
//摘要 Alias: { type: String },
Summary: {type: String},
//来源 // 摘要
Source: {type: String}, Summary: { type: String },
//内容
Content: {type: String}, // 来源
//分类Id Source: { type: String },
CategoryId: {type: String},
//标签 // 内容
Labels: {type: String}, Content: { type: String },
//外链Url
Url: {type: String}, // 内容类型:默认空 (html)可选markdown
//浏览次数 ContentType: { type: String },
ViewCount: {type: Number},
//是否草稿 // 分类Id
IsDraft: {type: Boolean}, CategoryId: { type: String },
//是否有效
IsActive: {type: Boolean, default: true} // 标签
Labels: { type: String },
// 外链Url
Url: { type: String },
// 浏览次数
ViewCount: { type: Number },
// 是否草稿
IsDraft: { type: Boolean },
// 是否有效
IsActive: { type: Boolean, default: true }
}); });
exports.PostModel = mongoose.model('post', postSchema, 'post'); exports.PostModel = mongoose.model('post', postSchema, 'post');

2460
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,34 +1,54 @@
{ {
"name": "iBlog2", "name": "iblog2",
"version": "1.0.0", "version": "1.0.0",
"private": true, "private": true,
"scripts": { "scripts": {
"start": "node ./bin/www", "start": "node ./bin/www"
"postinstall": "bower install"
}, },
"dependencies": { "dependencies": {
"async": "^1.5.2", "@fortawesome/fontawesome-free": "^5.2.0",
"ace-builds": "^1.3.3",
"animate.css": "^3.6.1",
"blueimp-file-upload": "^9.22.0",
"body-parser": "~1.13.2", "body-parser": "~1.13.2",
"bower": "^1.7.9", "bootstrap": "^3.3.7",
"codemirror": "^5.39.0",
"connect-ensure-login": "^0.1.1", "connect-ensure-login": "^0.1.1",
"cookie-parser": "~1.3.5", "cookie-parser": "~1.3.5",
"debug": "~2.2.0", "debug": "~2.2.0",
"express": "~4.13.1", "express": "~4.13.1",
"express-session": "^1.13.0", "express-session": "^1.13.0",
"fuelux": "^3.16.6",
"helmet": "^3.12.1",
"highlight.js": "git+https://github.com/highlightjs/highlight.js.git",
"i18n": "0.8.2", "i18n": "0.8.2",
"jQuery-cycleText": "git+https://github.com/eshengsky/jQuery-cycleText.git",
"jquery": "^2.2.4",
"jquery-file-upload-middleware": "^0.1.7", "jquery-file-upload-middleware": "^0.1.7",
"jquery-qrcode": "git+https://github.com/lrsjng/jquery-qrcode.git",
"jquery-sortable": "^0.9.13",
"js-md5": "^0.7.3",
"lightbox2": "^2.10.0",
"malihu-custom-scrollbar-plugin": "^3.1.5",
"metismenu": "^2.7.9",
"moment": "^2.11.1", "moment": "^2.11.1",
"mongoose": "~4.3.7", "mongoose": "~4.3.7",
"mongoose-schema-extend": "^0.2.0", "mongoose-schema-extend": "^0.2.0",
"morgan": "~1.6.1",
"multer": "^1.1.0", "multer": "^1.1.0",
"passport": "^0.3.2", "passport": "^0.3.2",
"passport-local": "^1.0.0", "passport-local": "^1.0.0",
"pug": "^2.0.3",
"redis": "^2.4.2", "redis": "^2.4.2",
"saker": "^1.0.0", "scrollnav": "git+https://github.com/jimmynotjim/scrollNav.git",
"semver": "^5.5.0",
"serve-favicon": "~2.3.0", "serve-favicon": "~2.3.0",
"shortid": "^2.2.4", "shortid": "^2.2.4",
"winston": "^2.1.1", "showdown": "^1.8.6",
"winston-mongodb": "^2.0.8" "simplemde": "^1.11.2",
"streamroller": "^0.8.3",
"sweetalert": "^1.1.3",
"switchery": "git+https://github.com/abpetkov/switchery.git",
"winston": "^2.4.3",
"winston-mongodb": "^2.0.10"
} }
} }

View File

@@ -1,84 +1,62 @@
var categoryModel = require('../models/category').CategoryModel; const categoryModel = require('../models/category')
var post = require('../models/post').PostModel; .CategoryModel;
var shortid = require('shortid'); const post = require('../models/post')
var tool = require('../utility/tool'); .PostModel;
var redisClient = require('../utility/redisClient'); const shortid = require('shortid');
var i18n = require('../models/i18n') const tool = require('../utility/tool');
const redisClient = require('../utility/redisClient');
//全部分类 const i18n = require('../models/i18n');
var cateAll = {
"_id": "",
"Alias": "",
"CateName": i18n.__("Category.all"),
"Img": "/images/全部分类.svg"
};
//未分类
var cateOther = {
"_id": "other",
"Alias": "other",
"CateName": i18n.__("Category.uncate"),
"Img": "/images/未分类.svg"
};
/** /**
* 获取分类数据 * 获取分类数据
* @param [isAll] 是否包含全部分类和未分类
* @param [cached] 是否读取缓存 * @param [cached] 是否读取缓存
* @param callback 回调函数 * @param callback 回调函数
*/ */
exports.getAll = function (isAll, cached, callback) { exports.getAll = function (cached, callback) {
if (typeof cached === 'function') { if (typeof cached === 'function') {
callback = cached; callback = cached;
cached = true; cached = true;
} else if (typeof isAll === 'function') {
callback = isAll;
isAll = true;
cached = true;
} }
//缓存的key名称
var cache_key = isAll ? 'categories_all' : 'categories'; // 缓存的key名称
const cache_key = 'categories';
if (cached) { if (cached) {
//尝试读取缓存 // 尝试读取缓存
redisClient.getItem(cache_key, function (err, categories) { redisClient.getItem(cache_key, (err, categories) => {
//读取缓存出错 // 读取缓存出错
if (err) { if (err) {
return callback(err); return callback(err);
} }
//缓存中有数据
// 缓存中有数据
if (categories) { if (categories) {
return callback(null, categories); return callback(null, categories);
} }
//缓存中没有数据,则从数据库中读取
categoryModel.find(function (err, categories) { // 缓存中没有数据,则从数据库中读取
//读取数据库出错 categoryModel.find((err, categories) => {
// 读取数据库出错
if (err) { if (err) {
return callback(err); return callback(err);
} }
if (isAll) {
categories.unshift(cateAll); // 从数据库中读到数据
categories.push(cateOther);
}
//从数据库中读到数据
if (categories) { if (categories) {
//将数据塞入缓存 // 将数据塞入缓存
redisClient.setItem(cache_key, categories, redisClient.defaultExpired, function (err) { redisClient.setItem(cache_key, categories, redisClient.defaultExpired, err => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
}) });
} }
return callback(null, categories); return callback(null, categories);
}); });
}); });
} else { } else {
categoryModel.find(function (err, categories) { categoryModel.find((err, categories) => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
if (isAll) {
categories.unshift(cateAll);
categories.push(cateOther);
}
return callback(null, categories); return callback(null, categories);
}); });
} }
@@ -91,33 +69,48 @@ exports.getAll = function (isAll, cached, callback) {
* @returns {*} * @returns {*}
*/ */
exports.getByAlias = function (alias, callback) { exports.getByAlias = function (alias, callback) {
var cache_key = 'category_' + alias; // 全部分类
const cateAll = {
_id: '',
Alias: '',
CateName: i18n.__('Category.all'),
Img: '/static/images/全部分类.svg'
};
// 未分类
const cateOther = {
_id: 'other',
Alias: 'other',
CateName: i18n.__('Category.uncate'),
Img: '/static/images/未分类.svg'
};
const cache_key = `category_${alias}`;
if (alias) { if (alias) {
if (alias === 'other') { if (alias === 'other') {
return callback(null, cateOther); return callback(null, cateOther);
} else { }
redisClient.getItem(cache_key, function (err, category) { redisClient.getItem(cache_key, (err, category) => {
if (err) {
return callback(err);
}
if (category) {
return callback(null, category);
}
categoryModel.findOne({ Alias: alias }, (err, category) => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
if (category) { if (category) {
return callback(null, category); redisClient.setItem(cache_key, category, redisClient.defaultExpired, err => {
if (err) {
return callback(err);
}
});
} }
categoryModel.findOne({"Alias": alias}, function (err, category) { return callback(null, category);
if (err) {
return callback(err);
}
if (category) {
redisClient.setItem(cache_key, category, redisClient.defaultExpired, function (err) {
if (err) {
return callback(err);
}
})
}
return callback(null, category);
});
}); });
} });
} else { } else {
return callback(null, cateAll); return callback(null, cateAll);
} }
@@ -129,12 +122,12 @@ exports.getByAlias = function (alias, callback) {
* @param callback 回调函数 * @param callback 回调函数
*/ */
exports.save = function (array, callback) { exports.save = function (array, callback) {
var jsonArray = [], let jsonArray = [],
toUpdate = [], toUpdate = [],
updateQuery = [], updateQuery = [],
cateNew; cateNew;
if (array.length > 0) { if (array.length > 0) {
array.forEach(function (item) { array.forEach(item => {
jsonArray.push({ jsonArray.push({
_id: item.uniqueid || shortid.generate(), _id: item.uniqueid || shortid.generate(),
CateName: item.catename, CateName: item.catename,
@@ -146,49 +139,50 @@ exports.save = function (array, callback) {
}); });
}); });
} }
categoryModel.find(function (err, categories) { categoryModel.find((err, categories) => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
categories.forEach(function (old) { categories.forEach(old => {
cateNew = tool.jsonQuery(jsonArray, {"_id": old._id}); cateNew = tool.jsonQuery(jsonArray, { _id: old._id });
if (!cateNew) { if (!cateNew) {
//该分类将被删除 // 该分类将被删除
toUpdate.push(old._id); toUpdate.push(old._id);
} else { } else {
//该分类依然存在,则创建时间沿用原创建时间 // 该分类依然存在,则创建时间沿用原创建时间
cateNew.CreateTime = old.CreateTime; cateNew.CreateTime = old.CreateTime;
//若该分类未做任何修改,则修改时间沿用原修改时间
// 若该分类未做任何修改,则修改时间沿用原修改时间
if (cateNew.CateName.toString() === old.CateName.toString() && cateNew.Alias.toString() === old.Alias.toString() && cateNew.Img === old.Img && cateNew.Link === old.Link) { if (cateNew.CateName.toString() === old.CateName.toString() && cateNew.Alias.toString() === old.Alias.toString() && cateNew.Img === old.Img && cateNew.Link === old.Link) {
cateNew.ModifyTime = old.ModifyTime; cateNew.ModifyTime = old.ModifyTime;
} }
} }
}); });
//将已被删除分类的文章设为"未分类" // 将已被删除分类的文章设为"未分类"
if (toUpdate.length > 0) { if (toUpdate.length > 0) {
toUpdate.forEach(function (cateId) { toUpdate.forEach(cateId => {
updateQuery.push({ updateQuery.push({
"CategoryId": cateId CategoryId: cateId
}); });
}); });
post.update({"$or": updateQuery}, {"CategoryId": "other"}, {multi: true}, function (err) { post.update({ $or: updateQuery }, { CategoryId: 'other' }, { multi: true }, err => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
}); });
} }
//将分类全部删除 // 将分类全部删除
categoryModel.remove(function (err) { categoryModel.remove(err => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
if (jsonArray.length > 0) { if (jsonArray.length > 0) {
//插入全部分类 // 插入全部分类
//categoryModel.create(jsonArray, function (err) {}); //不用这个,因为这个内部实现依然是循环插入,不是真正的批量插入 // categoryModel.create(jsonArray, function (err) {}); //不用这个,因为这个内部实现依然是循环插入,不是真正的批量插入
//这里采用mongodb原生的insert来批量插入多个文档 // 这里采用mongodb原生的insert来批量插入多个文档
categoryModel.collection.insert(jsonArray, function (err) { categoryModel.collection.insert(jsonArray, err => {
if (err) { if (err) {
return callback(err); return callback(err);
} }

View File

@@ -1,4 +1,5 @@
var logModel = require('../models/log').LogModel; const logModel = require('../models/log')
.LogModel;
/** /**
* 获取所有日志 * 获取所有日志
@@ -6,10 +7,10 @@ var logModel = require('../models/log').LogModel;
* @param callback 回调函数 * @param callback 回调函数
*/ */
exports.getAll = function (params, callback) { exports.getAll = function (params, callback) {
var page = parseInt(params.pageIndex) || 1; let page = parseInt(params.pageIndex) || 1;
var size = parseInt(params.pageSize) || 10; const size = parseInt(params.pageSize) || 10;
page = page > 0 ? page : 1; page = page > 0 ? page : 1;
var options = {}; const options = {};
options.skip = (page - 1) * size; options.skip = (page - 1) * size;
options.limit = size; options.limit = size;
switch (params.sortName) { switch (params.sortName) {
@@ -20,7 +21,7 @@ exports.getAll = function (params, callback) {
options.sort = params.sortOrder === 'desc' ? '-timestamp' : 'timestamp'; options.sort = params.sortOrder === 'desc' ? '-timestamp' : 'timestamp';
break; break;
} }
logModel.find({}, {}, options, function (err, logs) { logModel.find({}, {}, options, (err, logs) => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
@@ -34,11 +35,10 @@ exports.getAll = function (params, callback) {
* @param callback 回调函数 * @param callback 回调函数
*/ */
exports.getAllCount = function (params, callback) { exports.getAllCount = function (params, callback) {
logModel.count(function (err, count) { logModel.count((err, count) => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
return callback(null, count); return callback(null, count);
}); });
}; };

View File

@@ -1,6 +1,7 @@
var postModel = require('../models/post').PostModel; const postModel = require('../models/post')
var redisClient = require('../utility/redisClient'); .PostModel;
var tool = require('../utility/tool'); const redisClient = require('../utility/redisClient');
const tool = require('../utility/tool');
/** /**
* 为首页数据查询构建条件对象 * 为首页数据查询构建条件对象
@@ -8,7 +9,7 @@ var tool = require('../utility/tool');
* @returns {{}} * @returns {{}}
*/ */
function getPostsQuery(params) { function getPostsQuery(params) {
var query = {}; const query = {};
query.IsActive = true; query.IsActive = true;
query.IsDraft = false; query.IsDraft = false;
if (params.cateId) { if (params.cateId) {
@@ -17,34 +18,34 @@ function getPostsQuery(params) {
if (params.keyword) { if (params.keyword) {
switch (params.filterType) { switch (params.filterType) {
case '1': case '1':
query.Title = {"$regex": params.keyword, "$options": "gi"}; query.Title = { $regex: params.keyword, $options: 'gi' };
break; break;
case '2': case '2':
query.Labels = {"$regex": params.keyword, "$options": "gi"}; query.Labels = { $regex: params.keyword, $options: 'gi' };
break; break;
case '3': case '3':
query.CreateTime = {"$regex": params.keyword, "$options": "gi"}; query.CreateTime = { $regex: params.keyword, $options: 'gi' };
break; break;
default: default:
query.$or = [{ query.$or = [{
"Title": { Title: {
"$regex": params.keyword, $regex: params.keyword,
"$options": "gi" $options: 'gi'
} }
}, { }, {
'Labels': { Labels: {
"$regex": params.keyword, $regex: params.keyword,
"$options": "gi" $options: 'gi'
} }
}, { }, {
'Summary': { Summary: {
"$regex": params.keyword, $regex: params.keyword,
"$options": "gi" $options: 'gi'
} }
}, { }, {
'Content': { Content: {
"$regex": params.keyword, $regex: params.keyword,
"$options": "gi" $options: 'gi'
} }
}]; }];
} }
@@ -58,32 +59,32 @@ function getPostsQuery(params) {
* @param callback 回调函数 * @param callback 回调函数
*/ */
exports.getPosts = function (params, callback) { exports.getPosts = function (params, callback) {
var cache_key = tool.generateKey('posts', params); const cache_key = tool.generateKey('posts', params);
redisClient.getItem(cache_key, function (err, posts) { redisClient.getItem(cache_key, (err, posts) => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
if (posts) { if (posts) {
return callback(null, posts); return callback(null, posts);
} }
var page = parseInt(params.pageIndex) || 1; let page = parseInt(params.pageIndex) || 1;
var size = parseInt(params.pageSize) || 10; const size = parseInt(params.pageSize) || 10;
page = page > 0 ? page : 1; page = page > 0 ? page : 1;
var options = {}; const options = {};
options.skip = (page - 1) * size; options.skip = (page - 1) * size;
options.limit = size; options.limit = size;
options.sort = params.sortBy === 'title' ? 'Title -CreateTime' : '-CreateTime'; options.sort = params.sortBy === 'title' ? 'Title -CreateTime' : '-CreateTime';
var query = getPostsQuery(params); const query = getPostsQuery(params);
postModel.find(query, {}, options, function (err, posts) { postModel.find(query, {}, options, (err, posts) => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
if (posts) { if (posts) {
redisClient.setItem(cache_key, posts, redisClient.defaultExpired, function (err) { redisClient.setItem(cache_key, posts, redisClient.defaultExpired, err => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
}) });
} }
return callback(null, posts); return callback(null, posts);
}); });
@@ -96,21 +97,21 @@ exports.getPosts = function (params, callback) {
* @param callback 回调函数 * @param callback 回调函数
*/ */
exports.getPageCount = function (params, callback) { exports.getPageCount = function (params, callback) {
var cache_key = tool.generateKey('posts_count', params); const cache_key = tool.generateKey('posts_count', params);
redisClient.getItem(cache_key, function (err, pageCount) { redisClient.getItem(cache_key, (err, pageCount) => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
if (pageCount) { if (pageCount) {
return callback(null, pageCount); return callback(null, pageCount);
} }
var query = getPostsQuery(params); const query = getPostsQuery(params);
postModel.count(query, function (err, count) { postModel.count(query, (err, count) => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
var pageCount = count % params.pageSize === 0 ? parseInt(count / params.pageSize) : parseInt(count / params.pageSize) + 1; const pageCount = count % params.pageSize === 0 ? parseInt(count / params.pageSize) : parseInt(count / params.pageSize) + 1;
redisClient.setItem(cache_key, pageCount, redisClient.defaultExpired, function (err) { redisClient.setItem(cache_key, pageCount, redisClient.defaultExpired, err => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
@@ -126,30 +127,29 @@ exports.getPageCount = function (params, callback) {
* @param callback 回调函数 * @param callback 回调函数
*/ */
exports.getPostByAlias = function (alias, callback) { exports.getPostByAlias = function (alias, callback) {
var cache_key = 'article_' + alias; const cache_key = `article_${alias}`;
//此处不需要等待MongoDB的响应所以不想传一个回调函数但如果不传回调函数则必须在调用Query对象上的exec()方法! postModel.update({ Alias: alias }, { $inc: { ViewCount: 1 } })
//postModel.update({"Alias": alias}, {"ViewCount": 1}, function () {}); .exec();
postModel.update({"Alias": alias}, {"$inc": {"ViewCount": 1}}).exec(); redisClient.getItem(cache_key, (err, article) => {
redisClient.getItem(cache_key, function (err, article) {
if (err) { if (err) {
return callback(err); return callback(err);
} }
if (article) { if (article) {
return callback(null, article); return callback(null, article);
} }
postModel.findOne({"Alias": alias}, function (err, article) { postModel.findOne({ Alias: alias }, (err, article) => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
if (article) { if (article) {
redisClient.setItem(cache_key, article, redisClient.defaultExpired, function (err) { redisClient.setItem(cache_key, article, redisClient.defaultExpired, err => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
}); });
} }
return callback(null, article); return callback(null, article);
}) });
}); });
}; };
@@ -159,7 +159,7 @@ exports.getPostByAlias = function (alias, callback) {
* @returns {{}} * @returns {{}}
*/ */
function getArticlesQuery(params) { function getArticlesQuery(params) {
var query = {}; const query = {};
if (params.cateId) { if (params.cateId) {
query.CategoryId = params.cateId; query.CategoryId = params.cateId;
} }
@@ -167,40 +167,40 @@ function getArticlesQuery(params) {
query._id = params.uniqueId; query._id = params.uniqueId;
} }
if (params.title) { if (params.title) {
query.Title = {"$regex": params.title, "$options": "gi"}; query.Title = { $regex: params.title, $options: 'gi' };
} }
if (params.searchText) { if (params.searchText) {
query.$or = [{ query.$or = [{
"Alias": { Alias: {
"$regex": params.searchText, $regex: params.searchText,
"$options": "gi" $options: 'gi'
} }
}, { }, {
"Title": { Title: {
"$regex": params.searchText, $regex: params.searchText,
"$options": "gi" $options: 'gi'
} }
}, { }, {
"Summary": { Summary: {
"$regex": params.searchText, $regex: params.searchText,
"$options": "gi" $options: 'gi'
} }
}, { }, {
"Content": { Content: {
"$regex": params.searchText, $regex: params.searchText,
"$options": "gi" $options: 'gi'
} }
}, { }, {
"Labels": { Labels: {
"$regex": params.searchText, $regex: params.searchText,
"$options": "gi" $options: 'gi'
} }
}, { }, {
"Url": { Url: {
"$regex": params.searchText, $regex: params.searchText,
"$options": "gi" $options: 'gi'
} }
}] }];
} }
return query; return query;
} }
@@ -211,10 +211,10 @@ function getArticlesQuery(params) {
* @param callback 回调函数 * @param callback 回调函数
*/ */
exports.getArticles = function (params, callback) { exports.getArticles = function (params, callback) {
var page = parseInt(params.pageIndex) || 1; let page = parseInt(params.pageIndex) || 1;
var size = parseInt(params.pageSize) || 10; const size = parseInt(params.pageSize) || 10;
page = page > 0 ? page : 1; page = page > 0 ? page : 1;
var options = {}; const options = {};
options.skip = (page - 1) * size; options.skip = (page - 1) * size;
options.limit = size; options.limit = size;
switch (params.sortName) { switch (params.sortName) {
@@ -228,8 +228,8 @@ exports.getArticles = function (params, callback) {
options.sort = params.sortOrder === 'desc' ? '-CreateTime' : 'CreateTime'; options.sort = params.sortOrder === 'desc' ? '-CreateTime' : 'CreateTime';
break; break;
} }
var query = getArticlesQuery(params); const query = getArticlesQuery(params);
postModel.find(query, {}, options, function (err, posts) { postModel.find(query, {}, options, (err, posts) => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
@@ -243,8 +243,8 @@ exports.getArticles = function (params, callback) {
* @param callback 回调函数 * @param callback 回调函数
*/ */
exports.getArticlesCount = function (params, callback) { exports.getArticlesCount = function (params, callback) {
var query = getArticlesQuery(params); const query = getArticlesQuery(params);
postModel.count(query, function (err, count) { postModel.count(query, (err, count) => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
@@ -259,20 +259,18 @@ exports.getArticlesCount = function (params, callback) {
* @param callback 回调函数 * @param callback 回调函数
*/ */
exports.checkAlias = function (alias, articleId, callback) { exports.checkAlias = function (alias, articleId, callback) {
postModel.findOne({"Alias": alias}, function (err, article) { postModel.findOne({ Alias: alias }, (err, article) => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
if (!article) { if (!article) {
return callback(null, true); return callback(null, true);
} else {
if (article._id === articleId) {
return callback(null, true);
} else {
return callback(null, false);
}
} }
}) if (article._id === articleId) {
return callback(null, true);
}
return callback(null, false);
});
}; };
/** /**
@@ -281,7 +279,7 @@ exports.checkAlias = function (alias, articleId, callback) {
* @param callback 回调函数 * @param callback 回调函数
*/ */
exports.getById = function (id, callback) { exports.getById = function (id, callback) {
postModel.findById(id, function (err, article) { postModel.findById(id, (err, article) => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
@@ -295,45 +293,47 @@ exports.getById = function (id, callback) {
* @param callback 回调函数 * @param callback 回调函数
*/ */
exports.save = function (params, callback) { exports.save = function (params, callback) {
var _id = params.UniqueId, let _id = params.UniqueId,
entity = new postModel({ entity = new postModel({
Title: params.Title, Title: params.Title,
Alias: params.Alias, Alias: params.Alias,
Summary: params.Summary, Summary: params.Summary,
Source: params.Source, Source: params.Source,
Content: params.Content, Content: params.Content,
ContentType: params.ContentType || '',
CategoryId: params.CategoryId, CategoryId: params.CategoryId,
Labels: params.Labels, Labels: params.Labels,
Url: params.Url, Url: params.Url,
IsDraft: params.IsDraft === 'True', IsDraft: params.IsDraft === 'True',
IsActive: true, IsActive: params.IsActive === 'True',
ModifyTime: new Date() ModifyTime: new Date()
}); });
postModel.findById(_id, function (err, article) { postModel.findById(_id, (err, article) => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
if (!article) { if (!article) {
//新增 // 新增
entity._id = _id; entity._id = _id;
entity.IsActive = true;
entity.ViewCount = 0; entity.ViewCount = 0;
entity.CreateTime = new Date(); entity.CreateTime = new Date();
entity.save(function (err) { entity.save(err => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
return callback(null); return callback(null);
}); });
} else { } else {
//更新 // 更新
postModel.update({"_id": _id}, entity, function (err) { postModel.update({ _id }, entity, err => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
return callback(null); return callback(null);
}); });
} }
}) });
}; };
/** /**
@@ -342,11 +342,11 @@ exports.save = function (params, callback) {
* @param callback 回调函数 * @param callback 回调函数
*/ */
exports.delete = function (ids, callback) { exports.delete = function (ids, callback) {
var idArray = ids.split(','), let idArray = ids.split(','),
hasErr = false, hasErr = false,
index = 0; index = 0;
idArray.forEach(function (id) { idArray.forEach(id => {
postModel.update({'_id': id}, {'IsActive': false}, function (err) { postModel.update({ _id: id }, { IsActive: false }, err => {
index++; index++;
if (err) { if (err) {
hasErr = true; hasErr = true;
@@ -367,10 +367,10 @@ exports.delete = function (ids, callback) {
* @param callback 回调函数 * @param callback 回调函数
*/ */
exports.undo = function (id, callback) { exports.undo = function (id, callback) {
postModel.update({'_id': id}, {'IsActive': true}, function (err) { postModel.update({ _id: id }, { IsActive: true }, err => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
return callback(null); return callback(null);
}); });
}; };

View File

@@ -1,12 +1,3 @@
@import url("https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700");
@import url("https://fonts.googleapis.com/css?family=Roboto:400,300,500,700");
/*
*
* INSPINIA - Responsive Admin Theme
* version 2.4
*
*/
h1, h1,
h2, h2,
h3, h3,
@@ -204,7 +195,7 @@ h5 {
.nav-header { .nav-header {
padding: 33px 25px 20px; padding: 33px 25px 20px;
background: url("/images/header-profile.png") no-repeat; background: url("/static/images/header-profile.png") no-repeat;
} }
.pace-done .nav-header { .pace-done .nav-header {
@@ -2205,7 +2196,7 @@ div.dt-button-info {
background-color: #FFFFFF; background-color: #FFFFFF;
background-image: none; background-image: none;
border: 1px solid #e5e6e7; border: 1px solid #e5e6e7;
border-radius: 1px; border-radius: 3px;
color: inherit; color: inherit;
display: block; display: block;
padding: 6px 12px; padding: 6px 12px;
@@ -9956,8 +9947,6 @@ body.md-skin {
margin-left: auto; margin-left: auto;
} }
}
@media (max-width: 768px) { @media (max-width: 768px) {
#page-wrapper { #page-wrapper {
position: inherit; position: inherit;
@@ -10168,6 +10157,7 @@ input[type="checkbox"].input-validation-error {
.sweet-alert h2 { .sweet-alert h2 {
font-size: 20px !important; font-size: 20px !important;
font-weight: normal !important; font-weight: normal !important;
margin-bottom: 10px !important;
} }
.fixed-tool { .fixed-tool {
@@ -10199,10 +10189,6 @@ input[type="checkbox"].input-validation-error {
font-family: none !important; font-family: none !important;
} }
label {
/*display: block;*/
}
#postForm .selectlist button, #postForm .selectlist ul { #postForm .selectlist button, #postForm .selectlist ul {
width: auto !important; width: auto !important;
} }
@@ -10322,8 +10308,8 @@ img.wechat-img {
padding: 20px; padding: 20px;
} }
.widget-text-box .fa-wechat, .widget-text-box .fa-envelope { .widget-text-box .fa-github, .widget-text-box .fa-envelope {
color: #1ab394; color: #666;
} }
.widget-text-box .fa-qrcode { .widget-text-box .fa-qrcode {
@@ -10400,3 +10386,7 @@ img.wechat-img {
background: #1ab394 none repeat scroll 0 0; background: #1ab394 none repeat scroll 0 0;
border-color: #1ab394; border-color: #1ab394;
} }
#editor, #mdEditor {
display: none;
}

View File

@@ -3,7 +3,7 @@
} }
.back-img { .back-img {
background-image: url(/images/ErrorBack.jpg); background-image: url(/static/images/ErrorBack.jpg);
background-position: center center; background-position: center center;
background-size: cover; background-size: cover;
height: 100%; height: 100%;

View File

@@ -0,0 +1,695 @@
@font-face {
font-family: octicons-link;
src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAZwABAAAAAACFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEU0lHAAAGaAAAAAgAAAAIAAAAAUdTVUIAAAZcAAAACgAAAAoAAQAAT1MvMgAAAyQAAABJAAAAYFYEU3RjbWFwAAADcAAAAEUAAACAAJThvmN2dCAAAATkAAAABAAAAAQAAAAAZnBnbQAAA7gAAACyAAABCUM+8IhnYXNwAAAGTAAAABAAAAAQABoAI2dseWYAAAFsAAABPAAAAZwcEq9taGVhZAAAAsgAAAA0AAAANgh4a91oaGVhAAADCAAAABoAAAAkCA8DRGhtdHgAAAL8AAAADAAAAAwGAACfbG9jYQAAAsAAAAAIAAAACABiATBtYXhwAAACqAAAABgAAAAgAA8ASm5hbWUAAAToAAABQgAAAlXu73sOcG9zdAAABiwAAAAeAAAAME3QpOBwcmVwAAAEbAAAAHYAAAB/aFGpk3jaTY6xa8JAGMW/O62BDi0tJLYQincXEypYIiGJjSgHniQ6umTsUEyLm5BV6NDBP8Tpts6F0v+k/0an2i+itHDw3v2+9+DBKTzsJNnWJNTgHEy4BgG3EMI9DCEDOGEXzDADU5hBKMIgNPZqoD3SilVaXZCER3/I7AtxEJLtzzuZfI+VVkprxTlXShWKb3TBecG11rwoNlmmn1P2WYcJczl32etSpKnziC7lQyWe1smVPy/Lt7Kc+0vWY/gAgIIEqAN9we0pwKXreiMasxvabDQMM4riO+qxM2ogwDGOZTXxwxDiycQIcoYFBLj5K3EIaSctAq2kTYiw+ymhce7vwM9jSqO8JyVd5RH9gyTt2+J/yUmYlIR0s04n6+7Vm1ozezUeLEaUjhaDSuXHwVRgvLJn1tQ7xiuVv/ocTRF42mNgZGBgYGbwZOBiAAFGJBIMAAizAFoAAABiAGIAznjaY2BkYGAA4in8zwXi+W2+MjCzMIDApSwvXzC97Z4Ig8N/BxYGZgcgl52BCSQKAA3jCV8CAABfAAAAAAQAAEB42mNgZGBg4f3vACQZQABIMjKgAmYAKEgBXgAAeNpjYGY6wTiBgZWBg2kmUxoDA4MPhGZMYzBi1AHygVLYQUCaawqDA4PChxhmh/8ODDEsvAwHgMKMIDnGL0x7gJQCAwMAJd4MFwAAAHjaY2BgYGaA4DAGRgYQkAHyGMF8NgYrIM3JIAGVYYDT+AEjAwuDFpBmA9KMDEwMCh9i/v8H8sH0/4dQc1iAmAkALaUKLgAAAHjaTY9LDsIgEIbtgqHUPpDi3gPoBVyRTmTddOmqTXThEXqrob2gQ1FjwpDvfwCBdmdXC5AVKFu3e5MfNFJ29KTQT48Ob9/lqYwOGZxeUelN2U2R6+cArgtCJpauW7UQBqnFkUsjAY/kOU1cP+DAgvxwn1chZDwUbd6CFimGXwzwF6tPbFIcjEl+vvmM/byA48e6tWrKArm4ZJlCbdsrxksL1AwWn/yBSJKpYbq8AXaaTb8AAHja28jAwOC00ZrBeQNDQOWO//sdBBgYGRiYWYAEELEwMTE4uzo5Zzo5b2BxdnFOcALxNjA6b2ByTswC8jYwg0VlNuoCTWAMqNzMzsoK1rEhNqByEyerg5PMJlYuVueETKcd/89uBpnpvIEVomeHLoMsAAe1Id4AAAAAAAB42oWQT07CQBTGv0JBhagk7HQzKxca2sJCE1hDt4QF+9JOS0nbaaYDCQfwCJ7Au3AHj+LO13FMmm6cl7785vven0kBjHCBhfpYuNa5Ph1c0e2Xu3jEvWG7UdPDLZ4N92nOm+EBXuAbHmIMSRMs+4aUEd4Nd3CHD8NdvOLTsA2GL8M9PODbcL+hD7C1xoaHeLJSEao0FEW14ckxC+TU8TxvsY6X0eLPmRhry2WVioLpkrbp84LLQPGI7c6sOiUzpWIWS5GzlSgUzzLBSikOPFTOXqly7rqx0Z1Q5BAIoZBSFihQYQOOBEdkCOgXTOHA07HAGjGWiIjaPZNW13/+lm6S9FT7rLHFJ6fQbkATOG1j2OFMucKJJsxIVfQORl+9Jyda6Sl1dUYhSCm1dyClfoeDve4qMYdLEbfqHf3O/AdDumsjAAB42mNgYoAAZQYjBmyAGYQZmdhL8zLdDEydARfoAqIAAAABAAMABwAKABMAB///AA8AAQAAAAAAAAAAAAAAAAABAAAAAA==) format('woff');
}
.markdown-body {
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
line-height: 1.5;
color: #24292e;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 16px;
line-height: 1.5;
word-wrap: break-word;
}
.markdown-body .pl-c {
color: #6a737d;
}
.markdown-body .pl-c1,
.markdown-body .pl-s .pl-v {
color: #005cc5;
}
.markdown-body .pl-e,
.markdown-body .pl-en {
color: #6f42c1;
}
.markdown-body .pl-smi,
.markdown-body .pl-s .pl-s1 {
color: #24292e;
}
.markdown-body .pl-ent {
color: #22863a;
}
.markdown-body .pl-k {
color: #d73a49;
}
.markdown-body .pl-s,
.markdown-body .pl-pds,
.markdown-body .pl-s .pl-pse .pl-s1,
.markdown-body .pl-sr,
.markdown-body .pl-sr .pl-cce,
.markdown-body .pl-sr .pl-sre,
.markdown-body .pl-sr .pl-sra {
color: #032f62;
}
.markdown-body .pl-v,
.markdown-body .pl-smw {
color: #e36209;
}
.markdown-body .pl-bu {
color: #b31d28;
}
.markdown-body .pl-ii {
color: #fafbfc;
background-color: #b31d28;
}
.markdown-body .pl-c2 {
color: #fafbfc;
background-color: #d73a49;
}
.markdown-body .pl-c2::before {
content: "^M";
}
.markdown-body .pl-sr .pl-cce {
font-weight: bold;
color: #22863a;
}
.markdown-body .pl-ml {
color: #735c0f;
}
.markdown-body .pl-mh,
.markdown-body .pl-mh .pl-en,
.markdown-body .pl-ms {
font-weight: bold;
color: #005cc5;
}
.markdown-body .pl-mi {
font-style: italic;
color: #24292e;
}
.markdown-body .pl-mb {
font-weight: bold;
color: #24292e;
}
.markdown-body .pl-md {
color: #b31d28;
background-color: #ffeef0;
}
.markdown-body .pl-mi1 {
color: #22863a;
background-color: #f0fff4;
}
.markdown-body .pl-mc {
color: #e36209;
background-color: #ffebda;
}
.markdown-body .pl-mi2 {
color: #f6f8fa;
background-color: #005cc5;
}
.markdown-body .pl-mdr {
font-weight: bold;
color: #6f42c1;
}
.markdown-body .pl-ba {
color: #586069;
}
.markdown-body .pl-sg {
color: #959da5;
}
.markdown-body .pl-corl {
text-decoration: underline;
color: #032f62;
}
.markdown-body .octicon {
display: inline-block;
vertical-align: text-top;
fill: currentColor;
}
.markdown-body a {
background-color: transparent;
}
.markdown-body a:active,
.markdown-body a:hover {
outline-width: 0;
}
.markdown-body strong {
font-weight: inherit;
}
.markdown-body strong {
font-weight: bolder;
}
.markdown-body h1 {
font-size: 2em;
margin: 0.67em 0;
}
.markdown-body img {
border-style: none;
}
.markdown-body code,
.markdown-body kbd,
.markdown-body pre {
font-family: monospace, monospace;
font-size: 1em;
}
.markdown-body hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
.markdown-body input {
font: inherit;
margin: 0;
}
.markdown-body input {
overflow: visible;
}
.markdown-body [type="checkbox"] {
box-sizing: border-box;
padding: 0;
}
.markdown-body * {
box-sizing: border-box;
}
.markdown-body input {
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
.markdown-body a {
color: #0366d6;
text-decoration: none;
}
.markdown-body a:hover {
text-decoration: underline;
}
.markdown-body strong {
font-weight: 600;
}
.markdown-body hr {
height: 0;
margin: 15px 0;
overflow: hidden;
background: transparent;
border: 0;
border-bottom: 1px solid #dfe2e5;
}
.markdown-body hr::before {
display: table;
content: "";
}
.markdown-body hr::after {
display: table;
clear: both;
content: "";
}
.markdown-body table {
border-spacing: 0;
border-collapse: collapse;
}
.markdown-body td,
.markdown-body th {
padding: 0;
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
margin-top: 0;
margin-bottom: 0;
}
.markdown-body h1 {
font-size: 32px;
font-weight: 600;
}
.markdown-body h2 {
font-size: 24px;
font-weight: 600;
}
.markdown-body h3 {
font-size: 20px;
font-weight: 600;
}
.markdown-body h4 {
font-size: 16px;
font-weight: 600;
}
.markdown-body h5 {
font-size: 14px;
font-weight: 600;
}
.markdown-body h6 {
font-size: 12px;
font-weight: 600;
}
.markdown-body p {
margin-top: 0;
margin-bottom: 10px;
}
.markdown-body blockquote {
margin: 0;
}
.markdown-body ul,
.markdown-body ol {
padding-left: 0;
margin-top: 0;
margin-bottom: 0;
}
.markdown-body ol ol,
.markdown-body ul ol {
list-style-type: lower-roman;
}
.markdown-body ul ul ol,
.markdown-body ul ol ol,
.markdown-body ol ul ol,
.markdown-body ol ol ol {
list-style-type: lower-alpha;
}
.markdown-body dd {
margin-left: 0;
}
.markdown-body code {
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
font-size: 12px;
}
.markdown-body pre {
margin-top: 0;
margin-bottom: 0;
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
font-size: 12px;
}
.markdown-body .octicon {
vertical-align: text-bottom;
}
.markdown-body .pl-0 {
padding-left: 0 !important;
}
.markdown-body .pl-1 {
padding-left: 4px !important;
}
.markdown-body .pl-2 {
padding-left: 8px !important;
}
.markdown-body .pl-3 {
padding-left: 16px !important;
}
.markdown-body .pl-4 {
padding-left: 24px !important;
}
.markdown-body .pl-5 {
padding-left: 32px !important;
}
.markdown-body .pl-6 {
padding-left: 40px !important;
}
.markdown-body::before {
display: table;
content: "";
}
.markdown-body::after {
display: table;
clear: both;
content: "";
}
.markdown-body>*:first-child {
margin-top: 0 !important;
}
.markdown-body>*:last-child {
margin-bottom: 0 !important;
}
.markdown-body a:not([href]) {
color: inherit;
text-decoration: none;
}
.markdown-body .anchor {
float: left;
padding-right: 4px;
margin-left: -20px;
line-height: 1;
}
.markdown-body .anchor:focus {
outline: none;
}
.markdown-body p,
.markdown-body blockquote,
.markdown-body ul,
.markdown-body ol,
.markdown-body dl,
.markdown-body table,
.markdown-body pre {
margin-top: 0;
margin-bottom: 16px;
}
.markdown-body hr {
height: 0.25em;
padding: 0;
margin: 24px 0;
background-color: #e1e4e8;
border: 0;
}
.markdown-body blockquote {
padding: 0 1em;
color: #6a737d;
border-left: 0.25em solid #dfe2e5;
}
.markdown-body blockquote>:first-child {
margin-top: 0;
}
.markdown-body blockquote>:last-child {
margin-bottom: 0;
}
.markdown-body kbd {
display: inline-block;
padding: 3px 5px;
font-size: 11px;
line-height: 10px;
color: #444d56;
vertical-align: middle;
background-color: #fafbfc;
border: solid 1px #c6cbd1;
border-bottom-color: #959da5;
border-radius: 3px;
box-shadow: inset 0 -1px 0 #959da5;
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
margin-top: 24px;
margin-bottom: 16px;
font-weight: 600;
line-height: 1.25;
}
.markdown-body h1 .octicon-link,
.markdown-body h2 .octicon-link,
.markdown-body h3 .octicon-link,
.markdown-body h4 .octicon-link,
.markdown-body h5 .octicon-link,
.markdown-body h6 .octicon-link {
color: #1b1f23;
vertical-align: middle;
visibility: hidden;
}
.markdown-body h1:hover .anchor,
.markdown-body h2:hover .anchor,
.markdown-body h3:hover .anchor,
.markdown-body h4:hover .anchor,
.markdown-body h5:hover .anchor,
.markdown-body h6:hover .anchor {
text-decoration: none;
}
.markdown-body h1:hover .anchor .octicon-link,
.markdown-body h2:hover .anchor .octicon-link,
.markdown-body h3:hover .anchor .octicon-link,
.markdown-body h4:hover .anchor .octicon-link,
.markdown-body h5:hover .anchor .octicon-link,
.markdown-body h6:hover .anchor .octicon-link {
visibility: visible;
}
.markdown-body h1 {
padding-bottom: 0.3em;
font-size: 2em;
border-bottom: 1px solid #eaecef;
}
.markdown-body h2 {
padding-bottom: 0.3em;
font-size: 1.5em;
border-bottom: 1px solid #eaecef;
}
.markdown-body h3 {
font-size: 1.25em;
}
.markdown-body h4 {
font-size: 1em;
}
.markdown-body h5 {
font-size: 0.875em;
}
.markdown-body h6 {
font-size: 0.85em;
color: #6a737d;
}
.markdown-body ul,
.markdown-body ol {
padding-left: 2em;
}
.markdown-body ul ul,
.markdown-body ul ol,
.markdown-body ol ol,
.markdown-body ol ul {
margin-top: 0;
margin-bottom: 0;
}
.markdown-body li {
word-wrap: break-all;
}
.markdown-body li>p {
margin-top: 16px;
}
.markdown-body li+li {
margin-top: 0.25em;
}
.markdown-body dl {
padding: 0;
}
.markdown-body dl dt {
padding: 0;
margin-top: 16px;
font-size: 1em;
font-style: italic;
font-weight: 600;
}
.markdown-body dl dd {
padding: 0 16px;
margin-bottom: 16px;
}
.markdown-body table {
display: block;
width: 100%;
overflow: auto;
}
.markdown-body table th {
font-weight: 600;
}
.markdown-body table th,
.markdown-body table td {
padding: 6px 13px;
border: 1px solid #dfe2e5;
}
.markdown-body table tr {
background-color: #fff;
border-top: 1px solid #c6cbd1;
}
.markdown-body table tr:nth-child(2n) {
background-color: #f6f8fa;
}
.markdown-body img {
max-width: 100%;
box-sizing: content-box;
background-color: #fff;
}
.markdown-body img[align=right] {
padding-left: 20px;
}
.markdown-body img[align=left] {
padding-right: 20px;
}
.markdown-body code {
padding: 0.2em 0.4em;
margin: 0;
font-size: 85%;
background-color: rgba(27,31,35,0.05);
border-radius: 3px;
}
.markdown-body pre {
word-wrap: normal;
}
.markdown-body pre>code {
padding: 0;
margin: 0;
font-size: 100%;
word-break: normal;
white-space: pre;
background: transparent;
border: 0;
}
.markdown-body .highlight {
margin-bottom: 16px;
}
.markdown-body .highlight pre {
margin-bottom: 0;
word-break: normal;
}
.markdown-body .highlight pre,
.markdown-body pre {
padding: 16px;
overflow: auto;
font-size: 85%;
line-height: 1.45;
background-color: #f6f8fa;
border-radius: 3px;
}
.markdown-body pre code {
display: inline;
max-width: auto;
padding: 0;
margin: 0;
overflow: visible;
line-height: inherit;
word-wrap: normal;
background-color: transparent;
border: 0;
}
.markdown-body .full-commit .btn-outline:not(:disabled):hover {
color: #005cc5;
border-color: #005cc5;
}
.markdown-body kbd {
display: inline-block;
padding: 3px 5px;
font: 11px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
line-height: 10px;
color: #444d56;
vertical-align: middle;
background-color: #fafbfc;
border: solid 1px #d1d5da;
border-bottom-color: #c6cbd1;
border-radius: 3px;
box-shadow: inset 0 -1px 0 #c6cbd1;
}
.markdown-body :checked+.radio-label {
position: relative;
z-index: 1;
border-color: #0366d6;
}
.markdown-body .task-list-item {
list-style-type: none;
}
.markdown-body .task-list-item+.task-list-item {
margin-top: 3px;
}
.markdown-body .task-list-item input {
margin: 0 0.2em 0.25em -1.6em;
vertical-align: middle;
}
.markdown-body hr {
border-bottom-color: #eee;
}

27
public/css/icon-font.css Normal file
View File

@@ -0,0 +1,27 @@
@font-face {font-family: "iconfont";
src: url('//at.alicdn.com/t/font_763046_rsnoy98vrk.eot?t=1532504912578'); /* IE9*/
src: url('//at.alicdn.com/t/font_763046_rsnoy98vrk.eot?t=1532504912578#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAfwAAsAAAAACyQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFZW+UjkY21hcAAAAYAAAACBAAAB1pyToQ9nbHlmAAACBAAAA70AAASA3tzLCWhlYWQAAAXEAAAALgAAADYSG9ySaGhlYQAABfQAAAAeAAAAJAfeA4lobXR4AAAGFAAAABgAAAAcG+oAAGxvY2EAAAYsAAAAEAAAABADJgQubWF4cAAABjwAAAAfAAAAIAEXAGtuYW1lAAAGXAAAAUUAAAJtPlT+fXBvc3QAAAekAAAASQAAAFqzFk32eJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2Bk/ss4gYGVgYOpk+kMAwNDP4RmfM1gxMjBwMDEwMrMgBUEpLmmMDgwVDz7ytzwv4EhhrmBoRsozAiSAwA3jQ1xeJzFkdENwjAMRJ+TUiEUMQmjMABj9DNfjNZxvEG/yzkuEkzQi16Usy5yFAMXoIqHmMDeGKGuqo165TbqE0/5xpWic3fzxVff9j3Szo/7ypRu3McKV9Vt1t0iM3Oa7LzW/2pjfx0ufqQf6IlOEtNxS2JaviSR9zWJyfmWUD7QsSHNAAAAeJxlUt2LG1UUv+fe+Ug22ZnMJDM3m4/JfGRm0qbJbvMxY7YmWVhbd9OCNVbWUintg1uLbhGKLOgiW1CJYGEFEUSQWpeKLAg+aH0obF98Kv0XhNL1oSD0SWShHb3Z1Afxcrnn+5x7zu8gHqG/H5A7JIvSqIKOohfQaYRAqIIt4SJYfquOq6BZvEYzEvEd3xIdu066QG0hozeClkcFUZBBAgOaViPw69iHdquHj0FDLwLM5HOvqG5BJVswlfWNj6IBvglaySnIvVq0fKSfaZjp2HpSVWdU9dOYwPMxjDlZgjWqx/n4lBBt83JOu1M6hEuQnPFzp85Om3n14qh1pejSOMDmJqTzpvRdX8kp7G7k9LQ6I6amY9nctFPOwPpeIptOFr2HiB3Men2X/IAfIooMhHhdcCzbC6Ht2F4rYN/XM6xxTQaLtB2NXDf97tMrXd+EUlnWdRkO3vLXX8EXtwZyc3m5Cb/uaYauG9qe/yeI+/usBrAamxwim8hkFTSrXQe/B6E7pm3GGEA1CUSNZ0xGIHefbBYcEM4IYM4fB7K1trZF4Pg8mExVfk8QpubMzgm4sWhfXbrATMzhwtJVe/EGvPicOYee1XtAKqSBFpgQ9CEIRUFkFRgoDBqGmeeHQXhgGOtlLIhB2IOx7PXEUJewiN9Pp00lkeC5mDaVSF48nVJTlVowUyhWkpJbXrAM91B5paa/VLJB4GjG5DDHye6xwWvnzh2G6TRNwDVBiPPcYTWml6XUtCFJUjKnA8dN9TPZfv+d+VY1qG0MnI+bHSWnL9ZOxAmfnzu7+sb55VmSf/3Nt46MexFYL5+TP8jbqIDm0CI6hV5F5xFyHW3uqOZbYZO2m2yESh2q0G6yASoSuI7M8GPDVZjFmujSLc+32AgUJja1kMW0/THCY3yd/zHkg+GjaH9ld3uUNQCMbBDMdjHuRn/tfnh9eMDOYrveA+jFSvTpbxOn0f37tPSjks3alP6kUOpQ+vOEnInfvhuMRlCisERLIfTq0S+z3ZsvD79lieDLScLoEqP8JFV0idGNDcZtj+P/ew9m8jv5hliIIBnlkYOqY6Rdvx0Hj2OAUp2hq0KrBw0DNAl71ACmdkJSH1NtvA5CHbMd8IV/3UNYXwUF1pPR97snE63OveHOINpWTddUsdfxnidieeET3u6I12rz9ccyJvmA4yghciZlxTB/uSLzn63uRI/xSBzsDO91WomTu7ASPVFNtkhq0QXv0SQUas9S3SaEclyQJ1jm5cplHsesVIZB/g+Q18kBAAAAeJxjYGRgYADhqOvf4vltvjJwszCAwPU6nwAE/b+UhYG5AcjlYGACiQIAH2sJvwAAeJxjYGRgYG7438AQwwJkMTCwMDCAaSTADgBHJgJxAAB4nGNhYGBgfsnAwAKkWRihNBQDABbCAQYAAAAAAHYAqADgAUYB0AJAeJxjYGRgYGBniGdgYwABJiDmAkIGhv9gPgMAEtgBgwB4nGWPTU7DMBCFX/oHpBKqqGCH5AViASj9EatuWFRq911036ZOmyqJI8et1ANwHo7ACTgC3IA78EgnmzaWx9+8eWNPANzgBx6O3y33kT1cMjtyDRe4F65TfxBukF+Em2jjVbhF/U3YxzOmwm10YXmD17hi9oR3YQ8dfAjXcI1P4Tr1L+EG+Vu4iTv8CrfQ8erCPuZeV7iNRy/2x1YvnF6p5UHFockikzm/gple75KFrdLqnGtbxCZTg6BfSVOdaVvdU+zXQ+ciFVmTqgmrOkmMyq3Z6tAFG+fyUa8XiR6EJuVYY/62xgKOcQWFJQ6MMUIYZIjK6Og7VWb0r7FDwl57Vj3N53RbFNT/c4UBAvTPXFO6stJ5Ok+BPV8bUnV0K27LnpQ0kV7NSRKyQl7WtlRC6gE2ZVeOEXpc0Yk/KGdI/wAJWm7IAAAAeJxjYGKAAC4G7ICdkYmRmZGFkZWRjZGdkYOBsYI1LSexOJsrMzkvsSwxKb+0hLkgNY8jOT83NzWvxJCtKD85O7WEgQEAMokOAwAAAA==') format('woff'),
url('//at.alicdn.com/t/font_763046_rsnoy98vrk.ttf?t=1532504912578') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
url('//at.alicdn.com/t/font_763046_rsnoy98vrk.svg?t=1532504912578#iconfont') format('svg'); /* iOS 4.1- */
}
.iconfont {
font-family:"iconfont" !important;
font-size:16px;
font-style:normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-flask:before { content: "\e6f5"; }
.icon-icnavabout:before { content: "\e600"; }
.icon-pen:before { content: "\e6be"; }
.icon-comment1:before { content: "\e601"; }
.icon-rocket:before { content: "\e670"; }

View File

@@ -424,6 +424,7 @@ input[type="checkbox"].input-validation-error {
.sweet-alert h2 { .sweet-alert h2 {
font-size: 20px !important; font-size: 20px !important;
font-weight: normal !important; font-weight: normal !important;
margin-bottom: 10px !important;
} }
body.dragging, body.dragging * { body.dragging, body.dragging * {
@@ -715,6 +716,7 @@ body.dragging, body.dragging * {
border-style: solid solid none; border-style: solid solid none;
border-width: 1px 0; border-width: 1px 0;
transition: width 0.3s; transition: width 0.3s;
min-height: 400px;
} }
.post-title { .post-title {
@@ -1186,8 +1188,8 @@ img.wechat-img {
padding: 20px; padding: 20px;
} }
.widget-text-box .fa-wechat, .widget-text-box .fa-envelope { .widget-text-box .fa-github, .widget-text-box .fa-envelope {
color: #1ab394; color: #666;
} }
.widget-text-box .fa-qrcode { .widget-text-box .fa-qrcode {
@@ -1359,7 +1361,7 @@ img.wechat-img {
border-bottom-color: transparent; border-bottom-color: transparent;
} }
.post-content h2 { .post-content .normal-body h2 {
background: #fbfbfb none repeat scroll 0 0; background: #fbfbfb none repeat scroll 0 0;
border-left: 4px solid #39c; border-left: 4px solid #39c;
color: #222; color: #222;
@@ -1370,19 +1372,19 @@ img.wechat-img {
} }
.post-content .scroll-nav__section:nth-child(5n+1) h2 { .post-content .scroll-nav__section:nth-child(5n+1) h2 {
border-left: 4px solid #b9d329; border-left-color: #b9d329;
} }
.post-content .scroll-nav__section:nth-child(5n+2) h2 { .post-content .scroll-nav__section:nth-child(5n+2) h2 {
border-left: 4px solid #ffae5b; border-left-color: #ffae5b;
} }
.post-content .scroll-nav__section:nth-child(5n+3) h2 { .post-content .scroll-nav__section:nth-child(5n+3) h2 {
border-left: 4px solid #c0ebf7; border-left-color: #c0ebf7;
} }
.post-content .scroll-nav__section:nth-child(5n+4) h2 { .post-content .scroll-nav__section:nth-child(5n+4) h2 {
border-left: 4px solid #69bcf3; border-left-color: #69bcf3;
} }
.ueditor-body h2 { .ueditor-body h2 {
@@ -1395,14 +1397,14 @@ img.wechat-img {
padding: 17px 40px 16px 23px; padding: 17px 40px 16px 23px;
} }
.post-content h3 { .post-content .normal-body h3 {
color: #444; color: #444;
font-size: 15px; font-size: 15px;
margin: 26px auto 10px; margin: 26px auto 10px;
font-weight: bold; font-weight: bold;
} }
.post-content h3::before { .post-content .normal-body h3::before {
color: #39c; color: #39c;
content: "■"; content: "■";
margin-right: 5px; margin-right: 5px;
@@ -1450,3 +1452,12 @@ img.wechat-img {
#user_page li { #user_page li {
clear: none; clear: none;
} }
.nav > li > a.locale-link {
font-size: 12px;
color: #666;
}
.fa {
position: relative;
}

BIN
public/images/filterBar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
public/images/youlunhb.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -1,15 +0,0 @@
$(function () {
$(".my-nav-pills li:contains('关于')").addClass("active").siblings().removeClass("active");
$("#job-title").cycleText();
$(".fa-qrcode").mouseenter(function () {
$(".profile-img").hide();
$(".wechat-img").show();
});
$(".fa-qrcode").mouseleave(function () {
$(".wechat-img").hide();
$(".profile-img").show();
});
});

File diff suppressed because one or more lines are too long

4
public/js/about.js Normal file
View File

@@ -0,0 +1,4 @@
$(function () {
$(".my-nav-pills li:contains('关于')").addClass("active").siblings().removeClass("active");
$("#job-title").cycleText();
});

View File

@@ -6,7 +6,7 @@
dataType: "json", dataType: "json",
done: function (e, data) { done: function (e, data) {
$(this).prev("img").attr("src", data.result.files[0].url); $(this).prev("img").attr("src", data.result.files[0].url);
$(this).next(":hidden").val('/images/' + data.result.files[0].name); $(this).next(":hidden").val('/static/images/' + data.result.files[0].name);
} }
}); });

View File

@@ -16,9 +16,9 @@
slide_links: 'blank', // Individual links for each slide (Options: false, 'num', 'name', 'blank') slide_links: 'blank', // Individual links for each slide (Options: false, 'num', 'name', 'blank')
thumbnail_navigation: 0, // Thumbnail navigation thumbnail_navigation: 0, // Thumbnail navigation
slides: [ // Slideshow Images slides: [ // Slideshow Images
{image: "/images/s1.jpg"}, {image: "/static/images/s1.jpg"},
{image: "/images/s2.jpg"}, {image: "/static/images/s2.jpg"},
{image: "/images/s3.jpg"} {image: "/static/images/s3.jpg"}
], ],
progress_bar: 1 // Timer for each slide progress_bar: 1 // Timer for each slide
}); });
@@ -51,7 +51,7 @@ function verify() {
} }
password = md5(password); password = md5(password);
var $btn = $("#btnLogin"); var $btn = $("#btnLogin");
$btn.find("i").removeClass("fa-sign-in").addClass("fa-circle-o-notch fa-spin"); $btn.find("i").removeClass("fa-sign-in-alt").addClass("fa-circle-o-notch fa-spin");
$btn.attr("disabled", "disabled"); $btn.attr("disabled", "disabled");
$.ajax({ $.ajax({
url: "/login", url: "/login",
@@ -67,7 +67,7 @@ function verify() {
showConfirmButton: false, showConfirmButton: false,
timer: 2000 timer: 2000
}); });
$btn.find("i").removeClass("fa-circle-o-notch fa-spin").addClass("fa-sign-in"); $btn.find("i").removeClass("fa-circle-o-notch fa-spin").addClass("fa-sign-in-alt");
$btn.removeAttr("disabled"); $btn.removeAttr("disabled");
} }
} }

View File

@@ -1,25 +1,28 @@
$(function () { $(function () {
$(".my-nav-pills li:eq(0)").addClass("active").siblings().removeClass("active"); $(".my-nav-pills li:eq(0)").addClass("active").siblings().removeClass("active");
//如果目录默认为收起状态,则重新计算显示目录按钮的位置 // 如果目录默认为收起状态,则重新计算显示目录按钮的位置
if (expandMenu === 'false') { if (expandMenu === 'false') {
$(".btn-menu").css("margin-left", $(".post-content").width() + 31 + "px"); $(".btn-menu").css("margin-left", $(".post-content").width() + 31 + "px");
$(".btn-menu").show(); $(".btn-menu").show();
} }
//代码高亮 // 代码高亮
var pres = $('#main-context pre'); if (!contentType) {
pres.each(function (i, pre) { // UEditor 产出的文档要处理一下
$(pre).html($('<code></code>').html($(pre).html())) var pres = $('#main-context pre');
}); pres.each(function (i, pre) {
$(pre).html($('<code></code>').html($(pre).html()))
});
}
hljs.initHighlightingOnLoad(); hljs.initHighlightingOnLoad();
//将img套上a标签以使用lightbox显示图片 // 将img套上a标签以使用lightbox显示图片
$("#main-context").find("img").wrap(function (i) { $("#main-context").find("img").wrap(function (i) {
return "<a href=\"" + this.src + "\" data-lightbox=\"" + i + "\"></a>" return "<a href=\"" + this.src + "\" data-lightbox=\"" + i + "\"></a>"
}); });
//正常目录 // 正常目录
$("#main-context").scrollNav({ $("#main-context").scrollNav({
sections: "h2", //一级目录的元素 sections: "h2", //一级目录的元素
subSections: "h3", //二级目录的元素 subSections: "h3", //二级目录的元素
@@ -59,9 +62,16 @@
'.post-title h1', '.post-title h1',
'.post-content blockquote', '.post-content blockquote',
'.post-content blockquote h2', '.post-content blockquote h2',
'.post-content h1',
'.post-content h2', '.post-content h2',
'.post-content h3', '.post-content h3',
'.post-content pre' '.post-content h4',
'.post-content h5',
'.post-content pre',
'.post-content p',
'.post-content ul',
'.post-content table',
'.post-content'
]; ];
//缩小字体 //缩小字体

View File

@@ -28,7 +28,7 @@ $(function () {
showColumns: true, showColumns: true,
iconsPrefix: "fa", iconsPrefix: "fa",
icons: { icons: {
refresh: "fa-refresh", refresh: "fa-sync",
columns: "fa-th-list" columns: "fa-th-list"
}, },
idField: "UniqueId", idField: "UniqueId",
@@ -153,10 +153,10 @@ $(function () {
}, },
formatter: function (value, row) { formatter: function (value, row) {
if (row.IsActive) { if (row.IsActive) {
return "<a class=\"edit btn btn-white\" title=\"编辑\" href=\"/admin/editarticle/" + row.UniqueId + "\"><i class=\"fa fa-pencil\"></i></a> " return "<a class=\"edit btn btn-white\" title=\"编辑\" href=\"/admin/editarticle/" + row.UniqueId + "\"><i class=\"fa fa-pencil-alt\"></i></a> "
+ "<button type=\"button\" class=\"remove btn btn-white\" title=\"删除\"><i class=\"fa fa-trash-o\"></i></button>"; + "<button type=\"button\" class=\"remove btn btn-white\" title=\"删除\"><i class=\"far fa-trash-alt\"></i></button>";
} else { } else {
return "<a class=\"edit btn btn-white\" title=\"编辑\" href=\"/admin/editarticle/" + row.UniqueId + "\"><i class=\"fa fa-pencil\"></i></a> " return "<a class=\"edit btn btn-white\" title=\"编辑\" href=\"/admin/editarticle/" + row.UniqueId + "\"><i class=\"fa fa-pencil-alt\"></i></a> "
+ "<button type=\"button\" class=\"undo btn btn-white\" title=\"恢复\"><i class=\"fa fa-undo\"></i></button>"; + "<button type=\"button\" class=\"undo btn btn-white\" title=\"恢复\"><i class=\"fa fa-undo\"></i></button>";
} }
} }

View File

@@ -227,7 +227,7 @@ function addPage(index, data) {
+ value.Url.substring(0, value.Url.indexOf("://") + 3) + value.Host + value.Url.substring(0, value.Url.indexOf("://") + 3) + value.Host
+ "\" class=\"pull-right margin-left-20 hidden-xs\">" + "\" class=\"pull-right margin-left-20 hidden-xs\">"
+ " " + " "
+ "<i class=\"fa fa-globe\"></i> " + value.Host + "<i class=\"fa fa-globe-americas\"></i> " + value.Host
+ " <\/a>" + " <\/a>"
+ " <div class=\"clearfix\">" + " <div class=\"clearfix\">"
+ " <\/div>" + " <\/div>"

View File

@@ -196,8 +196,8 @@ function bindFileUpload() {
url: "/admin/uploadimg", url: "/admin/uploadimg",
dataType: "text", dataType: "text",
done: function (e, data) { done: function (e, data) {
$(this).prev().attr("src", '/images/' + data.files[0].name); $(this).prev().attr("src", '/static/images/' + data.files[0].name);
$(this).parent().parent().parent().parent().data("img", '/images/' + data.files[0].name); $(this).parent().parent().parent().parent().data("img", '/static/images/' + data.files[0].name);
} }
}); });
} }

View File

@@ -1,7 +1,8 @@
$(function () { $(function () {
$("#side-menu>li:eq(2)").addClass("active").find("ul").addClass("in").find("li:eq(2)").addClass("active"); $("#side-menu>li:eq(2)").addClass("active").find("ul").addClass("in").find("li:eq(2)").addClass("active");
refreshCate(); refreshCate();
var editor;
var simplemde;
if (source == "1") { if (source == "1") {
$("#soruceLink").radio("check") $("#soruceLink").radio("check")
@@ -10,10 +11,23 @@
} }
$("#myPillbox").pillbox("addItems", 0, JSON.parse($('#Labels').val())); $("#myPillbox").pillbox("addItems", 0, JSON.parse($('#Labels').val()));
var editor = UE.getEditor("editor", { $('[name=ContentType]').on('change', evt => {
var el = evt.currentTarget;
if (el.value === 'markdown') {
$('#editor').hide();
$('#mdEditor').show();
simplemde.value(editor.getContentTxt());
} else {
$('#mdEditor').hide();
$('#editor').show();
editor.setContent(simplemde.value());
}
});
editor = UE.getEditor("editor", {
allowDivTransToP: false, allowDivTransToP: false,
initialFrameHeight: 300, initialFrameHeight: 300,
textarea: "Content" textarea: 'no-use'
}); });
editor.ready(function () { editor.ready(function () {
@@ -22,6 +36,25 @@
}); });
}); });
simplemde = new SimpleMDE({
element: document.querySelector('#mdEditor textarea'),
status: false,
renderingConfig: {
codeSyntaxHighlighting: true,
},
toolbar: ['bold', 'italic', 'strikethrough', 'heading', 'code', 'quote', 'unordered-list', 'ordered-list',
'link', 'image', 'table', 'horizontal-rule', 'preview'],
spellChecker: false
});
if (editorType === 'markdown') {
$('#mdRadio').radio('check');
$('#mdEditor').show();
} else {
$('#ueRadio').radio('check');
$('#editor').css('display', 'block');
}
$(".btn-alias").on("click", function () { $(".btn-alias").on("click", function () {
var appid, var appid,
key, key,
@@ -36,6 +69,14 @@
$(that).addClass("disabled"); $(that).addClass("disabled");
appid = '20151219000008011'; appid = '20151219000008011';
key = translateKey; key = translateKey;
if (!translateKey) {
swal({
title: '生成失败',
text: '请先在系统设置中配置百度翻译key',
type: "error",
});
return;
}
salt = (new Date).getTime(); salt = (new Date).getTime();
from = 'zh'; from = 'zh';
to = 'en'; to = 'en';
@@ -54,6 +95,14 @@
sign: sign sign: sign
}, },
success: function (data) { success: function (data) {
if (data.error_code) {
swal({
title: '生成失败',
text: data.error_msg,
type: "error",
});
return;
}
var en = data.trans_result[0].dst; var en = data.trans_result[0].dst;
var result = en.trim().toLowerCase().split(' ').join('-'); var result = en.trim().toLowerCase().split(' ').join('-');
$("#Alias").val(result).focus(); $("#Alias").val(result).focus();
@@ -63,9 +112,25 @@
$(that).removeClass("disabled"); $(that).removeClass("disabled");
} }
}); });
} else {
$("#Title").focus();
} }
}); });
function getFormData() {
var data = $("#postForm").serialize();
var contentType = $('[name=ContentType]:checked').val();
var content;
if (contentType === 'markdown') {
content = simplemde.value();
} else {
content =editor.getContent();
}
content = encodeURIComponent(content);
data += '&Content=' + content;
return data;
}
$("#postForm").on('init.field.fv', function (e, data) { $("#postForm").on('init.field.fv', function (e, data) {
var $parent = data.element.parents('.form-group'), var $parent = data.element.parents('.form-group'),
$icon = $parent.find('.form-control-feedback[data-fv-icon-for="' + data.field + '"]'); $icon = $parent.find('.form-control-feedback[data-fv-icon-for="' + data.field + '"]');
@@ -79,7 +144,7 @@
icon: { icon: {
valid: 'fa fa-check', valid: 'fa fa-check',
invalid: 'fa fa-remove', invalid: 'fa fa-remove',
validating: 'fa fa-refresh' validating: 'fa fa-sync'
}, },
err: { err: {
container: 'tooltip' container: 'tooltip'
@@ -138,7 +203,7 @@
$('#IsDraft').val('False'); $('#IsDraft').val('False');
swal({ swal({
title: isPublish ? '确定要发布该文章吗?' : '确定提交更新吗?', title: isPublish ? '确定要发布该文章吗?' : '确定提交更新吗?',
text: $("#CategoryId").val() === "other" ? "<span style='color:#d9534f;'>注意:当前选择文章分类为\"未分类\"</span>" : null, text: $("#CategoryId").val() === "other" ? "<span style='color:#d9534f;'>注意:当前选择文章分类</span>" : null,
html: true, html: true,
type: "warning", type: "warning",
allowOutsideClick: true, allowOutsideClick: true,
@@ -151,10 +216,11 @@
function () { function () {
$(".sweet-alert .confirm").text(isPublish ? '发布中...' : '提交中...'); $(".sweet-alert .confirm").text(isPublish ? '发布中...' : '提交中...');
$(".sweet-alert .confirm").attr("disabled", "disabled"); $(".sweet-alert .confirm").attr("disabled", "disabled");
console.log(getFormData())
$.ajax({ $.ajax({
url: $("#postForm")[0].action, url: $("#postForm")[0].action,
type: $("#postForm")[0].method, type: $("#postForm")[0].method,
data: $("#postForm").serialize(), data: getFormData(),
success: function () { success: function () {
if (isPublish) { if (isPublish) {
swal({ swal({
@@ -197,7 +263,7 @@
$.ajax({ $.ajax({
url: $("#postForm")[0].action, url: $("#postForm")[0].action,
type: $("#postForm")[0].method, type: $("#postForm")[0].method,
data: $("#postForm").serialize(), data: getFormData(),
success: function () { success: function () {
swal({ swal({
title: '草稿保存成功!', title: '草稿保存成功!',

View File

@@ -20,7 +20,7 @@ $(function () {
showColumns: true, showColumns: true,
iconsPrefix: "fa", iconsPrefix: "fa",
icons: { icons: {
refresh: "fa-refresh", refresh: "fa-sync",
columns: "fa-th-list", columns: "fa-th-list",
detailOpen: "fa-plus", detailOpen: "fa-plus",
detailClose: "fa-minus" detailClose: "fa-minus"

View File

@@ -40,7 +40,7 @@ $(function () {
click: function () { click: function () {
var index = $(this).attr("page"); var index = $(this).attr("page");
var pageItem = $("#page" + index); var pageItem = $("#page" + index);
$("html,body").animate({scrollTop: $(pageItem).offset().top - 90}, 1000); $("html,body").animate({ scrollTop: $(pageItem).offset().top - 90 }, 1000);
} }
}, "#page-nav a"); }, "#page-nav a");
@@ -71,7 +71,7 @@ $(function () {
$.ajax({ $.ajax({
url: "/blog/getPreviewContent", url: "/blog/getPreviewContent",
type: "Post", type: "Post",
data: {alias: alias}, data: { alias: alias },
success: function (data) { success: function (data) {
var end = new Date(); var end = new Date();
$this.data('preview-data', data); $this.data('preview-data', data);
@@ -162,6 +162,7 @@ function requestData() {
function appendContent(data) { function appendContent(data) {
$(".sk-cube-grid").hide(); $(".sk-cube-grid").hide();
$(".post-content div").removeClass('markdown-body normal-body').addClass(data.ContentType === 'markdown' ? 'markdown-body' : 'normal-body');
$(".post-content div").html(data.Content); $(".post-content div").html(data.Content);
var labels = JSON.parse(data.Labels); var labels = JSON.parse(data.Labels);
@@ -174,7 +175,9 @@ function appendContent(data) {
$(".post-content div").fadeIn(); $(".post-content div").fadeIn();
var pres = $('.post-content pre'); var pres = $('.post-content pre');
pres.each(function (i, pre) { pres.each(function (i, pre) {
$(pre).html($('<code></code>').html($(pre).html())); if (!data.ContentType) {
$(pre).html($('<code></code>').html($(pre).html()));
}
hljs.highlightBlock($(pre).children('code')[0]); hljs.highlightBlock($(pre).children('code')[0]);
}); });
} }
@@ -192,6 +195,11 @@ function resetModal() {
} }
function searchPost() { function searchPost() {
var inputEl = $('#Keyword');
if (!inputEl.val()) {
inputEl.focus();
return;
}
$(".list-wrap ol").html(""); $(".list-wrap ol").html("");
$("[data-toggle='tooltip']").tooltip("hide"); $("[data-toggle='tooltip']").tooltip("hide");
$("#page-nav").html(""); $("#page-nav").html("");
@@ -240,7 +248,7 @@ function addPage(index, data) {
+ value.Url.substring(0, value.Url.indexOf("://") + 3) + value.Host + value.Url.substring(0, value.Url.indexOf("://") + 3) + value.Host
+ "\" class=\"pull-right margin-left-20 hidden-xs\">" + "\" class=\"pull-right margin-left-20 hidden-xs\">"
+ " " + " "
+ "<i class=\"fa fa-globe\"></i> " + value.Host + "<i class=\"fa fa-globe-americas\"></i> " + value.Host
+ " <\/a>" + " <\/a>"
+ " <div class=\"clearfix\">" + " <div class=\"clearfix\">"
+ " <\/div>" + " <\/div>"
@@ -277,7 +285,7 @@ function addPage(index, data) {
} }
} else { } else {
$(".list-wrap ol").append("<li id=\"page" + index + "\"></li>"); $(".list-wrap ol").append("<li id=\"page" + index + "\"></li>");
$("#page" + index).append("<div class=\"text-center text-muted\">暂无数据</div>"); $("#page" + index).append("<div class=\"text-center text-muted\" style=\"line-height: 34px;\">暂无数据</div>");
} }
isLoading = false; isLoading = false;
if ($(".home-loading").length > 0) { if ($(".home-loading").length > 0) {

View File

@@ -1,16 +1,29 @@
$(function () { $(function () {
$("#side-menu>li:eq(2)").addClass("active").find("ul").addClass("in").find("li:eq(0)").addClass("active"); $("#side-menu>li:eq(2)").addClass("active").find("ul").addClass("in").find("li:eq(0)").addClass("active");
$("#Title").focus(); $("#Title").focus();
refreshCate(); refreshCate();
var editor;
var simplemde;
var editor = UE.getEditor("editor", { $('[name=ContentType]').on('change', evt => {
var el = evt.currentTarget;
if (el.value === 'markdown') {
$('#editor').hide();
$('#mdEditor').show();
simplemde.value(editor.getContentTxt());
} else {
$('#mdEditor').hide();
$('#editor').show();
editor.setContent(simplemde.value());
}
});
editor = UE.getEditor("editor", {
allowDivTransToP: false, allowDivTransToP: false,
initialFrameHeight: 300, initialFrameHeight: 300,
initialContent: "请输入文章正文", initialContent: "请输入文章正文",
autoClearinitialContent: true, autoClearinitialContent: true,
textarea: "Content" textarea: 'no-use'
}); });
editor.ready(function () { editor.ready(function () {
@@ -19,6 +32,25 @@
}); });
}); });
simplemde = new SimpleMDE({
element: document.querySelector('#mdEditor textarea'),
status: false,
renderingConfig: {
codeSyntaxHighlighting: true,
},
toolbar: ['bold', 'italic', 'strikethrough', 'heading', 'code', 'quote', 'unordered-list', 'ordered-list',
'link', 'image', 'table', 'horizontal-rule', 'preview'],
spellChecker: false
});
if (editorType === 'markdown') {
$('#mdRadio').radio('check');
$('#mdEditor').show();
} else {
$('#ueRadio').radio('check');
$('#editor').css('display', 'block');
}
$(".btn-alias").on("click", function () { $(".btn-alias").on("click", function () {
var appid, var appid,
key, key,
@@ -33,6 +65,14 @@
$(that).addClass("disabled"); $(that).addClass("disabled");
appid = '20151219000008011'; appid = '20151219000008011';
key = translateKey; key = translateKey;
if (!translateKey) {
swal({
title: '生成失败',
text: '请先在系统设置中配置百度翻译key',
type: "error",
});
return;
}
salt = (new Date).getTime(); salt = (new Date).getTime();
from = 'zh'; from = 'zh';
to = 'en'; to = 'en';
@@ -51,6 +91,14 @@
sign: sign sign: sign
}, },
success: function (data) { success: function (data) {
if (data.error_code) {
swal({
title: '生成失败',
text: data.error_msg,
type: "error",
});
return;
}
var en = data.trans_result[0].dst; var en = data.trans_result[0].dst;
var result = en.trim().toLowerCase().split(' ').join('-'); var result = en.trim().toLowerCase().split(' ').join('-');
$("#Alias").val(result).focus(); $("#Alias").val(result).focus();
@@ -63,6 +111,20 @@
} }
}); });
function getFormData() {
var data = $("#postForm").serialize();
var contentType = $('[name=ContentType]:checked').val();
var content;
if (contentType === 'markdown') {
content = simplemde.value();
} else {
content =editor.getContent();
}
content = encodeURIComponent(content);
data += '&Content=' + content;
return data;
}
$("#postForm").on('init.field.fv', function (e, data) { $("#postForm").on('init.field.fv', function (e, data) {
var $parent = data.element.parents('.form-group'), var $parent = data.element.parents('.form-group'),
$icon = $parent.find('.form-control-feedback[data-fv-icon-for="' + data.field + '"]'); $icon = $parent.find('.form-control-feedback[data-fv-icon-for="' + data.field + '"]');
@@ -134,7 +196,7 @@
$('#IsDraft').val('False'); $('#IsDraft').val('False');
swal({ swal({
title: "确定要发布该文章吗?", title: "确定要发布该文章吗?",
text: $("#CategoryId").val() === "other" ? "<span style='color:#d9534f;'>注意:当前选择文章分类为\"未分类\"</span>" : null, text: $("#CategoryId").val() === "other" ? "<span style='color:#d9534f;'>注意:当前选择文章分类</span>" : null,
html: true, html: true,
type: "warning", type: "warning",
allowOutsideClick: true, allowOutsideClick: true,
@@ -150,7 +212,7 @@
$.ajax({ $.ajax({
url: $("#postForm")[0].action, url: $("#postForm")[0].action,
type: $("#postForm")[0].method, type: $("#postForm")[0].method,
data: $("#postForm").serialize(), data: getFormData(),
success: function () { success: function () {
swal({ swal({
title: "发布成功!", title: "发布成功!",
@@ -184,7 +246,7 @@
$.ajax({ $.ajax({
url: $("#postForm")[0].action, url: $("#postForm")[0].action,
type: $("#postForm")[0].method, type: $("#postForm")[0].method,
data: $("#postForm").serialize(), data: getFormData(),
success: function () { success: function () {
swal({ swal({
title: '草稿保存成功!', title: '草稿保存成功!',

View File

@@ -3,9 +3,14 @@
var elems = Array.prototype.slice.call(document.querySelectorAll('.js-switch')); var elems = Array.prototype.slice.call(document.querySelectorAll('.js-switch'));
elems.forEach(function (el) { elems.forEach(function (el) {
var switchery = new Switchery(el, { color: '#1AB394' }); var switchery = new Switchery(el, {
color: '#1AB394',
size: 'small'
});
}); });
$("#Editorlist").selectlist("selectByValue", $('#Editor').val());
$(document).on({ $(document).on({
change: function () { change: function () {
$(this).prev(":hidden").val(this.checked); $(this).prev(":hidden").val(this.checked);
@@ -17,7 +22,7 @@
dataType: "text", dataType: "text",
done: function (e, data) { done: function (e, data) {
if(data.result){ if(data.result){
var path = '/images/' + JSON.parse(data.result).files[0].name; var path = '/static/images/' + JSON.parse(data.result).files[0].name;
$(this).prev("img").attr("src", path); $(this).prev("img").attr("src", path);
$(this).next(":hidden").val(path); $(this).next(":hidden").val(path);
} }

View File

@@ -27,9 +27,9 @@ $(function () {
}); });
menu.on('transitionend webkitTransitionEnd oTransitionEnd', function () { menu.on('transitionend webkitTransitionEnd oTransitionEnd', function () {
if (rot / 180 % 2 == 0) { if (rot / 180 % 2 == 0) {
$("#share-menu i.fa").addClass('bounce'); $("#share-menu i.fab").addClass('bounce');
} else { } else {
$("#share-menu i.fa").removeClass('bounce'); $("#share-menu i.fab").removeClass('bounce');
} }
}); });
} }

View File

@@ -0,0 +1,13 @@
{
"name": "form.validation",
"homepage": "https://github.com/formvalidation/formvalidation",
"_release": "a6001290fe",
"_resolution": {
"type": "branch",
"branch": "master",
"commit": "a6001290fea95a3a38a6b1f32431dca962182c3a"
},
"_source": "https://github.com/formvalidation/formvalidation.git",
"_target": "*",
"_originalSource": "form.validation"
}

View File

@@ -0,0 +1,3 @@
.idea
_gh_pages
node_modules

View File

@@ -0,0 +1,788 @@
# Change Log
## v0.6.2 (not released yet)
__New Features__
* Add STATUS_IGNORED status. The field will be ignored for the current validation if the validator returns null/undefined
__Improvements__
* #44: [date](http://formvalidation.io/validators/date/) validator supports dot (.) separator for European countries
* #62: Allow to use callback for field's [excluded](http://formvalidation.io/settings/#field-excluded) option
__Bug Fixes__
* #47: Spanish VAT validator doesn't work with some examples
* #48: Override the options when adding field
* #50: The Brazilian [Id](http://formvalidation.io/validators/id/) (CPF) number must have 11 digits
* The [updateMessage()](http://formvalidation.io/api/#update-message) method must return the plugin instance for chaining
* When calling [resetField(true)](http://formvalidation.io/api/#reset-field) and [resetForm(true)](http://formvalidation.io/api/#reset-form) methods, the field need be reset value before updating the status
__Document__
* #38: Add [Loading and saving data in a modal](http://formvalidation.io/examples/loading-saving-data-modal/) example
* #43: Add [Playing with Bootstrap Combobox](http://formvalidation.io/examples/bootstrap-combobox/) example
* #45: Update the [Showing card icon](http://formvalidation.io/validators/creditCard/#showing-card-icon) example
* #49: Add [Switching validators on the same field](http://formvalidation.io/examples/switching-validators-same-field/) example
* #54: Add [Playing with geocomplete](http://formvalidation.io/examples/geocomplete/) example
* Add [Conditional validation](http://formvalidation.io/examples/conditional-validation/) example
* Fix the [Clearing field when clicking the icon](http://formvalidation.io/examples/clearing-field-when-clicking-icon/) example
* Update the [iCheck](http://formvalidation.io/examples/icheck/) example to support mobile browsers
## v0.6.1 (2015-02-24)
__New Features__
* #467: Add ```dataType```, ```crossDomain```, ```validKey``` options for [remote](http://formvalidation.io/validators/remote/) validator.
It's possible to use remote validator to connect to external validator API, such as [MailGun (#1315)](https://github.com/formvalidation/formvalidation/issues/1315)
* #940: Add ```declarative``` option to support big form
* #1328, #1330: Add Netherlands [phone](http://formvalidation.io/validators/phone/) validator, thanks to [@HendrikSwBase](https://github.com/HendrikSwBase)
* #1347: Add Bulgarian [zip code](http://formvalidation.io/validators/zipCode/) validator, thanks to [@Izopi4a](https://github.com/Izopi4a)
* #1350: Add Bulgarian [phone number](http://formvalidation.io/validators/phone/) validator, thanks to [@Izopi4a](https://github.com/Izopi4a)
* #1355: Add Polish [zip code](http://formvalidation.io/validators/zipCode/) and [id](http://formvalidation.io/validators/id/) validators, thanks to [@tjagusz](https://github.com/tjagusz)
* #1357: Support custom framework
__Improvements__
* #1327: [remote](http://formvalidation.io/validators/remote/) validator fails if Ajax request fails
* #1427: Update Netherlands [phone number](http://formvalidation.io/validators/phone/) validator, thanks to [@DiederikLascaris](https://github.com/DiederikLascaris)
* Add plugin instance to the 3rd parameter of [transformer](http://formvalidation.io/settings/#validator-transformer) callback
* Add Grunt task that runs the jasmine test suites
__Bug Fixes__
This version fixed the ```isValid()``` method which should return ```null``` when there is not validated or being validated field.
It also solves the issues where the submit button is disabled even when the form is valid.
* #962, #1318: remote validator and ```isValid()``` combined do not work
* #1160: Submit button is disabled
* #1171: Submit button being disabled
* #1220: Can only submit form after changing a value
* #1221, #1344: Remote validation trigger ```err.form.fv```
* #1394: Submit incorrectly enabled even though form has errors
Other issues are fixed in this version:
* #1107, #1279, #1280, #1419: Show the ```validating``` icon when the field is being validated
* #1282: Reset checkbox when calling [resetForm()](http://formvalidation.io/api/#reset-form) method
* #1320: Fix Slovakia [phone number](http://formvalidation.io/validators/phone/) validator
* #1343, #1369: Fix the issue where custom validator doesn't provide default message
* #1379: Don't continue if there is no validators attached to fields
* #1387: [transformer](http://formvalidation.io/settings/#validator-transformer) option doesn't work with [notEmpty](http://formvalidation.io/validators/notEmpty/) validator
* #1389: Fix ```isValidContainer()``` and ```validateContainer()``` methods to support fields with the same name
__Document__
* #673: Update [emailAddress](http://formvalidation.io/validators/emailAddress/) validator document
* #688: Add a [notice](http://formvalidation.io/settings/#form-icon) when using FontAwesome icon
* #973, #1021, #1346: 3 ways to [improve performance](http://formvalidation.io/validators/remote/#improving-the-performance) when using remote validator
* #1098, #1118, #1325: Add [Playing with Fuel UX Wizard](http://formvalidation.io/examples/fuel-ux-wizard/) example
* #1109, #1326: Add [Playing with Typehead](http://formvalidation.io/examples/typeahead/) example
* #1112: Support thousand separator
* #1124, #1329: Fix [CKEditor example](http://formvalidation.io/examples/ckeditor/) on Firefox
* #1205: Add [Playing with Bootstrap Material Design](http://formvalidation.io/examples/bootstrap-material-design/) example
* #1308: Update [Showing card icon](http://formvalidation.io/validators/creditCard/#showing-card-icon) example
* #1313: Add [Adding warning validation state](http://formvalidation.io/examples/adding-warning-validation-state/) example
* #1315: Add [Using Mailgun API to validate email address](http://formvalidation.io/examples/using-mailgun-api-validate-email-address/) example
* #1333: Update [Enabling the submit button](http://formvalidation.io/examples/enabling-submit-button/) example
* #1378: Add [Validating multiple inputs as one](http://formvalidation.io/examples/validating-multiple-inputs-one/) example
* #1388: Add [Field value is changed programmatically](http://formvalidation.io/examples/field-value-changed-programmatically/) example
* #1390: Fix the [isValid()](http://formvalidation.io/api/#is-valid) method document
* #1397: Add [Updating validator options](http://formvalidation.io/examples/updating-validator-options/) example
* #1423: Update the [UIKit icon usage](http://formvalidation.io/settings/#form-icon)
* formvalidation/formvalidation.io#11: Fix the issue in [Settings Structure](http://formvalidation.io/settings/#settings-structure) section, thanks to [@DiederikLascaris](https://github.com/DiederikLascaris)
* formvalidation/support#29: Add [Playing with jQuery UI Datepicker](http://formvalidation.io/examples/jquery-ui-datepicker/) example
* formvalidation/support#33: Add [Playing with Flat UI](http://formvalidation.io/examples/flat-ui/) example
* formvalidation/support#37: Add [Showing all messages when using callback validator](http://formvalidation.io/validators/callback/#showing-all-messages) example
__Language Packages__
* #1381: Update Slovak language package, thanks to [@PatrikGallik](https://github.com/PatrikGallik)
* #1400: Update Belgian Dutch language package, thanks to [@jdt](https://github.com/jdt)
* #1432: Fix some typos in the Hungarian translation, thanks to [@blackfyre](https://github.com/blackfyre)
## v0.6.0 (2015-01-06)
__New Features__
* #708, #899: Add ```setLocale()``` and ```getLocale()``` methods to support multiple languages
* #718: Add ```validateContainer()``` method
* #744: Add [transformer](http://formvalidation.io/settings/#validator-transformer) option, allowing to hook the value of field before validating
* #1131: Support add-on
* #1140: Add UAE [phone number](http://formvalidation.io/validators/phone/) validator, thanks to [@s-a-y](https://github.com/s-a-y)
* #1153: Add EIN validator, thanks to [@joshuachestang](https://github.com/joshuachestang)
* #1165: Add BIC (ISO 9362) validator, thanks to [@thomaslhotta](https://github.com/thomaslhotta)
* #1185: Add ```composer.json``` file, thanks to [@rbnvrw](https://github.com/rbnvrw)
* #1189, #1194: Add ```err```, ```icon```, ```row``` options
* #1204: __Support Zurb Foundation framework__
* #1207: Add Spanish [postal code](http://formvalidation.io/validators/zipCode/) validator, thanks to [@ethernet-zero](https://github.com/ethernet-zero)
* #1208: Support Spanish [CIF](http://formvalidation.io/validators/id/) validator, thanks to [@ethernet-zero](https://github.com/ethernet-zero)
* #1210: __Support UI Kit framework__
* #1211: __Support Semantic UI framework__
* #1212: __Support Pure framework__
* #1227, #1229: Add India [phone number](http://formvalidation.io/validators/phone/) validator, thanks to [@waveking](https://github.com/waveking)
* #1230, #1231: Add India [postal code](http://formvalidation.io/validators/zipCode/) validator, thanks to [@waveking](https://github.com/waveking)
__Changes__
* #1167: Remove hexColor validator. Use [color](http://formvalidation.io/validators/color/) validator instead
* #1272: Change event ```error.x.x``` to ```err.x.x``` to avoid ```window.onerror``` being invoked by jQuery
* Remove tab behavior from base class
__Add-ons__
* #1116: Showing only one message each time
* #1126: Required icon
* #1132: Google reCAPTCHA add-on
* multilingual add-on
__Improvements__
* #883: Look for the field inside form first when using selector, thanks to [@drebrez](https://github.com/drebrez)
* #908, #1156: Add option to set optional protocol in [uri](http://formvalidation.io/validators/uri/) validator, thanks to [@krecik](https://github.com/krecik)
* #914, #1035, #1163: Improve [identical](http://formvalidation.io/validators/identical/) validator, thanks to [@jazzzz](https://github.com/jazzzz)
* #1037: Show the credit card icon based on its type
* #1083, [#1092](https://github.com/formvalidation/formvalidation/pull/1092/): Showing tooltip/popover when moving over or clicking the feedback icon (Bootstrap 3.3.0), thanks to [@Arkni](https://github.com/Arkni)
* #1137: Use ```jQuery``` instead of ```window.jQuery```
* #1154: Allow to reuse data which is returned by the validator
* #1177: Don't need to set the [different](http://formvalidation.io/validators/different/) validator for both fields
* #1186, #1188: Improve the [CPF](http://formvalidation.io/validators/id/) validator, thanks to [@igorescobar](https://github.com/igorescobar)
* #1197: Add sample data for [CPF](http://formvalidation.io/validators/id/) validator, thanks to [@dgmike](https://github.com/dgmike)
* #1207: Improve Spanish [phone](http://formvalidation.io/validators/phone/) validator, thanks to [@ethernet-zero](https://github.com/ethernet-zero)
* #1218: Improve Slovenian [vat number](http://formvalidation.io/validators/vat/) validator, thanks to [@Glavic](https://github.com/Glavic)
* #1224: Improve tooltip style when working with Semantic UI form, thanks to [@Arkni](https://github.com/Arkni)
* #1226: Fix destroying Semantic UI popup, thanks to [@Arkni](https://github.com/Arkni)
* #1239: Fix typo in UIKit class, thanks to [@Arkni](https://github.com/Arkni)
* #1252: Validators return true for not supported countries
* #1255, #1258: Support to use a Date object as value for ```min``` and ```max``` options, thanks to [@Arkni](https://github.com/Arkni)
* #1261: Improve [cvv](http://formvalidation.io/validators/cvv/) validator
* #1268: [uri](http://formvalidation.io/validators/uri/) validator gets slower if more than 25 characters
* The ```isValidContainer()``` method should return ```null``` if the container consists of at least one field which is not validated yet or being validated
__Bug Fixes__
* #1101: The [cusip](http://formvalidation.io/validators/cusip/) validator doesn't work
* #1102: Fix the [date](http://formvalidation.io/validators/date/) validator issue where accepts ```2014-11-1 23:``` as valid ```YYYY-MM-DD h:m``` date
* #1105: The [color](http://formvalidation.io/validators/color/) validator doesn't provide ```html5Attributes``` mapping
* #1125, #1136: Update Brazil [ID](http://formvalidation.io/validators/id/) validator to support working with Mask plugin, thanks to [@jonasesteves](https://github.com/jonasesteves)
* #1243: Fix the icon without label class
* #1267: [identical](http://formvalidation.io/validators/identical/) validator allows to compare with any input
* #1274: Fix ```validateContainer()``` to use map value instead of key, thanks to [@jasonblalock](https://github.com/jasonblalock)
* #1279, #1280: Show the ```validating``` icon when the field is being validated, thanks to [@tmaly1980](https://github.com/tmaly1980)
* #1292: Fix bug of US [phone number](http://formvalidation.io/validators/phone/) validator
__Document__
* #800: Add [Using uri and regexp validators](http://formvalidation.io/validators/uri/#using-with-regexp-validator) example
* #825: Add [Bootstrap Datepicker](http://formvalidation.io/examples/bootstrap-datepicker/) example
* #919, #1114: Add [Google reCAPTCHA](http://formvalidation.io/examples/validating-google-recaptcha/) example
* #941: Add [Clearing field when clicking the icon](http://formvalidation.io/examples/clearing-field-when-clicking-icon/) example
* #948, #978, #1032, #1146, #1162: Add the [Is a@b valid email address](http://formvalidation.io/validators/emailAddress/#is-ab-valid-email-address) section
* #1034: Add [Only enable the submit button if all fields are valid](http://formvalidation.io/examples/enabling-submit-button/) example
* #1078, #1104: Update the [Enabling the submit button all the time](http://formvalidation.io/examples/enabling-submit-button/) example
* #1106: Add example to the [phone](http://formvalidation.io/validators/phone/) validator
* #1122: Add third parameter to ```callback``` method of [callback](http://formvalidation.io/validators/callback/) validator, thanks to [@Arkni](https://github.com/Arkni)
* #1128: Add link to the [Examples](http://formvalidation.io/examples/) from the [homepage](http://formvalidation.io/#2)
* #1139: Add sample [United Arab Emirates phone numbers](http://formvalidation.io/validators/phone/), thanks to [@s-a-y](https://github.com/s-a-y)
* #1143, #1176: Add [Form is submitted twice](http://formvalidation.io/examples/form-submit-twice/) example
* #1172: Add [Requiring at least one field](http://formvalidation.io/examples/requiring-at-least-one-field/) example
* #1174: Add [Pickadate](http://formvalidation.io/examples/pickadate/) example
* #1187: Add sample [Brazil ID (CPF) numbers](http://formvalidation.io/validators/id/), thanks to [@igorescobar](https://github.com/igorescobar)
* #1233: Add sample [India postal code numbers](http://formvalidation.io/validators/zipCode/), thanks to [@waveking](https://github.com/waveking)
__Language Packages__
* #1150: Add Catalan language package, thanks to [@ArnauAregall](https://github.com/ArnauAregall)
* #1216, #1248: Add Slovak language package, thanks to [@budik21](https://github.com/budik21)
* #1217, #1247: Update Czech language package, thanks to [@budik21](https://github.com/budik21)
* #1225: Add Finnish language package, thanks to [@traone](https://github.com/traone)
* #1246: Add Hindi language package, thanks to [@gladiatorAsh](https://github.com/gladiatorAsh)
* #1321: Add Basque language package, thanks to [@xabikip](https://github.com/xabikip)
## v0.5.3 (2014-11-05)
__New Features__
* #807, #821: Add ```min```, ```max``` options for the [date](http://formvalidation.io/validators/date/) validator, thanks to [@Arkni](https://github.com/Arkni)
* #822: Add [color](http://formvalidation.io/validators/color/) validator, thanks to [@emilchristensen](https://github.com/emilchristensen)
* #844, #874: The [stringLength](http://formvalidation.io/validators/stringLength/) validator adds option to evaluate length in UTF-8 bytes, thanks to [@thx2001r](https://github.com/thx2001r)
* #937, #1001: Add ```minFiles```, ```maxFiles```, ```minTotalSize```, ```maxTotalSize``` options for the [file](http://formvalidation.io/validators/file/) validator, thanks to [@morrizon](https://github.com/morrizon)
* #960, #1052: Add ```trim``` option for the [stringLength](http://formvalidation.io/validators/stringLength/) validator
* #1008: Add France [postal code](http://formvalidation.io/validators/zipCode/) validator, thanks to [@jazzzz](https://github.com/jazzzz)
* #1010: Add Ireland [postal code](http://formvalidation.io/validators/zipCode/) validator, thanks to [@zmira](https://github.com/zmira)
* #1018: Add German [phone number](http://formvalidation.io/validators/phone/) and [postal code](http://formvalidation.io/validators/zipCode/) validators, thanks to [@jhadenfeldt](https://github.com/jhadenfeldt)
* #1022: Add Portugal [postal code](http://formvalidation.io/validators/zipCode/) validator, thanks to [@zmira](https://github.com/zmira)
* #1033, #1043, #1068: Add ```autoFocus``` option
* #1072: Add Austria and Switzerland [postal code](http://formvalidation.io/validators/zipCode/) validators, thanks to [@thomaslhotta](https://github.com/thomaslhotta)
__Improvements__
* #823: The [hexColor](http://formvalidation.io/validators/color/) validator only accepts 6 hex character values when using HTML 5 ```type='color'``` attribute
* #864: Comma separator handling in [greaterThan](http://formvalidation.io/validators/greaterThan/), [lessThan](http://formvalidation.io/validators/lessThan/) validators, thanks to [@mgibas](https://github.com/mgibas)
* #999, #1048: Replace ',' with '.' to validate decimal numbers correct, thanks to [@johanronn77](https://github.com/johanronn77)
* #1002: Put tooltip/popover on bottom if there is not enough space on top, thanks to [@jazzzz](https://github.com/jazzzz)
* #1015: The [remote](http://formvalidation.io/validators/remote/) validator allows to set ```data``` options via HTML attributes, thanks to [@jazzzz](https://github.com/jazzzz)
* #1017: Enable validator when setting ```data-bv-validatorname="data-bv-validatorname"```, thanks to [@jazzzz](https://github.com/jazzzz)
* #1026: Requires jQuery 1.9.1 or higher
__Bug Fixes__
* #343, #481, #1045: Fix double submit with defered validators, thanks to [@jazzzz](https://github.com/jazzzz)
* #933, #959, #1047: Tooltip/popover isn't destroyed when the field is valid
* #991: The field is validated only one time when setting ```trigger: 'blur'```, ```container: 'tooltip'```
* #1014: Fix [isValidField()](http://formvalidation.io/api/#is-valid-field) and [validateField()](http://formvalidation.io/api/#validate-field) methods for fields without validators, thanks to [@jazzzz](https://github.com/jazzzz)
* #1050: Fix the issue when using multiple fields with same name, the tooltip of the last element is always shown
* #1055, #1063: The [error.field.bv](http://formvalidation.io/settings/#event-field) event isn't triggered if verbose is set to false, thanks to [@shineability](https://github.com/shineability)
* #1057, #1063: The [verbose](http://formvalidation.io/settings/#field-verbose) option for field doesn't override the form level, thanks to [@shineability](https://github.com/shineability)
__Document__
* #848: Update the [stringLength](http://formvalidation.io/validators/stringLength) document, thanks to [@Relequestual](https://github.com/Relequestual)
* #885: Add a notification about setting [identical](http://formvalidation.io/validators/identical/) validator for both fields
* #912: Add [Using language package](http://formvalidation.io/examples/using-language-package/) example
* #920, #929, #936: Update the [Changing the tooltip, popover's position](http://formvalidation.io/examples/tooltip-popover-position/) example, thanks to [@Arkni](https://github.com/Arkni)
* #938: Add [time](http://formvalidation.io/validators/regexp/#html-5-example) validator example
* #979: Add [Rails usage](http://formvalidation.io/validators/stringLength/#using-with-rails-form) for [stringLength](http://formvalidation.io/validators/stringLength/) validator
* #1006: Fix the order of [parameters](http://formvalidation.io/settings/#validator-enabled) for [enableFieldValidators()](http://formvalidation.io/api/#enable-field-validators) method, thanks to [@mchrapka](https://github.com/mchrapka)
* #1009: Fix mixed data/delay in [remote](http://formvalidation.io/validators/remote/) doc, thanks to [@jazzzz](https://github.com/jazzzz)
* #1019: Updated docs for added German [postal code](http://formvalidation.io/validators/zipCode/) and [phone number](http://formvalidation.io/validators/phone/) validators, thanks to [@jhadenfeldt](https://github.com/jhadenfeldt)
* #1038: Fix [Changing tooltip, popover's position](http://formvalidation.io/examples/changing-tooltip-position/) example link, thanks to [@Arkni](https://github.com/Arkni)
__Language Packages__
* #827: Update Dutch language package, thanks to [@JvanderHeide](https://github.com/JvanderHeide)
* #829: Update Swedish language package, thanks to [@ulsa](https://github.com/ulsa)
* #834: Update Ukrainian and Russian language packages, thanks to [@oleg-voloshyn](https://github.com/oleg-voloshyn)
* #835: Update Belgium (French) language package, thanks to [@neilime](https://github.com/neilime)
* #836: Update French language package, thanks to [@neilime](https://github.com/neilime)
* #837: Update Bulgarian language package, thanks to [@mraiur](https://github.com/mraiur)
* #846: Update simplified Chinese language package, thanks to [@shamiao](https://github.com/shamiao)
* #849: Update Serbian language package, thanks to [@markocrni](https://github.com/markocrni)
* #850, #851: Update Danish language package, thanks to [@Djarnis](https://github.com/Djarnis)
* #869: Update Polish language package, thanks to [@grzesiek](https://github.com/grzesiek)
* #870: Update Traditional Chinese language package, thanks to [@tureki](https://github.com/tureki)
* #871: Update Czech language package, thanks to [@cuchac](https://github.com/cuchac)
* #872: Update Indonesian language package, thanks to [@egig](https://github.com/egig)
* #879: Update Romanian language package, thanks to [@filipac](https://github.com/filipac)
* #880: Update Belgium (Dutch) language package, thanks to [@dokterpasta](https://github.com/dokterpasta)
* #881: Update Italian language package, thanks to [@maramazza](https://github.com/maramazza)
* #882: Update Spanish language package, thanks to [@vadail](https://github.com/vadail)
* #891: Update Portuguese (Brazil) language package, thanks to [@dgmike](https://github.com/dgmike)
* #893: Fix country name of Dominican Republic, thanks to [@sventech](https://github.com/sventech)
* #900: Update Persian (Farsi) language package, thanks to [@i0](https://github.com/i0)
* #903: Update Hungarian language package, thanks to [@blackfyre](https://github.com/blackfyre)
* #910: Update Greek language package, thanks to [@pRieStaKos](https://github.com/pRieStaKos)
* #913: Update Thai language package, thanks to [@figgaro](https://github.com/figgaro)
* #915: Update Turkish language package, thanks to [@CeRBeR666](https://github.com/CeRBeR666)
* #961: Update Chilean Spanish language package, thanks to [@marceloampuerop6](https://github.com/marceloampuerop6)
* #967: Add Hebrew language package, thanks to [@yakidahan](https://github.com/yakidahan)
* #974: Add Albanian language package, thanks to [@desaretiuss](https://github.com/desaretiuss)
* #1025: Fix French emailAddress message, thanks to [@jazzzz](https://github.com/jazzzz)
* #1051: Add Portuguese language package, thanks to [@rtbfreitas](https://github.com/rtbfreitas)
## v0.5.2 (2014-09-25)
__New Features__
* #480: Add ```verbose``` option, thanks to [@mbezhanov](https://github.com/mbezhanov)
* #542, #666: Add blank validator, thanks to [@bermo](https://github.com/bermo)
* #617: Add ```init``` and ```destroy``` methods to validator
* #724: Add Venezuelan VAT number (RIF) validator, thanks to [@paquitodev](https://github.com/paquitodev)
* #739: Add China phone number validator, thanks to [@caijh](https://github.com/caijh)
* #743: Add Venezuela phone number validator, thanks to [@paquitodev](https://github.com/paquitodev)
* #760: Add Romania phone number validator, thanks to [@adrian-dks](https://github.com/adrian-dks)
* #761: Add Romania postal code validator, thanks to [@adrian-dks](https://github.com/adrian-dks)
* #785: Add Denmark phone number validator, thanks to [@emilchristensen](https://github.com/emilchristensen)
* #787: Add Thailand phone number and ID validator, thanks to [@figgaro](https://github.com/figgaro)
* #793, #798: Add Chinese citizen ID validator, thanks to [@shamiao](https://github.com/shamiao)
* #802: Add Russia phone number validator, thanks to [@cylon-v](https://github.com/cylon-v). #816: Improved by [@stepin](https://github.com/stepin)
* #816: Add Russian postal code validator, thanks to [@stepin](https://github.com/stepin)
* #867: Add Czech and Slovakia phone number and postal code validators, thanks to [@cuchac](https://github.com/cuchac)
__Changes__
* #753: Change the default type of [remote](http://formvalidation.io/validators/remote/) validator to GET
__Improvements__
* #249, #574, #669: Add ```delay``` option to the [remote](http://formvalidation.io/validators/remote/) validator, thanks to [@q-state](https://github.com/q-state)
* #345, #454: The [different](http://formvalidation.io/validators/different/) validator allows more than a 2-way comparison, thanks to [@AlaskanShade](https://github.com/AlaskanShade)
* #557, #569: The [container](http://formvalidation.io/settings/#form-container) option can be defined by a callback, thanks to [@mattrick](https://github.com/mattrick)
* #570: Use CSS classes instead of inline styling to fix icons with ```input-group```, thanks to [@dlcrush](https://github.com/dlcrush)
* #578, #813: The [stringLength](http://formvalidation.io/validators/stringLength/) validator supports HTML 5 ```minlength``` attribute, thanks to [@emilchristensen](https://github.com/emilchristensen)
* #675: The [emailAddress](http://formvalidation.io/validators/emailAddress/) validator accepts multiple email addresses, thanks to [@kenny-evitt](https://github.com/kenny-evitt)
* #716, #765: Reuse data returned by [callback](http://formvalidation.io/validators/callback/), [remote](http://formvalidation.io/validators/remote/), custom validators
* #734: The [uri](http://formvalidation.io/validators/uri/) validator adds support for custom protocol, thanks to [@bcamarneiro](https://github.com/bcamarneiro)
* #737: Support VAT number without prefixing by country code
* #754: Support latest Bootstrap when using tooltip/popover to show the message
* #783: Improve behaviour of the [different](http://formvalidation.io/validators/different/) validator
* #792: Add "BootstrapValidator's JavaScript requires jQuery" warning, thanks to [@Arkni](https://github.com/Arkni)
* #803: Add ```minSize``` option for the [file](http://formvalidation.io/validators/file/) validator, thanks to [@Arkni](https://github.com/Arkni)
* #824: Add [phone](http://formvalidation.io/validators/phone/) number validator test suite
__Bug Fixes__
* #611, #703: Tabs get red even form is valid
* #612, #740, #741: Fix the [emailAddress](http://formvalidation.io/validators/emailAddress/) issue which email@server is not valid email address, thanks to [@kromit](https://github.com/kromit)
* #687, #711: Keep disabled validators VALID, thanks to [@talberti](https://github.com/talberti)
* #725: Fix the issue when adding field which does not exist but is already set in "fields" option
* #732: Fix the issue when removing the radio or checkbox field
* #746, #922: The form is still submitted when clicking on submit button which is set ```onclick="return false;"```
* #758: Using [notEmpty](http://formvalidation.io/validators/notEmpty/) validator with ```type="number"```
* #759, #764: The tooltip/popover isn't shown if there is disabled validator.
The tooltip/popover is shown automatically when the field gets the focus, thanks to [@leedorian](https://github.com/leedorian)
* #797, #799: Can't validate ipv4 and ipv6 at the same time. Add ip validator test suite, thanks to [@Arkni](https://github.com/Arkni)
* #816: Fix Russian [VAT](http://formvalidation.io/validators/vat/) number validator, thanks to [@stepin](https://github.com/stepin)
* #832: The form won't be validated if the submit button contains a HTML tag
__Document__
* #709, #715: Add [Bootstrap Select](http://formvalidation.io/examples/bootstrap-select/) and [Select2](http://formvalidation.io/examples/select2/) examples, thanks to [@Arkni](https://github.com/Arkni)
* #855, #858: Add [TinyMCE](http://formvalidation.io/examples/tinymce/) example, thanks to [@Arkni](https://github.com/Arkni)
* #859, #862, #865: Add [Changing tooltip/popover position](http://formvalidation.io/examples/tooltip-popover-position/) example, thanks to [@Arkni](https://github.com/Arkni)
__Language Packages__
* #706: Japanese language package, thanks to [@tsuyoshifujii](https://github.com/tsuyoshifujii)
* #712: Swedish language package, thanks to [@ulsa](https://github.com/ulsa)
* #727: Belgium (French) language package, thanks to [@neilime](https://github.com/neilime)
* #729: Persian (Farsi) language package, thanks to [@i0](https://github.com/i0)
* #779: Romanian language package, thanks to [@filipac](https://github.com/filipac)
* #787: Thai language package, thanks to [@figgaro](https://github.com/figgaro)
* #788: Fully re-translated Simplified Chinese language package, thanks to [@shamiao](https://github.com/shamiao)
* #795: Re-translated traditional Chinese language package, thanks to [@tureki](https://github.com/tureki)
* #802: Russian language package, thanks to [@cylon-v](https://github.com/cylon-v). #816: Improved by [@stepin](https://github.com/stepin)
* #806: Ukrainian language package, thanks to [@oleg-voloshyn](https://github.com/oleg-voloshyn)
* #840: Serbian language package, thanks to [@markocrni](https://github.com/markocrni)
* #856: Norwegian language package, thanks to [@trondulseth](https://github.com/trondulseth)
* #868: Indonesian language package, thanks to [@egig](https://github.com/egig)
## v0.5.1 (2014-08-22)
__New Features__
* #218, #531: Add meid validator, thanks to [@troymccabe](https://github.com/troymccabe)
* #267, #532: Add imo validator, thanks to [@troymccabe](https://github.com/troymccabe)
* #510, #646: Add French [phone number](http://formvalidation.io/validators/phone/) validator, thanks to [@dlucazeau](https://github.com/dlucazeau)
* #536: Add Spanish [phone number](http://formvalidation.io/validators/phone/) validator, thanks to [@vadail](https://github.com/vadail)
* #519: Add Iceland [VAT](http://formvalidation.io/validators/vat/) number validator, thanks to [@evilchili](https://github.com/evilchili)
* #620, #621: Add Pakistan [phone number](http://formvalidation.io/validators/phone/) validator, thanks to [@abuzer](https://github.com/abuzer)
* #630, #640: Add event name options to avoid ```window.onerror``` being invoked by jQuery, thanks to [@roryprimrose](https://github.com/roryprimrose). Thanks to [@stephengreentree](https://github.com/stephengreentree) for creating the test suite (#657)
* #637: Add South African [VAT](http://formvalidation.io/validators/vat/) number validator, thanks to [@evilchili](https://github.com/evilchili)
* #638, #647: Add Brazilian [phone number](http://formvalidation.io/validators/phone/) and [postal code](http://formvalidation.io/validators/zipCode/) validator, thanks to [@fhferreira](https://github.com/fhferreira)
* #643: Add [zipCode](http://formvalidation.io/validators/zipCode/) and [phone number](http://formvalidation.io/validators/phone/) validators for Morocco, thanks to [@Arkni](https://github.com/Arkni)
* #650: Add Brazilian [VAT](http://formvalidation.io/validators/vat/) number validator, thanks to [@fhferreira](https://github.com/fhferreira)
__Improvements__
* #502: Allowing sites without TLD to pass URI validation, thanks to [@troymccabe](https://github.com/troymccabe)
* #549, #600: Change the CSS/JS path in ```demo/remote.html``` and ```demo/message.html```, thanks to [@leegtang](https://github.com/leegtang), [@Arkni](https://github.com/Arkni)
* #604: Fix the ```demo/date.html``` and ```demo/tab.html``` examples, thanks to [@Arkni](https://github.com/Arkni)
* #609: Add content-type header for ```demo/remote.php```, thanks to [@etorres](https://github.com/etorres)
* #661: Add ```headers``` option to the [remote](http://formvalidation.io/validators/remote/) validator, thanks to [@ryan2049](https://github.com/ryan2049)
* #664: Fix the feedback icon position for Bootstrap 3.2
* #683: Force the format option to be ```YYYY-MM-DD``` when using ```<input type="date" />```
* #698: Ignore type checking if the file type is empty
__Bug Fixes__
* #284, #294, #441, #516, #580: The HTML 5 ```<input type="number" />``` input allows to input non-digits characters
* #548: Fix the issue when using [different](http://formvalidation.io/validators/different/) validator to compare with not existing field
* #550, #551: Cannot validate against both ipv4 and ipv6 at the same time, thanks to [@beeglebug](https://github.com/beeglebug)
* #588: Don't use min, max attributes (greaterThan, lessThan validators) for ```<input type="date" />```
* #665: The [submitButtons](http://formvalidation.io/settings/#form-submit-buttons) option doesn't work correctly
* #672: The [zipCode](http://formvalidation.io/validators/zipCode/) validator throw an exception when passing not supported country code
* #681: Fix the [date](http://formvalidation.io/validators/date/) validator issue where one of date/month/year or hours/minutes/seconds is prefixed by zero
* #692: The [remote](http://formvalidation.io/validators/remote/) validator can't set the type option via HTML attribute
* #700: The [between](http://formvalidation.io/validators/between/), [greaterThan](http://formvalidation.io/validators/greaterThan/), [lessThan](http://formvalidation.io/validators/lessThan/) validators accept param which isn't number
__Language Packages__
* #400: Italian language package, thanks to [@maramazza](https://github.com/maramazza)
* #503: French language package, thanks to [@dlucazeau](https://github.com/dlucazeau)
* #505: Czech language package, thanks to [@AdwinTrave](https://github.com/AdwinTrave)
* #507: Polish language package, thanks to [@grzesiek](https://github.com/grzesiek). #624: Typos fixed by [@lukaszbanasiak](https://github.com/lukaszbanasiak)
* #517: Belgium (Dutch) language package, thanks to [@dokterpasta](https://github.com/dokterpasta)
* #527: Bulgarian language package, thanks to [@mraiur](https://github.com/mraiur)
* #534: Turkish language package, thanks to [@CeRBeR666](https://github.com/CeRBeR666)
* #536: Spanish language package, thanks to [@vadail](https://github.com/vadail)
* #544: Greek language package, thanks to [@pRieStaKos](https://github.com/pRieStaKos)
* #545: Portuguese (Brazil) language package, thanks to [@marcuscarvalho6](https://github.com/marcuscarvalho6)
* #598: Danish language package, thanks to [@Djarnis](https://github.com/Djarnis)
* #674, #677: Dutch language package, thanks to [@jvanderheide](https://github.com/jvanderheide)
* #679: Add Arabic language package, thanks to [@Arkni](https://github.com/Arkni)
## v0.5.0 (2014-07-14)
__New Features__
* #2, #387: Provide the default error messages
* #93, #385: Support translating error messages. Provide the Vietnamese language file
* #121: Add events for form validate successfully or not
* #125: Support dynamic fields
* #130: Add ```addField()``` and ```removeField()``` methods for managing dynamic fields, thanks to [@jcnmulio](https://github.com/jcnmulio)
* #164: Add ```container``` option for indicating the element showing all errors
* #175: Showing errors in tooltip or popover
* #195: Add events for field validation
* #211, #235: Add new method ```getInvalidFields()``` that returns all invalid fields
* #275: Add ```destroy()``` method
* #282, #347: Use error message that is returned from [callback](http://formvalidation.io/validators/callback/), [remote](http://formvalidation.io/validators/remote/) validators
* Add ```status.field.bv``` event which is triggered after updating the field status. It can be used to solve #300, #301
* #316: Add ```isValidContainer(container)``` method
* #320: Add ```separator``` option to the [date validator](http://formvalidation.io/validators/date/)
* #323: Add ```isValidField(field)``` method
* #324: Add ```success.validator.bv``` and ```error.validator.bv``` events triggered after a validator completes
* #332: Add UK phone number support for the [phone validator](http://formvalidation.io/validators/phone/), thanks to [@aca02djr](https://github.com/aca02djr)
* #336: Add ```$field``` instance to the [callback validator](http://formvalidation.io/validators/callback/)
* #356: Add ```group``` option
* #374: Add Singapore postal code to the [zipCode validator](http://formvalidation.io/validators/zipCode/), thanks to [@thisisclement](https://github.com/thisisclement)
* #406: Add ```revalidateField(field)``` method
* #433: Add ```resetField(field, resetValue)``` method
* #434: Add ```updateMessage(field, validator, message)``` method
__Changes__
* #42: Remove the submit button from ```submitHandler()```. You can use new ```getSubmitButton()``` method to get the clicked submit button
* #109: Remove the ```setLiveMode()``` method
* ```FormValidator.Helper``` renames ```mod_11_10``` to ```mod11And10```, ```mod_37_36``` to ```mod37And36```
* Remove ```submitHandler()``` option. Use ```success.form.bv``` event instead:
_v0.4.5 and earlier versions_
```javascript
$(form).bootstrapValidator({
submitHandler: function(form, validator, submitButton) {
...
}
});
```
_v0.5.0_
Using ```success.form.bv``` event:
```javascript
$(form)
.bootstrapValidator(options)
.on('success.form.bv', function(e) {
// Prevent form submission
e.preventDefault();
var $form = $(e.target),
validator = $form.data('bootstrapValidator'),
submitButton = validator.getSubmitButton();
// Do whatever you want here ...
});
```
__Improvements__
* #244: Only enable the submit buttons if all fields are valid, thanks to [@smeagol74](https://github.com/smeagol74)
* #262: Improve the [```updateStatus()``` method](http://formvalidation.io/api/#update-status). The plugin now doesn't show the errors, feedback icons of given field if there are uncompleted validators
* #274: Fix feedback icons in ```input-group```, thanks to [@tiagofontella](https://github.com/tiagofontella)
* #287, #291: Only send the submit button which is clicked. It's an enhancement for #238
* #297: Disable feedback icons for particular fields
* #348: The [uri validator](http://formvalidation.io/validators/uri/) now provides an option to support private/local network address
* #364: Clicking the feedback icon also effect to the checkbox, radio fields
* #366: Don't change the enable setting when the new one is the same
* #371: Add H character to the Canadian postcode, thanks to [@jzhang6](https://github.com/jzhang6)
* #382: Add JSHint to Grunt build
* #388: Allow to override the default options. Useful for using multiple forms in the same page
* #393: The [remote validator](http://formvalidation.io/validators/remote/) adds support for dynamic ```url``` and method type (GET/POST), thanks to [@ericnakagawa](https://github.com/ericnakagawa)
* #416, #448: Add ```updateOption()``` method for updating the particular validator option, thanks to [@AlaskanShade](https://github.com/AlaskanShade)
* #420: Enable/disable particular validator
* #422: Exclude particular field by ```excluded``` option or ```data-bv-excluded``` attribute
* #426: Add test suite
* #430: [between](http://formvalidation.io/validators/between/), [greaterThan](http://formvalidation.io/validators/greaterThan/), [lessThan](http://formvalidation.io/validators/lessThan/) add support for comparing to other field, return value of a callback function
* #431: Add built time to the build file
* #432: Define the callback via ```data-bv-callback-callback``` attribute
* #447: [zipCode validator](http://formvalidation.io/validators/zipCode/) allow to set the country code via another field or callback, thanks to [@AlaskanShade](https://github.com/AlaskanShade)
* #451: Validation of numeric fields with decimal steps, thanks to [@Azuka](https://github.com/Azuka)
* #456: Adjust the feedback icon position for ```.input-group``` element
* #465: Support dynamic message
__Bug Fixes__
* #288: Fix [date validator](http://formvalidation.io/validators/date/) issue on IE8
* #292: Fix identical validator issue with not clearing ```has-error``` class, thanks to [@alavers](https://github.com/alavers)
* #305, #306, #307: Fix ```inclusive``` option in the [between](http://formvalidation.io/validators/between/), [greaterThan](http://formvalidation.io/validators/greaterThan/) and [lessThan](http://formvalidation.io/validators/lessThan/) validators, thanks to [@johanronn77](https://github.com/johanronn77)
* #310, #475: The [date validator](http://formvalidation.io/validators/date/) still return valid if the value doesn't contain digits
* #311: file validation extension is case sensitive
* #312: Fix broacast typo in the [uri validator](http://formvalidation.io/validators/uri/), thanks to [@mrpollo](https://github.com/mrpollo)
* #313: Fix the [file validator](http://formvalidation.io/validators/file/) issue on IE 8
* #314: The [creditCard validator](http://formvalidation.io/validators/creditCard/) doesn't work on IE 8
* #315: The [cvv validator](http://formvalidation.io/validators/cvv/) doesn't work on IE 8
* #325: The [```threshold``` option](http://formvalidation.io/settings/#threshold) doesn't work on IE 8
* #358: The [zipCode validator](http://formvalidation.io/validators/zipCode/) doesn't work for Canadian zip code
* #375: Don't submit form when the [callback validator](http://formvalidation.io/validators/callback/) completes and the submit button isn't clicked
* #377: The [id](http://formvalidation.io/validators/id/), [vat](http://formvalidation.io/validators/vat/) validators should return ```false``` if the country code is not supported
* #389: When using multiple forms with HTML attributes on the same page, the plugin options will be the same as the last one
* #401: [stringLength validator](http://formvalidation.io/validators/stringLength/) allows spaces after max length
* #411: Fix the [ean validator](http://formvalidation.io/validators/ean/) when the check digit is zero, thanks to [@manish-in-java](https://github.com/manish-in-java)
* #417: IPv6 validator doesn't work
* #425: Custom trigger event is ignored by field validators
* #447: Skip the ```_isExcluded()``` when initializing the form. This fixes #269, #273. Thanks to [@AlaskanShade](https://github.com/AlaskanShade)
* #483, #487: Added the letters 'W' and 'Z' in the second and third letter list for Canada postal code, thanks to [@jzhang6](https://github.com/jzhang6)
* #492, #493: Fixed Chilean ID (RUT/RUN) finished in 'K' or 'k', thanks to [@marceloampuerop6](https://github.com/marceloampuerop6)
__Document__
* #259: Typo "Support almost Bootstrap forms", thanks to [@lloydde](https://github.com/lloydde)
* #261: English fix to 'amazing contributors' section, thanks to [@lloydde](https://github.com/lloydde)
* #278: Update the [choice validator](http://formvalidation.io/validators/choice/) document, thanks to [@MrC0mm0n](https://github.com/MrC0mm0n)
* #303: Fix typo in [remote validator](http://formvalidation.io/validators/remote/) document, thanks to [@MartinDevillers](https://github.com/MartinDevillers)
* #334: No ID is specified on the form object for registration, thanks to [@jjshoe](https://github.com/jjshoe)
* #423: Add default column to settings table, thanks to [@MartinDevillers](https://github.com/MartinDevillers)
* #452: Update 'United State' to 'United States', thanks to [@mike1e](https://github.com/mike1e)
__Language Packages__
* #396: German language package, thanks to [@logemann](https://github.com/logemann)
* #474: Hungarian language package, thanks to [@blackfyre](https://github.com/blackfyre)
* #478: Simplified and traditional Chinese language package, thanks to [@tureki](https://github.com/tureki)
* #494: Chilean Spanish language package, thanks to [@marceloampuerop6](https://github.com/marceloampuerop6)
## v0.4.5 (2014-05-15)
* Add ```FormValidator.Helper.date``` for validating a date, re-used in [date](http://formvalidation.io/validators/date/), [id](http://formvalidation.io/validators/id/), [vat](http://formvalidation.io/validators/vat/) validators
* #233: Add ```threshold``` option
* #232: Add [id validator](http://formvalidation.io/validators/id/)
* #242: Add ```separator``` option to the [numeric validator](http://formvalidation.io/validators/numeric/)
* #248: Add [isin (International Securities Identification Number) validator](http://formvalidation.io/validators/issn/)
* #250: Add [rtn (Routing transit number) validator](http://formvalidation.io/validators/rtn/)
* #251: Add [cusip (North American Securities) validator](http://formvalidation.io/validators/cusip/)
* #252: Add [sedol (Stock Exchange Daily Official List) validator](http://formvalidation.io/validators/sedol/)
* The [zipCode validator](http://formvalidation.io/validators/zipCode/) adds support for Italian, Dutch postcodes
* #245: The [cvv validator](http://formvalidation.io/validators/cvv/) should support spaces in credit card, thanks to [@evilchili](https://github.com/evilchili)
* Change default ```submitButtons``` to ```[type="submit"]``` to support ```input type="submit"```
* #226: Fix the conflict issue with MooTools
* #238: The submit buttons are not sent
* #253: The [iban validator](http://formvalidation.io/validators/iban/) does not work on IE8
* #257: Plugin method invocation don't work
* Fix the issue that the hidden fields generated by other plugins might not be validated
* When parsing options from HTML attributes, don't add the field which hasn't validators. It improves fixes for #191, #223
## v0.4.4 (2014-05-05)
* Add ```FormValidator.Helper.mod_11_10``` method that implements modulus 11, 10 (ISO 7064) algorithm. The helper is then reused in validating [German and Croatian VAT](http://formvalidation.io/validators/vat/) numbers
* Add ```FormValidator.Helper.mod_37_36``` method that implements modulus 37, 36 (ISO 7064) algorithm, used in [GRid validator](http://formvalidation.io/validators/grid/)
* #213: Add [EAN (International Article Number) validator](http://formvalidation.io/validators/ean/)
* #214: Add [GRId (Global Release Identifier) validator](http://formvalidation.io/validators/grid/)
* #215: Add [IMEI (International Mobile Station Equipment Identity) validator](http://formvalidation.io/validators/imei/)
* #216: Add [ISMN (International Standard Music Number) validator](http://formvalidation.io/validators/ismn/)
* #217: Add [ISSN (International Standard Serial Number) validator](http://formvalidation.io/validators/issn/)
* #191, #223: Support using both the ```name``` attribute and ```selector``` option for field
* #206: Indicate success/error tab
* #220: Add UK postcode support for the [zipCode validator](http://formvalidation.io/validators/zipCode/)
* #229: The [date validator](http://formvalidation.io/validators/date/) supports seconds
* #231: Wrong prefix of Laser [credit card](http://formvalidation.io/validators/creditCard/) number
## v0.4.3 (2014-04-26)
* Add ```FormValidator.Helper.luhn``` method that implements the Luhn algorithm
* #77: Add [file validator](http://formvalidation.io/validators/file/)
* #179: Add [vat validator](http://formvalidation.io/validators/vat/), support 32 countries
* #198, #199: Add Canadian Postal Code support for the [zipCode validator](http://formvalidation.io/validators/zipCode/), thanks to [@Francismori7](https://github.com/Francismori7)
* #201: The [choice validator](http://formvalidation.io/validators/choice/) supports ```select``` element
* #202: Activate tab containing the first invalid field
* #205: Plugin method invocation
* #207: IE8 error. The field is only validated when its value is changed. It also fixes #153, #193, #197
* #209: The [```excluded: ':disabled'``` setting](http://formvalidation.io/settings/#excluded) does not work on IE 8, thanks to [@adgrafik](https://github.com/adgrafik)
* #210: The [isbn validator](http://formvalidation.io/validators/isbn/) accepts letters and special characters
## v0.4.2 (2014-04-19)
* #168: Add [siren](http://formvalidation.io/validators/siren/) and [siret](http://formvalidation.io/validators/siret/) validators, thanks to [@jswale](https://github.com/jswale)
* #177: Add [Vehicle Identification Number (VIN) validator](http://formvalidation.io/validators/vin/)
* #184: Add [```excluded``` option](http://formvalidation.io/settings/#excluded)
* #171: The [phone validator](http://formvalidation.io/validators/phone/) now supports +1 country code and area code for US phone number, thanks to [@tomByrer](https://github.com/tomByrer)
* #173: The [remote validator](http://formvalidation.io/validators/remote/) allows to override ```name``` option, thanks to [@jswale](https://github.com/jswale)
* #178: Do not validate fields that ```enabled``` is set to ```false```, thanks to [@henningda](https://github.com/henningda)
* #182: Improve [zipCode validator](http://formvalidation.io/validators/zipCode/), thanks to [@gercheq](https://github.com/gercheq)
* #169: Better to say: ```{validatorname}``` and ```{validatoroption}``` must be lowercase, thanks to [@tomByrer](https://github.com/tomByrer)
## v0.4.1 (2014-04-12)
* #144, #158: Fixed an issue that the custom submit handler is not fired from the second time
* #106: Prevent the [```validate()```](http://formvalidation.io/api/#validate) method from submit the form automatically. So we can call ```validate()``` to validate the form
* #131: Doesn't trigger validation on the first focus
* #145: The row state is now only marked as success if all fields on it are valid
* #157: Added support for element outside of form using the [```selector```](http://formvalidation.io/settings/#fields) option
* #159, #163: User doesn't need to submit the form twice when remote validator complete, thanks to [@jswale](https://github.com/jswale)
* #162: Fix errors in IE 8, thanks to [@adgrafik](https://github.com/adgrafik)
* #166, #167: The [phone validator](http://formvalidation.io/validators/phone/) now also checks the length of US phone number, thanks to [@gercheq](https://github.com/gercheq)
## v0.4.0 (2014-04-03)
* #14, #57: Set validator option by using [HTML 5 attributes](http://formvalidation.io/examples/#attribute)
Form attributes:
```html
<form
data-bv-message="This value is not valid"
data-bv-feedbackicons-valid="glyphicon glyphicon-ok"
data-bv-feedbackicons-invalid="glyphicon glyphicon-remove"
data-bv-feedbackicons-validating="glyphicon glyphicon-refresh"
>
```
Field attributes:
```html
<input type="text" class="form-control" name="username"
data-bv-message="The username is not valid"
data-bv-notempty data-bv-notempty-message="The username is required and cannot be empty"
data-bv-stringlength="true" data-bv-stringlength-min="6" data-bv-stringlength-max="30" data-bv-stringlength-message="The username must be more than 6 and less than 30 characters long"
data-bv-different="true" data-bv-different-field="password" data-bv-different-message="The username and password cannot be the same as each other"
data-bv-remote="true" data-bv-remote-url="remote.php" data-bv-remote-message="The username is not available"
/>
```
* Support [HTML 5 input types](http://formvalidation.io/examples/#html5):
HTML 5 attribute | Validator
----------------------|----------
```min="..."``` | [greaterThan validator](http://formvalidation.io/validators/greaterThan/)
```max="..."``` | [lessThan validator](http://formvalidation.io/validators/lessThan/)
```maxlength="..."``` | [stringLength validator](http://formvalidation.io/validators/stringLength/)
```pattern="..."``` | [regexp validator](http://formvalidation.io/validators/regexp/)
```required``` | [notEmpty validator](http://formvalidation.io/validators/notEmpty/)
```type="color"``` | [hexColor validator](http://formvalidation.io/validators/color/)
```type="email"``` | [emailAddress validator](http://formvalidation.io/validators/emailAddress/)
```type="range"``` | [between validator](http://formvalidation.io/validators/between/)
```type="url"``` | [uri validator](http://formvalidation.io/validators/uri/)
* #74, #103, #122: Set the custom [trigger event](http://formvalidation.io/settings/#trigger)
It's possible to use ```data-bv-trigger``` attribute:
```html
<form data-bv-trigger="keyup">
<input type="text" class="form-control" name="firstName" placeholder="First name"
data-bv-trigger="keyup" />
...
<input type="text" class="form-control" name="lastName" placeholder="First name"
data-bv-trigger="blur" />
</form>
```
or ```trigger``` option:
```javascript
$(form).bootstrapValidator({
trigger: 'blur', // Set for all fields
fields: {
firstName: {
trigger: 'keyup', // Custom for each field. Can be 'event1 event2 event3'
validators: {
...
}
},
lastName: {
trigger: 'blur',
validators: {
...
}
}
}
});
```
* #136: Support multiple elements with the [same name](http://formvalidation.io/examples/#fields-with-same-name)
```html
<div class="form-group">
<input class="form-control" type="text" name="surveyAnswer[]" />
</div>
<div class="form-group">
<input class="form-control" type="text" name="surveyAnswer[]" />
</div>
<div class="form-group">
<input class="form-control" type="text" name="surveyAnswer[]" />
</div>
```
* #109: Add [```setLiveMode()``` method](http://formvalidation.io/api/#set-live-mode) to turn on/off the live validating mode
* #114: Add [iban validator](http://formvalidation.io/validators/iban/) for validating IBAN (International Bank Account Number)
* #116: Add [uuid validator](http://formvalidation.io/validators/uuid/), support UUID v3, v4, v5
* #128: Add [numeric validator](http://formvalidation.io/validators/numeric/)
* #135: Add [integer validator](http://formvalidation.io/validators/integer/)
* #138: Add [hex validator](http://formvalidation.io/validators/hex/)
* #139: Add [stringCase validator](http://formvalidation.io/validators/stringCase/) to check a string is lower or upper case
* #137: Register the plugin with [jQuery plugins site](http://plugins.jquery.com/)
* #133: The [regexp validator](http://formvalidation.io/validators/regexp/) allows to pass a string
* #140: Do not validate hidden (```type="hidden"```) and invisible element, thanks to [@easonhan007](https://github.com/easonhan007)
* [```disableSubmitButtons()```](http://formvalidation.io/api/#disable-submit-buttons) is now marked as a public API
* The first parameter of [```updateStatus()``` method](http://formvalidation.io/api/#update-status) now accepts the field name only
* #126: Submit button remains disabled after calling custom ```submitHandler``` and the form is valid
* #132: The ```fields.[fieldName].message``` option is not used when showing the error message
## v0.3.3 (2014-03-27)
* #50: Don't validate disabled element
* #34, #105: Cannot call ```form.submit()``` inside [```submitHandler```](http://formvalidation.io/settings/#submit-handler)
* #77, #117: The [notEmpty validator](http://formvalidation.io/validators/notEmpty/) doesn't work on file input
* #120: Handle case where a field is removed after the bootstrap validation, thanks to [@patmoore](https://github.com/patmoore)
## v0.3.2 (2014-03-21)
* #56: Add [```selector``` option](http://formvalidation.io/settings/#fields) for each field. The field can be defined by CSS validator instead of the ```name``` attribute
* #107: Add [```container``` option](http://formvalidation.io/settings/#fields) for each field to indicate where the error messages are shown
* #5: Add [ip validator](http://formvalidation.io/validators/ip/). Support both IPv4 and IPv6
* #6: Add [isbn validator](http://formvalidation.io/validators/isbn/), support both ISBN 10 and ISBN 13
* #7: Add [step validator](http://formvalidation.io/validators/step/)
* #95: Add [mac validator](http://formvalidation.io/validators/mac/)
* #96: Add [base64 validator](http://formvalidation.io/validators/base64/)
* #97: Add [cvv validator](http://formvalidation.io/validators/cvv/)
* #99, #100: Add [phone validator](http://formvalidation.io/validators/phone/). Support US phone number only, thanks to [@gercheq](https://github.com/gercheq)
* #112: [creditCard validator](http://formvalidation.io/validators/creditCard/) now validates both IIN ranges and length
## v0.3.1 (2014-03-17)
* #4: Add [date validator](http://formvalidation.io/validators/date/)
* #72, #79: Improve [```updateStatus()``` method](http://formvalidation.io/api/#update-status) to make the plugin play well with another
* #80: Add [```enabled``` option](http://formvalidation.io/settings/#fields) and [```enableFieldValidators()``` method](http://formvalidation.io/api/#enable-field-validators) to enable/disable all validators to given field
* #90: Add ```bower.json``` file, thanks to [@ikanedo](https://github.com/ikanedo)
* #3, #92: Support more form controls on the same row
* Remove the ```columns``` option. Now the plugin works normally no matter how many columns the form uses
* #102: The [```resetForm``` method](http://formvalidation.io/api/#reset-form) now only resets fields with validator rules
* #82, #84: The error messages aren't shown if the form field doesn't have label
* #89: [```submitHandler```](http://formvalidation.io/settings/#submit-handler) or default submission isn't called after [remote validation](http://formvalidation.io/validators/remote/) completes
## v0.3.0 (2014-03-10)
* #44: Rewrite entirely using Deferred
* #26, #27, #67: Add [choice validator](http://formvalidation.io/validators/choice/), thanks to [@emilchristensen](https://github.com/emilchristensen)
* #31: The [remote validator](http://formvalidation.io/validators/remote/) supports dynamic data
* #36, #58: Add method to [validate form](http://formvalidation.io/api/#validate) manually
* #41: Disable submit button on successful form submit
* #42: Add submit button to [```submitHandler()```](http://formvalidation.io/settings/#submit-handler) parameter
* #48: Add optional [feedback icons](http://formvalidation.io/settings/#feedback-icons)
* #64: Support [Danish zip code](http://formvalidation.io/validators/zipCode/), thanks to [@emilchristensen](https://github.com/emilchristensen)
* #65: Support [Sweden zip code](http://formvalidation.io/validators/zipCode/), thanks to [@emilchristensen](https://github.com/emilchristensen)
* #70: Support custom grid columns
* #71: Show all errors
* #76: Add [```resetForm()``` method](http://formvalidation.io/api/#reset-form)
* #50: Don't validate disabled element
* #51: Submit after submit doesn't work
* #53, #54: Fix [notEmpty validator](http://formvalidation.io/validators/notEmpty/) for radios and checkboxes, thanks to [@kristian-puccio](https://github.com/kristian-puccio)
* #55: The plugin doesn't validate other fields if the [remote validator](http://formvalidation.io/validators/remote/) returns ```true```
* #62: The [callback validator](http://formvalidation.io/validators/callback/) passes wrong parameter, thanks to [@iplus](https://github.com/iplus)
* #59: Add example for Rail field convention, thanks to [@narutosanjiv](https://github.com/narutosanjiv)
* #60: Update the installation guide, thanks to [@vaz](https://github.com/vaz)
* #73: Describe which version should be [included](http://formvalidation.io/getting-started/#including-library) in the Usage section
## v0.2.2 (2014-01-07)
* #15: Focus to the first invalid element
* #31: [remote validator](http://formvalidation.io/validators/remote/): Allow to set additional data to remote URL
* #32, #43, #47: Only validate not empty field
* #39: Validate existing fields only
* #34: Avoid from calling form submit recursively
* #40: Fix the issue when the form label doesn't have class
## v0.2.1 (2013-11-08)
* #29: Upgrade Bootstrap to v3.0.2
* #30: Hide the error block containers before validating
## v0.2.0 (2013-10-21)
* #24: Add [```live``` option](http://formvalidation.io/settings/#live)
* #20: Add custom submit handler using [```submitHandler``` option](http://formvalidation.io/settings/#submit-handler)
* #9: Add [creditCard validator](http://formvalidation.io/validators/creditCard/)
* #18: Add [different validator](http://formvalidation.io/validators/different/)
* #21: Add [callback validator](http://formvalidation.io/validators/callback/)
* #22: Support form that labels are placed in extra small (```col-xs-```), small (```col-sm-```), medium (```col-md-```) elements
* #25: The [regexp validator](http://formvalidation.io/validators/regexp/) does not work
## v0.1.1 (2013-10-17)
* Added [```submitButtons``` option](http://formvalidation.io/settings/#submit-buttons)
* #16: Added disabling client side validation in HTML 5
* #17: Added support for default Bootstrap form without labels
* #19: Added support for select box validator
## v0.1.0 (2013-10-14)
* First release
* Provide various validators:
- [between validator](http://formvalidation.io/validators/between/)
- [digits validator](http://formvalidation.io/validators/digits/)
- [emailAddress validator](http://formvalidation.io/validators/emailAddress/)
- [greaterThan validator](http://formvalidation.io/validators/greaterThan/)
- [hexColor validator](http://formvalidation.io/validators/color/)
- [identical validator](http://formvalidation.io/validators/identical/)
- [lessThan validator](http://formvalidation.io/validators/lessThan/)
- [notEmpty validator](http://formvalidation.io/validators/notEmpty/)
- [regexp validator](http://formvalidation.io/validators/regexp/)
- [remote validator](http://formvalidation.io/validators/remote/)
- [stringLength validator](http://formvalidation.io/validators/stringLength/)
- [uri validator](http://formvalidation.io/validators/uri/)
- [zipCode validator](http://formvalidation.io/validators/zipCode/)

View File

@@ -0,0 +1,137 @@
# Contributors
Contributions are welcome!
Please notice that your code may be used as part of a commercial product if the pull request is merged.
I would like to give big thanks to the following contributors:
* [@abuzer](https://github.com/abuzer)
* [@aca02djr](https://github.com/aca02djr)
* [@adgrafik](https://github.com/adgrafik)
* [@adrian-dks](https://github.com/adrian-dks)
* [@AdwinTrave](https://github.com/AdwinTrave)
* [@AlaskanShade](https://github.com/AlaskanShade)
* [@alavers](https://github.com/alavers)
* [@Arkni](https://github.com/Arkni)
* [@ArnauAregall](https://github.com/ArnauAregall)
* [@Azuka](https://github.com/Azuka)
* [@bcamarneiro](https://github.com/bcamarneiro)
* [@beeglebug](https://github.com/beeglebug)
* [@bermo](https://github.com/bermo)
* [@blackfyre](https://github.com/blackfyre)
* [@budik21](https://github.com/budik21)
* [@caijh](https://github.com/caijh)
* [@CeRBeR666](https://github.com/CeRBeR666)
* [@cuchac](https://github.com/cuchac)
* [@cylon-v](https://github.com/cylon-v)
* [@desaretiuss](https://github.com/desaretiuss)
* [@dgmike](https://github.com/dgmike)
* [@DiederikLascaris](https://github.com/DiederikLascaris)
* [@Djarnis](https://github.com/Djarnis)
* [@dlcrush](https://github.com/dlcrush)
* [@dlucazeau](https://github.com/dlucazeau)
* [@dokterpasta](https://github.com/dokterpasta)
* [@drebrez](https://github.com/drebrez)
* [@easonhan007](https://github.com/easonhan007)
* [@egig](https://github.com/egig)
* [@emilchristensen](https://github.com/emilchristensen)
* [@ericnakagawa](https://github.com/ericnakagawa)
* [@ethernet-zero](https://github.com/ethernet-zero)
* [@etorres](https://github.com/etorres)
* [@evilchili](https://github.com/evilchili)
* [@fhferreira](https://github.com/fhferreira)
* [@figgaro](https://github.com/figgaro)
* [@filipac](https://github.com/filipac)
* [@Francismori7](https://github.com/Francismori7)
* [@gercheq](https://github.com/gercheq)
* [@gladiatorAsh](https://github.com/gladiatorAsh)
* [@Glavic](https://github.com/Glavic)
* [@grzesiek](https://github.com/grzesiek)
* [@HendrikSwBase](https://github.com/HendrikSwBase)
* [@henningda](https://github.com/henningda)
* [@i0](https://github.com/i0)
* [@igorescobar](https://github.com/igorescobar)
* [@ikanedo](https://github.com/ikanedo)
* [@iplus](https://github.com/iplus)
* [@Izopi4a](https://github.com/Izopi4a)
* [@jasonblalock](https://github.com/jasonblalock)
* [@jazzzz](https://github.com/jazzzz)
* [@jcnmulio](https://github.com/jcnmulio)
* [@jdt](https://github.com/jdt)
* [@jhadenfeldt](https://github.com/jhadenfeldt)
* [@jjshoe](https://github.com/jjshoe)
* [@johanronn77](https://github.com/johanronn77)
* [@jonasesteves](https://github.com/jonasesteves)
* [@joshuachestang](https://github.com/joshuachestang)
* [@jswale](https://github.com/jswale)
* [@Jvanderheide](https://github.com/Jvanderheide)
* [@jzhang6](https://github.com/jzhang6)
* [@kenny-evitt](https://github.com/kenny-evitt)
* [@khangvm53](https://github.com/khangvm53)
* [@krecik](https://github.com/krecik)
* [@kristian-puccio](https://github.com/kristian-puccio)
* [@kromit](https://github.com/kromit)
* [@leedorian](https://github.com/leedorian)
* [@leegtang](https://github.com/leegtang)
* [@lloydde](https://github.com/lloydde)
* [@logemann](https://github.com/logemann)
* [@lukaszbanasiak](https://github.com/lukaszbanasiak)
* [@manish-in-java](https://github.com/manish-in-java)
* [@maramazza](https://github.com/maramazza)
* [@marceloampuerop6](https://github.com/marceloampuerop6)
* [@marcuscarvalho6](https://github.com/marcuscarvalho6)
* [@markocrni](https://github.com/markocrni)
* [@MartinDevillers](https://github.com/MartinDevillers)
* [@mattrick](https://github.com/mattrick)
* [@mbezhanov](https://github.com/mbezhanov)
* [@mchrapka](https://github.com/mchrapka)
* [@mgibas](https://github.com/mgibas)
* [@mike1e](https://github.com/mike1e)
* [@morrizon](https://github.com/morrizon)
* [@mraiur](https://github.com/mraiur)
* [@MrC0mm0n](https://github.com/MrC0mm0n)
* [@mrpollo](https://github.com/mrpollo)
* [@narutosanjiv](https://github.com/narutosanjiv)
* [@nathanrosspowell](https://github.com/nathanrosspowell)
* [@neilime](https://github.com/neilime)
* [@oleg-voloshyn](https://github.com/oleg-voloshyn)
* [@paquitodev](https://github.com/paquitodev)
* [@patmoore](https://github.com/patmoore)
* [@PatrikGallik](https://github.com/PatrikGallik)
* [@phillprice](https://github.com/phillprice)
* [@pRieStaKos](https://github.com/pRieStaKos)
* [@q-state](https://github.com/q-state)
* [@rbnvrw](https://github.com/rbnvrw)
* [@Relequestual](https://github.com/Relequestual)
* [@roryprimrose](https://github.com/roryprimrose)
* [@rtbfreitas](https://github.com/rtbfreitas)
* [@ryan2049](https://github.com/ryan2049)
* [@s-a-y](https://github.com/s-a-y)
* [@shamiao](https://github.com/shamiao)
* [@shineability](https://github.com/shineability)
* [@smeagol74](https://github.com/smeagol74)
* [@stephengreentree](https://github.com/stephengreentree)
* [@stepin](https://github.com/stepin)
* [@sventech](https://github.com/sventech)
* [@talberti](https://github.com/talberti)
* [@tmaly1980](https://github.com/tmaly1980)
* [@thisisclement](https://github.com/thisisclement)
* [@thomaslhotta](https://github.com/thomaslhotta)
* [@thx2001r](https://github.com/thx2001r)
* [@tiagofontella](https://github.com/tiagofontella)
* [@tjagusz](https://github.com/tjagusz)
* [@tomByrer](https://github.com/tomByrer)
* [@traone](https://github.com/traone)
* [@trondulseth](https://github.com/trondulseth)
* [@troymccabe](https://github.com/troymccabe)
* [@tsuyoshifujii](https://github.com/tsuyoshifujii)
* [@tureki](https://github.com/tureki)
* [@ulsa](https://github.com/ulsa)
* [@vadail](https://github.com/vadail)
* [@vaz](https://github.com/vaz)
* [@xabikip](https://github.com/xabikip)
* [@yakidahan](https://github.com/yakidahan)
* [@zmira](https://github.com/zmira)
* [@waveking](https://github.com/waveking)
* ... might be you! Let's [fork](https://github.com/formvalidation/formvalidation/fork) and make a pull request.

View File

@@ -0,0 +1,215 @@
module.exports = function(grunt) {
grunt.initConfig({
// ~~~~~~~~~
// Variables
// ~~~~~~~~~
pkg: grunt.file.readJSON('package.json'),
dirs: {
src: 'src',
dist: 'dist',
test: 'test',
vendor: 'vendor'
},
// The host that servers the demo and test directories
host: 'http://fv.dev',
banner: [
'/*!',
' * FormValidation (<%= pkg.homepage %>)',
' * <%= pkg.description %>',
' *',
' * @version v<%= pkg.version %>, built on <%= grunt.template.today("yyyy-mm-dd h:MM:ss TT") %>',
' * @author <%= pkg.author.url %>',
' * @copyright (c) 2013 - 2015 Nguyen Huu Phuoc',
' * @license <%= pkg.homepage %>/license/',
' */\n'
].join('\n'),
// ~~~~
// Tasks
// ~~~~
copy: {
main: {
files: [
{ cwd: '<%= dirs.src %>/css', src: '**', dest: '<%= dirs.dist %>/css', expand: true, flatten: true, filter: 'isFile' },
{ cwd: '<%= dirs.src %>/js/language', src: '**', dest: '<%= dirs.dist %>/js/language', expand: true, flatten: true, filter: 'isFile' },
{ cwd: '<%= dirs.src %>/js/framework', src: '**', dest: '<%= dirs.dist %>/js/framework', expand: true, flatten: true, filter: 'isFile' }
]
}
},
cssmin: {
minify: { expand: true, cwd: '<%= dirs.src %>/css/', src: ['*.css'], dest: '<%= dirs.dist %>/css/', ext: '.min.css' },
add_banner: {
options: {
stripBanners: true,
banner: '<%= banner %>'
},
files: {
'<%= dirs.dist %>/css/formValidation.min.css': ['<%= dirs.src %>/css/formValidation.css']
}
}
},
concat: {
base: {
options: {
separator: ';',
stripBanners: true,
banner: '<%= banner %>'
},
src: ['<%= dirs.src %>/js/base.js', '<%= dirs.src %>/js/helper.js', '<%= dirs.src %>/js/validator/*.js'],
dest: '<%= dirs.dist %>/js/formValidation.js'
},
bootstrap: {
options: {
separator: ';',
stripBanners: true,
banner: '<%= banner %>'
},
src: ['<%= dirs.src %>/js/framework/bootstrap.js'],
dest: '<%= dirs.dist %>/js/framework/bootstrap.js'
},
foundation: {
options: {
separator: ';',
stripBanners: true,
banner: '<%= banner %>'
},
src: ['<%= dirs.src %>/js/framework/foundation.js'],
dest: '<%= dirs.dist %>/js/framework/foundation.js'
},
pure: {
options: {
separator: ';',
stripBanners: true,
banner: '<%= banner %>'
},
src: ['<%= dirs.src %>/js/framework/pure.js'],
dest: '<%= dirs.dist %>/js/framework/pure.js'
},
semantic: {
options: {
separator: ';',
stripBanners: true,
banner: '<%= banner %>'
},
src: ['<%= dirs.src %>/js/framework/semantic.js'],
dest: '<%= dirs.dist %>/js/framework/semantic.js'
},
uikit: {
options: {
separator: ';',
stripBanners: true,
banner: '<%= banner %>'
},
src: ['<%= dirs.src %>/js/framework/uikit.js'],
dest: '<%= dirs.dist %>/js/framework/uikit.js'
},
test: {
src: ['<%= dirs.test %>/spec/*.js', '<%= dirs.test %>/spec/validator/*.js'],
dest: '<%= dirs.test %>/spec.js'
}
},
uglify: {
options: {
banner: '<%= banner %>'
},
base: {
src: ['<%= dirs.dist %>/js/formValidation.js'],
dest: '<%= dirs.dist %>/js/formValidation.min.js'
},
bootstrap: {
src: ['<%= dirs.dist %>/js/framework/bootstrap.js'],
dest: '<%= dirs.dist %>/js/framework/bootstrap.min.js'
},
foundation: {
src: ['<%= dirs.dist %>/js/framework/foundation.js'],
dest: '<%= dirs.dist %>/js/framework/foundation.min.js'
},
pure: {
src: ['<%= dirs.dist %>/js/framework/pure.js'],
dest: '<%= dirs.dist %>/js/framework/pure.min.js'
},
semantic: {
src: ['<%= dirs.dist %>/js/framework/semantic.js'],
dest: '<%= dirs.dist %>/js/framework/semantic.min.js'
},
uikit: {
src: ['<%= dirs.dist %>/js/framework/uikit.js'],
dest: '<%= dirs.dist %>/js/framework/uikit.min.js'
}
},
jasmine: {
src: '<%= dirs.dist %>/js/**/*.js',
options: {
specs: '<%= dirs.test %>/spec/**/*.js',
host: '<%= host %>',
vendor: [
'<%= dirs.vendor %>/jquery/jquery.min.js',
'<%= dirs.vendor %>/bootstrap/js/bootstrap.min.js'
],
helpers: '<%= dirs.test %>/helper.js'
}
},
jshint: {
all: [
'<%= dirs.src %>/js/**/*.js'
],
options: {
browser: true,
camelcase: true,
curly: true,
eqeqeq: true,
eqnull: true,
es3: true,
expr: true,
laxbreak: true, // Allow line breaking before && or ||
loopfunc: true,
newcap: true,
noarg: true,
onevar: true,
sub: true,
undef: true,
white: true,
globals: {
jQuery: false,
FormValidation: false
}
}
},
watch: {
source: {
files: ['<%= dirs.src %>/css/**', '<%= dirs.src %>/js/**'],
tasks: ['build'],
options: {
spawn: false
}
},
test: {
files: ['<%= dirs.test %>/spec/**'],
tasks: ['concat:test']
}
}
});
grunt.registerTask('default', 'build');
grunt.registerTask('build', ['copy', 'cssmin', 'concat', 'uglify']);
grunt.registerTask('test', ['jshint', 'jasmine']);
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-jasmine');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
};

View File

@@ -0,0 +1,54 @@
FormValidation License
---
For more information about the license, see http://formvalidation.io/license/
## FormValidation commercial license agreement
This Commercial License Agreement is a binding legal agreement between you and Nguyen Huu Phuoc.
By installing, copying, or using FormValidation (the Software), you agree to be bound
by these terms of this Agreement.
### Grant of license
Subject to the payment of the fee required and the conditions herein, you are hereby granted
a non-exclusive, non-transferable right to use FormValidation (the Software) to design
and develop commercial applications (Applications).
### Developer grant
The FormValidation Commercial Developer License grants one license for you as one designated
user (Developer) to use the Software for developing Applications. A Developer is an individual
who implements the Software into Applications, most often writing the necessary code to do so.
You must purchase another separate license to the Software for each and any additional Developer,
or purchase a FormValidation Commercial Organization License to cover your entire organization.
### Organization grant
The FormValidation Commercial Organization License grants one license for your Organization
as one designated, collective user (Organization) to use the Software for developing Applications.
There is no limit or restriction of the number of Developers within your Organization who
may develop Applications using the Software.
### Usage
You are granted the right to use and to modify the source code of the Software for use in
Applications. There is no limit or restriction of the number of Applications which use the
Software. You own any original work authored by you. Nguyen Huu Phuoc continues to retain
all copyright and other intellectual property rights in the Software. You are not permitted
to move, remove, edit, or obscure any copyright, trademark, attribution, warning or disclaimer
notices in the Software.
You may use the Software only to create Applications that are significantly different than
and do not compete with the Software. You are granted the license to distribute the Software
as part of your Applications on a royalty-free basis. Users of your Applications are permitted
to use the Software or your modifications of the Software as part of your Applications.
Users do not need to purchase their own commercial license for the Software, so long as they
are not acting as Developers, developing their own commercial Applications with the Software.
### Warranties and remedies
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
non-infringement. Nguyen Huu Phuoc's entire liability and your exclusive remedy under this
agreement shall be return of the price paid for the Software.

View File

@@ -0,0 +1,97 @@
# FormValidation - [Download](http://formvalidation.io/download/)
| Quick links |
|----------------------------------------------------------------------------------|
| [Document](http://formvalidation.io) |
| [Examples](http://formvalidation.io/examples/) |
| [Report issues, Ask questions](https://github.com/formvalidation/support/issues) |
[http://formvalidation.io](http://formvalidation.io) - The best [jQuery](http://jquery.com/) plugin to validate form fields, designed to use with:
- [x] [Bootstrap](http://getbootstrap.com/)
- [x] [Foundation](http://foundation.zurb.com/)
- [x] [Pure](http://purecss.io/)
- [x] [Semantic UI](http://semantic-ui.com/)
- [x] [UIKit](http://getuikit.com/)
It's developed from scratch by [@nghuuphuoc](http://twitter.com/nghuuphuoc).
__Required__: [jQuery 1.9.1+](http://jquery.com/)
Screenshots first because we love it!
__Validating Bootstrap form__
![Screenshot](screenshots/bootstrap.gif)
__Validating Foundation form__
![Screenshot](screenshots/foundation.gif)
__Validating Pure form__
![Screenshot](screenshots/pure.gif)
__Validating Semantic UI form__
![Screenshot](screenshots/semantic.gif)
__Validating UI Kit form__
![Screenshot](screenshots/uikit.gif)
## Live demo
http://formvalidation.io/examples/
There are also many examples located in the [demo](demo) directory.
You also can run the ```demo``` locally by:
* Clone the repo:
```
git clone https://github.com/formvalidation/formvalidation.git
```
* Go to the cloned directory and run the command:
```
python -m SimpleHTTPServer 8000
```
* Access the demo at
```
http://localhost:8000/demo/the_demo_file_here.html
```
## Features
See the [official website](http://formvalidation.io) for the full list of features
## Download
* Latest version: http://formvalidation.io/download/
* Release History: Look at the [Change Log](CHANGELOG.md)
## Documentation
* [Official website](http://formvalidation.io)
## Author
The __FormValidation__ plugin is written by Nguyen Huu Phuoc, aka @nghuuphuoc
* [http://twitter.com/nghuuphuoc](http://twitter.com/nghuuphuoc)
* [http://github.com/nghuuphuoc](http://github.com/nghuuphuoc)
## Contribution
Contributions are welcome!
Please notice that **your code** may be used as part of a **commercial product** if the pull request is **merged**.
## License
For more information about the license, see http://formvalidation.io/license/

View File

@@ -0,0 +1,123 @@
<!DOCTYPE html>
<html>
<head>
<title>Using Ajax to submit data</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Using Ajax to submit data</h2>
</div>
<form id="defaultForm" method="post" class="form-horizontal" action="ajaxSubmit.php">
<div class="form-group">
<label class="col-lg-3 control-label">Username</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="username" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Email address</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="email" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Password</label>
<div class="col-lg-5">
<input type="password" class="form-control" name="password" />
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary">Sign up</button>
</div>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#defaultForm')
.formValidation({
message: 'This value is not valid',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
username: {
message: 'The username is not valid',
validators: {
notEmpty: {
message: 'The username is required and can\'t be empty'
},
stringLength: {
min: 6,
max: 30,
message: 'The username must be more than 6 and less than 30 characters long'
},
/*remote: {
url: 'remote.php',
message: 'The username is not available'
},*/
regexp: {
regexp: /^[a-zA-Z0-9_\.]+$/,
message: 'The username can only consist of alphabetical, number, dot and underscore'
}
}
},
email: {
validators: {
notEmpty: {
message: 'The email address is required and can\'t be empty'
},
emailAddress: {
message: 'The input is not a valid email address'
}
}
},
password: {
validators: {
notEmpty: {
message: 'The password is required and can\'t be empty'
}
}
}
}
})
.on('success.form.fv', function(e) {
// Prevent form submission
e.preventDefault();
// Get the form instance
var $form = $(e.target);
// Get the FormValidation instance
var bv = $form.data('formValidation');
// Use Ajax to submit form data
$.post($form.attr('action'), $form.serialize(), function(result) {
console.log(result);
}, 'json');
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,6 @@
<?php
$userName = $_POST['username'];
echo json_encode(array(
'message' => sprintf('Welcome %s', $userName),
));

View File

@@ -0,0 +1,215 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<!-- form: -->
<section>
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Sign up</h2>
</div>
<form id="defaultForm" method="post" class="form-horizontal" action="target.php"
data-fv-message="This value is not valid"
data-fv-icon-valid="glyphicon glyphicon-ok"
data-fv-icon-invalid="glyphicon glyphicon-remove"
data-fv-icon-validating="glyphicon glyphicon-refresh">
<div class="form-group">
<label class="col-lg-3 control-label">Full name</label>
<div class="col-lg-4">
<input type="text" class="form-control" name="firstName" placeholder="First name" required data-fv-notempty-message="The first name is required and cannot be empty" />
</div>
<div class="col-lg-4">
<input type="text" class="form-control" name="lastName" placeholder="Last name" required data-fv-notempty-message="The last name is required and cannot be empty" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Username</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="username"
data-fv-message="The username is not valid"
required data-fv-notempty-message="The username is required and cannot be empty"
pattern="^[a-zA-Z0-9]+$" data-fv-regexp-message="The username can only consist of alphabetical and digits"
data-fv-stringlength="true" data-fv-stringlength-min="6" data-fv-stringlength-max="30" data-fv-stringlength-message="The username must be more than 6 and less than 30 characters long"
data-fv-remote="true" data-fv-remote-url="remote.php" data-fv-remote-message="The username is not available" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Email address</label>
<div class="col-lg-5">
<input class="form-control" name="email" type="email" data-fv-emailaddress-message="The input is not a valid email address" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Password</label>
<div class="col-lg-5">
<input type="password" class="form-control" name="password"
required data-fv-notempty-message="The password is required and cannot be empty"
data-fv-different="true" data-fv-different-field="username" data-fv-different-message="The password cannot be the same as username" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Retype password</label>
<div class="col-lg-5">
<input type="password" class="form-control" name="confirmPassword"
required data-fv-notempty-message="The confirm password is required and cannot be empty"
data-fv-identical="true" data-fv-identical-field="password" data-fv-identical-message="The password and its confirm are not the same" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Gender</label>
<div class="col-lg-5">
<div class="radio">
<label>
<input type="radio" name="gender" value="male" required data-fv-notempty-message="The gender is required" /> Male
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="female" /> Female
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="other" /> Other
</label>
</div>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Birthday</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="birthday" data-fv-date="false" data-fv-date-format="YYYY/MM/DD" data-fv-date-message="The birthday is not valid" /> (YYYY/MM/DD)
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Country</label>
<div class="col-lg-5">
<select class="form-control" name="country" data-fv-notempty data-fv-notempty-message="The country is required">
<option value="">-- Select a country --</option>
<option value="fr">France</option>
<option value="de">Germany</option>
<option value="it">Italy</option>
<option value="jp">Japan</option>
<option value="ru">Russia</option>
<option value="gb">United Kingdom</option>
<option value="us">United State</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Languages</label>
<div class="col-lg-5">
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="english" data-fv-message="Please specify at least one language you can speak" /> English
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="french" /> French
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="german" required /> German
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="russian" /> Russian
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="other" /> Other
</label>
</div>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Programming Languages</label>
<div class="col-lg-5">
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="net" data-fv-choice="true" data-fv-choice-min="2" data-fv-choice-max="4" data-fv-choice-message="Please choose 2 - 4 programming languages you are good at" /> .Net
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="java" /> Java
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="c" /> C/C++
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="php" /> PHP
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="perl" /> Perl
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="ruby" /> Ruby
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="python" /> Python
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="javascript" /> Javascript
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary">Sign up</button>
</div>
</div>
</form>
</div>
</section>
<!-- :form -->
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#defaultForm').formValidation();
});
</script>
</body>
</html>

View File

@@ -0,0 +1,129 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<section>
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>choice validator</h2>
</div>
<form id="interviewForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-lg-3 control-label">Programming Languages</label>
<div class="col-lg-4">
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="net" /> .Net
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="java" /> Java
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="c" /> C/C++
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="php" /> PHP
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="perl" /> Perl
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="ruby" /> Ruby
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="python" /> Python
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="javascript" /> Javascript
</label>
</div>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Editors</label>
<div class="col-lg-4">
<select class="form-control" name="editors[]" multiple="multiple" style="height: 200px;">
<option value="" disabled>Choose 2 - 3 editors</option>
<option value="atom">Atom</option>
<option value="eclipse">Eclipse</option>
<option value="netbeen">NetBean</option>
<option value="nodepadplusplus">Nodepad++</option>
<option value="phpstorm">PHP Storm</option>
<option value="sublime">Sublime</option>
<option value="webstorm">Web Storm</option>
</select>
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
</div>
</section>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#interviewForm').formValidation({
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
'languages[]': {
validators: {
choice: {
min: 2,
max: 4,
message: 'Please choose %s - %s programming languages you are good at'
}
}
},
'editors[]': {
validators: {
choice: {
min: 2,
max: 3,
message: 'Please choose %s - %s editors you know'
}
}
}
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,264 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Using with Bootstrap Collapse</h2>
</div>
<form id="defaultForm" method="post" class="form-horizontal" action="target.php">
<div class="panel-group" id="steps">
<!-- Step 1 -->
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title"><a data-toggle="collapse" data-parent="#steps" href="#stepOne">Account</a></h4>
</div>
<div id="stepOne" class="panel-collapse collapse in">
<div class="panel-body">
<div class="form-group">
<label class="col-lg-3 control-label">Username</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="username" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Email address</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="email" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Password</label>
<div class="col-lg-5">
<input type="password" class="form-control" name="password" />
</div>
</div>
</div>
</div>
</div>
<!-- Step 2 -->
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title"><a data-toggle="collapse" data-parent="#steps" href="#stepTwo">Personal</a></h4>
</div>
<div id="stepTwo" class="panel-collapse collapse">
<div class="panel-body">
<div class="form-group">
<label class="col-lg-3 control-label">Full name</label>
<div class="col-lg-4">
<input type="text" class="form-control" name="firstName" placeholder="First name" />
</div>
<div class="col-lg-4">
<input type="text" class="form-control" name="lastName" placeholder="Last name" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Gender</label>
<div class="col-lg-5">
<div class="radio">
<label>
<input type="radio" name="gender" value="male" /> Male
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="female" /> Female
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="other" /> Other
</label>
</div>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Birthday</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="birthday" placeholder="YYYY/MM/DD" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Bio</label>
<div class="col-lg-5">
<textarea class="form-control" name="bio" rows="5"></textarea>
</div>
</div>
</div>
</div>
</div>
<!-- Step 3 -->
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title"><a data-toggle="collapse" data-parent="#steps" href="#stepThree">Contact</a></h4>
</div>
<div id="stepThree" class="panel-collapse collapse">
<div class="panel-body">
<div class="form-group">
<label class="col-lg-3 control-label">Phone number</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="phoneNumber" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Street</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="street" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">City</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="city" />
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary" name="signup" value="Sign up">Sign up</button>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#defaultForm').formValidation({
message: 'This value is not valid',
excluded: ':disabled',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
firstName: {
validators: {
notEmpty: {
message: 'The first name is required and cannot be empty'
},
stringCase: {
message: 'The first name must contain upper case characters only',
case: 'upper'
},
regexp: {
regexp: /^[A-Z\s]+$/i,
message: 'The first name can only consist of alphabetical characters and spaces'
}
}
},
lastName: {
validators: {
notEmpty: {
message: 'The last name is required and cannot be empty'
},
stringCase: {
message: 'The last name must contain upper case characters only',
case: 'upper'
},
regexp: {
regexp: /^[A-Z\s]+$/i,
message: 'The last name can only consist of alphabetical characters and spaces'
}
}
},
username: {
message: 'The username is not valid',
validators: {
notEmpty: {
message: 'The username is required and cannot be empty'
},
stringLength: {
min: 6,
max: 30,
message: 'The username must be more than 6 and less than 30 characters long'
},
regexp: {
regexp: /^[a-zA-Z0-9_\.]+$/,
message: 'The username can only consist of alphabetical, number, dot and underscore'
}
}
},
email: {
validators: {
emailAddress: {
message: 'The input is not a valid email address'
}
}
},
password: {
validators: {
notEmpty: {
message: 'The password is required and cannot be empty'
},
different: {
field: 'username',
message: 'The password cannot be the same as username'
}
}
},
gender: {
validators: {
notEmpty: {
message: 'The gender is required'
}
}
},
birthday: {
validators: {
date: {
format: 'YYYY/MM/DD',
message: 'The birthday is not valid'
}
}
},
phoneNumber: {
validators: {
digits: {
message: 'The value can contain only digits'
}
}
}
}
}).on('err.form.fv', function(e) {
console.log('error');
// Active the panel element containing the first invalid element
var $form = $(e.target),
validator = $form.data('formValidation'),
$invalidField = validator.getInvalidFields().eq(0),
$collapse = $invalidField.parents('.collapse');
$collapse.collapse('show');
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,100 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<!-- form: -->
<section>
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Profile</h2>
</div>
<form id="defaultForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-lg-3 control-label">Full name</label>
<div class="col-lg-4">
<input type="text" class="form-control" name="firstName" placeholder="First name" />
<span class="help-block" id="firstNameMessage" />
</div>
<div class="col-lg-4">
<input type="text" class="form-control" name="lastName" placeholder="Last name" />
<span class="help-block lastNameMessage" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Username</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="username" />
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary">Sign up</button>
</div>
</div>
</form>
</div>
</section>
<!-- :form -->
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#defaultForm').formValidation({
message: 'This value is not valid',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
firstName: {
err: '#firstNameMessage',
validators: {
notEmpty: {
message: 'The first name is required and cannot be empty'
}
}
},
lastName: {
err: '.lastNameMessage',
validators: {
notEmpty: {
message: 'The last name is required and cannot be empty'
}
}
},
username: {
message: 'The username is not valid',
validators: {
notEmpty: {
message: 'The username is required and cannot be empty'
},
stringLength: {
min: 6,
max: 30,
message: 'The username must be more than 6 and less than 30 characters long'
}
}
}
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,168 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<!-- form: -->
<section>
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Showing errors in custom container</h2>
</div>
<form id="defaultForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-lg-3 control-label">Full name</label>
<div class="col-lg-4">
<input type="text" class="form-control" name="firstName" placeholder="First name" />
</div>
<div class="col-lg-4">
<input type="text" class="form-control" name="lastName" placeholder="Last name" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Username</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="username" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Email address</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="email" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Password</label>
<div class="col-lg-5">
<input type="password" class="form-control" name="password" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Gender</label>
<div class="col-lg-5">
<div class="radio">
<label>
<input type="radio" name="gender" value="male" /> Male
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="female" /> Female
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="other" /> Other
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<div id="errors"></div>
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary" name="signup" value="Sign up">Sign up</button>
</div>
</div>
</form>
</div>
</section>
<!-- :form -->
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#defaultForm').formValidation({
message: 'This value is not valid',
err: {
container: '#errors'
},
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
firstName: {
validators: {
notEmpty: {
message: 'The first name is required and cannot be empty'
}
}
},
lastName: {
validators: {
notEmpty: {
message: 'The last name is required and cannot be empty'
}
}
},
username: {
message: 'The username is not valid',
validators: {
notEmpty: {
message: 'The username is required and cannot be empty'
},
stringLength: {
min: 6,
max: 30,
message: 'The username must be more than 6 and less than 30 characters long'
},
regexp: {
regexp: /^[a-zA-Z0-9_\.]+$/,
message: 'The username can only consist of alphabetical, number, dot and underscore'
}
}
},
email: {
validators: {
emailAddress: {
message: 'The input is not a valid email address'
}
}
},
password: {
validators: {
notEmpty: {
message: 'The password is required and cannot be empty'
},
different: {
field: 'username',
message: 'The password cannot be the same as username'
}
}
},
gender: {
validators: {
notEmpty: {
message: 'The gender is required'
}
}
}
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,178 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Showing errors in tooltip or popover</h2>
</div>
<form id="defaultForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-lg-3 control-label">Full name</label>
<div class="col-lg-4">
<input type="text" class="form-control" name="firstName" placeholder="First name" />
</div>
<div class="col-lg-4">
<input type="text" class="form-control" name="lastName" placeholder="Last name" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Username</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="username" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Email address</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="email" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Password</label>
<div class="col-lg-5">
<input type="password" class="form-control" name="password" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Gender</label>
<div class="col-lg-5">
<div class="radio">
<label>
<input type="radio" name="gender" value="male" /> Male
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="female" /> Female
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="other" /> Other
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary" name="signup" value="Sign up">Sign up</button>
</div>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#defaultForm').formValidation({
message: 'This value is not valid',
err: {
container: 'tooltip'
},
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
firstName: {
group: '.col-lg-4',
validators: {
notEmpty: {
message: 'The first name is required and cannot be empty'
},
stringCase: {
message: 'The first name must contain upper case characters only',
case: 'upper'
},
regexp: {
regexp: /^[A-Z\s]+$/i,
message: 'The first name can only consist of alphabetical characters and spaces'
}
}
},
lastName: {
group: '.col-lg-4',
validators: {
notEmpty: {
message: 'The last name is required and cannot be empty'
},
stringCase: {
message: 'The last name must contain upper case characters only',
case: 'upper'
},
regexp: {
regexp: /^[A-Z\s]+$/i,
message: 'The last name can only consist of alphabetical characters and spaces'
}
}
},
username: {
message: 'The username is not valid',
validators: {
notEmpty: {
message: 'The username is required and cannot be empty'
},
stringLength: {
min: 6,
max: 30,
message: 'The username must be more than 6 and less than 30 characters long'
},
regexp: {
regexp: /^[a-zA-Z0-9_\.]+$/,
message: 'The username can only consist of alphabetical, number, dot and underscore'
}
}
},
email: {
err: 'popover',
validators: {
emailAddress: {
message: 'The input is not a valid email address'
}
}
},
password: {
err: 'popover',
validators: {
notEmpty: {
message: 'The password is required and cannot be empty'
},
different: {
field: 'username',
message: 'The password cannot be the same as username'
}
}
},
gender: {
validators: {
notEmpty: {
message: 'The gender is required'
}
}
}
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,182 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<!-- form: -->
<section>
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Customizing errors</h2>
</div>
<form id="defaultForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-lg-3 control-label">Full name</label>
<div class="col-lg-4">
<input type="text" class="form-control" name="firstName" placeholder="First name" />
</div>
<div class="col-lg-4">
<input type="text" class="form-control" name="lastName" placeholder="Last name" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Username</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="username" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Email address</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="email" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Password</label>
<div class="col-lg-5">
<input type="password" class="form-control" name="password" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Gender</label>
<div class="col-lg-5">
<div class="radio">
<label>
<input type="radio" name="gender" value="male" /> Male
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="female" /> Female
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="other" /> Other
</label>
</div>
</div>
</div>
<div class="form-group hide">
<div class="col-lg-9 col-lg-offset-3">
<ul id="errors"></ul>
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary">Sign up</button>
</div>
</div>
</form>
</div>
</section>
<!-- :form -->
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#defaultForm')
.formValidation({
message: 'This value is not valid',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
firstName: {
validators: {
notEmpty: {
message: 'The first name is required and cannot be empty'
}
}
},
lastName: {
validators: {
notEmpty: {
message: 'The last name is required and cannot be empty'
}
}
},
username: {
message: 'The username is not valid',
validators: {
notEmpty: {
message: 'The username is required and cannot be empty'
},
stringLength: {
min: 6,
max: 30,
message: 'The username must be more than 6 and less than 30 characters long'
},
regexp: {
regexp: /^[a-zA-Z0-9_\.]+$/,
message: 'The username can only consist of alphabetical, number, dot and underscore'
}
}
},
email: {
validators: {
emailAddress: {
message: 'The input is not a valid email address'
}
}
},
password: {
validators: {
notEmpty: {
message: 'The password is required and cannot be empty'
},
different: {
field: 'username',
message: 'The password cannot be the same as username'
}
}
},
gender: {
validators: {
notEmpty: {
message: 'The gender is required'
}
}
}
}
})
.on('err.field.fv', function(e, data) {
var messages = data.fv.getMessages(data.field);
$('#errors').find('li[data-fv-for="' + data.field + '"]').remove();
for (var i in messages) {
$('<li/>').attr('data-fv-for', data.field).html(messages[i]).appendTo('#errors');
}
$('#errors').parents('.form-group').removeClass('hide');
})
.on('success.field.fv', function(e, data) {
$('#errors').find('li[data-fv-for="' + data.field + '"]').remove();
})
.on('success.form.fv', function(e) {
$('#errors')
.html('')
.parents('.form-group').addClass('hide');
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,186 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
<!-- Support datetime picker plugin: http://eonasdan.github.io/bootstrap-datetimepicker/ -->
<link rel="stylesheet" href="http://eonasdan.github.io/bootstrap-datetimepicker/content/bootstrap-datetimepicker.css"/>
<script type="text/javascript" src="http://eonasdan.github.io/bootstrap-datetimepicker/scripts/moment.js"></script>
<script type="text/javascript" src="http://eonasdan.github.io/bootstrap-datetimepicker/scripts/bootstrap-datetimepicker.js"></script>
<style type="text/css">
/* Override to make the feedback icons shown properly */
.form-horizontal .has-feedback .form-control-feedback {
top: 0;
right: -15px;
}
.form-horizontal .has-feedback .input-group .form-control-feedback {
top: 0;
right: -30px;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<!-- form: -->
<section>
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Date validator</h2>
</div>
<form id="defaultForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-lg-3 control-label">MM/DD/YYYY</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="monthDayYear" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">YYYY-DD-MM</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="yearDayMonth" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">YYYY.MM.DD</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="yearMonthDay" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">MM/DD/YYYY h:m A</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="monthDayYearTime" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">YYYY-DD-MM h:m A</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="yearDayMonthTime" />
</div>
</div>
<!-- datetime picker -->
<div class="form-group">
<label class="col-lg-3 control-label"><a href="http://eonasdan.github.io/bootstrap-datetimepicker/">DateTime Picker</a> (MM/DD/YYYY h:m A)</label>
<div class="col-lg-5">
<div class="input-group date" id="datetimePicker">
<input type="text" class="form-control" name="datetimePicker" />
<span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span></span>
</div>
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
</div>
</section>
<!-- :form -->
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#datetimePicker').datetimepicker();
$('#defaultForm').formValidation({
message: 'This value is not valid',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
monthDayYear: {
validators: {
notEmpty: {
message: 'The date is required and cannot be empty'
},
date: {
format: 'MM/DD/YYYY'
}
}
},
yearDayMonth: {
validators: {
notEmpty: {
message: 'The date is required and cannot be empty'
},
date: {
format: 'YYYY-DD-MM'
}
}
},
yearMonthDay: {
validators: {
notEmpty: {
message: 'The date is required and cannot be empty'
},
date: {
format: 'YYYY.MM.DD',
separator: '.'
}
}
},
monthDayYearTime: {
validators: {
notEmpty: {
message: 'The date is required and cannot be empty'
},
date: {
format: 'MM/DD/YYYY h:m A'
}
}
},
yearDayMonthTime: {
validators: {
notEmpty: {
message: 'The date is required and cannot be empty'
},
date: {
format: 'YYYY-DD-MM h:m A'
}
}
},
datetimePicker: {
validators: {
notEmpty: {
message: 'The date is required and cannot be empty'
},
date: {
format: 'MM/DD/YYYY h:m A'
}
}
}
}
});
$('#datetimePicker')
.on('dp.change dp.show', function(e) {
// Validate the date when user change it
$('#defaultForm').data('formValidation').revalidateField('datetimePicker');
// You also can call it as following:
// $('#defaultForm').formValidation('revalidateField', 'datetimePicker');
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,307 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Default messages</h2>
</div>
<form id="defaultForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-lg-3 control-label">Full name</label>
<div class="col-lg-4">
<input type="text" class="form-control" name="firstName" placeholder="First name" />
</div>
<div class="col-lg-4">
<input type="text" class="form-control" name="lastName" placeholder="Last name" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Username</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="username" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Email address</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="email" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Password</label>
<div class="col-lg-5">
<input type="password" class="form-control" name="password" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Retype password</label>
<div class="col-lg-5">
<input type="password" class="form-control" name="confirmPassword" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Gender</label>
<div class="col-lg-5">
<div class="radio">
<label>
<input type="radio" name="gender" value="male" /> Male
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="female" /> Female
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="other" /> Other
</label>
</div>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Age</label>
<div class="col-lg-3">
<input type="text" class="form-control" name="age" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Website</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="website" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Phone number</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="phoneNumber" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Languages</label>
<div class="col-lg-5">
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="english" /> English
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="french" /> French
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="german" /> German
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="russian" /> Russian
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="other" /> Other
</label>
</div>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Programming Languages</label>
<div class="col-lg-5">
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="net" /> .Net
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="java" /> Java
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="c" /> C/C++
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="php" /> PHP
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="perl" /> Perl
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="ruby" /> Ruby
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="python" /> Python
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="javascript" /> Javascript
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary" name="signup" value="Sign up">Sign up</button>
<button type="submit" class="btn btn-primary" name="signup2" value="Sign up 2">Sign up 2</button>
</div>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#defaultForm').formValidation({
message: 'This value is not valid',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
firstName: {
validators: {
notEmpty: {},
stringCase: {
'case': 'upper'
}
}
},
lastName: {
validators: {
notEmpty: {},
stringCase: {
'case': 'upper'
}
}
},
username: {
message: 'The username is not valid',
validators: {
notEmpty: {},
stringLength: {
min: 6,
max: 20
},
regexp: {
regexp: /^[a-zA-Z0-9_\.]+$/
},
remote: {
url: 'remote.php',
message: 'The username is not available'
}
}
},
email: {
validators: {
emailAddress: {}
}
},
password: {
validators: {
notEmpty: {},
different: {
field: 'username',
message: 'The password cannot be the same as username'
}
}
},
confirmPassword: {
validators: {
notEmpty: {},
identical: {
field: 'password',
message: 'The password and its confirm are not the same'
}
}
},
age: {
validators: {
notEmpty: {},
digits: {},
greaterThan: {
value: 18
},
lessThan: {
value: 100
}
}
},
website: {
validators: {
notEmpty: {},
uri: {}
}
},
phoneNumber: {
validators: {
notEmpty: {},
digits: {},
phone: {
country: 'US'
}
}
},
gender: {
validators: {
notEmpty: {}
}
},
'languages[]': {
validators: {
notEmpty: {}
}
},
'programs[]': {
validators: {
choice: {
min: 2,
max: 4
}
}
}
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,167 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<!-- form: -->
<section>
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Dynamic fields</h2>
</div>
<form id="defaultForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-lg-3 control-label">Textbox</label>
<div class="col-lg-5">
<input class="form-control" type="text" name="textbox[]" placeholder="Textbox #1" />
</div>
<div class="col-lg-4">
<button type="button" class="btn btn-default btn-sm addButton" data-template="textbox">Add</button>
</div>
</div>
<div class="form-group hide" id="textboxTemplate">
<div class="col-lg-offset-3 col-lg-5">
<input class="form-control" type="text" />
</div>
<div class="col-lg-4">
<button type="button" class="btn btn-default btn-sm removeButton">Remove</button>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Checkbox</label>
<div class="col-lg-5">
<div class="checkbox">
<label>
<input type="checkbox" name="checkbox[]" value="Choice #1" /> Choice <button type="button" class="btn btn-default btn-sm addButton" data-template="checkbox">Add</button>
</label>
</div>
<div class="checkbox hide template" id="checkboxTemplate">
<label>
<input type="checkbox" value="1" /> <span class="lbl">Choice</span> <button type="button" class="btn btn-default btn-sm removeButton">Remove</button>
</label>
</div>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Radio</label>
<div class="col-lg-5">
<div class="radio">
<label>
<input type="radio" name="radio[]" value="Choice #1" /> Choice <button type="button" class="btn btn-default btn-sm addButton" data-template="radio">Add</button>
</label>
</div>
<div class="radio hide" id="radioTemplate">
<label>
<input type="radio" value="1" /> <span class="lbl">Choice</span> <button type="button" class="btn btn-default btn-sm removeButton">Remove</button>
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-3 col-lg-3">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
</div>
</section>
<!-- :form -->
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('.addButton').on('click', function() {
var index = $(this).data('index');
if (!index) {
index = 1;
$(this).data('index', 1);
}
index++;
$(this).data('index', index);
var template = $(this).attr('data-template'),
$templateEle = $('#' + template + 'Template'),
$row = $templateEle.clone().removeAttr('id').insertBefore($templateEle).removeClass('hide'),
$el = $row.find('input').eq(0).attr('name', template + '[]');
$('#defaultForm').formValidation('addField', $el);
// Set random value for checkbox and textbox
if ('checkbox' == $el.attr('type') || 'radio' == $el.attr('type')) {
$el.val('Choice #' + index)
.parent().find('span.lbl').html('Choice #' + index);
} else {
$el.attr('placeholder', 'Textbox #' + index);
}
$row.on('click', '.removeButton', function(e) {
$('#defaultForm').formValidation('removeField', $el);
$row.remove();
});
});
$('#defaultForm')
.formValidation({
message: 'This value is not valid',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
'textbox[]': {
validators: {
notEmpty: {
message: 'The textbox field is required'
}
}
},
'checkbox[]': {
validators: {
notEmpty: {
message: 'The checkbox field is required'
}
}
},
'radio[]': {
validators: {
notEmpty: {
message: 'The radio field is required'
}
}
}
}
})
.on('err.field.fv', function(e, data) {
//console.log('err.field.fv -->', data.element);
})
.on('success.field.fv', function(e, data) {
//console.log('success.field.fv -->', data.element);
})
.on('added.field.fv', function(e, data) {
//console.log('Added element -->', data.field, data.element);
})
.on('removed.field.fv', function(e, data) {
//console.log('Removed element -->', data.field, data.element);
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,132 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Dynamic fields</h2>
</div>
<form id="contactForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-lg-3 control-label">Phone number</label>
<div class="col-lg-6">
<input class="form-control" type="text" name="phone" />
</div>
<div class="col-lg-3">
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">Add more <span class="caret"></span></button>
<ul class="dropdown-menu" role="menu">
<li><a href="#" class="addPhoneButton" data-name="phone_iphone">iPhone</a></li>
<li><a href="#" class="addPhoneButton" data-name="phone_home">Home</a></li>
<li><a href="#" class="addPhoneButton" data-name="phone_office">Office</a></li>
</ul>
</div>
</div>
</div>
<!-- Template for dynamic field -->
<div class="form-group" id="template" style="display: none;">
<label class="col-lg-3 control-label"></label>
<div class="col-lg-6">
<input class="form-control" type="text" />
</div>
<div class="col-lg-3">
<button type="button" class="btn btn-link removeButton">Remove</button>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-3 col-lg-3">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('.addPhoneButton').on('click', function() {
var $that = $(this),
$template = $('#template'),
$newRow = $template.clone().removeAttr('id').insertBefore($template).show();
$that.parent().addClass('disabled');
// Set the label and field name
var fieldName = $that.attr('data-name');
$newRow
.find('.control-label')
.html($that.html())
.end()
.find('input')
.attr('name', fieldName)
.end()
.on('click', '.removeButton', function() {
// Remove field when clicking the Remove button
$('#contactForm').formValidation('removeField', fieldName);
// Enable the Add button
$that.parent().removeClass('disabled');
// Remove element
$newRow.remove();
});
// Add new field
$('#contactForm').formValidation('addField', fieldName, {
message: 'The phone number is not valid',
validators: {
digits: {
message: 'The value can contain only digits'
}
}
});
});
$('#contactForm')
.formValidation({
message: 'This value is not valid',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
phone: {
message: 'The phone number is not valid',
validators: {
notEmpty: {
message: 'The phone number is required'
},
digits: {
message: 'The value can contain only digits'
}
}
}
}
})
.on('err.field.fv', function(e, data) {
console.log(data.field, data.element, '-->error');
})
.on('success.field.fv', function(e, data) {
console.log(data.field, data.element, '-->success');
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,201 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Dynamic fields</h2>
</div>
<p>Please enter the information of sender and receiver:</p>
<form id="shippingForm" method="post" class="form-horizontal" action="target.php">
<fieldset>
<legend>Sender</legend>
<div class="form-group">
<label class="col-lg-3 control-label">Name</label>
<div class="col-lg-5">
<input class="form-control" type="text" name="senderName" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Phone</label>
<div class="col-lg-5">
<input class="form-control" type="text" name="senderPhone" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Address</label>
<div class="col-lg-5">
<input class="form-control" type="text" name="senderAddress" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">City</label>
<div class="col-lg-5">
<input class="form-control" type="text" name="senderCity" />
</div>
</div>
</fieldset>
<fieldset>
<legend>Receiver</legend>
<div class="form-group">
<div class="col-lg-5 col-lg-offset-3">
<div class="checkbox">
<label>
<input type="checkbox" name="receiver" value="0" checked /> Same as sender
</label>
</div>
</div>
</div>
<div id="receiverInfo" style="display: none;">
<div class="form-group">
<label class="col-lg-3 control-label">Name</label>
<div class="col-lg-5">
<input class="form-control" type="text" name="receiverName" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Phone</label>
<div class="col-lg-5">
<input class="form-control" type="text" name="receiverPhone" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Address</label>
<div class="col-lg-5">
<input class="form-control" type="text" name="receiverAddress"
required data-fv-notempty-message="The address is required" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">City</label>
<div class="col-lg-5">
<input class="form-control" type="text" name="receiverCity"
required data-fv-notempty-message="The city is required" />
</div>
</div>
</div>
</fieldset>
<div class="form-group">
<div class="col-lg-offset-3 col-lg-3">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#shippingForm')
.on('init.form.fv', function(e, data) {
//console.log(data);
})
.formValidation({
message: 'This value is not valid',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
senderName: {
validators: {
notEmpty: {
message: 'The name is required'
}
}
},
senderPhone: {
message: 'The phone number is not valid',
validators: {
notEmpty: {
message: 'The phone number is required'
},
digits: {
message: 'The value can contain only digits'
}
}
},
senderAddress: {
validators: {
notEmpty: {
message: 'The address is required'
}
}
},
senderCity: {
validators: {
notEmpty: {
message: 'The city is required'
}
}
}
}
})
.on('added.field.fv', function(e, data) {
console.log('Added element --> ', data.field, data.element, data.options);
})
.on('change', 'input[type="checkbox"][name="receiver"]', function() {
var sameAsSender = $(this).is(':checked'),
$receiverPhone = $('#shippingForm').find('input[name="receiverPhone"]').eq(0),
$receiverCity = $('#shippingForm').find('input[name="receiverCity"]').eq(0);
if (sameAsSender) {
$('#receiverInfo').hide();
$('#shippingForm')
// Remove field
.formValidation('removeField', 'receiverName')
.formValidation('removeField', 'receiverAddress')
.formValidation('removeField', $receiverPhone)
.formValidation('removeField', $receiverCity);
} else {
$('#receiverInfo').show();
$('#shippingForm')
// Add field
.formValidation('addField', 'receiverName', {
validators: {
notEmpty: {
message: 'The name is required'
}
}
})
.formValidation('addField', 'receiverAddress') // The options are automatically parsed from HTML attributes
.formValidation('addField', $receiverPhone, {
message: 'The phone number is not valid',
validators: {
notEmpty: {
message: 'The phone number is required'
},
digits: {
message: 'The value can contain only digits'
}
}
})
.formValidation('addField', $receiverCity); // The options are automatically parsed from HTML attributes
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,183 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Dynamic fields</h2>
</div>
<form id="interviewForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-lg-3 control-label">Your name</label>
<div class="col-lg-5">
<input class="form-control" type="text" name="name" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Topic</label>
<div class="col-lg-5">
<div class="checkbox">
<label>
<input type="checkbox" name="topic[]" value="css" /> CSS
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="topic[]" value="javascript" /> Javascript
</label>
</div>
</div>
</div>
<div style="display: none;" data-topic="css">
<fieldset>
<legend>CSS</legend>
<p>Choose the frameworks that support responsive:</p>
<div class="form-group">
<div class="col-lg-offset-3 col-lg-5">
<div class="checkbox">
<label>
<input type="checkbox" name="css_frameworks[]" value="Bootstrap" /> Bootstrap
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="css_frameworks[]" value="Foundation" /> Foundation
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="css_frameworks[]" value="Blueprint" /> Blueprint
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="css_frameworks[]" value="960gs" /> 960 Grid System
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="css_frameworks[]" value="Pure" /> Pure
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="css_frameworks[]" value="YAML" /> YAML
</label>
</div>
</div>
</div>
</fieldset>
</div>
<div style="display: none;" data-topic="javascript">
<fieldset>
<legend>Javascript</legend>
<p>Name 4 Javascript frameworks you have heard about</p>
<div class="form-group">
<div class="col-lg-offset-3 col-lg-5">
<input class="form-control" type="text" name="js_frameworks[]" />
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-3 col-lg-5">
<input class="form-control" type="text" name="js_frameworks[]" />
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-3 col-lg-5">
<input class="form-control" type="text" name="js_frameworks[]" />
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-3 col-lg-5">
<input class="form-control" type="text" name="js_frameworks[]" />
</div>
</div>
</fieldset>
</div>
<div class="form-group">
<div class="col-lg-offset-3 col-lg-3">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#interviewForm')
.formValidation({
message: 'This value is not valid',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
name: {
validators: {
notEmpty: {
message: 'The name is required'
}
}
}
}
})
.find('input[type="checkbox"][name="topic[]"]')
.on('change', function() {
var topic = $(this).val(),
$container = $('[data-topic="' + topic + '"]');
$container.toggle();
var display = $container.css('display');
switch (true) {
case ('css' == topic && 'block' == display):
$('#interviewForm').formValidation('addField', 'css_frameworks[]', {
validators: {
notEmpty: {
message: 'Please choose at least 1 framework'
}
}
});
break;
case ('css' == topic && 'none' == display):
$('#interviewForm').formValidation('removeField', 'css_frameworks[]');
break;
case ('javascript' == topic && 'block' == display):
$('#interviewForm').formValidation('addField', 'js_frameworks[]', {
validators: {
notEmpty: {
message: 'The name of framework is required'
}
}
});
break;
case ('javascript' == topic && 'none' == display):
$('#interviewForm').formValidation('removeField', 'js_frameworks[]');
break;
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,214 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<!-- form: -->
<section>
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Checkout</h2>
</div>
<form id="checkoutForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-lg-3 control-label">Shipping address</label>
<div class="col-lg-5">
<div class="radio">
<label>
<input type="radio" name="shipping_to" value="current" checked /> Same as my account address
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="shipping_to" value="new" /> New address
</label>
</div>
</div>
</div>
<div id="newAddress">
<div class="form-group">
<label class="col-lg-3 control-label">Country</label>
<div class="col-lg-5">
<select name="country" class="form-control" disabled>
<option value="">Select a country</option>
<option value="AU">Australia</option>
<option value="CA">Canada</option>
<option value="FR">France</option>
<option value="DE">Germany</option>
<option value="IT">Italy</option>
<option value="JP">Japan</option>
<option value="GB">United Kingdom</option>
<option value="US">United States</option>
<option value="VN">Viet Nam</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Street</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="street" disabled />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">City</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="city" disabled />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">State</label>
<div class="col-lg-5">
<select name="state" class="form-control" disabled>
<option value="">Select a state</option>
<option value="AL">Alabama</option>
<option value="AK">Alaska</option>
<option value="AZ">Arizona</option>
<option value="AR">Arkansas</option>
<option value="CA">California</option>
<option value="CO">Colorado</option>
<option value="CT">Connecticut</option>
<option value="DE">Delaware</option>
<option value="DC">District of Columbia</option>
<option value="FL">Florida</option>
<option value="GA">Georgia</option>
<option value="HI">Hawaii</option>
<option value="ID">Idaho</option>
<option value="IL">Illinois</option>
<option value="IN">Indiana</option>
<option value="IA">Iowa</option>
<option value="KS">Kansas</option>
<option value="KY">Kentucky</option>
<option value="LA">Louisiana</option>
<option value="ME">Maine</option>
<option value="MD">Maryland</option>
<option value="MA">Massachusetts</option>
<option value="MI">Michigan</option>
<option value="MN">Minnesota</option>
<option value="MS">Mississippi</option>
<option value="MO">Missouri</option>
<option value="MT">Montana</option>
<option value="NE">Nebraska</option>
<option value="NV">Nevada</option>
<option value="NH">New Hampshire</option>
<option value="NJ">New Jersey</option>
<option value="NM">New Mexico</option>
<option value="NY">New York</option>
<option value="NC">North Carolina</option>
<option value="ND">North Dakota</option>
<option value="OH">Ohio</option>
<option value="OK">Oklahoma</option>
<option value="OR">Oregon</option>
<option value="PA">Pennsylvania</option>
<option value="RI">Rhode Island</option>
<option value="SC">South Carolina</option>
<option value="SD">South Dakota</option>
<option value="TN">Tennessee</option>
<option value="TX">Texas</option>
<option value="UT">Utah</option>
<option value="VT">Vermont</option>
<option value="VA">Virginia</option>
<option value="WA">Washington</option>
<option value="WV">West Virginia</option>
<option value="WI">Wisconsin</option>
<option value="WY">Wyoming</option>
</select>
<span class="help-block"><small>Required if you choose United States country</small></span>
</div>
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary">Checkout</button>
</div>
</div>
</form>
</div>
</section>
<!-- :form -->
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#checkoutForm').formValidation({
message: 'This value is not valid',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
street: {
enabled: false,
validators: {
notEmpty: {
message: 'The street is required and cannot be empty'
}
}
},
city: {
enabled: false,
validators: {
notEmpty: {
message: 'The city is required and cannot be empty'
}
}
},
country: {
enabled: false,
validators: {
notEmpty: {
message: 'The country is required and cannot be empty'
}
}
},
state: {
enabled: false,
validators: {
notEmpty: {
message: 'The state is required and cannot be empty'
}
}
}
}
});
// Enable street/city/country validators if user want to ship to other address
$('input[name="shipping_to"]').on('change', function() {
var formValidation = $('#checkoutForm').data('formValidation'),
shipNewAddress = ($(this).val() == 'new');
shipNewAddress ? $('#newAddress').find('.form-control').removeAttr('disabled')
: $('#newAddress').find('.form-control').attr('disabled', 'disabled');
formValidation.enableFieldValidators('street', shipNewAddress)
.enableFieldValidators('city', shipNewAddress)
.enableFieldValidators('country', shipNewAddress)
.enableFieldValidators('state', shipNewAddress && $('select[name="country"]').val() == 'US');
});
$('select[name="country"]').on('change', function() {
var formValidation = $('#checkoutForm').data('formValidation');
formValidation.enableFieldValidators('state', $(this).val() == 'US');
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,109 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Enable/disable validator</h2>
</div>
<form id="signupForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-md-3 control-label">Full name (*)</label>
<div class="col-md-5">
<input type="text" class="form-control" name="full_name" />
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">Password</label>
<div class="col-md-5">
<input type="password" class="form-control" name="password" />
<span class="help-block">Leave it blank if you don't want to change it</span>
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">Confirm password</label>
<div class="col-md-5">
<input type="password" class="form-control" name="confirm_password" />
<span class="help-block">Required if the password above is not empty</span>
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#signupForm').formValidation({
message: 'This value is not valid',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
full_name: {
validators: {
notEmpty: {
message: 'The full name is required and cannot be empty'
}
}
},
password: {
enabled: false,
validators: {
notEmpty: {
message: 'The password is required and cannot be empty'
}
}
},
confirm_password: {
enabled: false,
validators: {
notEmpty: {
message: 'The confirm password is required and cannot be empty'
},
identical: {
field: 'password',
message: 'The password and its confirm must be the same'
}
}
}
}
});
// Enable the password/confirm password validators if the password is not empty
$('#signupForm').find('[name="password"]').on('keyup', function() {
var isEmpty = $(this).val() == '';
$('#signupForm').formValidation('enableFieldValidators', 'password', !isEmpty)
.formValidation('enableFieldValidators', 'confirm_password', !isEmpty);
if ($(this).val().length == 1) {
$('#signupForm').formValidation('validateField', 'password')
.formValidation('validateField', 'confirm_password');
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,310 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<!-- form: -->
<section>
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Sign up</h2>
</div>
<form id="defaultForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-lg-3 control-label">Full name</label>
<div class="col-lg-4">
<input type="text" class="form-control" name="firstName" placeholder="First name" />
</div>
<div class="col-lg-4">
<input type="text" class="form-control" name="lastName" placeholder="Last name" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Username</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="username" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Email address</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="email" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Password</label>
<div class="col-lg-5">
<input type="password" class="form-control" name="password" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Retype password</label>
<div class="col-lg-5">
<input type="password" class="form-control" name="confirmPassword" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Gender</label>
<div class="col-lg-5">
<div class="radio">
<label>
<input type="radio" name="gender" value="male" /> Male
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="female" /> Female
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="other" /> Other
</label>
</div>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Languages</label>
<div class="col-lg-5">
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="english" /> English
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="french" /> French
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="german" /> German
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="russian" /> Russian
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="other" /> Other
</label>
</div>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Programming Languages</label>
<div class="col-lg-5">
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="net" /> .Net
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="java" /> Java
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="c" /> C/C++
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="php" /> PHP
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="perl" /> Perl
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="ruby" /> Ruby
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="python" /> Python
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="javascript" /> Javascript
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary">Sign up</button>
<button type="button" class="btn btn-info" id="validateBtn">Manual validate</button>
</div>
</div>
</form>
</div>
</section>
<!-- :form -->
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#defaultForm')
.formValidation({
message: 'This value is not valid',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
firstName: {
validators: {
notEmpty: {
message: 'The first name is required and cannot be empty'
}
}
},
lastName: {
validators: {
notEmpty: {
message: 'The last name is required and cannot be empty'
}
}
},
username: {
message: 'The username is not valid',
validators: {
notEmpty: {
message: 'The username is required and cannot be empty'
},
stringLength: {
min: 6,
max: 30,
message: 'The username must be more than 6 and less than 30 characters long'
},
regexp: {
regexp: /^[a-zA-Z0-9_\.]+$/,
message: 'The username can only consist of alphabetical, number, dot and underscore'
},
// remote: {
// url: 'remote.php',
// message: 'The username is not available'
// }
}
},
email: {
validators: {
emailAddress: {
message: 'The input is not a valid email address'
}
}
},
password: {
validators: {
notEmpty: {
message: 'The password is required and cannot be empty'
},
different: {
field: 'username',
message: 'The password cannot be the same as username'
}
}
},
confirmPassword: {
validators: {
notEmpty: {
message: 'The confirm password is required and cannot be empty'
},
identical: {
field: 'password',
message: 'The password and its confirm are not the same'
}
}
},
gender: {
validators: {
notEmpty: {
message: 'The gender is required'
}
}
},
'languages[]': {
validators: {
notEmpty: {
message: 'Please specify at least one language you can speak'
}
}
},
'programs[]': {
validators: {
choice: {
min: 2,
max: 4,
message: 'Please choose 2 - 4 programming languages you are good at'
}
}
}
}
})
.on('err.form.fv', function(e) {
console.log('err.form.fv');
// You can get the form instance and then access API
var $form = $(e.target);
console.log($form.data('formValidation').getInvalidFields());
// If you want to prevent the default handler (formValidation._onError(e))
// e.preventDefault();
})
.on('success.form.fv', function(e) {
console.log('success.form.fv');
// If you want to prevent the default handler (formValidation._onSuccess(e))
// e.preventDefault();
})
.on('err.field.fv', function(e, data) {
console.log('err.field.fv -->', data);
})
.on('success.field.fv', function(e, data) {
console.log('success.field.fv -->', data);
})
.on('status.field.fv', function(e, data) {
// I don't want to add has-success class to valid field container
data.element.parents('.form-group').removeClass('has-success');
// I want to enable the submit button all the time
data.fv.disableSubmitButtons(false);
});
// Validate the form manually
$('#validateBtn').click(function() {
$('#defaultForm').formValidation('validate');
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,89 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Using events</h2>
</div>
<form id="pickupForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-lg-3 control-label">Postal Code<sup>*</sup></label>
<div class="col-lg-6">
<div class="input-group">
<span class="input-group-addon">Singapore</span>
<input type="text" class="form-control" name="postalCode" placeholder="Postal Code" />
</div>
</div>
<div class="col-lg-1">
<button type="button" class="btn btn-default" id="lookupBtn">Lookup Address</button>
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#pickupForm')
.formValidation({
message: 'This value is not valid',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
postalCode: {
message: 'The postal code is not valid',
validators: {
notEmpty: {
message: 'Your postal code is required and cannot be empty'
},
regexp: {
regexp: /^([0][1-9]|[1-6][0-9]|[7]([0-3]|[5-9])|[8][0-2])(\d{4})$/,
message: 'The input is not a valid Singapore postal code'
},
numeric: {
message: 'Only numbers are allowed'
}
}
}
}
})
.on('err.field.fv', function(e, data) {
if (data.field == 'postalCode') {
// The postal code is not valid
$('#lookupBtn').prop('disabled', true).removeClass('btn-success btn-warning').addClass('btn-warning');
}
})
.on('success.field.fv', function(e, data) {
if (data.field == 'postalCode') {
// The postal code is valid
$('#lookupBtn').prop('disabled', false).removeClass('btn-success btn-warning').addClass('btn-success');
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,101 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Using events</h2>
<p class="lead">The captcha is regenerated if the input is not valid</p>
</div>
<form id="form" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-lg-3 control-label">Full name</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="fullName" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label" id="captchaOperation"></label>
<div class="col-lg-2">
<input type="text" class="form-control" name="captcha" />
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
// Generate a simple captcha
function randomNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
};
function generateCaptcha() {
$('#captchaOperation').html([randomNumber(1, 100), '+', randomNumber(1, 200), '='].join(' '));
};
generateCaptcha();
$('#form')
.formValidation({
message: 'This value is not valid',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
fullName: {
validators: {
notEmpty: {
message: 'The full name is required'
}
}
},
captcha: {
validators: {
callback: {
message: 'Wrong answer',
callback: function(value, validator, $field) {
var items = $('#captchaOperation').html().split(' '), sum = parseInt(items[0]) + parseInt(items[2]);
return value == sum;
}
}
}
}
}
})
.on('err.form.fv', function(e) {
var $form = $(e.target),
formValidation = $form.data('formValidation');
if (!formValidation.isValidField('captcha')) {
// The captcha is not valid
// Regenerate the captcha
generateCaptcha();
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,123 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>File validator</h2>
</div>
<form id="defaultForm" method="post" class="form-horizontal">
<div class="form-group">
<label class="col-lg-4 control-label">File</label>
<div class="col-lg-7">
<input type="file" class="form-control" name="firstFile" />
<span class="help-block">Choose a pdf file.</span>
</div>
</div>
<div class="form-group">
<label class="col-lg-4 control-label">File with min size</label>
<div class="col-lg-7">
<input type="file" class="form-control" name="secondFile" />
<span class="help-block">Choose a pdf file with a size more than 1M.</span>
</div>
</div>
<div class="form-group">
<label class="col-lg-4 control-label">File with max size</label>
<div class="col-lg-7">
<input type="file" class="form-control" name="thirdFile" />
<span class="help-block">Choose a pdf file with a size less than 10M.</span>
</div>
</div>
<div class="form-group">
<label class="col-lg-4 control-label">File with min and max size</label>
<div class="col-lg-7">
<input type="file" class="form-control" name="fourthFile" />
<span class="help-block">Choose a pdf file with a size between 1M and 10M.</span>
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-4">
<button type="submit" class="btn btn-primary" name="filevalidate" value="Validate">Validate</button>
</div>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#defaultForm').formValidation({
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
firstFile: {
validators: {
file: {
extension: 'pdf',
type: 'application/pdf',
message: 'Please choose a pdf file.'
}
}
},
secondFile: {
validators: {
file: {
extension: 'pdf',
type: 'application/pdf',
minSize: 1024*1024,
message: 'Please choose a pdf file with a size more than 1M.'
}
}
},
thirdFile: {
validators: {
file: {
extension: 'pdf',
type: 'application/pdf',
maxSize: 10*1024*1024,
message: 'Please choose a pdf file with a size less than 10M.'
}
}
},
fourthFile: {
validators: {
file: {
extension: 'pdf',
type: 'application/pdf',
minSize: 1024*1024,
maxSize: 10*1024*1024,
message: 'Please choose a pdf file with a size between 1M and 10M.'
}
}
}
}
})
.on('success.form.fv', function(e) {
e.preventDefault();
$('#defaultForm').data('formValidation').disableSubmitButtons(true);
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,214 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation &rarr; Foundation demo</title>
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/css/normalize.min.css"/>
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/css/foundation.min.css"/>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" />
<link rel="stylesheet" href="../../dist/css/formValidation.css"/>
<script type="text/javascript" src="../../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/js/vendor/modernizr.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/js/foundation/foundation.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/js/foundation/foundation.tooltip.js"></script>
<script type="text/javascript" src="../../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../../dist/js/framework/foundation.js"></script>
<style type="text/css">
body {
padding: 50px 0;
}
</style>
</head>
<body>
<div class="row">
<div class="small-8 small-centered columns">
<h2>Foundation Form</h2>
<hr/>
<form id="horizontalForm" method="post" action="../target.php">
<div class="row">
<div class="small-3 columns">
<label class="right">Full name</label>
</div>
<div class="small-9 columns">
<div class="row">
<div class="small-6 columns">
<input type="text" name="firstName" placeholder="First name" />
</div>
<div class="small-6 columns">
<input type="text" name="lastName" placeholder="Last name" />
</div>
</div>
</div>
</div>
<div class="row">
<div class="small-3 columns">
<label class="right">Username</label>
</div>
<div class="small-6 small-pull-3 columns">
<input type="text" name="username" />
</div>
</div>
<div class="row">
<div class="small-3 columns">
<label class="right">Email address</label>
</div>
<div class="small-6 small-pull-3 columns">
<input type="text" name="email" />
</div>
</div>
<div class="row">
<div class="small-3 columns">
<label class="right">Password</label>
</div>
<div class="small-6 small-pull-3 columns">
<input type="password" name="password" />
</div>
</div>
<div class="row">
<div class="small-3 columns">
<label class="right">Gender</label>
</div>
<div class="small-9 columns">
<input type="radio" name="gender" value="male" /><label>Male</label>
<input type="radio" name="gender" value="female" /><label>Female</label>
<input type="radio" name="gender" value="other" /><label>Other</label>
</div>
</div>
<div class="row">
<div class="small-3 columns">
<label class="right" id="captchaOperation"></label>
</div>
<div class="small-3 small-pull-6 columns">
<input type="text" name="captcha" />
</div>
</div>
<div class="row">
<div class="small-9 small-push-3 columns">
<input type="checkbox" name="agree" value="agree" /> <label>Agree with the terms and conditions</label>
</div>
</div>
<div class="row">
<div class="small-9 small-push-3 columns">
<button type="submit" class="button small" name="signup" value="Sign up">Submit</button>
</div>
</div>
</form>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$(document).foundation();
// Generate a simple captcha
function randomNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
};
$('#captchaOperation').html([randomNumber(1, 100), '+', randomNumber(1, 200), '='].join(' '));
$('#horizontalForm').formValidation({
framework: 'foundation',
icon: {
valid: 'fa fa-check',
invalid: 'fa fa-times',
validating: 'fa fa-refresh',
feedback: 'fv-control-feedback'
},
fields: {
firstName: {
row: '.small-6',
validators: {
notEmpty: {
message: 'The first name is required'
}
}
},
lastName: {
row: '.small-6',
validators: {
notEmpty: {
message: 'The last name is required'
}
}
},
username: {
message: 'The username is not valid',
validators: {
notEmpty: {
message: 'The username is required'
},
stringLength: {
min: 6,
max: 30,
message: 'The username must be more than 6 and less than 30 characters long'
},
regexp: {
regexp: /^[a-zA-Z0-9_\.]+$/,
message: 'The username can only consist of alphabetical, number, dot and underscore'
}
}
},
email: {
validators: {
notEmpty: {
message: 'The email address is required'
},
emailAddress: {
message: 'The input is not a valid email address'
}
}
},
password: {
validators: {
notEmpty: {
message: 'The password is required'
},
different: {
field: 'username',
message: 'The password cannot be the same as username'
}
}
},
gender: {
validators: {
notEmpty: {
message: 'The gender is required'
}
}
},
captcha: {
validators: {
callback: {
message: 'Wrong answer',
callback: function(value, validator) {
var items = $('#captchaOperation').html().split(' '), sum = parseInt(items[0]) + parseInt(items[2]);
return value == sum;
}
}
}
},
agree: {
validators: {
notEmpty: {
message: 'You must agree with the terms and conditions'
}
}
}
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,217 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation &rarr; Foundation demo</title>
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/css/normalize.min.css"/>
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/css/foundation.min.css"/>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" />
<link rel="stylesheet" href="../../dist/css/formValidation.css"/>
<script type="text/javascript" src="../../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/js/vendor/modernizr.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/js/foundation/foundation.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/js/foundation/foundation.tooltip.js"></script>
<script type="text/javascript" src="../../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../../dist/js/framework/foundation.js"></script>
<style type="text/css">
body {
padding: 50px 0;
}
</style>
</head>
<body>
<div class="row">
<div class="small-8 small-centered columns">
<h2>Foundation Form</h2>
<hr/>
<form id="horizontalForm" method="post" action="../target.php">
<div class="row">
<div class="small-3 columns">
<label class="right">Full name</label>
</div>
<div class="small-9 columns">
<div class="row">
<div class="small-6 columns">
<input type="text" name="firstName" placeholder="First name" />
</div>
<div class="small-6 columns">
<input type="text" name="lastName" placeholder="Last name" />
</div>
</div>
</div>
</div>
<div class="row">
<div class="small-3 columns">
<label class="right">Username</label>
</div>
<div class="small-6 small-pull-3 columns">
<input type="text" name="username" />
</div>
</div>
<div class="row">
<div class="small-3 columns">
<label class="right">Email address</label>
</div>
<div class="small-6 small-pull-3 columns">
<input type="text" name="email" />
</div>
</div>
<div class="row">
<div class="small-3 columns">
<label class="right">Password</label>
</div>
<div class="small-6 small-pull-3 columns">
<input type="password" name="password" />
</div>
</div>
<div class="row">
<div class="small-3 columns">
<label class="right">Gender</label>
</div>
<div class="small-9 columns">
<input type="radio" name="gender" value="male" /><label>Male</label>
<input type="radio" name="gender" value="female" /><label>Female</label>
<input type="radio" name="gender" value="other" /><label>Other</label>
</div>
</div>
<div class="row">
<div class="small-3 columns">
<label class="right" id="captchaOperation"></label>
</div>
<div class="small-3 small-pull-6 columns">
<input type="text" name="captcha" />
</div>
</div>
<div class="row">
<div class="small-9 small-push-3 columns">
<input type="checkbox" name="agree" value="agree" /> <label>Agree with the terms and conditions</label>
</div>
</div>
<div class="row">
<div class="small-9 small-push-3 columns">
<button type="submit" class="button small" name="signup" value="Sign up">Submit</button>
</div>
</div>
</form>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$(document).foundation();
// Generate a simple captcha
function randomNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
};
$('#captchaOperation').html([randomNumber(1, 100), '+', randomNumber(1, 200), '='].join(' '));
$('#horizontalForm').formValidation({
framework: 'foundation',
icon: {
valid: 'fa fa-check',
invalid: 'fa fa-times',
validating: 'fa fa-refresh',
feedback: 'fv-control-feedback'
},
err: {
container: 'tooltip'
},
fields: {
firstName: {
row: '.small-6',
validators: {
notEmpty: {
message: 'The first name is required'
}
}
},
lastName: {
row: '.small-6',
validators: {
notEmpty: {
message: 'The last name is required'
}
}
},
username: {
message: 'The username is not valid',
validators: {
notEmpty: {
message: 'The username is required'
},
stringLength: {
min: 6,
max: 30,
message: 'The username must be more than 6 and less than 30 characters long'
},
regexp: {
regexp: /^[a-zA-Z0-9_\.]+$/,
message: 'The username can only consist of alphabetical, number, dot and underscore'
}
}
},
email: {
validators: {
notEmpty: {
message: 'The email address is required'
},
emailAddress: {
message: 'The input is not a valid email address'
}
}
},
password: {
validators: {
notEmpty: {
message: 'The password is required'
},
different: {
field: 'username',
message: 'The password cannot be the same as username'
}
}
},
gender: {
validators: {
notEmpty: {
message: 'The gender is required'
}
}
},
captcha: {
validators: {
callback: {
message: 'Wrong answer',
callback: function(value, validator) {
var items = $('#captchaOperation').html().split(' '), sum = parseInt(items[0]) + parseInt(items[2]);
return value == sum;
}
}
}
},
agree: {
validators: {
notEmpty: {
message: 'You must agree with the terms and conditions'
}
}
}
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,111 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<!-- form: -->
<section>
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Sign up</h2>
</div>
<form id="defaultForm" method="post" class="form-horizontal" action="target.php"
data-fv-message="This value is not valid"
data-fv-icon-valid="glyphicon glyphicon-ok"
data-fv-icon-invalid="glyphicon glyphicon-remove"
data-fv-icon-validating="glyphicon glyphicon-refresh">
<div class="form-group">
<label class="col-lg-3 control-label">Full name</label>
<div class="col-lg-4">
<input type="text" class="form-control" name="firstName" placeholder="First name" data-fv-trigger="keyup" required data-fv-notempty-message="The first name is required and cannot be empty" />
</div>
<div class="col-lg-4">
<input type="text" class="form-control" name="lastName" placeholder="Last name" required data-fv-trigger="blur" data-fv-notempty-message="The last name is required and cannot be empty" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Username</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="username"
data-fv-trigger="blur"
data-fv-message="The username is not valid"
required data-fv-notempty-message="The username is required and cannot be empty"
pattern="[a-zA-Z0-9_\.]+" data-fv-regexp-message="The username can only consist of alphabetical, number, dot and underscore"
minlength="5" data-fv-stringlength-message="The username must have at least 5 characters" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Email address</label>
<div class="col-lg-5">
<input class="form-control" name="email" type="email" required data-fv-emailaddress-message="The input is not a valid email address" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Website</label>
<div class="col-lg-5">
<input class="form-control" name="website" type="url" required data-fv-uri-message="The input is not a valid website address" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Fav color</label>
<div class="col-lg-3">
<input class="form-control" name="color" type="color" required data-fv-color-message="The input is not a valid color code" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Age</label>
<div class="col-lg-2">
<input type="number" class="form-control" name="age" step="1"
min="10" data-fv-greaterthan-inclusive="false" data-fv-greaterthan-message="The input must be greater than or equal to 10"
max="100" data-fv-lessthan-inclusive="true" data-fv-lessthan-message="The input must be less than 100"
/>
<!--<input type="range" class="form-control" name="age"
required
min="10" max="100" data-fv-between-message="The input must be between 10 and 100"
/>-->
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Bio</label>
<div class="col-lg-5">
<textarea class="form-control" name="bio" rows="10" data-fv-stringlength data-fv-stringlength-max="100" data-fv-stringlength-message="The bio must be less than 100 characters long"></textarea>
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary">Sign up</button>
</div>
</div>
</form>
</div>
</section>
<!-- :form -->
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#defaultForm').formValidation();
});
</script>
</body>
</html>

View File

@@ -0,0 +1,306 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
<script type="text/javascript" src="../dist/js/language/vi_VN.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Default messages</h2>
</div>
<form id="defaultForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-lg-3 control-label">Full name</label>
<div class="col-lg-4">
<input type="text" class="form-control" name="firstName" placeholder="First name" />
</div>
<div class="col-lg-4">
<input type="text" class="form-control" name="lastName" placeholder="Last name" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Username</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="username" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Email address</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="email" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Password</label>
<div class="col-lg-5">
<input type="password" class="form-control" name="password" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Retype password</label>
<div class="col-lg-5">
<input type="password" class="form-control" name="confirmPassword" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Gender</label>
<div class="col-lg-5">
<div class="radio">
<label>
<input type="radio" name="gender" value="male" /> Male
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="female" /> Female
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="other" /> Other
</label>
</div>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Age</label>
<div class="col-lg-3">
<input type="text" class="form-control" name="age" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Website</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="website" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Phone number</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="phoneNumber" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Languages</label>
<div class="col-lg-5">
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="english" /> English
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="french" /> French
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="german" /> German
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="russian" /> Russian
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="languages[]" value="other" /> Other
</label>
</div>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Programming Languages</label>
<div class="col-lg-5">
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="net" /> .Net
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="java" /> Java
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="c" /> C/C++
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="php" /> PHP
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="perl" /> Perl
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="ruby" /> Ruby
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="python" /> Python
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="programs[]" value="javascript" /> Javascript
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary" name="signup" value="Sign up">Sign up</button>
<button type="submit" class="btn btn-primary" name="signup2" value="Sign up 2">Sign up 2</button>
</div>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#defaultForm').formValidation({
message: 'This value is not valid',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
firstName: {
validators: {
notEmpty: {},
stringCase: {
'case': 'upper'
}
}
},
lastName: {
validators: {
notEmpty: {},
stringCase: {
'case': 'upper'
}
}
},
username: {
validators: {
notEmpty: {},
stringLength: {
min: 6,
max: 20
},
regexp: {
regexp: /^[a-zA-Z0-9_\.]+$/
},
remote: {
url: 'remote.php',
message: 'Tên tài khoản này đã được đăng ký'
}
}
},
email: {
validators: {
emailAddress: {}
}
},
password: {
validators: {
notEmpty: {},
different: {
field: 'username',
message: 'Mật khẩu và tên đăng nhập phải khác nhau'
}
}
},
confirmPassword: {
validators: {
notEmpty: {},
identical: {
field: 'password'
}
}
},
age: {
validators: {
notEmpty: {},
digits: {},
greaterThan: {
value: 18
},
lessThan: {
value: 100
}
}
},
website: {
validators: {
notEmpty: {},
uri: {}
}
},
phoneNumber: {
validators: {
notEmpty: {},
digits: {},
phone: {
country: 'US'
}
}
},
gender: {
validators: {
notEmpty: {}
}
},
'languages[]': {
validators: {
notEmpty: {}
}
},
'programs[]': {
validators: {
choice: {
min: 2,
max: 4
}
}
}
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,163 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Disable feedback icons for particular fields</h2>
</div>
<form id="defaultForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-lg-3 control-label">Full name</label>
<div class="col-lg-4">
<input type="text" class="form-control" name="firstName" placeholder="First name" />
</div>
<div class="col-lg-4">
<input type="text" class="form-control" name="lastName" placeholder="Last name" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Username</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="username" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Email address</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="email" data-fv-icon="false" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Password</label>
<div class="col-lg-5">
<input type="password" class="form-control" name="password" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Gender</label>
<div class="col-lg-5">
<div class="radio">
<label>
<input type="radio" name="gender" value="male" /> Male
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="female" /> Female
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="other" /> Other
</label>
</div>
</div>
</div>
<div class="form-group hide">
<div class="col-lg-9 col-lg-offset-3">
<ul id="errors"></ul>
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary">Sign up</button>
</div>
</div>
</form>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#defaultForm')
.formValidation({
message: 'This value is not valid',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
firstName: {
validators: {
notEmpty: {
message: 'The first name is required and cannot be empty'
}
}
},
lastName: {
validators: {
notEmpty: {
message: 'The last name is required and cannot be empty'
}
}
},
username: {
message: 'The username is not valid',
validators: {
notEmpty: {
message: 'The username is required and cannot be empty'
},
stringLength: {
min: 6,
max: 30,
message: 'The username must be more than 6 and less than 30 characters long'
},
regexp: {
regexp: /^[a-zA-Z0-9_\.]+$/,
message: 'The username can only consist of alphabetical, number, dot and underscore'
}
}
},
email: {
validators: {
emailAddress: {
message: 'The input is not a valid email address'
}
}
},
password: {
icon: 'false',
validators: {
notEmpty: {
message: 'The password is required and cannot be empty'
},
different: {
field: 'username',
message: 'The password cannot be the same as username'
}
}
},
gender: {
icon: false,
validators: {
notEmpty: {
message: 'The gender is required'
}
}
}
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,94 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-xs-8 col-xs-offset-2">
<div class="page-header">
<h1>Ignoring field validator</h1>
</div>
<form id="surveyForm" method="post" action="target.php">
<div class="form-group">
<label class="control-label">How do you know about FormValidation?</label>
<div class="radio">
<label><input type="radio" name="channel" value="google" /> Google</label>
</div>
<div class="radio">
<label><input type="radio" name="channel" value="github" /> Github</label>
</div>
<div class="radio">
<label><input type="radio" name="channel" value="twitter" /> Twitter</label>
</div>
<div class="radio">
<label><input type="radio" name="channel" value="facebook" /> Facebook</label>
</div>
<div class="radio">
<label><input type="radio" name="channel" value="other" /> Other</label>
</div>
</div>
<div class="form-group">
<label class="control-label">Please specify it:</label>
<input type="text" class="form-control" name="otherChannel" />
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#surveyForm')
.formValidation({
framework: 'bootstrap',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
channel: {
validators: {
notEmpty: {
message: 'Please select a channel'
}
}
},
otherChannel: {
validators: {
callback: {
message: 'Please specific the channel',
callback: function(value, validator, $field) {
var channel = $('#surveyForm').find('[name="channel"]:checked').val();
return (channel === 'other')
? (value !== '')
: null; // Ignore if given channel is selected
}
}
}
}
}
})
.on('change', '[name="channel"]', function(e) {
$('#surveyForm').formValidation('revalidateField', 'otherChannel');
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,204 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<!-- Include the FontAwesome CSS if you want to use feedback icons provided by FontAwesome -->
<!--<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" />-->
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-sm-8 col-sm-offset-2">
<div class="page-header">
<h2>Bootstrap Form</h2>
</div>
<form id="defaultForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-sm-3 control-label">Full name</label>
<div class="col-sm-4">
<input type="text" class="form-control" name="firstName" placeholder="First name" />
</div>
<div class="col-sm-4">
<input type="text" class="form-control" name="lastName" placeholder="Last name" />
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Username</label>
<div class="col-sm-5">
<input type="text" class="form-control" name="username" />
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Email address</label>
<div class="col-sm-5">
<input type="text" class="form-control" name="email" />
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Password</label>
<div class="col-sm-5">
<input type="password" class="form-control" name="password" />
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Gender</label>
<div class="col-sm-6">
<div class="radio">
<label>
<input type="radio" name="gender" value="male" /> Male
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="female" /> Female
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="other" /> Other
</label>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" id="captchaOperation"></label>
<div class="col-sm-2">
<input type="text" class="form-control" name="captcha" />
</div>
</div>
<div class="form-group">
<div class="col-sm-6 col-sm-offset-3">
<div class="checkbox">
<label>
<input type="checkbox" name="agree" value="agree" /> Agree with the terms and conditions
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-9 col-sm-offset-3">
<button type="submit" class="btn btn-primary" name="signup" value="Sign up">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
// Generate a simple captcha
function randomNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
};
$('#captchaOperation').html([randomNumber(1, 100), '+', randomNumber(1, 200), '='].join(' '));
$('#defaultForm').formValidation({
message: 'This value is not valid',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
firstName: {
row: '.col-sm-4',
validators: {
notEmpty: {
message: 'The first name is required'
}
}
},
lastName: {
row: '.col-sm-4',
validators: {
notEmpty: {
message: 'The last name is required'
}
}
},
username: {
message: 'The username is not valid',
validators: {
notEmpty: {
message: 'The username is required'
},
stringLength: {
min: 6,
max: 30,
message: 'The username must be more than 6 and less than 30 characters long'
},
regexp: {
regexp: /^[a-zA-Z0-9_\.]+$/,
message: 'The username can only consist of alphabetical, number, dot and underscore'
}
}
},
email: {
validators: {
notEmpty: {
message: 'The email address is required'
},
emailAddress: {
message: 'The input is not a valid email address'
}
}
},
password: {
validators: {
notEmpty: {
message: 'The password is required'
},
different: {
field: 'username',
message: 'The password cannot be the same as username'
}
}
},
gender: {
validators: {
notEmpty: {
message: 'The gender is required'
}
}
},
captcha: {
validators: {
callback: {
message: 'Wrong answer',
callback: function(value, validator, $field) {
var items = $('#captchaOperation').html().split(' '), sum = parseInt(items[0]) + parseInt(items[2]);
return value == sum;
}
}
}
},
agree: {
validators: {
notEmpty: {
message: 'You must agree with the terms and conditions'
}
}
}
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,125 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<!-- form: -->
<section>
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Contact</h2>
</div>
<form id="contactForm" method="post" class="form-horizontal" action="target.php"
data-fv-message="This value is not valid"
data-fv-icon-valid="glyphicon glyphicon-ok"
data-fv-icon-invalid="glyphicon glyphicon-remove"
data-fv-icon-validating="glyphicon glyphicon-refresh">
<div class="form-group">
<label class="col-lg-3 control-label">Full name <sup>*</sup></label>
<div class="col-lg-4">
<input type="text" class="form-control" name="firstName" placeholder="First name" required data-fv-notempty-message="The first name is required" />
</div>
<div class="col-lg-4">
<input type="text" class="form-control" name="lastName" placeholder="Last name" required data-fv-notempty-message="The last name is required" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Company <sup>*</sup></label>
<div class="col-lg-5">
<input type="text" class="form-control" name="company"
required data-fv-notempty-message="The company name is required" />
</div>
<div class="col-lg-2">
<button type="button" class="btn btn-link" data-toggle="#jobInfo">Add more info</button>
</div>
</div>
<div id="jobInfo" style="display: none;">
<div class="form-group">
<label class="col-lg-3 control-label">Job title <sup>*</sup></label>
<div class="col-lg-5">
<input type="text" class="form-control" name="job"
required data-fv-notempty-message="The job title is required" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Department <sup>*</sup></label>
<div class="col-lg-5">
<input type="text" class="form-control" name="department"
required data-fv-notempty-message="The department name is required" />
</div>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Mobile phone <sup>*</sup></label>
<div class="col-lg-5">
<input type="text" class="form-control" name="mobilePhone"
required data-fv-notempty-message="The mobile phone number is required"
data-fv-digits data-fv-digits-message="The mobile phone number is not valid" />
</div>
<div class="col-lg-2">
<button type="button" class="btn btn-link" data-toggle="#phoneInfo">Add more phone numbers</button>
</div>
</div>
<div id="phoneInfo" style="display: none;">
<div class="form-group">
<label class="col-lg-3 control-label">Home phone</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="homePhone"
data-fv-digits data-fv-digits-message="The home phone number is not valid" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Office phone</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="officePhone"
data-fv-digits data-fv-digits-message="The office phone number is not valid" />
</div>
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary btn-lg">Save</button>
</div>
</div>
</form>
</div>
</section>
<!-- :form -->
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('button[data-toggle]').on('click', function() {
var $target = $($(this).attr('data-toggle'));
$target.toggle();
if (!$target.is(':visible')) {
// Enable the submit buttons in case additional fields are not valid
$('#contactForm').data('formValidation').disableSubmitButtons(false);
}
});
$('#contactForm').formValidation();
});
</script>
</body>
</html>

View File

@@ -0,0 +1,105 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-xs-8 col-xs-offset-2">
<div class="page-header">
<h1>Using MailGun API to validate email address</h1>
</div>
<form id="defaultForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-xs-3 control-label">Email address</label>
<div class="col-xs-6">
<input type="text" class="form-control" name="email" />
</div>
</div>
<div class="form-group">
<div class="col-xs-9 col-xs-offset-3">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#defaultForm')
.formValidation({
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
email: {
verbose: false,
validators: {
notEmpty: {
message: 'The email address is required and can\'t be empty'
},
emailAddress: {
message: 'The input is not a valid email address'
},
stringLength: {
max: 512,
message: 'Cannot exceed 512 characters'
},
remote: {
type: 'GET',
url: 'https://api.mailgun.net/v2/address/validate?callback=?',
crossDomain: true,
name: 'address',
data: {
api_key: 'pubkey-83a6-sl6j2m3daneyobi87b3-ksx3q29'
},
dataType: 'jsonp',
validKey: 'is_valid',
message: 'The email is not valid'
}
}
}
}
})
.on('success.validator.fv', function(e, data) {
if (data.field === 'email' && data.validator === 'remote') {
var response = data.result; // response is the result returned by MailGun API
if (response.did_you_mean) {
// Update the message
data.element // The field element
.data('fv.messages') // The message container
.find('[data-fv-validator="remote"][data-fv-for="email"]')
.html('Did you mean ' + response.did_you_mean + '?')
.show();
}
}
})
.on('err.validator.fv', function(e, data) {
if (data.field === 'email' && data.validator === 'remote') {
// We need to reset the error message
data.element // The field element
.data('fv.messages') // The message container
.find('[data-fv-validator="remote"][data-fv-for="email"]')
.html('The email is not valid')
.show();
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,135 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="page-header">
<h1>Use error message that is returned from remote/callback validator</h1>
</div>
<div class="col-lg-8 col-lg-offset-2">
<form id="defaultForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-lg-3 control-label">Username</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="username" autocomplete="off" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Email address</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="email" autocomplete="off" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Password</label>
<div class="col-lg-5">
<input type="password" class="form-control" name="password" />
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#defaultForm').formValidation({
message: 'This value is not valid',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
username: {
message: 'The username is not valid',
validators: {
notEmpty: {
message: 'The username is required and can\'t be empty'
},
remote: {
url: 'remote2.php'
}
}
},
email: {
validators: {
notEmpty: {
message: 'The email address is required and can\'t be empty'
},
emailAddress: {
message: 'The input is not a valid email address'
},
remote: {
url: 'remote2.php'
}
}
},
password: {
validators: {
notEmpty: {
message: 'The password is required and can\'t be empty'
},
different: {
field: 'username',
message: 'The password can\'t be the same as username'
},
callback: {
callback: function(value, validator) {
// Check the password strength
if (value.length < 6) {
return {
valid: false,
message: 'The password must be more than 6 characters'
}
}
if (value === value.toLowerCase()) {
return {
valid: false,
message: 'The password must contain at least one upper case character'
}
}
if (value === value.toUpperCase()) {
return {
valid: false,
message: 'The password must contain at least one lower case character'
}
}
if (value.search(/[0-9]/) < 0) {
return {
valid: false,
message: 'The password must contain at least one digit'
}
}
return true;
}
}
}
}
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,152 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<section>
<div class="col-lg-8 col-lg-offset-2">
<div class="page-header">
<h2>Multiple elements with the same name</h2>
</div>
<form id="defaultForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-lg-3 control-label">Gender</label>
<div class="col-lg-5">
<div class="radio">
<label>
<input type="radio" name="gender" value="male" /> Male
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="female" /> Female
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="gender" value="other" /> Other
</label>
</div>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Browser</label>
<div class="col-lg-5">
<div class="checkbox">
<label>
<input type="checkbox" name="browsers[]" value="chrome" /> Google Chrome
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="browsers[]" value="firefox" /> Firefox
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="browsers[]" value="ie" /> IE
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="browsers[]" value="safari" /> Safari
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="browsers[]" value="opera" /> Opera
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="browsers[]" value="other" /> Other
</label>
</div>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Editors</label>
<div class="col-lg-5">
<input class="form-control" type="text" name="editors[]" />
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-3 col-lg-5">
<input class="form-control" type="text" name="editors[]" />
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-3 col-lg-5">
<input class="form-control" type="text" name="editors[]" />
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-3 col-lg-5">
<input class="form-control" type="text" name="editors[]" />
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-3 col-lg-3">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
</div>
</section>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#defaultForm').formValidation({
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
err: {
container: 'tooltip'
},
fields: {
gender: {
validators: {
notEmpty: {
message: 'The gender is required'
}
}
},
'browsers[]': {
validators: {
notEmpty: {
message: 'Please specify at least one browser you use daily for development'
}
}
},
'editors[]': {
validators: {
notEmpty: {
message: 'The editor names are required'
}
}
}
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,126 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
<style type="text/css">
.row.no-gutter {
margin-left: 0;
margin-right: 0;
}
.row.no-gutter .form-control-feedback {
right: 0;
}
.row.no-gutter [class*='col-']:not(:first-child) input {
border-left: none;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.row.no-gutter [class*='col-']:not(:last-child) input {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.row.no-gutter [class*='col-']:not(:first-child),
.row.no-gutter [class*='col-']:not(:last-child) {
padding-right: 0;
padding-left: 0;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-xs-8 col-xs-offset-2">
<div class="page-header">
<h1>Validating multiple inputs as one</h1>
</div>
<form id="profileForm" class="form-horizontal" method="post" action="target.php">
<div class="form-group">
<label class="col-xs-3 control-label">Birthday</label>
<div class="col-xs-9">
<div class="row no-gutter">
<div class="col-xs-4">
<input type="text" class="form-control" name="date" placeholder="Date" />
</div>
<div class="col-xs-4">
<input type="text" class="form-control" name="month" placeholder="Month" />
</div>
<div class="col-xs-4">
<input type="text" class="form-control" name="year" placeholder="Year" />
</div>
</div>
<input type="hidden" name="dob" />
</div>
</div>
<div class="form-group">
<div class="col-xs-5 col-xs-offset-3">
<button type="submit" class="btn btn-default">Validate</button>
</div>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#profileForm')
.formValidation({
framework: 'bootstrap',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
dob: {
excluded: false,
validators: {
notEmpty: {
message: 'Please fill out each field',
transformer: function($field, validatorName) {
var y = $('#profileForm').find('[name="year"]').val(),
m = $('#profileForm').find('[name="month"]').val(),
d = $('#profileForm').find('[name="date"]').val();
return (y === '' || m === '' || d === '') ? '' : [y, m, d].join('.');
}
},
date: {
format: 'YYYY.MM.DD',
separator: '.',
transformer: function($field, validatorName) {
var y = $('#profileForm').find('[name="year"]').val(),
m = $('#profileForm').find('[name="month"]').val(),
d = $('#profileForm').find('[name="date"]').val();
return [y, m, d].join('.');
},
message: 'Please enter a valid date'
}
}
}
}
})
.on('keyup', 'input[name="date"], input[name="month"], input[name="year"]', function(e) {
$('#profileForm').formValidation('revalidateField', 'dob');
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,187 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>FormValidation &rarr; Pure demo</title>
<link rel="stylesheet" href="http://yui.yahooapis.com/pure/0.5.0/pure-min.css"/>
<!--[if lte IE 8]><link rel="stylesheet" href="http://yui.yahooapis.com/pure/0.5.0/grids-responsive-old-ie-min.css"><![endif]-->
<!--[if gt IE 8]><!--><link rel="stylesheet" href="http://yui.yahooapis.com/pure/0.5.0/grids-responsive-min.css"><!--<![endif]-->
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" />
<link rel="stylesheet" href="../../dist/css/formValidation.css"/>
<script type="text/javascript" src="../../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../../dist/js/framework/pure.js"></script>
<style type="text/css">
body {
padding: 50px 0;
}
</style>
</head>
<body>
<div class="pure-g">
<div class="pure-u-1 pure-u-md-6-24"></div>
<div class="pure-u-1 pure-u-md-12-24">
<form id="horizontalForm" class="pure-form pure-form-aligned">
<fieldset>
<legend>Pure Form</legend>
<div class="pure-control-group">
<label>Full name</label>
<input name="firstName" type="text" placeholder="First name" />
</div>
<div class="pure-control-group">
<label></label>
<input name="lastName" type="text" placeholder="Last name" />
</div>
<div class="pure-control-group">
<label>Username</label>
<input name="username" type="text" placeholder="Username" />
</div>
<div class="pure-control-group">
<label>Email address</label>
<input name="email" type="text" placeholder="Email address" />
</div>
<div class="pure-control-group">
<label>Password</label>
<input name="password" type="password" placeholder="Password" />
</div>
<div class="pure-control-group">
<label>Gender</label>
<input name="gender" type="radio" value="male" /> Male<br/>
<label></label>
<input name="gender" type="radio" value="female" /> Female<br/>
<label></label>
<input name="gender" type="radio" value="other" /> Other<br/>
</div>
<div class="pure-control-group">
<label id="captchaOperation"></label>
<input type="text" name="captcha" />
</div>
<div class="pure-control-group">
<label></label>
<input name="agree" type="checkbox" /> Agree with the terms and conditions
</div>
<div class="pure-control-group">
<label></label>
<button type="submit" class="pure-button pure-button-primary">Submit</button>
</div>
</fieldset>
</form>
</div>
<div class="pure-u-1 pure-u-md-6-24"></div>
</div>
<script type="text/javascript">
$(document).ready(function() {
// Generate a simple captcha
function randomNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
};
$('#captchaOperation').html([randomNumber(1, 100), '+', randomNumber(1, 200), '='].join(' '));
$('#horizontalForm').formValidation({
framework: 'pure',
icon: {
valid: 'fa fa-check',
invalid: 'fa fa-times',
validating: 'fa fa-refresh',
feedback: 'fv-control-feedback'
},
fields: {
firstName: {
validators: {
notEmpty: {
message: 'The first name is required'
}
}
},
lastName: {
validators: {
notEmpty: {
message: 'The last name is required'
}
}
},
username: {
message: 'The username is not valid',
validators: {
notEmpty: {
message: 'The username is required'
},
stringLength: {
min: 6,
max: 30,
message: 'The username must be more than 6 and less than 30 characters long'
},
regexp: {
regexp: /^[a-zA-Z0-9_\.]+$/,
message: 'The username can only consist of alphabetical, number, dot and underscore'
}
}
},
email: {
validators: {
notEmpty: {
message: 'The email address is required'
},
emailAddress: {
message: 'The input is not a valid email address'
}
}
},
password: {
validators: {
notEmpty: {
message: 'The password is required'
},
different: {
field: 'username',
message: 'The password cannot be the same as username'
}
}
},
gender: {
validators: {
notEmpty: {
message: 'The gender is required'
}
}
},
captcha: {
validators: {
callback: {
message: 'Wrong answer',
callback: function(value, validator) {
var items = $('#captchaOperation').html().split(' '), sum = parseInt(items[0]) + parseInt(items[2]);
return value == sum;
}
}
}
},
agree: {
validators: {
notEmpty: {
message: 'You must agree with the terms and conditions'
}
}
}
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,189 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>FormValidation &rarr; Pure demo</title>
<link rel="stylesheet" href="http://yui.yahooapis.com/pure/0.5.0/pure-min.css"/>
<!--[if lte IE 8]><link rel="stylesheet" href="http://yui.yahooapis.com/pure/0.5.0/grids-responsive-old-ie-min.css"><![endif]-->
<!--[if gt IE 8]><!--><link rel="stylesheet" href="http://yui.yahooapis.com/pure/0.5.0/grids-responsive-min.css"><!--<![endif]-->
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" />
<link rel="stylesheet" href="../../dist/css/formValidation.css"/>
<script type="text/javascript" src="../../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../../dist/js/framework/pure.js"></script>
<style type="text/css">
body {
padding: 50px 0;
}
</style>
</head>
<body>
<div class="pure-g">
<div class="pure-u-1 pure-u-md-6-24"></div>
<div class="pure-u-1 pure-u-md-12-24">
<form id="stackedForm" class="pure-form pure-form-stacked">
<fieldset>
<legend>Pure Form</legend>
<div class="pure-control-group">
<label>Full name</label>
<input name="firstName" type="text" placeholder="First name" />
</div>
<div class="pure-control-group">
<label></label>
<input name="lastName" type="text" placeholder="Last name" />
</div>
<div class="pure-control-group">
<label>Username</label>
<input name="username" type="text" placeholder="Username" />
</div>
<div class="pure-control-group">
<label>Email address</label>
<input name="email" type="text" placeholder="Email address" />
</div>
<div class="pure-control-group">
<label>Password</label>
<input name="password" type="password" placeholder="Password" />
</div>
<div class="pure-control-group">
<label>Gender</label>
<label class="pure-radio">
<input name="gender" type="radio" value="male" /> Male
</label>
<label class="pure-radio">
<input name="gender" type="radio" value="female" /> Female
</label>
<label class="pure-radio">
<input name="gender" type="radio" value="other" /> Other
</label>
</div>
<div class="pure-control-group">
<label id="captchaOperation"></label>
<input type="text" name="captcha" />
</div>
<div class="pure-control-group">
<label class="pure-checkbox">
<input name="agree" type="checkbox" /> Agree with the terms and conditions
</label>
</div>
<button type="submit" class="pure-button pure-button-primary">Submit</button>
</fieldset>
</form>
</div>
<div class="pure-u-1 pure-u-md-6-24"></div>
</div>
<script type="text/javascript">
$(document).ready(function() {
// Generate a simple captcha
function randomNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
};
$('#captchaOperation').html([randomNumber(1, 100), '+', randomNumber(1, 200), '='].join(' '));
$('#stackedForm').formValidation({
framework: 'pure',
icon: {
valid: 'fa fa-check',
invalid: 'fa fa-times',
validating: 'fa fa-refresh',
feedback: 'fv-control-feedback'
},
fields: {
firstName: {
validators: {
notEmpty: {
message: 'The first name is required'
}
}
},
lastName: {
validators: {
notEmpty: {
message: 'The last name is required'
}
}
},
username: {
message: 'The username is not valid',
validators: {
notEmpty: {
message: 'The username is required'
},
stringLength: {
min: 6,
max: 30,
message: 'The username must be more than 6 and less than 30 characters long'
},
regexp: {
regexp: /^[a-zA-Z0-9_\.]+$/,
message: 'The username can only consist of alphabetical, number, dot and underscore'
}
}
},
email: {
validators: {
notEmpty: {
message: 'The email address is required'
},
emailAddress: {
message: 'The input is not a valid email address'
}
}
},
password: {
validators: {
notEmpty: {
message: 'The password is required'
},
different: {
field: 'username',
message: 'The password cannot be the same as username'
}
}
},
gender: {
validators: {
notEmpty: {
message: 'The gender is required'
}
}
},
captcha: {
validators: {
callback: {
message: 'Wrong answer',
callback: function(value, validator) {
var items = $('#captchaOperation').html().split(' '), sum = parseInt(items[0]) + parseInt(items[2]);
return value == sum;
}
}
}
},
agree: {
validators: {
notEmpty: {
message: 'You must agree with the terms and conditions'
}
}
}
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,193 @@
<!DOCTYPE html>
<html>
<head>
<title>FormValidation demo</title>
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="../dist/css/formValidation.css"/>
<script type="text/javascript" src="../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/js/formValidation.js"></script>
<script type="text/javascript" src="../dist/js/framework/bootstrap.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<!-- form: -->
<section>
<div class="page-header">
<h1>Sign up</h1>
</div>
<div class="col-lg-8 col-lg-offset-2">
<form id="defaultForm" method="post" class="form-horizontal" action="target.php">
<div class="form-group">
<label class="col-lg-3 control-label">Username</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="username" autocomplete="off" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Email address</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="email[]" autocomplete="off" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Other email address</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="email[]" autocomplete="off" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Password</label>
<div class="col-lg-5">
<input type="password" class="form-control" name="password" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Retype password</label>
<div class="col-lg-5">
<input type="password" class="form-control" name="confirmPassword" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Website</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="website" placeholder="http://" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Phone number</label>
<div class="col-lg-5">
<input type="text" class="form-control" name="phoneNumber" />
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Country</label>
<div class="col-lg-5">
<select class="form-control" name="country">
<option value="">-- Select a country --</option>
<option value="fr">France</option>
<option value="de">Germany</option>
<option value="it">Italy</option>
<option value="jp">Japan</option>
<option value="ru">Russia</option>
<option value="gb">United Kingdom</option>
<option value="us">United State</option>
</select>
</div>
</div>
<div class="form-group">
<div class="col-lg-9 col-lg-offset-3">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
</div>
</section>
<!-- :form -->
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#defaultForm').formValidation({
message: 'This value is not valid',
// live: 'disabled',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
username: {
message: 'The username is not valid',
validators: {
notEmpty: {
message: 'The username is required and can\'t be empty'
},
remote: {
type: 'POST',
url: 'remote.php',
message: 'The username is not available',
//delay: 1000
}
}
},
'email[]': {
validators: {
notEmpty: {
message: 'The email address is required and can\'t be empty'
},
emailAddress: {
message: 'The input is not a valid email address'
},
remote: {
type: 'POST',
url: 'remote.php',
message: 'The email is not available',
delay: 2000
}
}
},
password: {
validators: {
notEmpty: {
message: 'The password is required and can\'t be empty'
},
different: {
field: 'username',
message: 'The password can\'t be the same as username'
}
}
},
confirmPassword: {
validators: {
notEmpty: {
message: 'The confirm password is required and can\'t be empty'
},
identical: {
field: 'password',
message: 'The password and its confirm are not the same'
}
}
},
website: {
validators: {
uri: {
message: 'The input is not a valid URL'
}
}
},
phoneNumber: {
validators: {
digits: {
message: 'The value can contain only digits'
}
}
},
country: {
validators: {
notEmpty: {
message: 'The country is required and can\'t be empty'
}
}
}
}
}).on('err.field.fv', function(e, data) {
console.log(data.field, data.validator);
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,33 @@
<?php
// This is a sample PHP script which demonstrates the 'remote' validator
// To make it work, point the web server to root Bootstrap Validate directory
// and open the remote.html file:
// http://domain.com/demo/remote.html
header('Content-type: application/json');
//sleep(5);
$valid = true;
$users = array(
'admin' => 'admin@domain.com',
'administrator' => 'administrator@domain.com',
'root' => 'root@domain.com',
);
if (isset($_POST['username']) && array_key_exists($_POST['username'], $users)) {
$valid = false;
} else if (isset($_POST['email'])) {
$email = $_POST['email'][0];
foreach ($users as $k => $v) {
if ($email == $v) {
$valid = false;
break;
}
}
}
echo json_encode(array(
'valid' => $valid,
));

View File

@@ -0,0 +1,34 @@
<?php
// This is a sample PHP script which demonstrates the 'remote' validator
// To make it work, point the web server to root Bootstrap Validate directory
// and open the remote.html file:
// http://domain.com/demo/remote.html
//sleep(5);
$valid = true;
$message = '';
$users = array(
'admin' => 'admin@domain.com',
'administrator' => 'administrator@domain.com',
'root' => 'root@domain.com',
);
if (isset($_POST['username']) && array_key_exists($_POST['username'], $users)) {
$valid = false;
$message = 'The username is not available';
} else if (isset($_POST['email'])) {
$email = $_POST['email'];
foreach ($users as $k => $v) {
if ($email == $v) {
$valid = false;
$message = 'The email is not available';
break;
}
}
}
echo json_encode(
$valid ? array('valid' => $valid) : array('valid' => $valid, 'message' => $message)
);

Some files were not shown because too many files have changed in this diff Show More