esqueleto basico

This commit is contained in:
Sergio 2017-09-25 14:03:53 +02:00
parent 8eb441e5f5
commit 0dc723713d
350 changed files with 90726 additions and 0 deletions

724
bower_components/jbox/Demo/Demo.css vendored Normal file
View file

@ -0,0 +1,724 @@
/* Global */
html {
height: 100%;
min-height: 100%;
}
body {
position: relative;
min-height: 100%;
font-family: 'Helvetica Neue', 'Segoe UI', Arial, sans-serif;
font-size: 17px;
line-height: 1.4;
color: #202428;
background: #fff;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
main {
padding: 20px 0;
}
.container {
position: relative;
width: calc(100% - 60px);
max-width: 1000px;
margin: auto;
}
h2 {
font-size: 22px;
font-weight: normal;
}
@media (max-width: 768px) {
.container {
width: calc(100% - 30px);
}
}
/* Target elements */
.targets-wrapper {
margin: 0 -5px;
padding: 10px 0 20px;
}
.targets-wrapper:after,
.targets-wrapper:before {
content: " ";
display: table;
}
.targets-wrapper:after {
clear: both;
}
.target,
.target-click,
.target-notice {
cursor: default;
font-size: 13px;
line-height: 52px;
height: 52px;
border-radius: 2px;
border: 1px solid #e2e2e2;
text-align: center;
background: #fafafa;
position: relative;
text-transform: uppercase;
float: left;
width: calc(25% - 10px);
margin: 5px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.target-click,
.target-notice {
cursor: pointer;
}
.target.active,
.target-click.active,
.target-notice.active {
color: #07d;
}
.demo-img {
float: left;
width: calc(25% - 10px);
margin: 5px;
}
.demo-img > img {
border: 4px solid #eee;
border-radius: 2px;
width: 100%;
height: auto;
filter: grayscale(100%);
transition: filter .2s, border-color .2s;
}
.demo-img:hover > img {
filter: none;
border-color: #ddd;
}
@media (max-width: 768px) {
.target,
.target-click,
.target-notice {
width: calc(50% - 10px);
}
.demo-img > img {
border-width: 2px;
}
}
/* jBox styles */
.ajax-sending {
color: #07d;
}
.ajax-complete {
color: #6c0;
}
.ajax-success tt {
color: #666;
display: block;
padding-top: 10px;
font-size: 13px;
}
.ajax-error {
color: #d00;
}
/* Header */
header {
height: 50px;
line-height: 50px;
font-size: 17px;
background: #262c33;
color: #99a3ad;
box-shadow: 0 0 4px rgba(0, 0, 0, .6);
}
header a {
margin-right: 20px;
color: #99a3ad;
text-decoration: none;
}
header a:last-child,
header a:nth-child(3) {
margin-right: 0;
}
header a.active,
header a:hover {
color: #fff;
text-decoration: none;
}
#stephan {
display: block;
position: absolute;
top: 50%;
right: 0;
width: 40px;
height: 40px;
margin-top: -20px;
border-radius: 3px;
background: no-repeat -3px -2px url(https://stephanwagner.me/img/stephan.jpg);
background-size: 50px;
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .3);
}
#stephan > span {
font-size: 0;
line-height: 0;
white-space: nowrap;
position: absolute;
top: 50%;
right: 50%;
pointer-events: none;
transition: font-size .2s, margin .2s, opacity .2s, line-height .2s;
opacity: 0;
}
#stephan:hover > span {
opacity: 1;
font-size: 17px;
margin-right: 40px;
}
@media (max-width: 500px) {
#stephan > span {
display: none;
}
}
/* Common */
.truncate {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.noselect {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.clearfix:after,
.clearfix:before {
content: " ";
display: table;
}
.clearfix:after {
clear: both;
}
/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
/**
* 1. Set default font family to sans-serif.
* 2. Prevent iOS and IE text size adjust after device orientation change,
* without disabling user zoom.
*/
html {
font-family: sans-serif; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/**
* Remove default margin.
*/
body {
margin: 0;
}
/* HTML5 display definitions
========================================================================== */
/**
* Correct `block` display not defined for any HTML5 element in IE 8/9.
* Correct `block` display not defined for `details` or `summary` in IE 10/11
* and Firefox.
* Correct `block` display not defined for `main` in IE 11.
*/
article,
aside,
details,
figcaption,
figure,
footer,
header,
main,
menu,
nav,
section,
summary {
display: block;
}
/**
* 1. Correct `inline-block` display not defined in IE 8/9.
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
*/
audio,
canvas,
progress,
video {
display: inline-block; /* 1 */
vertical-align: baseline; /* 2 */
}
/**
* Prevent modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Address `[hidden]` styling not present in IE 8/9/10.
* Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
*/
[hidden],
template {
display: none;
}
/* Links
========================================================================== */
/**
* Remove the gray background color from active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* Improve readability of focused elements when they are also in an
* active/hover state.
*/
a:active,
a:hover {
outline: 0;
}
/* Text-level semantics
========================================================================== */
/**
* Address inconsistent styling of `abbr[title]`.
* 1. Correct styling in Firefox 39 and Opera 12.
* 2. Correct missing styling in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none; /* 1 */
text-decoration: underline; /* 2 */
text-decoration: underline dotted; /* 2 */
}
/**
* Address inconsistent styling of b and strong.
* 1. Correct duplicate application of `bolder` in Safari 6.0.2.
* 2. Correct style set to `bold` in Edge 12+, Safari 6.2+, and Chrome 18+.
*/
b,
strong {
font-weight: inherit; /* 1 */
}
b,
strong {
font-weight: bolder; /* 2 */
}
/**
* Address styling not present in Safari and Chrome.
*/
dfn {
font-style: italic;
}
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari, and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/**
* Address styling not present in IE 8/9.
*/
mark {
background-color: #ff0;
color: #000;
}
/**
* Address inconsistent and variable font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
/* Embedded content
========================================================================== */
/**
* Remove border when inside `a` element in IE 8/9/10.
*/
img {
border: 0;
}
/**
* Correct overflow not hidden in IE 9/10/11.
*/
svg:not(:root) {
overflow: hidden;
}
/* Grouping content
========================================================================== */
/**
* Address margin not present in IE 8/9 and Safari.
*/
figure {
margin: 1em 40px;
}
/**
* Address inconsistent styling of `hr`.
* 1. Correct `box-sizing` set to `border-box` in Firefox.
* 2. Correct `overflow` set to `hidden` in IE 8/9/10/11 and Edge 12.
*/
hr {
box-sizing: content-box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
/**
* Contain overflow in all browsers.
*/
pre {
overflow: auto;
}
/**
* 1. Correct inheritance and scaling of font-size for preformatted text.
* 2. Address odd `em`-unit font size rendering in all browsers.
*/
code,
kbd,
pre,
samp {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/* Forms
========================================================================== */
/**
* Known limitation: by default, Chrome and Safari on OS X allow very limited
* styling of `select`, unless a `border` property is set.
*/
/**
* 1. Correct font properties not being inherited.
* 2. Address margins set differently in Firefox 4+, Safari, and Chrome.
*/
button,
input,
optgroup,
select,
textarea {
font: inherit; /* 1 */
margin: 0; /* 2 */
}
/**
* Address `overflow` set to `hidden` in IE 8/9/10/11.
*/
button {
overflow: visible;
}
/**
* Address inconsistent `text-transform` inheritance for `button` and `select`.
* All other form control elements do not inherit `text-transform` values.
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
* Correct `select` style inheritance in Firefox.
*/
button,
select {
text-transform: none;
}
/**
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
* and `video` controls.
* 2. Correct inability to style clickable `input` types in iOS.
* 3. Improve usability and consistency of cursor style between image-type
* `input` and others.
*/
button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button; /* 2 */
cursor: pointer; /* 3 */
}
/**
* Re-set default cursor for disabled elements.
*/
button[disabled],
html input[disabled] {
cursor: default;
}
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
/**
* Restore focus style in Firefox 4+ (unset by a rule above)
*/
button:-moz-focusring,
input:-moz-focusring {
outline: 1px dotted ButtonText;
}
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
input {
line-height: normal;
}
/**
* It's recommended that you don't attempt to style these elements.
* Firefox's implementation doesn't respect box-sizing, padding, or width.
*
* 1. Address box sizing set to `content-box` in IE 8/9/10.
* 2. Remove excess padding in IE 8/9/10.
*/
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
* `font-size` values of the `input`, it causes the cursor style of the
* decrement button to change from `default` to `text`.
*/
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* Address `appearance` set to `searchfield` in Safari and Chrome.
*/
input[type="search"] {
-webkit-appearance: textfield;
}
/**
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
* Safari (but not Chrome) clips the cancel button when the search input has
* padding (and `textfield` appearance).
*/
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* Define consistent border, margin, and padding.
*/
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
/**
* 1. Correct `color` not being inherited in IE 8/9/10/11.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
*/
legend {
border: 0; /* 1 */
padding: 0; /* 2 */
}
/**
* Remove default vertical scrollbar in IE 8/9/10/11.
*/
textarea {
overflow: auto;
}
/**
* Restore font weight (unset by a rule above).
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
*/
optgroup {
font-weight: bold;
}
/* Reset */
html, body,
ul, ol, li,
h1, h2, h3, h4, h5, h6,
form, table, tr, td,
div, p, img, pre, iframe {
margin: 0;
padding: 0;
border: 0;
}
input, textarea, button, select {
margin: 0;
}
textarea, img {
display: block;
}
html, body {
min-width: 100%;
min-height: 100%;
}
header, nav, footer, section, img {
display: block;
}
ul, ol {
list-style: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
td {
vertical-align: top;
}
h1, h2, h3, h4, h5, h6 {
font-weight: normal;
}
* {
outline: none;
box-sizing: border-box;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-text-size-adjust: none;
}
input::-moz-focus-inner,
button::-moz-focus-inner {
border: 0;
}

95
bower_components/jbox/Demo/Demo.html vendored Normal file
View file

@ -0,0 +1,95 @@
<!DOCTYPE html>
<html>
<head>
<title>jBox Demos</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0">
<link rel="stylesheet" href="../Source/jBox.css">
<link rel="stylesheet" href="../Source/plugins/Notice/jBox.Notice.css">
<link rel="stylesheet" href="../Source/plugins/Confirm/jBox.Confirm.css">
<link rel="stylesheet" href="../Source/plugins/Image/jBox.Image.css">
<link rel="stylesheet" href="../Source/themes/NoticeFancy.css">
<link rel="stylesheet" href="../Source/themes/TooltipBorder.css">
<link rel="stylesheet" href="../Source/themes/TooltipBorderThick.css">
<link rel="stylesheet" href="../Source/themes/TooltipDark.css">
<link rel="stylesheet" href="../Source/themes/TooltipSmall.css">
<link rel="stylesheet" href="../Source/themes/TooltipSmallGray.css">
<link rel="stylesheet" href="../Source/themes/TooltipError.css">
<link rel="stylesheet" href="./Demo.css">
<link rel="stylesheet" href="./Playground/Playground.Avatars.css">
<link rel="stylesheet" href="./Playground/Playground.Login.css">
<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
<header>
<nav class="container">
<a href="https://stephanwagner.me/jBox/documentation">Documentation</a>
<a href="https://stephanwagner.me/jBox/demos">More Demos</a>
<a href="https://stephanwagner.me/Coding" id="stephan"><span>Stephan Wagner</span></a>
</nav>
</header>
<main class="container">
<h2>Tooltip</h2>
<div class="targets-wrapper">
<div id="Tooltip-1" class="target">Hover me</div>
<div id="Tooltip-2" class="target">Hover me</div>
<div id="Tooltip-3" class="target">Hover me</div>
<div id="Tooltip-4" class="target">Hover me</div>
<div id="Tooltip-5" class="target">Hover me</div>
<div id="Tooltip-6" class="target">Hover me</div>
<div id="Tooltip-7" class="target-click">Click me</div>
<div id="Tooltip-8" class="target-click">Click me</div>
</div>
<h2>Modal</h2>
<div class="targets-wrapper">
<div id="Modal-1" class="target-click">Click me</div>
<div id="Modal-2" class="target-click">Click me</div>
<div id="Modal-3" class="target-click">Click me</div>
<div class="target-click" data-confirm onclick="new jBox('Notice', {content: 'Yay! You clicked the confirm button', color: 'green', attributes: {y: 'bottom'}})">Click me</div>
</div>
<h2>Notice</h2>
<div class="targets-wrapper">
<div id="Notice-1" class="target-notice">Click me</div>
<div id="Notice-2" class="target-notice">Click me</div>
<div id="Notice-3" class="target-notice">Click me</div>
<div id="Notice-4" class="target-notice">Click me</div>
</div>
<h2>Image</h2>
<div class="targets-wrapper">
<a class="demo-img" href="https://stephanwagner.me/img/jBox/demo/image1.jpg" data-jbox-image="gallery1" title="Navigate with your keyboard: Press the [right] or [left] key"><img src="https://stephanwagner.me/img/jBox/demo/image1-preview.jpg" alt=""></a>
<a class="demo-img" href="https://stephanwagner.me/img/jBox/demo/image2.jpg" data-jbox-image="gallery1" title="jBox is smart, the next image gets preloaded"><img src="https://stephanwagner.me/img/jBox/demo/image2-preview.jpg" alt=""></a>
<a class="demo-img" href="https://stephanwagner.me/img/jBox/demo/image3.jpg" data-jbox-image="gallery1" title="You can easily group your images into galleries"><img src="https://stephanwagner.me/img/jBox/demo/image3-preview.jpg" alt=""></a>
<a class="demo-img" href="https://stephanwagner.me/img/jBox/demo/image4.jpg" data-jbox-image="gallery1" title="As usual, attaching jBox to images is easy as pie"><img src="https://stephanwagner.me/img/jBox/demo/image4-preview.jpg" alt=""></a>
<a href="https://stephanwagner.me/img/jBox/demo/NOT-FOUND.jpg" data-jbox-image="gallery1" title="You can adjust this image-not-found notice with CSS"></a>
</div>
<h2>Playground</h2>
<div class="targets-wrapper">
<div id="DemoAvatars" class="target-click">Click me</div>
<div id="DemoLogin" class="target-click">Click me</div>
</div>
</main>
<script src="../Source/jBox.js"></script>
<script src="../Source/plugins/Notice/jBox.Notice.js"></script>
<script src="../Source/plugins/Confirm/jBox.Confirm.js"></script>
<script src="../Source/plugins/Image/jBox.Image.js"></script>
<script src="./Demo.js"></script>
<script src="./Playground/Playground.Avatars.js"></script>
<script src="./Playground/Playground.Login.js"></script>
</body>
</html>

285
bower_components/jbox/Demo/Demo.js vendored Normal file
View file

@ -0,0 +1,285 @@
$(document).ready(function() {
/* Tooltip */
new jBox('Tooltip', {
attach: '#Tooltip-1',
content: 'This is a basic jBox tooltip'
});
new jBox('Tooltip', {
attach: '#Tooltip-2',
theme: 'TooltipBorderThick',
width: 200,
position: {
x: 'left',
y: 'center'
},
outside: 'x',
pointer: 'top:15',
content: 'You have many options to position and animate your jBoxes',
animation: 'move'
});
new jBox('Tooltip', {
attach: '#Tooltip-3',
theme: 'TooltipDark',
animation: 'zoomOut',
content: 'Use themes to change appearance',
});
new jBox('Tooltip', {
attach: '#Tooltip-4',
width: 300,
pointer: 'right:80',
animation: 'move',
delayOpen: 1000,
delayClose: 2000,
content: 'This tooltip waits 1 second to open and closes after 2 seconds',
onOpen: function() {
this.source.removeClass('active').html('Hover me');
},
onClose: function() {
this.source.removeClass('active').html('Hover me');
}
});
new jBox('Mouse', {
attach: '#Tooltip-5',
position: {x: 'right', y: 'bottom'},
content: 'I will follow you!'
});
new jBox('Tooltip', {
attach: '#Tooltip-6',
width: 280,
closeOnMouseleave: true,
animation: 'zoomIn',
content: 'I won\'t close when you move your mouse over me'
});
new jBox('Tooltip', {
attach: '#Tooltip-7',
target: '#Tooltip-1',
theme: 'TooltipBorder',
trigger: 'click',
adjustTracker: true,
closeOnClick: 'body',
closeButton: 'box',
animation: 'move',
position: {
x: 'left',
y: 'top'
},
outside: 'y',
pointer: 'left:20',
offset: {
x: 25
},
content: 'You can position your tooltips at any element.<br>Scroll up and down to see this tooltip flip position!',
onOpen: function() {
this.source.addClass('active').html('Now scroll');
},
onClose: function() {
this.source.removeClass('active').html('Click me');
}
});
new jBox('Tooltip', {
attach: '#Tooltip-8',
theme: 'TooltipBorder',
trigger: 'click',
width: 200,
height: ($(window).height() - 160),
adjustTracker: true,
closeOnClick: 'body',
closeOnEsc: true,
animation: 'move',
position: {
x: 'right',
y: 'center'
},
outside: 'x',
content: 'Scroll up and down or resize your browser, I will adjust my position!<br><br>Press [ESC] or click anywhere to close.',
onOpen: function() {
this.source.addClass('active').html('Now scroll');
},
onClose: function() {
this.source.removeClass('active').html('Click me');
}
});
/* Modal */
new jBox('Modal', {
attach: '#Modal-1',
height: 200,
title: 'I\'m a basic jBox modal window',
content: '<div style="line-height: 30px;">Try to scroll ...it\'s blocked.<br>Press [ESC] or click anywhere to close.</div>'
});
new jBox('Modal', {
attach: '#Modal-2',
width: 350,
height: 200,
blockScroll: false,
animation: 'zoomIn',
draggable: 'title',
closeButton: true,
content: 'You can move this modal window',
title: 'Click here to drag me around',
overlay: false,
reposition: false,
repositionOnOpen: false
});
new jBox('Modal', {
attach: '#Modal-3',
width: 450,
height: 250,
closeButton: 'title',
animation: false,
title: 'AJAX request',
ajax: {
url: 'https://ajaxresponse.com/2',
data: {
id: '1982',
name: 'Stephan Wagner'
},
reload: 'strict',
setContent: false,
beforeSend: function() {
this.setContent('');
this.setTitle('<div class="ajax-sending">Sending AJAX request...</div>');
},
complete: function(response) {
this.setTitle('<div class="ajax-complete">AJAX request complete</div>');
},
success: function(response) {
this.setContent('<div class="ajax-success">Response:<tt>' + response + '</tt></div>');
},
error: function() {
this.setContent('<div class="ajax-error">Oops, something went wrong</div>');
}
}
});
/* Confirm */
new jBox('Confirm', {
content: 'Do you really want to do this?',
cancelButton: 'Nope',
confirmButton: 'Sure do!'
});
/* Notice */
$('#Notice-1').click(function() {
new jBox('Notice', {
content: 'Hello, I\'m a notice',
color: 'black'
});
});
$('#Notice-2').click(function() {
new jBox('Notice', {
animation: 'flip',
color: getColor(),
content: 'Oooh! They also come in colors'
});
});
$('#Notice-3').click(function() {
new jBox('Notice', {
theme: 'NoticeFancy',
attributes: {
x: 'left',
y: 'bottom'
},
color: getColor(),
content: 'Hello, I\'m down here',
audio: '../Source/audio/bling2',
volume: 80,
animation: {open: 'slide:bottom', close: 'slide:left'}
});
});
$('#Notice-4').click(function() {
new jBox('Notice', {
attributes: {
x: 'right',
y: 'bottom'
},
stack: false,
animation: {
open: 'tada',
close: 'zoomIn'
},
color: getColor(),
title: 'Tadaaa! I\'m single',
content: 'Open another notice, I won\'t stack'
});
});
/* Image */
new jBox('Image', {
imageCounter: true,
imageCounterSeparator: ' of '
});
/* Additional JS for demo purposes */
$('#Tooltip-4').mouseenter(function() {
$('#Tooltip-4').addClass('active').html('Wait...');
}).mouseleave(function() {
$('#Tooltip-4').addClass('active').html('Wait...');
});
$('.target-notice').click(function() {
$(this).addClass('active').html('Click me again');
}).mouseleave(function() {
$(this).removeClass('active').html('Click me');
});
var colors = ['red', 'green', 'blue', 'yellow'], index = 0;
var getColor = function () {
(index >= colors.length) && (index = 0);
return colors[index++];
};
});

View file

@ -0,0 +1,174 @@
.AvatarsModal .jBox-footer button {
width: 50%;
height: 50px;
border: 0;
padding: 0;
display: block;
float: left;
background: center center no-repeat;
transition: background-color .2s;
}
.AvatarsModal .jBox-footer button:active {
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .2);
}
#AvatarsComplete.AvatarsModal .jBox-footer button {
width: 100%;
float: none;
}
.AvatarsModal .jBox-footer .button-cross {
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj4KPHBhdGggZmlsbD0iI2ZmZmZmZiIgZD0iTTUwNy4zLDQxMS4zQzUwNy4zLDQxMS4zLDUwNy4zLDQxMS4zLDUwNy4zLDQxMS4zTDM1MiwyNTZsMTU1LjMtMTU1LjNjMCwwLDAsMCwwLDBDNTA5LDk5LDUxMC4yLDk3LDUxMSw5NQpjMi4xLTUuNywwLjktMTIuMy0zLjctMTYuOUw0MzQsNC43QzQyOS40LDAuMSw0MjIuNy0xLjEsNDE3LDFjLTIuMSwwLjgtNCwyLTUuNywzLjdjMCwwLDAsMCwwLDBMMjU2LDE2MEwxMDAuNyw0LjdjMCwwLDAsMCwwLDAKQzk5LDMsOTcsMS44LDk1LDFjLTUuNy0yLjEtMTIuMy0wLjktMTYuOSwzLjdMNC43LDc4QzAuMSw4Mi42LTEuMSw4OS4zLDEsOTVjMC44LDIuMSwyLDQsMy43LDUuN2MwLDAsMCwwLDAsMEwxNjAsMjU2TDQuNyw0MTEuMwpjMCwwLDAsMCwwLDBDMyw0MTMsMS44LDQxNSwxLDQxN2MtMi4xLDUuNy0wLjksMTIuMywzLjcsMTYuOWw3My40LDczLjRjNC42LDQuNiwxMS4yLDUuOCwxNi45LDMuN2MyLjEtMC44LDQtMiw1LjctMy43YzAsMCwwLDAsMCwwCkwyNTYsMzUybDE1NS4zLDE1NS4zYzAsMCwwLDAsMCwwYzEuNywxLjcsMy42LDIuOSw1LjcsMy43YzUuNywyLjEsMTIuMywwLjksMTYuOS0zLjdsNzMuNC03My40YzQuNi00LjYsNS44LTExLjIsMy43LTE2LjkKQzUxMC4yLDQxNSw1MDksNDEzLDUwNy4zLDQxMS4zTDUwNy4zLDQxMS4zeiIvPgo8L3N2Zz4K);
background-color: #e33;
background-size: 24px auto;
border-radius: 0 0 0 4px;
}
.AvatarsModal .jBox-footer .button-cross:hover {
background-color: #f33;
}
.AvatarsModal .jBox-footer .button-cross:active {
background-color: #e33;
}
.AvatarsModal .jBox-footer .button-heart {
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0NDggMzg0Ij4KPHBhdGggZmlsbD0iI2ZmZmZmZiIgZD0iTTIyNCwzODRjLTQsMC04LTEuNS0xMS00LjVMNTcsMjI5Yy0yLTEuOC01Ny01Mi01Ny0xMTJDMCw0My44LDQ0LjgsMCwxMTkuNSwwYzQzLjgsMCw4NC44LDM0LjUsMTA0LjUsNTQKYzE5LjgtMTkuNSw2MC44LTU0LDEwNC41LTU0QzQwMy4yLDAsNDQ4LDQzLjgsNDQ4LDExN2MwLDYwLTU1LDExMC4yLTU3LjIsMTEyLjVMMjM1LDM3OS41QzIzMiwzODIuNSwyMjgsMzg0LDIyNCwzODR6Ii8+Cjwvc3ZnPg==);
background-color: #7d0;
background-size: 30px auto;
border-radius: 0 0 4px 0;
}
.AvatarsModal .jBox-footer .button-heart:hover {
background-color: #8e0;
}
.AvatarsModal .jBox-footer .button-heart:active {
background-color: #7d0;
}
.AvatarsModal .jBox-footer .button-close {
background-color: #ddd;
border-radius: 0 0 4px 4px;
}
.AvatarsModal .jBox-footer .button-close:hover {
background-color: #eee;
}
.AvatarsModal .jBox-footer .button-close:active {
background-color: #ddd;
}
.AvatarsModal .jBox-content {
padding: 0;
background: center -10px no-repeat;
}
#AvatarsComplete.AvatarsModal .jBox-content {
font-style: italic;
text-align: center;
color: #999;
}
#AvatarsComplete.AvatarsModal .jBox-content > div {
position: absolute;
top: calc(50% - 23px);
left: 25px;
right: 25px;
}
.AvatarsModal .jBox-title {
font-size: 26px;
color: #000;
font-weight: 300;
text-align: center;
padding: 0;
line-height: 60px;
}
.AvatarsModal .jBox-footer {
border-top: 0;
background: none;
padding: 0;
}
.AvatarsTooltip .jBox-content {
color: #fff;
text-align: center;
}
.AvatarsTooltip .jBox-container,
.AvatarsTooltip .jBox-pointer:after {
background: #000;
box-shadow: none;
}
.AvatarsTooltipLike .jBox-container,
.AvatarsTooltipLike .jBox-pointer:after {
border-color: #7d0;
}
.AvatarsTooltipDislike .jBox-container,
.AvatarsTooltipDislike .jBox-pointer:after {
border-color: #e33;
}
.AvatarsCollection {
width: 50%;
position: fixed;
bottom: 5px;
z-index: 11000;
}
.AvatarsCollection#DislikedAvatars {
left: 4px;
}
.AvatarsCollection#LikedAvatars {
right: 4px;
}
.AvatarsCollection > div {
width: 47px;
height: 45px;
padding: 0 1px;
}
.AvatarsCollection#DislikedAvatars > div {
float: left;
}
.AvatarsCollection#LikedAvatars > div {
float: right;
}
.AvatarsCollection > div > div {
position: relative;
overflow: hidden;
width: 45px;
height: 45px;
border: 2px solid red;
border-radius: 50%;
background: #000;
}
.AvatarsCollection#DislikedAvatars > div > div {
border-color: #e33;
}
.AvatarsCollection#LikedAvatars > div > div {
border-color: #7d0;
}
.AvatarsCollection > div > div > img {
position: absolute;
top: 50%;
left: 50%;
width: 60px;
height: 60px;
margin-top: -27px;
margin-left: -30px;
}

View file

@ -0,0 +1,272 @@
/* Playground Demo: Avatars */
// All data we are using for this demo we will store in the variable DemoAvatars
var DemoAvatars = {
Avatars: ['Stephan', 'Susan', 'Jack', 'Elizabeth', 'Fungus', 'Donald', 'Gary', 'Trixi', 'Samuel', 'Maria'],
Modals: {}
};
// All the magic happens in the function generateAvatarJBox
function generateAvatarJBox(initial)
{
// We only need to initialize the tooltips for the avatar collection once
// We can later refer to this jBox instance with DemoAvatars.AvatarsTooltip
!DemoAvatars.AvatarsTooltip && (DemoAvatars.AvatarsTooltip = new jBox('Tooltip', {
theme: 'TooltipBorder', // We are using the border theme...
addClass: 'AvatarsTooltip', // ...and add a class so we can adjust the theme with CSS
attach: '[data-avatar-tooltip]', // We attach the tooltip to the elements with the attribute data-avatar-tooltip...
getContent: 'data-avatar-tooltip', // ... and also get the content from the same attribute
zIndex: 12000, // These tooltips have the highest z-index
animation: 'move',
// Adding the liked or disliked class depending on the container the avatar is in
onOpen: function () {
this.wrapper.removeClass('AvatarsTooltipLike AvatarsTooltipDislike').addClass('AvatarsTooltip' + (this.source.parent().attr('id') == 'LikedAvatars' ? 'Like' : 'Dislike'));
}
}));
// When we are creating the initial jBox, reset global variables
if (initial) {
DemoAvatars.clicked = false;
DemoAvatars.current = -1;
}
// Increase current avatar index
DemoAvatars.current++;
// When we looped through all the avatars, show a jBox Modal with a hint that there are no more avatars nearby
if (DemoAvatars.current >= DemoAvatars.Avatars.length) {
DemoAvatars.Modals.AvatarsComplete = new jBox('Modal', {
// We use similar options to our Avatar modal so they look similar
id: 'AvatarsComplete',
addClass: 'AvatarsModal',
width: 300,
height: 250,
animation: 'zoomIn',
overlay: false,
blockScroll: false,
closeButton: false,
closeOnEsc: false,
adjustDistance: {
top: 40,
right: 5,
bottom: 55,
left: 5
},
footer: '<button class="button-close">Close</button>',
title: 'Whoops',
content: '<div>There are currently no more avatars near you</div>',
zIndex: 10000,
// Once this jBox is created, we tel the close button to close the initial avatar modal
onCreated: function () {
this.footer.find('button').on('click', function () {
DemoAvatars.Modals.AvatarsInitial.close();
});
}
}).open();
// Nothing more to do, abort here
return null;
}
// We are creating a new jBox Modal with the avatars each time this function gets called
var jBoxAvatar = new jBox('Modal', {
addClass: 'AvatarsModal',
width: 300,
height: 250,
animation: 'zoomIn',
zIndex: 10000,
// Adjusting the distance to the viewport so we have space for the avatar collection at the bottom and the close button of the modal at the top
adjustDistance: {
top: 40,
right: 5,
bottom: 55,
left: 5
},
// We are setting these options differently for the initial and the following jBoxes
id: initial ? 'AvatarsInitial' : 'AvatarsModal' + DemoAvatars.current,
overlay: initial ? true : false, // Only one overlay is needed
blockScroll: initial ? true : false, // The initial jBox will block scrolling, no need for the others to o the same
closeButton: initial ? 'overlay' : false, // The initial jBox will have the close button in the overlay, the others won't need one
closeOnEsc: initial ? true : false, // Only the inital jBox can be closed with [ESC] button
// Placing the buttons in the footer area
footer: '<div class="clearfix"><button class="button-cross cross"></button><button class="button-heart heart"></button></div>',
// Open this jBox when it is being initialized
onInit: function () {
this.open();
// Here we store the index we used for this jBox
this.AvatarIndex = DemoAvatars.current;
},
// When the jBox is created, add the click events to the buttons
onCreated: function () {
// Create the containers for the liked or disliked avatars
if (initial) {
$('<div id="LikedAvatars" class="AvatarsCollection"/>').appendTo($('body'));
$('<div id="DislikedAvatars" class="AvatarsCollection"/>').appendTo($('body'));
}
$.each(this.footer.find('button'), function (index, el) {
// Adding the click events for the buttons in the footer
$(el).on('click', function () {
// Storing a global var that the user clicked on a button
DemoAvatars.clicked = true;
// When a user clicks a button close the tooltips
DemoAvatars.AvatarsTooltipLike && DemoAvatars.AvatarsTooltipLike.close();
DemoAvatars.AvatarsTooltipDislike && DemoAvatars.AvatarsTooltipDislike.close();
// When we click a button, the jBox disappears, let's tell this jBox that we removed it
this.AvatarRemoved = true;
// Did we like or dislike the avatar?
var liked = $(el).hasClass('button-heart');
// Slide the jBox to the left or right depending on which button the user clicked
this.animate('slide' + (liked ? 'Right' : 'Left'), {
// Once the jBox is removed, hide it and show the avatar in the collection
complete: function () {
this.wrapper.css('display', 'none');
// Which container to use
var collectionContainer = liked ? $('#LikedAvatars') : $('#DislikedAvatars');
// If there if not enough space for the avatars to show in one line remove the first one
if (collectionContainer.find('div[data-avatar-tooltip]').length && ((collectionContainer.find('div[data-avatar-tooltip]').length + 1) * $(collectionContainer.find('div[data-avatar-tooltip]')[0]).outerWidth(true) > collectionContainer.outerWidth())) {
$(collectionContainer.find('div[data-avatar-tooltip]')[0]).remove();
}
// Add the avatar to the collection
this.animate('popIn', {
element: $('<div data-avatar-tooltip="You ' + (liked ? 'liked' : 'disliked') + ' ' + DemoAvatars.Avatars[this.AvatarIndex] + '"/>').append($('<div/>').html('<img src="https://stephanwagner.me/img/jBox/avatar/' + DemoAvatars.Avatars[this.AvatarIndex] + '.svg"/>')).appendTo(collectionContainer)
});
// Attach the avatar tooltip
DemoAvatars.AvatarsTooltip && DemoAvatars.AvatarsTooltip.attach();
}.bind(this)
});
// Open another Avatar jBox
generateAvatarJBox();
}.bind(this));
}.bind(this));
},
// When we open the jBox, set the new content and show the tooltips if it's the initial jBox
onOpen: function () {
// Set title and content depending on current index
this.setTitle(DemoAvatars.Avatars[DemoAvatars.current]);
this.content.css({backgroundImage: 'url(https://stephanwagner.me/img/jBox/avatar/' + DemoAvatars.Avatars[DemoAvatars.current] + '.svg)'});
// If it's the inital jBox, show the tooltips after a short delay
initial && setTimeout(function () {
// We are creating the two tooltips in a loop as they are very similar
$.each(['Dislike', 'Like'], function (index, item) {
// We store the tooltips in the global var so we can refer to them later
DemoAvatars['AvatarsTooltip' + item] = new jBox('Tooltip', {
theme: 'TooltipBorder',
addClass: 'AvatarsTooltip AvatarsTooltip' + item,
minWidth: 110,
content: item,
position: {
y: 'bottom'
},
offset: {
y: 5
},
target: '#AvatarsInitial .jBox-footer .button-' + (item == 'Like' ? 'heart' : 'cross'),
animation: 'move',
zIndex: 11000,
// Abort opening the tooltips when we clicked on a like or dislike button already
onOpen: function () {
DemoAvatars.clicked && this.close();
}
}).open();
});
}, 500);
}
});
// If it's the inital jBox add onClose events
initial && (jBoxAvatar.options.onClose = function ()
{
// Loop through all avatar jBoxes and close them if they are not removed yet
$.each(DemoAvatars.Modals, function (index, jBox) {
jBox.id != 'AvatarsInitial' && !jBox.AvatarRemoved && jBox.close();
}.bind(this));
// Remove the collection containers with a sliding animation
$.each(['Liked', 'Disliked'], function (index, item) {
this.animate('slide' + (item == 'Liked' ? 'Right' : 'Left'), {
element: $('#' + item + 'Avatars'),
complete: function () {
$('#' + item + 'Avatars').remove();
}
});
}.bind(this));
// Close the tooltips
DemoAvatars.AvatarsTooltipLike && DemoAvatars.AvatarsTooltipLike.close();
DemoAvatars.AvatarsTooltipDislike && DemoAvatars.AvatarsTooltipDislike.close();
});
// If it's the inital jBox add onCloseComplete events
initial && (jBoxAvatar.options.onCloseComplete = function ()
{
// Loop through all modal jBoxes and remove them from DOM
$.each(DemoAvatars.Modals, function (index, jBox) {
jBox.destroy();
delete DemoAvatars.Modals[jBox.id];
});
// Remove the tooltips from DOM
DemoAvatars.AvatarsTooltipLike && DemoAvatars.AvatarsTooltipLike.destroy();
DemoAvatars.AvatarsTooltipDislike && DemoAvatars.AvatarsTooltipDislike.destroy();
});
// Store the jBox in the modal collection
DemoAvatars.Modals[jBoxAvatar.id] = jBoxAvatar;
}
// On domready, add the click event to the button
$(document).ready(function() {
$('#DemoAvatars').click(function () { generateAvatarJBox(true); });
});

View file

@ -0,0 +1,269 @@
/* Restyle jBoxes */
#jBoxLogin .jBox-content {
padding: 0;
}
#jBoxLogin .jBox-title {
text-align: center;
line-height: 1.6;
padding: 15px 0;
font-size: 20px;
}
.jBox-TooltipSmall.LoginTooltipSmall .jBox-content,
.jBox-TooltipError.LoginTooltipError .jBox-content {
font-size: 13px;
padding: 5px 10px;
line-height: 18px;
}
.jBox-TooltipSmall.LoginTooltipSmall .jBox-container,
.jBox-TooltipError.LoginTooltipError .jBox-container {
border-radius: 2px;
font-weight: bold;
color: #fff;
}
.jBox-TooltipSmall.LoginTooltipError .jBox-container {
background: #d00;
}
.jBox-TooltipSmall.LoginTooltipSmall .jBox-container {
background: #246bb3;
}
.jBox-TooltipSmall.LoginTooltipSmall .jBox-pointer:after {
background: #246bb3;
}
/* Content */
.login-container {
display: none;
}
.login-container.active {
display: block;
}
.login-body {
padding: 0 25px;
}
.login-container button {
margin: 25px 0 0;
}
.login-textfield-wrapper {
position: relative;
}
.login-remember {
margin: 25px 0 0;
height: 20px;
}
#LoginWrapper.request-running .login-footer a,
#LoginWrapper.request-running .login-footer span {
cursor: default !important;
text-decoration: none !important;
}
/* Form elements */
.login-textfield {
width: 100%;
border: 0;
border-bottom: 2px solid #ddd;
padding: 6px 2px;
font-size: 18px;
margin-top: 25px;
transition: border-color .2s;
}
.login-textfield:hover {
border-bottom-color: #ccc;
}
.login-textfield:focus {
border-bottom-color: #246bb3;
}
.login-textfield.textfield-error {
border-bottom-color: #d00;
}
.login-checkbox {
float: left;
position: relative;
cursor: pointer;
width: 20px;
height: 20px;
border-radius: 3px;
background: #eee;
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .05);
transition: background .2s;
}
.login-checkbox.login-checkbox-active {
box-shadow: none;
background: #7d0;
}
.login-checkbox-check {
opacity: 0;
background: no-repeat center center;
background-size: 14px;
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MjQuNTMgMzE1LjczIj4KPHBhdGggZmlsbD0iI2ZmZmZmZiIgZD0iTTQ2NS4wNywxNTMuNmExMC4zMSwxMC4zMSwwLDAsMCwwLTE0LjkzTDQyOC44LDEwMi40YTEwLjMxLDEwLjMxLDAsMCwwLTE0LjkzLDBMMjAwLjUzLDMxNS43Myw5OC4xMywyMTMuMzNhMTAuMzEsMTAuMzEsMCwwLDAtMTQuOTMsMEw0Ni45MywyNDkuNmExMC4zMSwxMC4zMSwwLDAsMCwwLDE0LjkzbDE0Ny4yLDE0Ny4yYTEwLjMxLDEwLjMxLDAsMCwwLDE0LjkzLDBsMjU2LTI1OC4xM1oiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC00My43MyAtOTkuMikiLz4KPC9zdmc+);
width: 20px;
height: 20px;
position: absolute;
top: 50%;
left: 50%;
margin-top: -10px;
margin-left: -10px;
transition: opacity .2s;
}
.login-checkbox.login-checkbox-active .login-checkbox-check {
opacity: 1;
}
.login-checkbox-label {
float: left;
cursor: pointer;
width: calc(100% - 20px);
line-height: 20px;
font-size: 17px;
padding: 0 0 0 12px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.login-button {
width: 100%;
border: 0;
color: #fff;
background: #246bb3;
border-radius: 4px;
height: 40px;
line-height: 40px;
font-size: 20px;
padding: 0;
transition: background .2s;
}
.login-button:hover {
background: #3878c1;
}
.login-button:active {
background: #246bb3;
}
.login-button[disabled] {
cursor: default !important;
color: #ccc !important;
background: #eee !important;
}
.loading-bar,
.login-button[disabled].loading-bar {
background-image: linear-gradient(-45deg, rgba(255, 255, 255, .4) 25%, rgba(255, 255, 255, .0) 25%, rgba(255, 255, 255, .0) 50%, rgba(255, 255, 255, .4) 50%, rgba(255, 255, 255, .4) 75%, rgba(255, 255, 255, .0) 75%, rgba(255, 255, 255, .0)) !important;
background-size: 32px 32px !important;
background-repeat: repeat !important;
transition: background-position 60000s linear !important;
background-position: 4000000px !important;
}
/* Footer */
.login-footer {
background: #fafafa;
border-top: 1px solid #eee;
border-radius: 0 0 4px 4px;
font-size: 17px;
line-height: 1.6;
padding: 15px 0 15px 25px;
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
.login-footer span {
cursor: pointer;
color: #297acc;
}
.login-footer span:hover {
text-decoration: underline;
}
/*
TODO
.password-strength {
width: 10px;
height: 6px;
top: 39px;
right: 11px;
}
.password-strength:before,
.password-strength:after {
content: '';
width: 10px;
top: 0;
bottom: 0;
}
.password-strength,
.password-strength:before,
.password-strength:after {
position: absolute;
background: #eee;
transition: background .15s;
}
.password-strength:before {
right: calc(100% + 1px);
border-radius: 2px 0 0 2px;
}
.password-strength:after {
left: calc(100% + 1px);
border-radius: 0 2px 2px 0;
}
.password-strength.level1:before {
background: #e00;
}
.password-strength.level2,
.password-strength.level2:before {
background: #fc0;
}
.password-strength.level3,
.password-strength.level3:before,
.password-strength.level3:after {
background: #7d0;
}
*/
/* Common */
.noselect {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}

View file

@ -0,0 +1,399 @@
/* Playground Demo: Login */
/*
This playground demo is still in production
I will improve this shortly and add the options to recover and reset the password
Let me know if you have questions or ideas how to improve this login modal:
stephanwagner.me@gmail.com
*/
// We are ssetting up a global variable where we can adjust html and texts
var jBoxLogin = {
jBox: null,
// The html of each of the content containers
html: {
login: '<div id="LoginContainer-login" class="login-container"><div class="login-body"><input type="text" id="loginUsername" class="login-textfield" placeholder="Username" autocorrect="off" autocapitalize="off" spellcheck="false"><input type="password" id="loginPassword" class="login-textfield" placeholder="Password" autocorrect="off" autocapitalize="off" spellcheck="false"><div class="login-remember"><div class="login-checkbox"><div class="login-checkbox-check"></div></div><div class="login-checkbox-label">Remember me</div><input type="hidden" name="login-remember" value="1"></div><button class="login-button">Login</button></div><div class="login-footer"><span onclick="jBoxLogin.jBox.showContent(\'register\')">Create new account</span><br><span style="display: none" onclick="jBoxLogin.jBox.showContent(\'password-recovery\')">Forgot password?</span></div></div>',
register: '<div id="LoginContainer-register" class="login-container"><div class="login-body"><input type="text" id="registerUsername" class="login-textfield" placeholder="Username" maxlength="24" autocorrect="off" autocapitalize="off" spellcheck="false"><input type="text" id="registerEmail" class="login-textfield" placeholder="Email address" maxlength="128" autocorrect="off" autocapitalize="off" spellcheck="false"><div class="login-textfield-wrapper"><input type="password" class="login-textfield" id="registerPassword" placeholder="Password" maxlength="32" autocorrect="off" autocapitalize="off" spellcheck="false"><div class="password-strength" style="display: none"></div></div><button class="login-button">Create account</button></div><div class="login-footer"><span onclick="jBoxLogin.jBox.showContent(\'login\')">Already registered? Login!</span></div></div>',
passwordRecovery: '', // TODO '<div id="LoginContainer-password-recovery" class="login-container"><div class="login-body"><input type="text" class="login-textfield" placeholder="Email address" autocorrect="off" autocapitalize="off" spellcheck="false"><button class="login-button">Reset password</button></div><div class="login-footer"><span onclick="jBoxLogin.jBox.showContent(\'login\')">Already registered? Login!</span></div></div>',
passwordReset: '' // TODO '<div id="LoginContainer-password-reset" class="login-container"><div class="login-body"><input type="text" placeholder="Recovery Code"><input type="password" placeholder="Password" autocorrect="off" autocapitalize="off" spellcheck="false"><button class="login-button">Reset password</button></div><div class="login-footer"><span onclick="jBoxLogin.jBox.showContent(\'login\')">Already registered? Login!</span></div></div>'
},
// Corresponding titles for content elements
title: {
login: 'Login',
register: 'Create new account',
// TODO passwordRecovery: 'Recover password',
// TODO passwordReset: 'Reset password'
},
// These tooltips will show when a textelemet gets focus
textfieldTooltips: {
loginUsername: 'For this demo the username is "username"',
loginPassword: 'For this demo the password is "password"',
registerUsername: 'Choose a unique username',
registerEmail: 'Your email address',
registerPassword: 'Be tricky, use numbers and special characters'
}
};
$(document).ready(function() {
// On domready create the login modal
jBoxLogin.jBox = new jBox('Modal', {
// Unique id for CSS access
id: 'jBoxLogin',
// Dimensions
width: 320, // TODO move to global var
height: 350,
// Attach to elements
attach: '#DemoLogin',
// Create the content with the html provided in global var
content: '<div id="LoginWrapper">' + jBoxLogin.html.login + jBoxLogin.html.register + jBoxLogin.html.passwordRecovery + jBoxLogin.html.passwordReset + '</div>',
// When the jBox is being initialized add internal functions
onInit: function () {
// Internal function to show content
this.showContent = function (id, force) {
// Abort if an ajax call is loading
if (!force && $('#LoginWrapper').hasClass('request-running')) return null;
// Set the title depending on id
this.setTitle(jBoxLogin.title[id]);
// Show content depending on id
$('.login-container.active').removeClass('active');
$('#LoginContainer-' + id).addClass('active');
// Remove error tooltips
// TODO only loop through active elements or store tooltips in global var rather than on the element
$.each(jBoxLogin.textfieldTooltips, function (id, tt) {
$('#' + id).data('jBoxTextfieldError') && $('#' + id).data('jBoxTextfieldError').close();
});
};
// Initially show content for login
this.showContent('login', true);
// Add focus and blur events to textfields
$.each(jBoxLogin.textfieldTooltips, function (id, tt) {
// Focus an textelement
$('#' + id).on('focus', function () {
// When there is an error tooltip close it
$(this).data('jBoxTextfieldError') && $(this).data('jBoxTextfieldError').close();
// Remove the error state from the textfield
$(this).removeClass('textfield-error');
// Store the tooltip jBox in the elements data
if (!$(this).data('jBoxTextfieldTooltip')) {
// TODO create a small jbox plugin
$(this).data('jBoxTextfieldTooltip', new jBox('Tooltip', {
width: 310, // TODO use modal width - 10
theme: 'TooltipSmall',
addClass: 'LoginTooltipSmall',
target: $(this),
position: {
x: 'left',
y: 'top'
},
outside: 'y',
offset: {
y: 6,
x: 8
},
pointer: 'left:17',
content: tt,
animation: 'move'
}));
}
$(this).data('jBoxTextfieldTooltip').open();
// Loose focus of textelement
}).on('blur', function () {
$(this).data('jBoxTextfieldTooltip').close();
});
});
// Internal function to show errors
this.showError = function (element, message) {
if (!element.data('errorTooltip')) {
// TODO add the error class here
element.data('errorTooltip', new jBox('Tooltip', {
width: 310,
theme: 'TooltipError',
addClass: 'LoginTooltipError',
target: element,
position: {
x: 'left',
y: 'top'
},
outside: 'y',
offset: {
y: 6
},
pointer: 'left:9',
content: message,
animation: 'move'
}));
}
element.data('errorTooltip').open();
};
// Internal function to change checkbox state
this.toggleCheckbox = function () {
// Abort if an ajax call is loading
if ($('#LoginWrapper').hasClass('request-running')) return null;
$('.login-checkbox').toggleClass('login-checkbox-active');
};
// Add checkbox events to checkbox and label
$('.login-checkbox, .login-checkbox-label').on('click', function () {
this.toggleCheckbox();
}.bind(this));
// Parse an ajax repsonse
this.parseResponse = function(response) {
try {
response = JSON.parse(response.responseText || response);
} catch (e) {}
return response;
};
// Show a global error
this.globalError = function () {
new jBox('Notice', {
color: 'red',
content: 'Oops, something went wrong.',
attributes: {
x: 'right',
y: 'bottom'
}
});
};
// Internal function to disable or enable the form while request is running
this.startRequest = function() {
this.toggleRequest();
}.bind(this);
this.completeRequest = function() {
this.toggleRequest(true);
}.bind(this);
this.toggleRequest = function (enable) {
$('#LoginWrapper')[enable ? 'removeClass' : 'addClass']('request-running');
$('#LoginWrapper button')[enable ? 'removeClass' : 'addClass']('loading-bar');
$('#LoginWrapper input, #LoginWrapper button').attr('disabled', enable ? false : 'disabled');
}.bind(this);
// Bind ajax login function to login button
$('#LoginContainer-login button').on('click', function () {
$.ajax({
url: 'https://stephanwagner.me/PlaygroundLogin/login',
data: {
username: $('#loginUsername').val(),
password: $('#loginPassword').val(),
remember: $('.login-checkbox').hasClass('login-checkbox-active') ? 1 : 0
},
method: 'post',
beforeSend: function () {
this.startRequest();
}.bind(this),
// Ajax call successfull
success: function (response) {
this.completeRequest();
response = this.parseResponse(response);
// Login successfull
if (response.success) {
this.close();
new jBox('Notice', {
color: 'green',
content: 'You are now logged in',
attributes: {
x: 'right',
y: 'bottom'
}
});
// Redirect or own login behavior here
// Login failed
} else {
// Shake submit button
this.animate('shake', {element: $('#LoginContainer-login button')});
if (response.errors) {
// Show error on textfields, for login no error tooltips neccessary, username or password is wrong
$('#loginUsername, #loginPassword').addClass('textfield-error');
} else {
// Backend error
this.globalError();
}
}
}.bind(this),
// Ajax call failed
error: function () {
this.completeRequest();
this.animate('shake', {element: $('#LoginContainer-login button')});
this.globalError();
}.bind(this)
});
}.bind(this));
// Bind ajax register function to register button
$('#LoginContainer-register button').on('click', function () {
$.ajax({
url: 'https://stephanwagner.me/PlaygroundLogin/register',
data: {
username: $('#registerUsername').val(),
email: $('#registerEmail').val(),
password: $('#registerPassword').val()
},
method: 'post',
beforeSend: function () {
this.startRequest();
}.bind(this),
success: function (response) {
this.completeRequest();
response = this.parseResponse(response);
// Registration successfull
if (response.success) {
this.close();
new jBox('Notice', {
color: 'green',
content: 'Your account was created',
attributes: {
x: 'right',
y: 'bottom'
}
});
// Redirect or own register behavior here
// Registration failed
} else {
// Shake submit button
this.animate('shake', {element: $('#LoginContainer-register button')});
if (response.errors) {
// Loop through errors and open tooltips
$.each(response.errors, function (id, error) {
// TODO Only one tooltip at a time
var id_selector = 'register' + (id).substr(0,1).toUpperCase() + (id).substr(1);
$('#' + id_selector).addClass('textfield-error');
if (!$('#' + id_selector).data('jBoxTextfieldError')) {
$('#' + id_selector).data('jBoxTextfieldError', new jBox('Tooltip', {
width: 310,
theme: 'TooltipError',
addClass: 'LoginTooltipError',
target: $('#' + id_selector),
position: {
x: 'left',
y: 'top'
},
outside: 'y',
offset: {
y: 6,
x: 8
},
pointer: 'left:17',
//content: error,
animation: 'move'
}));
}
$('#' + id_selector).data('jBoxTextfieldError').setContent(error).open();
});
// Backend error
} else {
this.globalError();
}
}
}.bind(this),
// Ajax call failed
error: function () {
this.completeRequest();
this.animate('shake', {element: $('#RegisterContainer-login button')});
this.globalError();
}.bind(this)
});
}.bind(this));
},
onOpen: function () {
// Go back to login when we open the modal
this.showContent('login', true);
},
onClose: function () {
// TODO reset form completely
// TODO only close jBox with close button, not on overlay click
// Remove error tooltips
// TODO Better to reset the form, this loop is also in showContent
$.each(jBoxLogin.textfieldTooltips, function (id, tt) {
$('#' + id).data('jBoxTextfieldError') && $('#' + id).data('jBoxTextfieldError').close();
});
}
});
});