myLib
/*jslint nomen: true*/
/*global
Buffer, clearInterval, clearTimeout, console, exports, global, module, process, querystring, require, setInterval, setTimeout, __dirname, __filename
*/
/*global myLib, component, button, modal */
console.assert(Object.prototype.toString(myLib.ui) === '[object Object]', 'myLib.ui не является обьектом');
console.assert(Object.prototype.toString(myLib.ui.Component) === '[object Object]', 'myLib.ui.Component не является обьектом');
console.assert(document.getElementsByTagName('div')[0], 'myLib.ui.Component.render() не смог нарисовать элемент');
component.hide();
console.assert(document.getElementsByTagName('div')[0].style.display === 'none', 'myLib.ui.Component.hide() не смог спрятать элемент');
component.show();
console.assert(document.getElementsByTagName('div')[0].style.display === 'block', 'myLib.ui.Component.show() не смог показать элемент');
console.assert(Object.prototype.toString(myLib.ui.Button) === '[object Object]', 'myLib.ui.Button не является обьектом');
console.assert(document.getElementsByTagName('button')[1], 'myLib.ui.Button.render() не смог нарисовать элемент');
button.disable();
console.assert(document.getElementsByTagName('button')[1].getAttribute('disabled'), 'myLib.ui.Button.disable() не смог спрятать элемент');
button.enable();
console.assert(!document.getElementsByTagName('button')[1].getAttribute('disabled'), 'myLib.ui.Button.enable() не смог показать элемент');
html,
body {
min-height: 100%;
min-width: 100%;
padding: 0;
margin: 0;
}
body {
background: #fff;
}
.modal-content,
.modal-footer {
box-shadow: 4px 4px 2px -2px rgba(0, 0, 0, .5);
}
button {
border: ThreeDFace solid 1px;
padding: .5em 1em;
background-color: #eee;
border-radius: 4px;
border-style: solid;
}
button:hover,
button:focus {
background-color: #bbb;
}
.modal-overlay {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 1;
background: rgba(0, 0, 0, .3);
}
.modal {
position: fixed;
top: 50%;
margin-top:-100px;
left: 50%;
z-index: 2;
overflow: visible;
height: 0;
}
.modal,
.modal-content,
.modal-footer {
background: inherit;
}
.modal-content,
.modal-footer {
position: relative;
margin-left: -50%;
width: 100%;
}
.modal-content {
padding: 1em 1em;
border: ThreeDFace solid 1px;
border-bottom: none;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
bottom: -4px;
}
.modal-footer {
padding: .5em 1em 1em;
border: ThreeDFace solid 1px;
border-top: none;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
background-color: #eee;
text-align: center;
}
var component = new myLib.ui.Component();
var button = new myLib.ui.Button();
var modal = new myLib.ui.Modal('MyWindow');
component.render();
modal.on('beforeOpen', function(title) {
console.log('You have opened the ' + title + ' window');
});
var isSaved = false;
modal.on('beforeClose', function() {
if (isSaved === false) {
isSaved = true;
return false;
}
});
modal.on('closes', function(title) {
console.log('You have closed the ' + title + ' window');
});
modal.render();
modal.setContent('<h3>Modal window</h3><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus quis lectus metus, at posuere neque. Sed pharetra nibh eget orci convallis at posuere leo convallis. Sed blandit augue vitae augue scelerisque bibendum. Vivamus sit amet libero turpis, non venenatis urna. In blandit, odio convallis suscipit venenatis, ante ipsum cursus augue.</p>');
button.text = 'Open Modal';
button.render();
button.elem.addEventListener('click', function(){modal.open()});
/*jslint nomen: true*/
/*global
Buffer, clearInterval, clearTimeout, console, exports, global, module, process, querystring, require, setInterval, setTimeout, __dirname, __filename
*/
/*
Давай добавим еще один компонент - модальное окно Modal.
<div class='...'></div> - оверлей, отдельный элемент
<div class='...'>
<div class='...'>Content</div> - тут будет контент
<div class='...'><button>Close</button></div> - нижняя панель с кнопками
</div> - оверлей, отдельный элемент
Методы:
- setContent(html) - рендерит контент в контентную область (<div class='...'>Content</div> - тут будет контент)
- По методу open/close - повяляется или скрывается. Это мы частично наследуем от родителя. Смотри пример для open
open: function() {
myLib.ui.Component.prototype.open();
this.overlayNode.style.display = 'block' - показали оверлей окна
}
*/
/*global myLib*/
'use strict';
//var myLib = new MyLib();
myLib.define('myLib.ui.Modal');
function Modal(title) {this.title = title || 'Untitled'}
myLib.inherits(Modal, myLib.ui.Component);
myLib.mixin(Modal.prototype, myLib.ui.Component.prototype);
myLib.mixin(Modal.prototype, {
render: function (root) {
var overlayNode = new myLib.ui.Component(),
contentNode = new myLib.ui.Component(),
footerNode = new myLib.ui.Component(),
button = new myLib.ui.Button();
overlayNode.render();
overlayNode.elem.setAttribute('class', 'modal-overlay');
this.overlayNode = overlayNode.elem;
//myLib.ui.Component.apply(this, arguments);
this.elem = document.createElement('div');
this.elem.setAttribute('class', 'modal');
contentNode.text = this.text;
contentNode.render(this.elem);
contentNode.elem.setAttribute('class', 'modal-content');
footerNode.render(this.elem);
footerNode.elem.setAttribute('class', 'modal-footer');
//console.log([myLib.ui.Button,myLib.ui.Button.prototype,myLib.ui.Button.constructor,button]);
button.text = 'Close';
button.render(footerNode.elem);
button.elem.addEventListener('click', function () {
this.close();
}.bind(this));
(root || document.body).appendChild(this.elem);
this.close();
this.contentNode = contentNode;
},
setContent: function (html) {
this.contentNode.elem.innerHTML = html;
},
open: function () {
if (this.fire('beforeOpen', this.title) === false) {
return false;
}
myLib.ui.Component.prototype.show.call(this);
this.overlayNode.style.display = 'block';
},
close: function () {
if (this.fire('beforeClose') === false) {
return false;
}
myLib.ui.Component.prototype.hide.call(this);
this.overlayNode.style.display = 'none';
this.fire('closes', this.title)
}
});
myLib.ui.Modal = Modal;
/*jslint nomen: true*/
/*global
Buffer, clearInterval, clearTimeout, console, exports, global, module, process, querystring, require, setInterval, setTimeout, __dirname, __filename
*/
/*
jsLib.ui.Component
Методы:
- конструктор
- render - создает elem и рендерит его в body
- show
- hide
Свойства:
- elem - ссылка на DOM елемент, который рендерится в body
*/
/*global myLib */
'use strict';
//var myLib = new MyLib();
function Component(text) {
this.text = text || this.text || '';
}
myLib.inherits(Component, myLib.Observable);
myLib.mixin(Component.prototype, {
render: function (root) {
this.elem = document.createElement('div');
if (this.text) {
this.elem.innerText = this.text;
}
if (this.cssClasses) {
this.elem.setAttribute('class', this.cssClasses);
}
(root || document.body).appendChild(this.elem);
},
show: function () {
this.elem.style.display = 'block';
},
hide: function () {
this.elem.style.display = 'none';
},
text: ''
});
myLib.mixin(Component.prototype, myLib.Observable.prototype);
myLib.define('myLib.ui.Component');
myLib.ui.Component = Component;
/*jslint nomen: true*/
/*global
Buffer, clearInterval, clearTimeout, console, exports, global, module, process, querystring, require, setInterval, setTimeout, __dirname, __filename
*/
/*
jsLib.ui.Button наследуется от jsLib.ui.Component
Методы:
- конструктор (в котором обязательно вызывается родительский конструктор)
-disable
- enable
Свойства:
- elem который и будет нашей кнопкой - наследуется от родителя
- text - текст кнопки
*/
/*global myLib*/
'use strict';
//var myLib = new MyLib();
myLib.define('myLib.ui.Button');
function Button() {}
myLib.inherits(Button, myLib.ui.Component);
myLib.mixin(Button.prototype, {
render: function (root) {
this.elem = document.createElement('button');
this.elem.innerText = this.text;
(root || document.body).appendChild(this.elem);
},
disable: function () {
if (!this.elem) {
throw new Error('Element is not defined');
}
this.disabled = true;
this.elem.setAttribute('disabled', true);
},
enable: function () {
this.disabled = false;
this.elem.removeAttribute('disabled');
}
});
myLib.ui.Button = Button;
/*jslint nomen: true*/
/*global
Buffer, clearInterval, clearTimeout, console, exports, global, module, process, querystring, require, setInterval, setTimeout, __dirname, __filename
*/
'use strict';
var myLib = {
// создает неймспейс, но не перезаписывает существующий
define: function (namespace) {
// 'myLib.ui.Button' => myLib.ui.Button === {};
var self = this,
parent = self,
child;
namespace.split('.').splice(1).forEach(function (n) {
child = parent[n] = (parent.prototype && parent.prototype[n]) || parent[n] || ({});
self.inherits(child, parent);
parent = child;
});
},
// наследует один класс от другого
inherits: function (Child, Parent) {
Child.prototype = new Parent.constructor();
Child.prototype.constructor = Child;
Child.superclass = Parent.prototype;
},
//к первому объекту примерживает все поля второго
mixin: function (expandable, extendable) {
var key;
for (key in extendable) {
if (extendable.hasOwnProperty(key)) {
expandable[key] = extendable[key];
}
}
}
};
//myLib.prototype = new function () {};
myLib.prototype = myLib;
function MyLib() {}
MyLib.prototype = myLib;
myLib.define('myLib.Observable');
function Observable() {}
myLib.mixin(Observable.prototype, {
on: function(key, observer) {
this.observers[key] = observer;
},
fire: function(key, context) {
if(!this.observers[key]){
throw Error('There is no ' + key + ' observer');
}
this.observers[key](context);
},
off: function(key) {
delete this.observers[key];
},
observers: {}
});
myLib.Observable = Observable;
<!DOCTYPE html>
<html lang="ru">
<head>
<link type="text/css" href="style.css" rel="stylesheet"/>
</head>
<body>
<script src="myLib.js"></script>
<script src="myLib.Observable.js"></script>
<script src="myLib.ui.Component.js"></script>
<script src="myLib.ui.Button.js"></script>
<script src="myLib.ui.Modal.js"></script>
<script src="script.js"></script>
<script src="tests.js"></script>
</body>
</html>