{"serverTime": 1405438911833, "talks": [{"title": "Unituning ", "presenter": "", "summary": " ", "comment": []}]}
console.log("/talks/" + encodeURIComponent("How to Idle")); // → /talks/How%20to%20Idle
var Router = module.exports = function() { this.routes = []; }; Router.prototype.add = function(method, url, handler) { this.routes.push({method: method, url: url, handler: handler}); }; Router.prototype.resolve = function(request, response) { var path = require("url").parse(request.url).pathname; return this.routes.some(function(route) { var match = route.url.exec(path); if (!match || route.method != request.method) return false; var urlParts = match.slice(1).map(decodeURIComponent); route.handler.apply(null, [request, response] .concat(urlParts)); return true; }); };
var http = require("http"); var Router = require("./router"); var ecstatic = require("ecstatic"); var fileServer = ecstatic({root: "./public"}); var router = new Router(); http.createServer(function(request, response) { if (!router.resolve(request, response)) fileServer(request, response); }).listen(8000); respond respondJSON , . function respond(response, status, data, type) { response.writeHead(status, { "Content-Type": type || "text/plain" }); response.end(data); } function respondJSON(response, status, data) { respond(response, status, JSON.stringify(data), "application/json"); }
var talks = Object.create(null); router.add("GET", /^\/talks\/([^\/]+)$/, function(request, response, title) { if (title in talks) respondJSON(response, 200, talks[title]); else respond(response, 404, "No talk '" + title + "' found"); }); talks. router.add("DELETE", /^\/talks\/([^\/]+)$/, function(request, response, title) { if (title in talks) { delete talks[title]; registerChange(title); } respond(response, 204, null); });
function readStreamAsJSON(stream, callback) { var data = ""; stream.on("data", function(chunk) { data += chunk; }); stream.on("end", function() { var result, error; try { result = JSON.parse(data); } catch (e) { error = e; } callback(error, result); }); stream.on("error", function(error) { callback(error); }); }
router.add("PUT", /^\/talks\/([^\/]+)$/, function(request, response, title) { readStreamAsJSON(request, function(error, talk) { if (error) { respond(response, 400, error.toString()); } else if (!talk || typeof talk.presenter != "string" || typeof talk.summary != "string") { respond(response, 400, "Bad talk data"); } else { talks[title] = {title: title, presenter: talk.presenter, summary: talk.summary, comments: []}; registerChange(title); respond(response, 204, null); } }); });
router.add("POST", /^\/talks\/([^\/]+)\/comments$/, function(request, response, title) { readStreamAsJSON(request, function(error, comment) { if (error) { respond(response, 400, error.toString()); } else if (!comment || typeof comment.author != "string" || typeof comment.message != "string") { respond(response, 400, "Bad comment data"); } else if (title in talks) { talks[title].comments.push(comment); registerChange(title); respond(response, 204, null); } else { respond(response, 404, "No talk '" + title + "' found"); } }); });
function sendTalks(talks, response) { respondJSON(response, 200, { serverTime: Date.now(), talks: talks }); }
router.add("GET", /^\/talks$/, function(request, response) { var query = require("url").parse(request.url, true).query; if (query.changesSince == null) { var list = []; for (var title in talks) list.push(talks[title]); sendTalks(list, response); } else { var since = Number(query.changesSince); if (isNaN(since)) { respond(response, 400, "Invalid parameter"); } else { var changed = getChangedTalks(since); if (changed.length > 0) sendTalks(changed, response); else waitForChanges(since, response); } } });
var waiting = []; function waitForChanges(since, response) { var waiter = {since: since, response: response}; waiting.push(waiter); setTimeout(function() { var found = waiting.indexOf(waiter); if (found > -1) { waiting.splice(found, 1); sendTalks([], response); } }, 90 * 1000); }
var changes = []; function registerChange(title) { changes.push({title: title, time: Date.now()}); waiting.forEach(function(waiter) { sendTalks(getChangedTalks(waiter.since), waiter.response); }); waiting = []; }
function getChangedTalks(since) { var found = []; function alreadySeen(title) { return found.some(function(f) {return f.title == title;}); } for (var i = changes.length - 1; i >= 0; i--) { var change = changes[i]; if (change.time <= since) break; else if (alreadySeen(change.title)) continue; else if (change.title in talks) found.push(talks[change.title]); else found.push({title: change.title, deleted: true}); } return found; }
<!doctype html> <title> </title> <link rel="stylesheet" href="skillsharing.css"> <h1> </h1> <p> : <input type="text" id="name"></p> <div id="talks"></div>
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
ID “talks” . , .
.
<form id="newtalk"> <h3>Submit a talk</h3> : <input type="text" style="width: 40em" name="title"> <br> Summary: <input type="text" style="width: 40em" name="summary"> <button type="submit"> </button> </form>
“submit” , HTTP-, .
, display none, . , ?
<div id="template" style="display: none"> <div class="talk"> <h2>{{title}}</h2> <div>by <span class="name">{{presenter}}</span></div> <p>{{summary}}</p> <div class="comments"></div> <form> <input type="text" name="comment"> <button type="submit"> </button> <button type="button" class="del"> </button> </form> </div> <div class="comment"> <span class="name">{{author}}</span>: {{message}} </div> </div>
DOM JavaScript . elt 13, , HTML, - DOM-.
DOM- , , , , – .
, HTML , .
<script src="skillsharing_client.js"></script>
, , . HTTP-, XMLHttpRequest, .
function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); req.send(options.body || null); }
, waitForChanges.
var lastServerTime = 0; request({pathname: "talks"}, function(error, response) { if (error) { reportError(error); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } });
lastServerTime , . , , . , serverTime, , lastServerTime.
, , . reportError, , .
function reportError(error) { if (error) alert(error.toString()); }
, , . , , . , .
, , . , , , . , , DOM .
displayTalks , . shownTalks, DOM, , .
var talkDiv = document.querySelector("#talks"); var shownTalks = Object.create(null); function displayTalks(talks) { talks.forEach(function(talk) { var shown = shownTalks[talk.title]; if (talk.deleted) { if (shown) { talkDiv.removeChild(shown); delete shownTalks[talk.title]; } } else { var node = drawTalk(talk); if (shown) talkDiv.replaceChild(node, shown); else talkDiv.appendChild(node); shownTalks[talk.title] = node; } }); }
DOM , HTML . instantiateTemplate, .
name – . , , , ID “template”. querySelector . “talk” “comment”.
function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == document.TEXT_NODE) { return document.createTextNode( instantiateText(node.nodeValue)); } } var template = document.querySelector("#template ." + name); return instantiate(template); }
cloneNode, DOM, . , true. instantiate , .
instantiateTemplate , , . {{title}} “title”.
, drawTalk .
function drawTalk(talk) { var node = instantiateTemplate("talk", talk); var comments = node.querySelector(".comments"); talk.comments.forEach(function(comment) { comments.appendChild( instantiateTemplate("comment", comment)); }); node.querySelector("button.del").addEventListener( "click", deleteTalk.bind(null, talk.title)); var form = node.querySelector("form"); form.addEventListener("submit", function(event) { event.preventDefault(); addComment(talk.title, form.elements.comment.value); form.reset(); }); return node; }
“talk” . -, , “comment” "comments". , , , .
, drawTalk, deleteTalk addComment , . URL, , talkURL.
function talkURL(title) { return "talks/" + encodeURIComponent(title); }
deleteTalk DELETE .
function deleteTalk(title) { request({pathname: talkURL(title), method: "DELETE"}, reportError); }
JSON POST-.
function addComment(title, comment) { var comment = {author: nameField.value, message: comment}; request({pathname: talkURL(title) + "/comments", body: JSON.stringify(comment), method: "POST"}, reportError); }
nameField, author, , . localStorage, .
var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); “submit”. ( ), PUT- . var talkForm = document.querySelector("#newtalk"); talkForm.addEventListener("submit", function(event) { event.preventDefault(); request({pathname: talkURL(talkForm.elements.title.value), method: "PUT", body: JSON.stringify({ presenter: nameField.value, summary: talkForm.elements.summary.value })}, reportError); talkForm.reset(); });
, , , , , , . - , .
, displayTalks , , .
function waitForChanges() { request({pathname: "talks?changesSince=" + lastServerTime}, function(error, response) { if (error) { setTimeout(waitForChanges, 2500); console.error(error.stack); } else { response = JSON.parse(response); displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); }
, , , , . , reportError, . ( ), 2.5 .
, , lastServerTime , , . , .
, localhost:8000, , , , .
, . , , Node.js .
. , .
, . , .
, DOM , . . - , , , , .
, , . , ?
, . , if, , .
, ("comment") . “talk”, , comments, , , .
:
<div class="comments"> <div class="comment" template-repeat="comments"> <span class="name">{{author}}</span>: {{message}} </div> </div>
: template-repeat, , , , , . ( values instantiateTemplate) , {{author}} comment, .
instantiateTemplate , , , , drawTalk.
, , true false?
?
- JavaScript, . - .
- JavaScript. , . .
, - JavaScript. , . , .
. . , , ?
Source: https://habr.com/ru/post/246331/
All Articles