Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Workshop/01. HTTP & AJAX Workshop - Forum/bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
],
"dependencies": {
"bootstrap": "~3.3.5",
"jquery": "~2.1.4"
"jquery": "~2.1.4",
"moment": "^2.15.1"
}
}
18 changes: 10 additions & 8 deletions Workshop/01. HTTP & AJAX Workshop - Forum/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ <h3 class="panel-title">Threads</h3>
<div><h3><a class="thread-title" href="#"></a></h3></div>
<div>
<p>
<span>Created on</span><span class="thread-date"></span>
<span>Created </span><span class="thread-date"></span>
by <a class="thread-creator" href="#"></a>
</p>
</div>
Expand Down Expand Up @@ -114,18 +114,18 @@ <h3 class="panel-title">
<script id="messages-template" type="text/template">
<div class="message">
<div>
<p class="message-content"></p>
<p>
<span>Created on </span><span class="message-date"></span>
by <a class="message-creator" href="#"></a>
</p>
</div>
<p class="message-content"></p>
<p>
<span>Created </span><span class="message-date"></span>
by <a class="message-creator" href="#"></a>
</p>
</div>
</div>
</script>

<script id="message-new-template" type="text/template">

<form class="" role="search">
<form class="add-message" role="search">
<div class="input-group">
<input class="input-add-message message-content form-control" placeholder="Add new message..." />
<span class="input-group-btn">
Expand Down Expand Up @@ -158,8 +158,10 @@ <h4 class="gallery-item-title"></h4>
</div>
</script>
<!-- end templates -->

<!-- libs -->
<script src="bower_components/jquery/dist/jquery.js"></script>
<script src="bower_components/moment/moment.js"></script>

<!-- app code -->
<script src="./scripts/data.js"></script>
Expand Down
204 changes: 123 additions & 81 deletions Workshop/01. HTTP & AJAX Workshop - Forum/public/scripts/main.js
Original file line number Diff line number Diff line change
@@ -1,94 +1,123 @@
$(() => { // on document ready
const GLYPH_UP = 'glyphicon-chevron-up',
GLYPH_DOWN = 'glyphicon-chevron-down',
root = $('#root'),
navbar = root.find('nav.navbar'),
mainNav = navbar.find('#main-nav'),
contentContainer = $('#root #content'),
loginForm = $('#login'),
logoutForm = $('#logout'),
usernameSpan = $('#span-username'),
usernameInput = $('#login input'),
alertTemplate = $($('#alert-template').text());
GLYPH_DOWN = 'glyphicon-chevron-down',
root = $('#root'),
navbar = root.find('nav.navbar'),
mainNav = navbar.find('#main-nav'),
contentContainer = root.find('#content'),
loginForm = $('#login'),
logoutForm = $('#logout'),
usernameSpan = $('#span-username'),
usernameInput = loginForm.find('input'),
alertTemplate = $($('#alert-template').text());

(function checkForLoggedUser() {
data.users.current()
.then((user) => {
if (user) {
usernameSpan.text(user);
loginForm.addClass('hidden');
logoutForm.removeClass('hidden');
}
});
.then((user) => {
if (user) {
usernameSpan.text(user);
loginForm.addClass('hidden');
logoutForm.removeClass('hidden');
}
});
})();

function showMsg(msg, type, cssClass, delay) {
let container = alertTemplate.clone(true)
.addClass(cssClass).text(`${type}: ${msg}`)
.appendTo(root);
.addClass(cssClass).text(`${type}: ${msg}`)
.appendTo(root);

setTimeout(() => {
container.remove();
}, delay || 2000)
}

// start threads
function loadThreadsContent(threads) {
function loadThreadsContent() {
let container = $($('#threads-container-template').text()),
threadsContainer = container.find('#threads');

function getThreadUI(title, id, creator, date) {
let template = $($('#thread-template').text()).attr('data-id', id),
threadTitle = template.find('.thread-title').text(title),
threadCreator = template.find('.thread-creator').text(creator || 'anonymous'),
threadDate = template.find('.thread-date').text(date || 'unknown');
getThreads()
.then((threads) => threads.forEach((thread) => {
let currentThreadUI = getThreadUI(thread);
threadsContainer.append(currentThreadUI);
}));

function getThreads() {
return data.threads.get()
.then((response) => response.result);
}

function getThreadUI(thread) {
let dateString = getDateTimeAgoString(thread.postDate);

let template = $($('#thread-template').text()).attr('data-id', thread.id),
threadTitle = template.find('.thread-title').text(thread.title),
threadCreator = template.find('.thread-creator')
.text(thread.username || 'anonymous'),
threadDate = template.find('.thread-date').text(dateString);

return template.clone(true);
}

threadsContainer.append(getAddNewThreadUI());

function getAddNewThreadUI() {
let template = $($('#thread-new-template').html());
return template.clone(true);
}

threads.forEach((th) => {
let currentThreadUI = getThreadUI(th.title, th.id, th.username, th.date);
threadsContainer.append(currentThreadUI);
})
threadsContainer.append(getAddNewThreadUI());

contentContainer.find('#container-thraeds').remove();
contentContainer.html('').prepend(container);
}

function loadMessagesContent(data) {
let container = $($('#messages-container-template').text()),
messagesContainer = container.find('.panel-body');
container.attr('data-thread-id', data.result.id);
function loadMessagesContent(threadId) {
let container = $($('#messages-container-template').text());
let messagesContainer = container.find('.panel-body');
container.attr('data-thread-id', threadId);

function getMsgUI(msg, author, date) {
let template = $($('#messages-template').text());
template.find('.message-content').text(msg);
template.find('.message-creator').text(author || 'anonymous');
template.find('.message-date').text(date || 'unknown');
return template.clone(true);
getThread(threadId)
.then(loadThreadMessages);

function getThread(threadId) {
return data.threads.getById(threadId)
.then((response) => response.result)
.catch((err) => showMsg(err, 'Error', 'alert-danger'));
}

function loadThreadMessages(thread) {
container.find('.thread-title').text(thread.title);
messagesContainer.append(getAddNewMsgUI());

if (thread.messages && thread.messages.length > 0) {
thread.messages.forEach((msg) => {
appendNewMessage(messagesContainer, msg);

});
}

contentContainer.append(container);
}

function getAddNewMsgUI() {
let template = $($('#message-new-template').html());
return template.clone(true);
}
}

if (data.result.messages && data.result.messages.length > 0) {
data.result.messages.forEach((msg) => {
messagesContainer.append(getMsgUI(msg))
})
} else {
messagesContainer.append(getMsgUI('No messages!'))
}
function appendNewMessage(messagesContainer, message) {
messagesContainer.find('.add-message')
.before(getMsgUI(message));
}

messagesContainer.append(getAddNewMsgUI());
function getMsgUI(message) {
let dateString = getDateTimeAgoString(message.postDate);

container.find('.thread-title').text(data.result.title);
contentContainer.append(container);
let template = $($('#messages-template').text());
template.find('.message-content').text(message.content);
template.find('.message-creator').text(message.username || 'anonymous');
template.find('.message-date').text(dateString);
return template.clone(true);
}

function loadGalleryContent(data) {
Expand All @@ -109,35 +138,40 @@
contentContainer.html('').append(containerGallery);
}

function getDateTimeAgoString(date) {
let momentDate = moment(date, 'YYYY-MM-DD HH:mm Z');
if (momentDate.isValid()) {
return momentDate.fromNow();
}
else {
return 'on unknown date';
}
}

navbar.on('click', 'li', (ev) => {
let $target = $(ev.target);
$target.parents('nav').find('li').removeClass('active');
$target.parents('li').addClass('active');
});

navbar.on('click', '#btn-threads', (ev) => {
data.threads.get()
.then((data) => {
loadThreadsContent(data.result)
})
loadThreadsContent();
});

contentContainer.on('click', '#btn-add-thread', (ev) => {
let title = $(ev.target).parents('form').find('input#input-add-thread').val() || null;
data.threads.add(title)
.then(/* add to UI */)
.then(showMsg('Successfuly added the new thread', 'Success', 'alert-success'))
.then(loadThreadsContent)
.then(showMsg('Successfully added the new thread', 'Success', 'alert-success'))
.catch((err) => showMsg(JSON.parse(err.responseText).err, 'Error', 'alert-danger'));
})
});

contentContainer.on('click', 'a.thread-title', (ev) => {
let $target = $(ev.target),
threadId = $target.parents('.thread').attr('data-id');

data.threads.getById(threadId)
.then(loadMessagesContent)
.catch((err) => showMsg(err, 'Error', 'alert-danger'))
})
loadMessagesContent(threadId);
});

contentContainer.on('click', '.btn-add-message', (ev) => {
let $target = $(ev.target),
Expand All @@ -146,20 +180,28 @@
msg = $container.find('.input-add-message').val();

data.threads.addMessage(thId, msg)
.then(/* add to UI */)
.then(showMsg('Successfuly added the new mssagee', 'Success', 'alert-success'))
.then(appendMessage)
.then(showMsg('Successfully added the new message', 'Success', 'alert-success'))
.catch((err) => showMsg(JSON.parse(err.responseText).err, 'Error', 'alert-danger'));
})

function appendMessage(result) {
let last = result.messages.length - 1;
let message = result.messages[last];

appendNewMessage($(`[data-thread-id="${thId}"] .panel-body`), message);
}
});

contentContainer.on('click', '.btn-close-msg', (ev) => {
let msgContainer = $(ev.target).parents('.container-messages').remove();
$(ev.target).parents('.container-messages').remove();
});

contentContainer.on('click', '.btn-collapse-msg', (ev) => {
let $target = $(ev.target);
if ($target.hasClass(GLYPH_UP)) {
$target.removeClass(GLYPH_UP).addClass(GLYPH_DOWN);
} else {
}
else {
$target.removeClass(GLYPH_DOWN).addClass(GLYPH_UP);
}

Expand All @@ -170,29 +212,29 @@
// start gallery
navbar.on('click', '#btn-gallery', (ev) => {
data.gallery.get()
.then(loadGalleryContent)
.catch(console.log)
})
.then(loadGalleryContent)
.catch(console.log)
});
// end gallery

// start login/logout
navbar.on('click', '#btn-login', (ev) => {
let username = usernameInput.val() || 'anonymous';
data.users.login(username)
.then((user) => {
usernameInput.val('')
usernameSpan.text(user);
loginForm.addClass('hidden');
logoutForm.removeClass('hidden');
})
.then((user) => {
usernameInput.val('');
usernameSpan.text(user);
loginForm.addClass('hidden');
logoutForm.removeClass('hidden');
})
});
navbar.on('click', '#btn-logout', (ev) => {
data.users.logout()
.then(() => {
usernameSpan.text('');
loginForm.removeClass('hidden');
logoutForm.addClass('hidden');
})
.then(() => {
usernameSpan.text('');
loginForm.removeClass('hidden');
logoutForm.addClass('hidden');
})
});
// end login/logout
});