рд╡реЗрдирд┐рд▓рд╛рдЬреЗрдПрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЬреАрдердм рдкрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЦреЛрдЬ рдХреИрд╕реЗ рдХрд░реЗрдВ

рдирдорд╕реНрддреЗ рдореЗрд░рд╛ рдирд╛рдо рдЕрд▓реЗрдХреНрдЬреЗрдВрдбрд░ рд╣реИ рдФрд░ рдореИрдВ 2018 рдореЗрдВ рдПрдХ рд╡реИрдирд┐рд▓рд╛ ES5.1 рдбреЗрд╡рд▓рдкрд░ рд╣реВрдВред


рдпрд╣ рд▓реЗрдЦ рд▓реЗрдЦ-рдЙрддреНрддрд░ "рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рдмрд┐рдирд╛ GitHub рдкрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреА рдЦреЛрдЬ рдХреИрд╕реЗ рдХрд░реЗрдВ + RxJS 6 + рдкреБрдирд░реНрдкреНрд░рд╛рдкреНрддрд┐" рд╣реИ , рдЬрд┐рд╕рдиреЗ рд╣рдореЗрдВ SvelteJS рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рддрд░реАрдХрд╛ рджрд┐рдЦрд╛рдпрд╛ред


рдореЗрд░рд╛ рд╕реБрдЭрд╛рд╡ рд╣реИ рдХрд┐ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдХреЛ рдЫреЛрдбрд╝рдХрд░ рдХрд┐рд╕реА рднреА рдирд┐рд░реНрднрд░рддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдмрд┐рдирд╛ рдЗрд╕реЗ рдХреИрд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, GitHub рдиреЗ рд╕реНрд╡рдпрдВ рдХрд╣рд╛ рдХрд┐ рд╡реЗ рдЪреМрдЦрдЯреЗ рдХреЗ рдмрд┐рдирд╛ рдПрдХ рджреГрд╢реНрдп рд╡рд┐рдХрд╕рд┐рдд рдХрд░ рд░рд╣реЗ рд╣реИрдВред


рд╣рдо GitHub рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдкреНрд▓реЗрдЯ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддреЗ рд╣реБрдП рдПрдХ рд╣реА рдЗрдирдкреБрдЯ рдХрд░реЗрдВрдЧреЗ:



рддреНрдпрд╛рдЧ

рдпрд╣ рд▓реЗрдЦ рдЖрдзреБрдирд┐рдХ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдФрд░ рд╡реЗрдм рд╡рд┐рдХрд╛рд╕ рдХреЗ рд╕рднреА рд╕рдВрднрд╡ рдкреНрд░рдерд╛рдУрдВ рдХреА рдЙрдкреЗрдХреНрд╖рд╛ рдХрд░рддрд╛ рд╣реИред


рдЯреНрд░реЗрдирд┐рдВрдЧ


рд╣рдореЗрдВ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдФрд░ рд▓рд┐рдЦрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рд▓реЗрдЖрдЙрдЯ рдХреЗ рд╕рд╛рде index.html рдмрдирд╛рдПрдВ:


index.html
<!doctype html> <html> <head> <meta charset='utf-8'> <title>GitHub users</title> <link rel='stylesheet' type='text/css' href='index.css'> </head> <body> <div id='root'></div> <div id='templates' style='display:none;'> <div data-template-id='username_input'> <input type='text' data-onedit='onNameEdit' placeholder='GitHub username'> </div> <div data-template-id='usercard' class='x-user-card'> <div class='background'></div> <div class='avatar-container'> <a class='avatar' data-href='userUrl'> <img data-src='avatarImageUrl'> </a> </div> <div class='name' data-text='userName'></div> <div class='content'> <a class='block' data-href='reposUrl'> <b data-text='reposCount'></b> <span>Repos</span> </a> <a class='block' data-href='gistsUrl'> <b data-text='gistsCount'></b> <span>Gists</span> </a> <a class='block' data-href='followersUrl'> <b data-text='followersCount'></b> <span>Followers</span> </a> </div> </div> <div data-template-id='error'><b data-text='status'></b>: <span data-text='text'></span></div> <div data-template-id='loading'>Loading...</div> </div> </body> </html> 

рдЕрдЧрд░ рдХрд┐рд╕реА рдХреЛ CSS рдореЗрдВ рджрд┐рд▓рдЪрд╕реНрдкреА рд╣реИ, рддреЛ рдЖрдк рдЙрд╕реЗ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВред


рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╕рдмрд╕реЗ рдЖрдо рд╢реИрд▓рд┐рдпреЛрдВ рд╣реИрдВ, рдХреЛрдИ рд╕реАрдПрд╕рдПрд╕-рдореЙрдбреНрдпреВрд▓ рдФрд░ рдЕрдиреНрдп рд╕реНрдХреЛрдкрд┐рдВрдЧ рдирд╣реАрдВ рд╣реИред рд╣рдо рдмрд╕ x- рд╕реЗ рд╢реБрд░реВ рд╣реЛрдиреЗ рд╡рд╛рд▓реА рдХрдХреНрд╖рд╛рдУрдВ рдХреЗ рдШрдЯрдХреЛрдВ рдХреЛ рдЪрд┐рд╣реНрдирд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЧрд╛рд░рдВрдЯреА рджреЗрддреЗ рд╣реИрдВ рдХрд┐ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рдФрд░ рдЕрдзрд┐рдХ рдирд╣реАрдВ рд╣реЛрдЧрд╛ред рд╣рдо рдЙрдирдХреЗ рд╡рд┐рд╖рдп рдореЗрдВ рдХреЛрдИ рднреА рдЪрдпрдирдХрд░реНрддрд╛ рд▓рд┐рдЦрддреЗ рд╣реИрдВред


рдЗрдирдкреБрдЯ рдлрд╝реАрд▓реНрдб


рд╣рдо рдЕрдкрдиреЗ рдЗрдирдкреБрдЯ рдХреНрд╖реЗрддреНрд░ рд╕реЗ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдХрд┐ рдЗрд╕рдХреЗ рдмрджрд▓рд╛рд╡ рдХреА рдШрдЯрдирд╛рдПрдБ, рд╕рд╛рде рд╣реА рд╕рд╛рде рдЗрдирдкреБрдЯ рд╢реБрд░реВ рд╣реЛрдиреЗ рдХреА рдШрдЯрдирд╛ рднреА рд╣реЛ, рддрд╛рдХрд┐ рдпрд╣ рддреБрд░рдВрдд рд▓реЛрдб рд╕рдВрдХреЗрдд рджрд┐рдЦрд╛рддрд╛ рд╣реИред рдпрд╣ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдирд┐рдХрд▓рд╛:


 in_package('GitHubUsers', function() { this.provide('UserNameInput', UserNameInput); function UserNameInput(options) { var onNameInput = options.onNameInput, onNameChange = options.onNameChange; var element = GitHubUsers.Dom.instantiateTemplate('username_input'); var debouncedChange = GitHubUsers.Util.delay(1000, function() { onNameChange(this.value); }); GitHubUsers.Dom.binding(element, { onNameEdit: function() { onNameInput(this.value); debouncedChange.apply(this, arguments); } }); this.getElement = function() { return element; }; } }); 

рдпрд╣рд╛рдВ рд╣рдордиреЗ рдХреБрдЫ рдЙрдкрдпреЛрдЧрд┐рддрд╛рд╡рд╛рджреА рдХрд╛рд░реНрдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рд╣реИ, рд╣рдо рдЙрдирдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЬрд╛рдПрдВрдЧреЗ:


рдЪреВрдБрдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ RequireJS рдирд╣реАрдВ рд╣реИ, рдХреЛрдИ рднреА RequireJS , рдХреЛрдИ рднреА RequireJS рдирд╣реАрдВ рд╣реИ, рд╣рдо рд╕рдм рдХреБрдЫ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╡рд╕реНрддреБрдУрдВ рдореЗрдВ рдХрд░рддреЗ рд╣реИрдВ:


packages.js
 window.in_package = function(path, fun) { path = path.split('.'); var obj = path.reduce(function(acc, p) { var o = acc[p]; if (!o) { o = {}; acc[p] = o; } return o; }, window); fun.call({ provide: function(name, value) { obj[name] = value; } }); }; 

consumeTemplates() рдлрд╝рдВрдХреНрд╢рди рд╣рдореЗрдВ DOM рддрддреНрд╡ рдХреА рдПрдХ рдЧрд╣рд░реА рдкреНрд░рддрд┐ рджреЗрддрд╛ рд╣реИ, рдЬреЛ рд╣рдорд╛рд░реЗ index.html рдореЗрдВ consumeTemplates() рддрддреНрд╡ рд╕реЗ consumeTemplates() рдлрд╝рдВрдХреНрд╢рди рджреНрд╡рд╛рд░рд╛ рдкреНрд░рд╛рдкреНрдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред


templates.js
 in_package('GitHubUsers.Dom', function() { var templatesMap = new Map(); this.provide('consumeTemplates', function(containerEl) { var templates = containerEl.querySelectorAll('[data-template-id]'); for (var i = 0; i < templates.length; i++) { var templateEl = templates[i], templateId = templateEl.getAttribute('data-template-id'); templatesMap.set(templateId, templateEl); templateEl.parentNode.removeChild(templateEl); } if (containerEl.parentNode) containerEl.parentNode.removeChild(containerEl); }); this.provide('instantiateTemplate', function(templateId) { var templateEl = templatesMap.get(templateId); return templateEl.cloneNode(true); }); }); 

Dom.binding() рдлрд╝рдВрдХреНрд╢рди рдХрд┐рд╕реА рддрддреНрд╡, рд╡рд┐рдХрд▓реНрдк рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ, рд╡рд┐рд╢рд┐рд╖реНрдЯ рдбреЗрдЯрд╛ рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдЦреЛрдЬ рдХрд░рддрд╛ рд╣реИ рдФрд░ рддрддреНрд╡реЛрдВ рдХреЗ рд╕рд╛рде рд╣рдорд╛рд░реЗ рджреНрд╡рд╛рд░рд╛ рдЖрд╡рд╢реНрдпрдХ рдХреНрд░рд┐рдпрд╛рдПрдВ рдХрд░рддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, data-element рд╡рд┐рд╢реЗрд╖рддрд╛ рдХреЗ рд▓рд┐рдП, рдпрд╣ рдЪрд┐рд╣реНрдирд┐рдд рддрддреНрд╡ рдХреЗ рд▓рд┐рдВрдХ рдХреЗ рд╕рд╛рде рдкрд░рд┐рдгрд╛рдо рдХреЗ рд▓рд┐рдП рдПрдХ рдлрд╝реАрд▓реНрдб рдЬреЛрдбрд╝рддрд╛ рд╣реИ, data-onedit рд╡рд┐рд╢реЗрд╖рддрд╛ рдХреЗ рд▓рд┐рдП, keyup рдФрд░ change рд╣реИрдВрдбрд▓рд░ рд╡рд┐рдХрд▓реНрдк рд╣реИрдВрдбрд▓рд░ рдХреЗ рд╕рд╛рде рддрддреНрд╡ рдкрд░ рд▓рдЯрдХрд╛рдП рдЬрд╛рддреЗ рд╣реИрдВред


binding.js
 in_package('GitHubUsers.Dom', function() { this.provide('binding', function(element, options) { options = options || {}; var binding = {}; handleAttribute('data-element', function(el, name) { binding[name] = el; }); handleAttribute('data-text', function(el, key) { var text = options[key]; if (typeof text !== 'string' && typeof text !== 'number') return; el.innerText = text; }); handleAttribute('data-src', function(el, key) { var src = options[key]; if (typeof src !== 'string') return; el.src = src; }); handleAttribute('data-href', function(el, key) { var href = options[key]; if (typeof href !== 'string') return; el.href = href; }); handleAttribute('data-onedit', function(el, key) { var handler = options[key]; if (typeof handler !== 'function') return; el.addEventListener('keyup', handler); el.addEventListener('change', handler); }); function handleAttribute(attribute, fun) { var elements = element.querySelectorAll('[' + attribute + ']'); for (var i = 0; i < elements.length; i++) { var el = elements[i], attributeValue = el.getAttribute(attribute); fun(el, attributeValue); } } return binding; }); }); 

рдЦреИрд░, delay рдХреА рдЬрд░реВрд░рдд рд╣реИ рдХрд┐ рд╣рдо рдХрд┐рд╕ рдкреНрд░рдХрд╛рд░ рдХреА рдмрд╣рд╕ рд╕реЗ рдирд┐рдкрдЯрддреЗ рд╣реИрдВ:


debounce.js
 in_package('GitHubUsers.Util', function() { this.provide('delay', function(timeout, fun) { var timeoutId = 0; return function() { var that = this, args = arguments; if (timeoutId) clearTimeout(timeoutId); timeoutId = setTimeout(function() { timeoutId = 0; fun.apply(that, args); }, timeout); }; }); }); 

рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХрд╛рд░реНрдб


рдЗрд╕рдХрд╛ рдХреЛрдИ рддрд░реНрдХ рдирд╣реАрдВ рд╣реИ, рдХреЗрд╡рд▓ рдПрдХ рдЯреЗрдореНрдкрд▓реЗрдЯ рд╣реИ рдЬреЛ рдбреЗрдЯрд╛ рд╕реЗ рднрд░рд╛ рд╣реИ:


 in_package('GitHubUsers', function() { this.provide('UserCard', UserCard); function UserCard() { var element = GitHubUsers.Dom.instantiateTemplate('usercard'); this.getElement = function() { return element; }; this.setData = function(data) { GitHubUsers.Dom.binding(element, data); }; } }); 

рдмреЗрд╢рдХ, рд╣рд░ рдмрд╛рд░ рдЬрдм рд╣рдо рдбреЗрдЯрд╛ рдмрджрд▓рддреЗ рд╣реИрдВ, рддреЛ рдХрдИ querySelectorAll рдХрд░рддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдпрд╣ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдФрд░ рд╣рдо рдЗрд╕реЗ рдкреВрд░рд╛ рдХрд░рддреЗ рд╣реИрдВред рдпрджрд┐ рдпрд╣ рдЕрдЪрд╛рдирдХ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ рдХрд┐ рдЗрд╕рдХреА рд╡рдЬрд╣ рд╕реЗ рд╕рдм рдХреБрдЫ рдзреАрдорд╛ рд╣реЛ рд░рд╣рд╛ рд╣реИ, рддреЛ рд╣рдо рд╕рдВрдЧреНрд░рд╣реАрдд data-element рдХреЛ рдбреЗрдЯрд╛ рд▓рд┐рдЦреЗрдВрдЧреЗред рдпрд╛ рд╣рдо рдПрдХ рдФрд░ рдмрд╛рдзреНрдпрдХрд╛рд░реА рдХрд╛рд░реНрдп рдХрд░реЗрдВрдЧреЗ, рдЬреЛ рд╕реНрд╡рдпрдВ рддрддреНрд╡реЛрдВ рдХреЛ рдмрдЪрд╛рддрд╛ рд╣реИ рдФрд░ рдирдП рдбреЗрдЯрд╛ рдХреЛ рдкрдврд╝ рд╕рдХрддрд╛ рд╣реИред рдпрд╛ рд╣рдо рди рдХреЗрд╡рд▓ рд╕реНрдереИрддрд┐рдХ рдореВрд▓реНрдпреЛрдВ, рдЙрдирдХреЗ рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреА рдПрдХ рдзрд╛рд░рд╛ рдХреЗ рдЙрджреНрджреЗрд╢реНрдп рдХреЗ рд▓рд┐рдП рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХреЗ рд╣рд╕реНрддрд╛рдВрддрд░рдг рдХрд╛ рд╕рдорд░реНрдерди рдХрд░реЗрдВрдЧреЗ рддрд╛рдХрд┐ рдмрд╛рдЗрдВрдбрд░ рдЙрдирдХрд╛ рдЕрдиреБрд╕рд░рдг рдХрд░ рд╕рдХреЗрдВред


рд▓реЛрдбрд┐рдВрдЧ / рдЕрдиреБрд░реЛрдз рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХрд╛ рд╕рдВрдХреЗрдд


рд╣рдо рдорд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рдпреЗ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рднреА рд╕реНрдерд┐рд░ рд╣реЛрдВрдЧреЗ, рдХреЗрд╡рд▓ рдПрдХ рд╣реА рд╕реНрдерд╛рди рдкрд░ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдПрдВрдЧреЗ, рдФрд░ рд╕рдВрднрд╛рд╡рдирд╛ рд╣реИ рдХрд┐ рдЙрдирдХреЗ рдкрд╛рд╕ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рддрд░реНрдХ рдмреЗрд╣рдж рдЫреЛрдЯреЗ рд╣реЛрдВрдЧреЗ (рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рдХрд╛рд░реНрдб рдХреЗ рд╡рд┐рдкрд░реАрдд), рдЗрд╕рд▓рд┐рдП рд╣рдо рдЙрдирдХреЗ рд▓рд┐рдП рдЕрд▓рдЧ рдШрдЯрдХ рдирд╣реАрдВ рдмрдирд╛рдПрдВрдЧреЗред рд╡реЗ рдЖрд╡реЗрджрди рдШрдЯрдХ рдХреЗ рд▓рд┐рдП рд╕рд┐рд░реНрдл рдЯреЗрдореНрдкрд▓реЗрдЯ рд╣реЛрдВрдЧреЗред


рдбреЗрдЯрд╛ рдЕрдиреБрд░реЛрдз


рд╣рдо рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдиреБрд░реЛрдз рд╡рд┐рдзрд┐ рдХреЗ рд╕рд╛рде рдПрдХ рд╡рд░реНрдЧ рдмрдирд╛рдПрдВрдЧреЗ, рдЬрд┐рд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ рд╣рдо рдЖрд╕рд╛рдиреА рд╕реЗ рдЗрд╕рдХреЗ рдЙрджрд╛рд╣рд░рдг рдХреЛ рдореЛрдЪ / рдЕрдиреНрдп рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд╕рд╛рде рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВ:


 in_package('GitHubUsers', function() { this.provide('GitHubApi', GitHubApi); function GitHubApi() { this.getUser = function(options, callback) { var url = 'https://api.github.com/users/' + options.userName; return GitHubUsers.Http.doRequest(url, function(error, data) { if (error) { if (error.type === 'not200') { if (error.status === 404) callback(null, null); else callback({ status: error.status, message: data && data.message }); } else { callback(error); } return; } // TODO: validate `data` against schema callback(null, data); }); }; } }); 

рдмреЗрд╢рдХ, рд╣рдореЗрдВ XMLHttpRequest рдкрд░ рдПрдХ рдЖрд╡рд░рдг рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд╣рдо fetch рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рд╡реНрдпрд╡рдзрд╛рди рдХрд╛ рд╕рдорд░реНрдерди рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдФрд░ рди рд╣реА рд╣рдо рдПрдХ рд╣реА рдХрд╛рд░рдг рдХреЗ рд▓рд┐рдП рд╡рд╛рджреЛрдВ рдХреЗ рд╕рд╛рде рд╕рдВрд╡рд╛рдж рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред


ajax.js
 in_package('GitHubUsers.Http', function() { this.provide('doRequest', function(options, callback) { var url; if (typeof options === "string") { url = options; options = {}; } else { if (!options) options = {}; url = options.url; } var method = options.method || "GET", headers = options.headers || [], body = options.body, dataType = options.dataType || "json", timeout = options.timeout || 10000; var old_callback = callback; callback = function() { callback = function(){}; // ignore all non-first calls old_callback.apply(this, arguments); }; var isAborted = false; var request = new XMLHttpRequest(); // force timeout var timeoutId = setTimeout(function() { timeoutId = 0; if (!isAborted) { request.abort(); isAborted = true; } callback({msg: "fetch_timeout", request: request, opts: options}); }, timeout); request.addEventListener("load", function() { var error = null; if (request.status !== 200) { error = { type: 'not200', status: request.status }; } if (typeof request.responseText === "string") { if (dataType !== "json") { callback(error, request.responseText); return; } var parsed; try { parsed = JSON.parse(request.responseText); } catch (e) { callback(e); return; } if (parsed) { callback(error, parsed); } else { callback({msg: "bad response", request: request}); } } else { callback({msg: "no response text", request: request}); } }); request.addEventListener("error", function() { callback({msg: "request_error", request: request}); }); request.open(method, url, true /*async*/); request.timeout = timeout; request.responseType = ""; headers.forEach(function(header) { try { request.setRequestHeader(header[0], header[1]); } catch (e) {} }); try { if (body) request.send(body); else request.send(); } catch (e) { callback({exception: e, type: 'send'}); } return { cancel: function() { if (!isAborted) { request.abort(); isAborted = true; } if (timeoutId) { clearTimeout(timeoutId); timeoutId = 0; } } }; }); }); 

рдЕрдВрддрд┐рдо рдЖрд╡реЗрджрди


app.js
 in_package('GitHubUsers', function() { this.provide('App', App); function App(options) { var api = options.api; var element = document.createElement('div'); // Create needed components var userNameInput = new GitHubUsers.UserNameInput({ onNameInput: onNameInput, onNameChange: onNameChange }); var userCard = new GitHubUsers.UserCard(); var errorElement = GitHubUsers.Dom.instantiateTemplate('error'); var displayElements = [ { type: 'loading', element: GitHubUsers.Dom.instantiateTemplate('loading') }, { type: 'error', element: errorElement }, { type: 'userCard', element: userCard.getElement() } ]; // Append elements to DOM element.appendChild(userNameInput.getElement()); userNameInput.getElement().style.marginBottom = '1em'; // HACK displayElements.forEach(function(x) { var el = x.element; el.style.display = 'none'; element.appendChild(el); }); var contentElements = new GitHubUsers.DomUtil.DisplayOneOf({ items: displayElements }); // User name processing var activeRequest = null; function onNameInput(name) { name = name.trim(); // Instant display of `loading` or current request result if (activeRequest && activeRequest.name === name) { activeRequest.activateState(); } else if (name) { contentElements.showByType('loading'); } else { contentElements.showByType(null); } } function onNameChange(name) { name = name.trim(); // Cancel old request if (activeRequest && activeRequest.name !== name) { activeRequest.request.cancel(); activeRequest = null; } else if (activeRequest) { // same name return; } if (!name) return; // Do new request activeRequest = { name: name, request: api.getUser({ userName: name }, onUserData), // method for `onNameInput` activateState: function() { contentElements.showByType('loading'); } }; activeRequest.activateState(); function onUserData(error, data) { if (error) { activeRequest = null; contentElements.showByType('error'); GitHubUsers.Dom.binding(errorElement, { status: error.status, text: error.message }); return; } if (!data) { activeRequest.activateState = function() { GitHubUsers.Dom.binding(errorElement, { status: 404, text: 'Not found' }); contentElements.showByType('error'); }; activeRequest.activateState(); return; } activeRequest.activateState = function() { userCard.setData({ userName: data.name || data.login, // `data.name` can be `null` userUrl: data.html_url, avatarImageUrl: data.avatar_url + '&s=80', reposCount: data.public_repos, reposUrl: 'https://github.com/' + data.login + '?tab=repositories', gistsCount: data.public_gists, gistsUrl: 'https://gist.github.com/' + data.login, followersCount: data.followers, followersUrl: 'https://github.com/' + data.login + '/followers' }); contentElements.showByType('userCard'); }; activeRequest.activateState(); } } this.getElement = function() { return element; }; } }); 

рд╣рдореЗрдВ рдмрд╣реБрдд рд╕рд╛рд░реЗ рдХреЛрдб рдорд┐рд▓реЗ, рдЬрд┐рдирдореЗрдВ рд╕реЗ рдЖрдзрд╛ рд╣рдореЗрдВ рдЙрди рд╕рднреА рдШрдЯрдХреЛрдВ рдХреЗ рдЖрд░рдВрднреАрдХрд░рдг рдореЗрдВ рд╣реИ, рдЬрд┐рдиреНрд╣реЗрдВ рдЕрдиреБрд░реЛрдз рднреЗрдЬрдиреЗ рдФрд░ рд▓реЛрдб / рддреНрд░реБрдЯрд┐ / рдкрд░рд┐рдгрд╛рдо рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рддрд░реНрдХ рдореЗрдВ рдЖрдзрд╛ рд╣реИред рд▓реЗрдХрд┐рди рд╕рдм рдХреБрдЫ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдкрд╛рд░рджрд░реНрд╢реА рд╣реИ, рд╕реНрдкрд╖реНрдЯ рд╣реИ рдФрд░ рдпрджрд┐ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ, рддреЛ рд╣рдо рддрд░реНрдХ рдХреЛ рдХрд╣реАрдВ рднреА рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВред


рд╣рдордиреЗ рдЙрдкрдпреЛрдЧрд┐рддрд╛ DisplayOneOf рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛, рдЬреЛ рджрд┐рдП рдЧрдП рддрддреНрд╡реЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдХреЛ рджрд┐рдЦрд╛рддрд╛ рд╣реИ, рдмрд╛рдХреА рдХреЛ рдЫреБрдкрд╛рддрд╛ рд╣реИ:


рдбреЛрдо-util.js
 in_package('GitHubUsers.DomUtil', function() { this.provide('DisplayOneOf', function(options) { var items = options.items; var obj = {}; items.forEach(function(item) { obj[item.type] = item; }); var lastDisplayed = null; this.showByType = function(type) { if (lastDisplayed) { lastDisplayed.element.style.display = 'none'; } if (!type) { lastDisplayed = null; return; } lastDisplayed = obj[type]; lastDisplayed.element.style.display = ''; }; }); }); 

рдЗрд╕реЗ рдЕрдВрдд рдореЗрдВ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдЯреЗрдореНрдкрд▓реЗрдЯреНрд╕ рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рдФрд░ рдкреЗрдЬ рдкрд░ App рдЗрдВрд╕реНрдЯреЗрдВрд╕ рдХреЛ рдЫреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛:


 function onReady() { GitHubUsers.Dom.consumeTemplates(document.getElementById('templates')); var rootEl = document.getElementById('root'); var app = new GitHubUsers.App({ api: new GitHubUsers.GitHubApi() }); rootEl.appendChild(app.getElement()); } 

рдкрд░рд┐рдгрд╛рдо?


рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рдЕрдкрдиреЗ рд▓рд┐рдП рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рд╣рдордиреЗ рдЗрд╕ рддрд░рд╣ рдХреЗ рдПрдХ рдЫреЛрдЯреЗ рд╕реЗ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рд╕рд╛рд░реЗ рдХреЛрдб рд▓рд┐рдЦреЗред рдХреЛрдИ рднреА рд╣рдорд╛рд░реЗ рд▓рд┐рдП рд╕рднреА рдЬрд╛рджреВ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рд╣рдо рдЦреБрдж рд╕рдм рдХреБрдЫ рд╣рд╛рд╕рд┐рд▓ рдХрд░рддреЗ рд╣реИрдВред рд╣рдо рдЦреБрдж рд╡рд╣ рдЬрд╛рджреВ рд░рдЪрддреЗ рд╣реИрдВ рдЬреЛ рд╣рдореЗрдВ рдЪрд╛рд╣рд┐рдП рддреЛ рд╣рдореЗрдВ рдЪрд╛рд╣рд┐рдПред


тЖТ рдбреЗрдореЛ тЖТ рдХреЛрдб


рдПрдХ рдЧреВрдВрдЧрд╛ рдФрд░ рд╢рд╛рд╢реНрд╡рдд рдХреЛрдб рд▓рд┐рдЦреЗрдВред рдлреНрд░реЗрдорд╡рд░реНрдХ рдХреЗ рдмрд┐рдирд╛ рд▓рд┐рдЦреЗрдВ, рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рдЖрдк рдмреЗрд╣рддрд░ рд╕реЛрддреЗ рд╣реИрдВ рдФрд░ рдбрд░рддреЗ рдирд╣реАрдВ рд╣реИрдВ рдХрд┐ рдХрд▓ рдЖрдкрдХреЗ рд╕рднреА рдХреЛрдб рдХреЛ рд╣рдЯрд╛ рджрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдпрд╛ рдкрд░реНрдпрд╛рдкреНрдд рдлреИрд╢рдиреЗрдмрд▓ рдирд╣реАрдВ рд╣реЛрдЧрд╛ред


рдЖрдЧреЗ рдХреНрдпрд╛ рд╣реИ?


рдпрд╣ рдЙрджрд╛рд╣рд░рдг рд╕рд┐рджреНрдзрд╛рдВрдд рд░реВрдк рдореЗрдВ рд╡реЗрдирд┐рд▓рд╛рдЬреЗрдПрд╕ рдореЗрдВ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдЫреЛрдЯрд╛ рд╣реИред рдореЗрд░рд╛ рдорд╛рдирдирд╛ тАЛтАЛрд╣реИ рдХрд┐ рд╡реЗрдирд┐рд▓рд╛ рдореЗрдВ рд▓рд┐рдЦрдирд╛ рдХреЗрд╡рд▓ рддрднреА рд╕рдордЭ рдореЗрдВ рдЖрддрд╛ рд╣реИ рдЬрдм рдЖрдкрдХреА рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХрд┐рд╕реА рднреА рдврд╛рдБрдЪреЗ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдЕрдзрд┐рдХ рд╕рдордп рддрдХ рдЬреАрдиреЗ рдХреА рдпреЛрдЬрдирд╛ рдмрдирд╛рддреА рд╣реИ рдФрд░ рдЖрдкрдХреЗ рдкрд╛рд╕ рдЗрд╕рдХреА рд╕рдВрдкреВрд░реНрдгрддрд╛ рдореЗрдВ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдВрд╕рд╛рдзрди рдирд╣реАрдВ рд╣реИрдВред


рд▓реЗрдХрд┐рди рдЕрдЧрд░ рд╡рд╣ рд╡реИрд╕реЗ рднреА рдмрдбрд╝реЗ рдереЗ, рддреЛ рдпрд╣рд╛рдВ рд╣рдо рдХреНрдпрд╛ рдХрд░реЗрдВрдЧреЗ:


HTML рдЯреЗрдореНрдкрд▓реЗрдЯ рд╣рдо рдореЙрдбреНрдпреВрд▓ / рдШрдЯрдХреЛрдВ рдХреЗ рд╕рдВрдмрдВрдз рдореЗрдВ рдХрд░реЗрдВрдЧреЗред рд╡реЗ рдШрдЯрдХреЛрдВ рдХреЗ рд╕рд╛рде рдлрд╝реЛрд▓реНрдбрд░реЛрдВ рдореЗрдВ рд╣реЛрдВрдЧреЗ рдФрд░ instantiateTemplate рдореЙрдбреНрдпреВрд▓ рдХрд╛ рдирд╛рдо рд▓реЗрдЧрд╛, рди рдХрд┐ рд╡реИрд╢реНрд╡рд┐рдХ рдирд╛рдо рдХрд╛ред


рдлрд┐рд▓рд╣рд╛рд▓, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЬреЛ рднреА CSS рд╣реИрдВ, рд╡реЗ index.css , рдЬрд╛рд╣рд┐рд░ рд╣реИ, рд╣рдореЗрдВ рдЗрд╕реЗ рдШрдЯрдХреЛрдВ рдХреЗ рдмрдЧрд▓ рдореЗрдВ рднреА рд░рдЦрдирд╛ рд╣реЛрдЧрд╛ред


рдмрдВрдбрд▓реЛрдВ рдХреА рдкрд░реНрдпрд╛рдкреНрдд рд╡рд┐рдзрд╛рдирд╕рднрд╛ рдирд╣реАрдВ рд╣реИ, рд╣рдо рд╕рднреА рдлрд╛рдЗрд▓реЛрдВ рдХреЛ рдЕрдкрдиреЗ рд╣рд╛рдереЛрдВ рд╕реЗ index.html рдореЗрдВ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ, рдпрд╣ рдЕрдЪреНрдЫрд╛ рдирд╣реАрдВ рд╣реИред


рдПрдХ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд▓рд┐рдЦрдиреЗ рдореЗрдВ рдХреЛрдИ рд╕рдорд╕реНрдпрд╛ рдирд╣реАрдВ рд╣реИ, рдЬреЛ рдХрд┐ рдореЙрдбреНрдпреВрд▓ рдХреА рд╕реВрдЪрд┐рдпреЛрдВ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЬрд┐рдиреНрд╣реЗрдВ рдмрдВрдбрд▓ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рдЗрди рдореЙрдбреНрдпреВрд▓ рдХреЗ рд╕рднреА рдЬреЗрдПрд╕, рдПрдЪрдЯреАрдПрдордПрд▓, рд╕реАрдПрд╕рдПрд╕ рдПрдХрддреНрд░ рдХрд░реЗрдЧрд╛ рдФрд░ рд╣рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдмрдВрдбрд▓ рдХреЗ рд▓рд┐рдП рдПрдХ рдЬреЗрдПрд╕ рдмрдирд╛ рджреЗрдЧрд╛ред рдпрд╣ рд╡реЗрдмрдкреИрдХ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╕рд░рд▓ рдФрд░ рдЖрд╕рд╛рди рд╣реЛрдЧрд╛, рдФрд░ рдПрдХ рд╡рд░реНрд╖ рдХреЗ рдмрд╛рдж рдкрддрд╛ рдЪрд▓реЗрдЧрд╛ рдХрд┐ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдПрдХ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЕрд▓рдЧ рд╕рдВрд╕реНрдХрд░рдг рд╣реИ рдФрд░ рдЖрдкрдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрдиреЗ рдФрд░ рдЕрдиреНрдп рд▓реЛрдбрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред


рдХреБрдЫ рдкреНрд░рдХрд╛рд░ рдХреЗ рдзреНрд╡рдЬ рд░рдЦрдиреЗ рдХреА рд╕рд▓рд╛рд╣ рджреА рдЬрд╛рддреА рд╣реИ рдЬреЛ рдЗрдВрдбреЗрдХреНрд╕ html рдореЗрдВ рдПрдХ рд╡рд┐рд╢рд╛рд▓ рд╕реВрдЪреА рдХреЗ рд╕рд╛рде js / html / css рдХрдиреЗрдХреНрд╢рди рдпреЛрдЬрдирд╛ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддреЗ рд╣реИрдВред рдлрд┐рд░ рдЕрд╕реЗрдВрдмрд▓реА рдореЗрдВ рдХреЛрдИ рджреЗрд░реА рдирд╣реАрдВ рд╣реЛрдЧреА, рдФрд░ рдХреНрд░реЛрдо рдореЗрдВ рд╕реНрд░реЛрддреЛрдВ рдореЗрдВ рдЖрдкрдХреЗ рдкрд╛рд╕ рдкреНрд░рддреНрдпреЗрдХ рдлрд╝рд╛рдЗрд▓ рдПрдХ рдЕрд▓рдЧ рдЯреИрдм рдореЗрдВ рд╣реЛрдЧреА рдФрд░ рдХрд┐рд╕реА рд╕реЛрд░реНрд╕рдореИрдк рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред


рдкреБрдирд╢реНрдЪ


рдпрд╣ рд╕рд┐рд░реНрдл рдПрдХ рд╡рд┐рдХрд▓реНрдк рд╣реИ рдХрд┐ рдпрд╣ рд╕рдм рд╡реИрдирд┐рд▓рд╛рдЬреЗрдПрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреИрд╕реЗ рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдореЗрдВ, рдЕрдиреНрдп рдЙрдкрдпреЛрдЧ рдорд╛рдорд▓реЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реБрдирдирд╛ рджрд┐рд▓рдЪрд╕реНрдк рд╣реЛрдЧрд╛ред


рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред

Source: https://habr.com/ru/post/hi419893/


All Articles