[BIGUPDATE] [lib.field-validator] added generic field validator with error message generation + is_valid() checker [popup] refactored all
This commit is contained in:
parent
a494f2a45e
commit
236b03775e
|
@ -41,10 +41,8 @@ export default class ChannelController{
|
||||||
/* (4) Update buffer */
|
/* (4) Update buffer */
|
||||||
this._buffer = {};
|
this._buffer = {};
|
||||||
for( let c of this.list )
|
for( let c of this.list )
|
||||||
if( c.id === this.current ){
|
if( c.id === this.current )
|
||||||
console.warn(c);
|
|
||||||
this._buffer = c;
|
this._buffer = c;
|
||||||
}
|
|
||||||
|
|
||||||
/* (5) Load rooms */
|
/* (5) Load rooms */
|
||||||
gs.get.room.fetch();
|
gs.get.room.fetch();
|
||||||
|
@ -203,11 +201,11 @@ export default class ChannelController{
|
||||||
create(name=null, link=null){
|
create(name=null, link=null){
|
||||||
|
|
||||||
/* (1) Manage invalid @link */
|
/* (1) Manage invalid @link */
|
||||||
if( typeof link !== 'string' || /^[a-z0-9\._-]$/i.test(link) )
|
if( typeof link !== 'string' || /^[a-z0-9-]$/i.test(link) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* (2) Manage invalid @name */
|
/* (2) Manage invalid @name */
|
||||||
if( typeof name !== 'string' || /^[a-z0-9\._-]$/i.test(name) )
|
if( typeof name !== 'string' || !/^[a-z0-9\/_-]{3,}$/i.test(name) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* (3) Try to create room in API */
|
/* (3) Try to create room in API */
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/* (1) Init all
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
/* (1) Import field validator */
|
||||||
|
const fv = require('./field-validator.js');
|
||||||
|
|
||||||
|
/* (2) Create class easy access */
|
||||||
|
window.FieldValidator = fv.Class;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* (1) Create basic validators
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
/* (1) BYPASS */
|
||||||
|
FieldValidator.pushFormat('bypass', () => true);
|
||||||
|
|
||||||
|
/* (2) Basic name */
|
||||||
|
FieldValidator.pushFormat('basic-name', (input) => {
|
||||||
|
return typeof input === 'string' && /^[a-z0-9 _-]{3,20}$/i.test(input);
|
||||||
|
}, '3 characters required: letters, numbers, spaces, dots, hyphens');
|
||||||
|
|
||||||
|
/* (3) URL name */
|
||||||
|
FieldValidator.pushFormat('url-name', (input) => {
|
||||||
|
return typeof input === 'string' && /^[a-z0-9_-]{3,20}$/i.test(input);
|
||||||
|
}, '3 characters required: letters, numbers, dots, hyphens');
|
||||||
|
|
||||||
|
/* (4) Password */
|
||||||
|
FieldValidator.pushFormat('password', (input) => {
|
||||||
|
return typeof input === 'string' && /^[^<>\/\\]{8,50}$/.test(input);
|
||||||
|
}, '8 characters required');
|
||||||
|
|
||||||
|
/* (5) Room type */
|
||||||
|
FieldValidator.pushFormat('room.type', (input) => {
|
||||||
|
return typeof input === 'string' && ['text', 'voice'].indexOf(input) > -1;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
export const validatorStack = {};
|
||||||
|
export const inputStack = new WeakMap();
|
||||||
|
|
||||||
|
export class Class{
|
||||||
|
|
||||||
|
static get _validators(){ return validatorStack; }
|
||||||
|
|
||||||
|
|
||||||
|
/* (1) Push a new Format
|
||||||
|
*
|
||||||
|
* @_format<String> Format name
|
||||||
|
* @_validator<Function> Format callback
|
||||||
|
* @_error<String> Error message
|
||||||
|
*
|
||||||
|
* @return pushed<bool> Whether the validator has been pushed
|
||||||
|
*
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
static pushFormat(_format=null, _validator=null, _error='error'){
|
||||||
|
|
||||||
|
/* (1) Error: invalid _format */
|
||||||
|
if( typeof _format !== 'string' )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* (2) Error: invalid _validator */
|
||||||
|
if( !(_validator instanceof Function) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* (3) Store validator */
|
||||||
|
Class._validators[_format] = { error: _error, validator: _validator };
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (1) Pop an existing Format
|
||||||
|
*
|
||||||
|
* @_format<String> Format name
|
||||||
|
*
|
||||||
|
* @return popped<bool> Whether the validator has been popped
|
||||||
|
*
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
static popFormat(_format=null){
|
||||||
|
|
||||||
|
/* (1) Error: invalid _format */
|
||||||
|
if( typeof _format !== 'string' )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* (2) Error: _validator not found */
|
||||||
|
if( Class._validators[_format] == null )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* (3) Remove validator */
|
||||||
|
delete Class._validators[_format];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* (2) Builds an validat-able input
|
||||||
|
*
|
||||||
|
* @_format<String> Existing validator name
|
||||||
|
* @_default<mixed> [OPT] Mutable input default value (default to NULL)
|
||||||
|
*
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
constructor(_format, _default=null){
|
||||||
|
|
||||||
|
/* (1) Store fields (default value) */
|
||||||
|
this.mutable = _default;
|
||||||
|
|
||||||
|
/* (2) Store _format in STATIC inputStack */
|
||||||
|
inputStack.set(this, { format: _format });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (3) Checks if the _mutable has a current valid value
|
||||||
|
*
|
||||||
|
* @return valid<bool> Whether the _mutable is valid or not
|
||||||
|
*
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
is_valid(){
|
||||||
|
|
||||||
|
// 1. Extract validator name
|
||||||
|
let format = inputStack.get(this).format;
|
||||||
|
|
||||||
|
// 2. Dispatch validation
|
||||||
|
return validatorStack[format].validator( this.mutable );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (3) Get current error message
|
||||||
|
*
|
||||||
|
* @return NULL if is_valid()
|
||||||
|
*
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
get error(){
|
||||||
|
|
||||||
|
// 1. NULL if valid
|
||||||
|
if( this.is_valid() )
|
||||||
|
return '';
|
||||||
|
|
||||||
|
// 2. Extract validator name
|
||||||
|
let format = inputStack.get(this).format;
|
||||||
|
|
||||||
|
// 3. Dispatch validation
|
||||||
|
return validatorStack[format].error;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -22,58 +22,115 @@ export default class PopupController{
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
/* (1) Create a new Room */
|
/* (1) Create a new Room */
|
||||||
this.register('room.create', {
|
this.register('room.create', {
|
||||||
data: {
|
|
||||||
type: 'text',
|
type: new FieldValidator('room.type', 'text'),
|
||||||
name: ''
|
name: new FieldValidator('basic-name', ''),
|
||||||
|
reset(){
|
||||||
|
this.type.mutable = 'text';
|
||||||
|
this.name.mutable = '';
|
||||||
},
|
},
|
||||||
reset(){ this.data.type = 'text'; this.data.name = ''; },
|
submit(){
|
||||||
submit(){ gs.get.room.create(this.data.type, this.data.name) && this.parent.hide(); }
|
|
||||||
|
// validators
|
||||||
|
if( !this.name.is_valid() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( gs.get.room.create(this.type.mutable, this.name.mutable) )
|
||||||
|
return this.parent.hide();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/* (2) Create a new Channel */
|
/* (2) Create a new Channel */
|
||||||
this.register('channel.create', {
|
this.register('channel.create', {
|
||||||
data: {
|
name: new FieldValidator('basic-name', ''),
|
||||||
name: '',
|
link: new FieldValidator('url-name', ''),
|
||||||
link: ''
|
reset(){
|
||||||
|
this.link.mutable = '',
|
||||||
|
this.name.mutable = '';
|
||||||
},
|
},
|
||||||
reset(){ this.data.link = '', this.data.name = ''; },
|
submit(){
|
||||||
submit(){ gs.get.channel.create(this.data.name, this.data.link) && this.parent.hide(); }
|
|
||||||
|
// validators
|
||||||
|
if( !this.name.is_valid() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( !this.link.is_valid() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( gs.get.channel.create(this.name.mutable, this.link.mutable) )
|
||||||
|
return this.parent.hide();
|
||||||
|
|
||||||
|
}
|
||||||
});
|
});
|
||||||
/* (3) Change nickname */
|
|
||||||
this.register('nickname.change', {
|
/* (3) Change username */
|
||||||
data: {
|
this.register('username.change', {
|
||||||
value: ''
|
username: new FieldValidator('basic-name', ''),
|
||||||
},
|
reset(){ this.username.mutable = ''; },
|
||||||
reset(){ this.data.value = ''; },
|
submit(){
|
||||||
submit(){ gs.get.content.change_username(this.data.value) && this.parent.hide(); }
|
|
||||||
|
// validators
|
||||||
|
if( !this.username.is_valid() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( gs.get.content.change_username(this.username.mutable) )
|
||||||
|
this.parent.hide();
|
||||||
|
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/* (4) Invite to channel */
|
/* (4) Invite to channel */
|
||||||
this.register('channel.invite', {
|
this.register('channel.invite', {
|
||||||
data: {
|
username: new FieldValidator('basic-name', ''),
|
||||||
username: ''
|
reset(){ this.username.mutable = ''; },
|
||||||
},
|
submit(){
|
||||||
reset(){ this.data.username = ''; },
|
|
||||||
submit(){ gs.get.channel.invite(this.data.username) && this.parent.hide(); }
|
// validators
|
||||||
|
if( !this.username.is_valid() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( gs.get.channel.invite(this.username.mutable) )
|
||||||
|
return this.parent.hide();
|
||||||
|
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/* (5) Remove channel */
|
/* (5) Remove channel */
|
||||||
this.register('channel.remove', {
|
this.register('channel.remove', {
|
||||||
data: {},
|
|
||||||
reset(){ },
|
reset(){ },
|
||||||
submit(){ gs.get.channel.remove() && this.parent.hide(); }
|
submit(){ gs.get.channel.remove() && this.parent.hide(); }
|
||||||
});
|
});
|
||||||
|
|
||||||
/* (6) Leave channel */
|
/* (6) Leave channel */
|
||||||
this.register('channel.leave', {
|
this.register('channel.leave', {
|
||||||
data: {},
|
|
||||||
reset(){ },
|
reset(){ },
|
||||||
submit(){ gs.get.channel.remove() && this.parent.hide(); }
|
submit(){ gs.get.channel.remove() && this.parent.hide(); }
|
||||||
});
|
});
|
||||||
|
|
||||||
/* (6) Change password */
|
/* (6) Change password */
|
||||||
this.register('password.change', {
|
this.register('password.change', {
|
||||||
data: {
|
password: new FieldValidator('password', ''),
|
||||||
password: '',
|
confirm: new FieldValidator('password', ''),
|
||||||
confirm: ''
|
matches: true,
|
||||||
},
|
reset(){ this.password.mutable = ''; this.confirm.mutable = ''; },
|
||||||
reset(){ this.data.password = ''; this.data.confirm = ''; },
|
submit(){
|
||||||
submit(){ this.data.password === this.data.confirm && gs.get.content.change_password(this.data.password) && this.parent.hide(); }
|
|
||||||
|
this.matches = this.password.mutable === this.confirm.mutable;
|
||||||
|
|
||||||
|
// check passwords matches
|
||||||
|
if( !this.matches )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// field validator
|
||||||
|
if( !this.password.is_valid || !this.confirm.is_valid() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( gs.get.content.change_password(this.data.password.mutable) )
|
||||||
|
return this.parent.hide();
|
||||||
|
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -223,7 +223,7 @@ export default class RoomController{
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* (2) Manage invalid @name */
|
/* (2) Manage invalid @name */
|
||||||
if( typeof name !== 'string' )
|
if( typeof name !== 'string' || !/^[a-z0-9\/_-]{3,}$/i.test(name) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* (3) Try to create room in API */
|
/* (3) Try to create room in API */
|
||||||
|
|
|
@ -3,23 +3,15 @@
|
||||||
/* (1) Default data structure */
|
/* (1) Default data structure */
|
||||||
gs.set('login', {
|
gs.set('login', {
|
||||||
// fields
|
// fields
|
||||||
username: {
|
username: new FieldValidator('basic-name', ''),
|
||||||
model: '',
|
password: new FieldValidator('password', ''),
|
||||||
timeout: '',
|
|
||||||
error: '',
|
// login failed
|
||||||
validate: (_username) => /^[a-z0-9_-]{3,20}$/i.test(_username)
|
failed: false,
|
||||||
},
|
|
||||||
|
|
||||||
password: {
|
|
||||||
model: '',
|
|
||||||
timeout: '',
|
|
||||||
error: '',
|
|
||||||
validate: (_password) => /^[^<>\/\\]{8,50}$/.test(_password)
|
|
||||||
},
|
|
||||||
|
|
||||||
// functions
|
// functions
|
||||||
func: {
|
func: {
|
||||||
print_err(_field, _message, _duration){},
|
|
||||||
login(){},
|
login(){},
|
||||||
forgot_pass(){},
|
forgot_pass(){},
|
||||||
press_enter(){}
|
press_enter(){}
|
||||||
|
@ -30,93 +22,28 @@ gs.set('login', {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* (2) Manage error messages
|
/* (2) Login attempt
|
||||||
*
|
|
||||||
* @_field<String> Field to print errors to
|
|
||||||
* @_message<String> Error message to print
|
|
||||||
* @_duration<int> Durations (sec) for the message to be displayed
|
|
||||||
*
|
|
||||||
---------------------------------------------------------*/
|
|
||||||
gs.get.login.func.print_err = function(_field, _message='error', _duration=null){
|
|
||||||
|
|
||||||
/* (1) Fail: invalid _field */
|
|
||||||
if( typeof _field !== 'string' || this[_field] == null )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* (2) Fail: invalid _message */
|
|
||||||
if( typeof _message !== 'string' )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* (3) Fail: invalid _message */
|
|
||||||
if( isNaN(_duration) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* (4) Clear timeout if exists */
|
|
||||||
!isNaN(this[_field].err_to) && clearTimeout(this[_field].err_to);
|
|
||||||
|
|
||||||
/* (5) Display error */
|
|
||||||
this[_field].error = _message;
|
|
||||||
|
|
||||||
/* (6) No timeout if _duration if null */
|
|
||||||
if( _duration === null )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/* (7) Setup Timeout */
|
|
||||||
this[_field].err_to = setTimeout( function(){
|
|
||||||
this.error = '';
|
|
||||||
}.bind(this[_field]), _duration*1000);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}.bind(gs.get.login);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* (3) Login attempt
|
|
||||||
*
|
*
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
gs.get.login.func.login = function(){
|
gs.get.login.func.login = function(){
|
||||||
|
|
||||||
/* (1) Cache fields' values */
|
/* (1) Cache fields' values */
|
||||||
let username = this.username.model;
|
let username = this.username.mutable;
|
||||||
let password = this.password.model;
|
let password = this.password.mutable;
|
||||||
|
|
||||||
/* (2) Manage errors */
|
/* (2) Manage errors */
|
||||||
let errors = false;
|
if( !this.username.is_valid() )
|
||||||
|
return false;
|
||||||
|
|
||||||
// username error
|
if( !this.password.is_valid() )
|
||||||
if( !this.username.validate(username) ){
|
|
||||||
errors = true;
|
|
||||||
this.func.print_err('username', '3 characters are required: letters, numbers, dot');
|
|
||||||
}else
|
|
||||||
this.func.print_err('username', '', 0);
|
|
||||||
|
|
||||||
|
|
||||||
// password error
|
|
||||||
if( !this.password.validate(password) ){
|
|
||||||
errors = true;
|
|
||||||
this.func.print_err('password', '8 characters are required');
|
|
||||||
}else
|
|
||||||
this.func.print_err('password', '', 0);
|
|
||||||
|
|
||||||
// if errors -> fail
|
|
||||||
if( errors )
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* (3) API bindings */
|
/* (3) API bindings */
|
||||||
api.call('GET /user/token', {}, function(rs){
|
api.call('GET /user/token', {}, function(rs){
|
||||||
|
|
||||||
// manage error
|
// manage error
|
||||||
if( rs.error !== 0 || rs.token == null ){
|
if( rs.error !== 0 || rs.token == null )
|
||||||
this.func.print_err('username', 'Invalid combination');
|
return this.failed = true;
|
||||||
this.func.print_err('password', 'Invalid combination');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// store TOKEN + user data
|
// store TOKEN + user data
|
||||||
auth.token = rs.token;
|
auth.token = rs.token;
|
||||||
|
|
|
@ -3,31 +3,12 @@
|
||||||
/* (1) Default data structure */
|
/* (1) Default data structure */
|
||||||
gs.set('register', {
|
gs.set('register', {
|
||||||
// fields
|
// fields
|
||||||
mail: {
|
mail: new FieldValidator('bypass', ''),
|
||||||
model: '',
|
username: new FieldValidator('basic-name', ''),
|
||||||
timeout: '',
|
password: new FieldValidator('password', ''),
|
||||||
error: '',
|
|
||||||
validate: (_mail) => true
|
|
||||||
// validate: (_mail) => /^[\w\.]+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$/i.test(_mail)
|
|
||||||
},
|
|
||||||
|
|
||||||
username: {
|
|
||||||
model: '',
|
|
||||||
timeout: '',
|
|
||||||
error: '',
|
|
||||||
validate: (_username) => /^[a-z0-9_-]{3,20}$/i.test(_username)
|
|
||||||
},
|
|
||||||
|
|
||||||
password: {
|
|
||||||
model: '',
|
|
||||||
timeout: '',
|
|
||||||
error: '',
|
|
||||||
validate: (_password) => /^[^<>\/\\]{8,50}$/.test(_password)
|
|
||||||
},
|
|
||||||
|
|
||||||
// functions
|
// functions
|
||||||
func: {
|
func: {
|
||||||
print_err(_field, _message, _duration){},
|
|
||||||
register(){},
|
register(){},
|
||||||
press_enter(){}
|
press_enter(){}
|
||||||
}
|
}
|
||||||
|
@ -37,90 +18,30 @@ gs.set('register', {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* (2) Manage error messages
|
|
||||||
*
|
|
||||||
* @_field<String> Field to print errors to
|
|
||||||
* @_message<String> Error message to print
|
|
||||||
* @_duration<int> Durations (sec) for the message to be displayed
|
|
||||||
*
|
|
||||||
---------------------------------------------------------*/
|
|
||||||
gs.get.register.func.print_err = function(_field, _message='error', _duration=null){
|
|
||||||
|
|
||||||
/* (1) Fail: invalid _field */
|
|
||||||
if( typeof _field !== 'string' || this[_field] == null )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* (2) Fail: invalid _message */
|
|
||||||
if( typeof _message !== 'string' )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* (3) Fail: invalid _message */
|
|
||||||
if( isNaN(_duration) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* (4) Clear timeout if exists */
|
|
||||||
!isNaN(this[_field].err_to) && clearTimeout(this[_field].err_to);
|
|
||||||
|
|
||||||
/* (5) Display error */
|
|
||||||
this[_field].error = _message;
|
|
||||||
|
|
||||||
/* (6) No timeout if _duration if null */
|
|
||||||
if( _duration === null )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/* (7) Setup Timeout */
|
|
||||||
this[_field].err_to = setTimeout( function(){
|
|
||||||
this.error = '';
|
|
||||||
}.bind(this[_field]), _duration*1000);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}.bind(gs.get.register);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* (2) Login attempt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* (3) Login attempt
|
|
||||||
*
|
*
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
gs.get.register.func.register = function(){
|
gs.get.register.func.register = function(){
|
||||||
|
|
||||||
/* (1) Cache fields' values */
|
/* (1) Cache fields' values */
|
||||||
let mail = this.mail.model;
|
let mail = this.mail.mutable;
|
||||||
let username = this.username.model;
|
let username = this.username.mutable;
|
||||||
let password = this.password.model;
|
let password = this.password.mutable;
|
||||||
|
|
||||||
/* (2) Manage errors */
|
/* (2) Manage errors */
|
||||||
let errors = false;
|
|
||||||
|
|
||||||
// mail error
|
// mail error
|
||||||
if( !this.mail.validate(mail) ){
|
if( !this.mail.is_valid() )
|
||||||
errors = true;
|
return false;
|
||||||
this.func.print_err('mail', 'This field is required');
|
|
||||||
}else
|
|
||||||
this.func.print_err('mail', '', 0);
|
|
||||||
|
|
||||||
// username error
|
// username error
|
||||||
if( !this.username.validate(username) ){
|
if( !this.username.is_valid() )
|
||||||
errors = true;
|
return false;
|
||||||
this.func.print_err('username', '3 characters are required: letters, numbers, dot');
|
|
||||||
}else
|
|
||||||
this.func.print_err('username', '', 0);
|
|
||||||
|
|
||||||
|
|
||||||
// password error
|
// password error
|
||||||
if( !this.password.validate(password) ){
|
if( !this.password.is_valid() )
|
||||||
errors = true;
|
|
||||||
this.func.print_err('password', '8 characters are required');
|
|
||||||
}else
|
|
||||||
this.func.print_err('password', '', 0);
|
|
||||||
|
|
||||||
// if errors -> fail
|
|
||||||
if( errors )
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* (3) API bindings */
|
/* (3) API bindings */
|
||||||
|
|
|
@ -14,6 +14,25 @@
|
||||||
font-size: .7em;
|
font-size: .7em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 1px;
|
letter-spacing: 1px;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
& > span{
|
||||||
|
|
||||||
|
color: #f04747;
|
||||||
|
text-transform: none;
|
||||||
|
|
||||||
|
&:before{ content: '(' attr(data-err) ')'; }
|
||||||
|
|
||||||
|
&:not([data-err]),
|
||||||
|
&[data-err='']{
|
||||||
|
color: inherit;
|
||||||
|
|
||||||
|
&:before{ content: ''; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// input
|
// input
|
||||||
|
@ -148,7 +167,7 @@
|
||||||
&:active{ background-color: darken($main, 10%);}
|
&:active{ background-color: darken($main, 10%);}
|
||||||
|
|
||||||
&.invalid{
|
&.invalid{
|
||||||
$main: #e65835;
|
$main: #f04747;
|
||||||
background-color: $main;
|
background-color: $main;
|
||||||
&:hover{ background-color: darken($main, 5%);}
|
&:hover{ background-color: darken($main, 5%);}
|
||||||
&:active{ background-color: darken($main, 10%);}
|
&:active{ background-color: darken($main, 10%);}
|
||||||
|
|
|
@ -139,23 +139,8 @@ body > #WRAPPER.login{
|
||||||
margin-top: 1.2em;
|
margin-top: 1.2em;
|
||||||
letter-spacing: .2em;
|
letter-spacing: .2em;
|
||||||
|
|
||||||
& > span{
|
&.err > span{
|
||||||
|
|
||||||
color: inherit;
|
|
||||||
text-transform: none;
|
|
||||||
|
|
||||||
&:before{ content: ''; }
|
|
||||||
&:after{ content: ''; }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
&.err{
|
|
||||||
color: #f04747;
|
color: #f04747;
|
||||||
|
|
||||||
& > span{
|
|
||||||
&:before{ content: '('; }
|
|
||||||
&:after{ content: ')'; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.link{
|
&.link{
|
||||||
|
|
|
@ -72,6 +72,11 @@
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 1px;
|
letter-spacing: 1px;
|
||||||
|
|
||||||
|
strong{
|
||||||
|
color: $main;
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -106,6 +111,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strong{
|
||||||
|
color: darken($main,5%);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,22 +9,23 @@ import XHRClientDriver from './lib/client/xhr.js'
|
||||||
import WebSocketClientDriver from './lib/client/ws.js'
|
import WebSocketClientDriver from './lib/client/ws.js'
|
||||||
import APIClient from './lib/api-client.js'
|
import APIClient from './lib/api-client.js'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* (1) Custom lib accessors
|
/* (1) Custom lib accessors
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
/* (1) Global Store for Vue */
|
/* (1) Field validation */
|
||||||
|
require('./lib/field-manager.js');
|
||||||
|
|
||||||
|
/* (2) Global Store for Vue */
|
||||||
window.gs = new GlobalStore();
|
window.gs = new GlobalStore();
|
||||||
|
|
||||||
/* (2) Authentication token management */
|
/* (3) Authentication token management */
|
||||||
window.auth = new Authentication();
|
window.auth = new Authentication();
|
||||||
gs.set('auth', auth);
|
gs.set('auth', auth);
|
||||||
|
|
||||||
/* (3) XHR / WebSocket drivers */
|
/* (4) XHR / WebSocket drivers */
|
||||||
window.xhrcd = XHRClientDriver;
|
window.xhrcd = XHRClientDriver;
|
||||||
window.wscd = WebSocketClientDriver;
|
window.wscd = WebSocketClientDriver;
|
||||||
|
|
||||||
/* (4) ClientDriver instances */
|
/* (5) ClientDriver instances */
|
||||||
window.api = new APIClient('api.douscord.xdrm.io');
|
window.api = new APIClient('api.douscord.xdrm.io');
|
||||||
window.ws = new WebSocketClientDriver('ws.douscord.xdrm.io');
|
window.ws = new WebSocketClientDriver('ws.douscord.xdrm.io');
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@
|
||||||
<span data-icon='create' @click='gs.popup.show(`channel.create`); minipop=false'>Create channel</span>
|
<span data-icon='create' @click='gs.popup.show(`channel.create`); minipop=false'>Create channel</span>
|
||||||
<span class ='invalid-h' data-icon='remove' @click='gs.popup.show(`channel.remove`); minipop=false'>Remove channel</span>
|
<span class ='invalid-h' data-icon='remove' @click='gs.popup.show(`channel.remove`); minipop=false'>Remove channel</span>
|
||||||
<span data-icon='category' @click='gs.popup.show(`room.create`); minipop=false'>Create room</span>
|
<span data-icon='category' @click='gs.popup.show(`room.create`); minipop=false'>Create room</span>
|
||||||
<span data-icon='edit' @click='gs.popup.show(`nickname.change`); minipop=false'>Change nickname</span>
|
<span data-icon='edit' @click='gs.popup.show(`username.change`); minipop=false'>Change nickname</span>
|
||||||
<span data-icon='password' @click='gs.popup.show(`password.change`); minipop=false'>Change password</span>
|
<span data-icon='password' @click='gs.popup.show(`password.change`); minipop=false'>Change password</span>
|
||||||
<span class='sb invalid-h' data-icon='leave' @click='gs.popup.show(`channel.leave`); minipop=false'>Leave channel</span>
|
<span class='sb invalid-h' data-icon='leave' @click='gs.popup.show(`channel.leave`); minipop=false'>Leave channel</span>
|
||||||
<span class='sb invalid' data-icon='logout' @click='gs.auth.token=null; gs.refresh()'>Logout</span>
|
<span class='sb invalid' data-icon='logout' @click='gs.auth.token=null; gs.refresh()'>Logout</span>
|
||||||
|
|
|
@ -18,15 +18,15 @@
|
||||||
|
|
||||||
<!-- Pop-up ROOM CREATE -->
|
<!-- Pop-up ROOM CREATE -->
|
||||||
<div class='popup' v-show='gs.popup.get(`room.create`).active'>
|
<div class='popup' v-show='gs.popup.get(`room.create`).active'>
|
||||||
<span class='header'>Create {{ gs.popup.get(`room.create`).data.type }} room</span>
|
<span class='header'>Create {{ gs.popup.get(`room.create`).type.mutable }} room</span>
|
||||||
|
|
||||||
<span class='body form'>
|
<span class='body form'>
|
||||||
<label for='channel_name'>Room Name</label>
|
<label>Room Name <span :data-err='gs.popup.get(`room.create`).name.error'></span></label>
|
||||||
<input type='text' name='channel_name' v-model='gs.popup.get(`room.create`).data.name'>
|
<input type='text' v-model='gs.popup.get(`room.create`).name.mutable'>
|
||||||
|
|
||||||
<label for='channel_name'>Room Type</label>
|
<label>Room Type</label>
|
||||||
<span class='select-box' @click='gs.popup.get(`room.create`).data.type=`text`' :data-selected='gs.popup.get(`room.create`).data.type==`text`?1:0' data-type='text'>Text Room</span>
|
<span class='select-box' @click='gs.popup.get(`room.create`).type.mutable=`text`' :data-selected='gs.popup.get(`room.create`).type.mutable==`text`?1:0' data-type='text'>Text Room</span>
|
||||||
<span class='select-box' @click='gs.popup.get(`room.create`).data.type=`voice`' :data-selected='gs.popup.get(`room.create`).data.type==`voice`?1:0' data-type='voice'>Voice Room</span>
|
<span class='select-box' @click='gs.popup.get(`room.create`).type.mutable=`voice`' :data-selected='gs.popup.get(`room.create`).type.mutable==`voice`?1:0' data-type='voice'>Voice Room</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class='footer form'>
|
<span class='footer form'>
|
||||||
|
@ -37,13 +37,14 @@
|
||||||
|
|
||||||
<!-- Pop-up CHANNEL CREATE -->
|
<!-- Pop-up CHANNEL CREATE -->
|
||||||
<div class='popup' v-show='gs.popup.get(`channel.create`).active'>
|
<div class='popup' v-show='gs.popup.get(`channel.create`).active'>
|
||||||
<span class='header'>Create {{ gs.popup.get(`channel.create`).data.type }} channel</span>
|
<span class='header'>Create channel #<strong>{{ gs.popup.get(`channel.create`).name.mutable }}</strong><br>url: <strong>/{{gs.popup.get(`channel.create`).link.mutable}}</strong></span>
|
||||||
|
|
||||||
<span class='body form'>
|
<span class='body form'>
|
||||||
<label for='channel_name'>Channel Name</label>
|
<label>Channel Name <span :data-err='gs.popup.get(`channel.create`).name.error'></span></label>
|
||||||
<input type='text' name='channel_name' v-model='gs.popup.get(`channel.create`).data.name'>
|
<input type='text' v-model='gs.popup.get(`channel.create`).name.mutable'>
|
||||||
<label for='channel_link'>Channel Link</label>
|
|
||||||
<input type='text' name='channel_link' v-model='gs.popup.get(`channel.create`).data.link'>
|
<label>Channel Link <span :data-err='gs.popup.get(`channel.create`).link.error'></span></label>
|
||||||
|
<input type='text' v-model='gs.popup.get(`channel.create`).link.mutable'>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class='footer form'>
|
<span class='footer form'>
|
||||||
|
@ -53,14 +54,14 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Pop-up NICKNAME CHANGE -->
|
<!-- Pop-up NICKNAME CHANGE -->
|
||||||
<div class='popup' v-show='gs.popup.get(`nickname.change`).active'>
|
<div class='popup' v-show='gs.popup.get(`username.change`).active'>
|
||||||
<span class='header'>Change nickname</span>
|
<span class='header'>Change nickname</span>
|
||||||
|
|
||||||
<span class='body form'>
|
<span class='body form'>
|
||||||
<label for='nickname'>Nickname</label>
|
<label for='username'>Nickname <span :data-err='gs.popup.get(`username.change`).username.error'></span></label>
|
||||||
<input type='text' name='nickname' v-model='gs.popup.get(`nickname.change`).data.value' :placeholder='gs.auth.user.username'>
|
<input type='text' name='username' v-model='gs.popup.get(`username.change`).username.mutable' :placeholder='gs.auth.user.username'>
|
||||||
|
|
||||||
<a @click='gs.popup.get(`nickname.change`).reset()'>Reset Nickname</a>
|
<a @click='gs.popup.get(`username.change`).reset()'>Reset Nickname</a>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class='footer form'>
|
<span class='footer form'>
|
||||||
|
@ -74,8 +75,8 @@
|
||||||
<span class='header'>Invite a friend</span>
|
<span class='header'>Invite a friend</span>
|
||||||
|
|
||||||
<span class='body form'>
|
<span class='body form'>
|
||||||
<label for='username'>friend's username</label>
|
<label for='username'>friend's username <span :data-err='gs.popup.get(`channel.invite`).username.error'></span></label>
|
||||||
<input type='text' name='username' v-model='gs.popup.get(`channel.invite`).data.username'>
|
<input type='text' name='username' v-model='gs.popup.get(`channel.invite`).username.mutable'>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class='footer form'>
|
<span class='footer form'>
|
||||||
|
@ -89,7 +90,7 @@
|
||||||
<span class='header'>Remove channel</span>
|
<span class='header'>Remove channel</span>
|
||||||
|
|
||||||
<span class='body form'>
|
<span class='body form'>
|
||||||
<p>You are about to remove the channel #<b>{{ gs.content.cbuf.label }}</b>, this operation cannot be undone.</p>
|
<p>You are about to remove the channel #<strong>{{ gs.content.cbuf.label }}</strong>, this operation cannot be undone.</p>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class='footer form'>
|
<span class='footer form'>
|
||||||
|
@ -103,7 +104,7 @@
|
||||||
<span class='header'>Leave channel</span>
|
<span class='header'>Leave channel</span>
|
||||||
|
|
||||||
<span class='body form'>
|
<span class='body form'>
|
||||||
<p>You are about to leave the channel #<b>{{ gs.content.cbuf.label }}</b>, this operation cannot be undone.</p>
|
<p>You are about to leave the channel #<strong>{{ gs.content.cbuf.label }}</strong>, this operation cannot be undone.</p>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class='footer form'>
|
<span class='footer form'>
|
||||||
|
@ -117,11 +118,12 @@
|
||||||
<span class='header'>Change password</span>
|
<span class='header'>Change password</span>
|
||||||
|
|
||||||
<span class='body form'>
|
<span class='body form'>
|
||||||
<label for='password'>New password</label>
|
<label v-show='!gs.popup.get(`password.change`).matches'><span data-err='passwords does not match'></span></label>
|
||||||
<input type='password' name='password' v-model='gs.popup.get(`password.change`).data.password'>
|
<label>New password <span :data-err='gs.popup.get(`password.change`).password.error'></span></label>
|
||||||
|
<input type='password' v-model='gs.popup.get(`password.change`).password.mutable'>
|
||||||
|
|
||||||
<label for='password'>Confirmation</label>
|
<label>Confirmation <span :data-err='gs.popup.get(`password.change`).confirm.error'></span></label>
|
||||||
<input type='password' name='password' v-model='gs.popup.get(`password.change`).data.confirm'>
|
<input type='password' v-model='gs.popup.get(`password.change`).confirm.mutable'>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class='footer form'>
|
<span class='footer form'>
|
||||||
|
|
|
@ -6,10 +6,11 @@
|
||||||
|
|
||||||
<div class='form'>
|
<div class='form'>
|
||||||
<h3>Welcome back!</h3>
|
<h3>Welcome back!</h3>
|
||||||
<label for='username' :class='gs.login.username.error.length<1?``:`err`'>USERNAME <span>{{ gs.login.username.error }}</span></label>
|
<label v-show='gs.login.failed' class='err'><span>Invalid Combination</span></label>
|
||||||
<input @keyup='gs.login.func.press_enter' type='text' name='username' v-model='gs.login.username.model' class='flat' autofocus>
|
<label>USERNAME <span :data-err='gs.login.username.error'></span></label>
|
||||||
<label for='password' :class='gs.login.password.error.length<1?``:`err`'>PASSWORD <span>{{ gs.login.password.error }}</span></label>
|
<input @keyup='gs.login.func.press_enter' type='text' v-model='gs.login.username.mutable' class='flat' autofocus>
|
||||||
<input @keyup='gs.login.func.press_enter' type='password' name='password' v-model='gs.login.password.model' class='flat'>
|
<label>PASSWORD <span :data-err='gs.login.password.error'></span></label>
|
||||||
|
<input @keyup='gs.login.func.press_enter' type='password' v-model='gs.login.password.mutable' class='flat'>
|
||||||
<!-- <label for='fpass' class='link' @click='gs.login.func.forgot_pass()'>FORGOT YOUR PASSWORD ?</label> -->
|
<!-- <label for='fpass' class='link' @click='gs.login.func.forgot_pass()'>FORGOT YOUR PASSWORD ?</label> -->
|
||||||
|
|
||||||
<button class='submit' @click='gs.login.func.login()'>Login</button>
|
<button class='submit' @click='gs.login.func.login()'>Login</button>
|
||||||
|
|
|
@ -6,12 +6,12 @@
|
||||||
|
|
||||||
<div class='form'>
|
<div class='form'>
|
||||||
<h3>Create an account</h3>
|
<h3>Create an account</h3>
|
||||||
<label for='mail' :class='gs.register.mail.error.length<1?``:`err`'>EMAIL <span>{{ gs.register.mail.error }}</span></label>
|
<label>EMAIL <span :data-err='gs.register.mail.error'></span></label>
|
||||||
<input @keyup='gs.register.func.press_enter' type='email' name='mail' v-model='gs.register.mail.model' class='flat' autofocus>
|
<input @keyup='gs.register.func.press_enter' type='email' v-model='gs.register.mail.mutable' class='flat' autofocus>
|
||||||
<label for='username' :class='gs.register.username.error.length<1?``:`err`'>USERNAME <span>{{ gs.register.username.error }}</span></label>
|
<label>USERNAME <span :data-err='gs.register.username.error'></span></label>
|
||||||
<input @keyup='gs.register.func.press_enter' type='text' name='username' v-model='gs.register.username.model' class='flat'>
|
<input @keyup='gs.register.func.press_enter' type='text' v-model='gs.register.username.mutable' class='flat'>
|
||||||
<label for='password' :class='gs.register.password.error.length<1?``:`err`'>PASSWORD <span>{{ gs.register.password.error }}</span></label>
|
<label>PASSWORD <span :data-err='gs.register.password.error'></span></label>
|
||||||
<input @keyup='gs.register.func.press_enter' type='password' name='password' v-model='gs.register.password.model' class='flat'>
|
<input @keyup='gs.register.func.press_enter' type='password' v-model='gs.register.password.mutable' class='flat'>
|
||||||
|
|
||||||
<button class='submit' @click='gs.register.func.register()'>Continue</button>
|
<button class='submit' @click='gs.register.func.register()'>Continue</button>
|
||||||
<span>By registering, you agree to Discord's <a href='https://discordapp.com/terms'>Terms of Service</a> and <a href='https://discordapp.com/privacy'>Privacy Policy</a></span>
|
<span>By registering, you agree to Discord's <a href='https://discordapp.com/terms'>Terms of Service</a> and <a href='https://discordapp.com/privacy'>Privacy Policy</a></span>
|
||||||
|
|
Loading…
Reference in New Issue