finished initial client side & server side language parsing methods; integrated preloading into ajaxify and server app.js

v1.18.x
psychobunny 12 years ago
parent b5274a0d91
commit 451ffafb9e

@ -1,7 +1,8 @@
var ajaxify = {}; var ajaxify = {};
(function($) { (function ($) {
/*global app, templates, utils*/
var location = document.location || window.location, var location = document.location || window.location,
rootUrl = location.protocol + '//' + (location.hostname || location.host) + (location.port ? ':' + location.port : ''), rootUrl = location.protocol + '//' + (location.hostname || location.host) + (location.port ? ':' + location.port : ''),
@ -11,7 +12,7 @@ var ajaxify = {};
var executed = {}; var executed = {};
var events = []; var events = [];
ajaxify.register_events = function(new_page_events) { ajaxify.register_events = function (new_page_events) {
for (var i = 0, ii = events.length; i < ii; i++) { for (var i = 0, ii = events.length; i < ii; i++) {
socket.removeAllListeners(events[i]); // optimize this to user removeListener(event, listener) instead. socket.removeAllListeners(events[i]); // optimize this to user removeListener(event, listener) instead.
} }
@ -20,14 +21,14 @@ var ajaxify = {};
}; };
window.onpopstate = function(event) { window.onpopstate = function (event) {
// "quiet": If set to true, will not call pushState // "quiet": If set to true, will not call pushState
if (event !== null && event.state && event.state.url !== undefined) ajaxify.go(event.state.url, null, null, true); if (event !== null && event.state && event.state.url !== undefined) ajaxify.go(event.state.url, null, null, true);
}; };
var pagination; var pagination;
ajaxify.go = function(url, callback, template, quiet) { ajaxify.go = function (url, callback, template, quiet) {
// start: the following should be set like so: ajaxify.onchange(function(){}); where the code actually belongs // start: the following should be set like so: ajaxify.onchange(function(){}); where the code actually belongs
$(window).off('scroll'); $(window).off('scroll');
app.enter_room('global'); app.enter_room('global');
@ -66,10 +67,12 @@ var ajaxify = {};
}, url, RELATIVE_PATH + "/" + url); }, url, RELATIVE_PATH + "/" + url);
} }
translator.load(tpl_url);
jQuery('#footer, #content').fadeOut(100); jQuery('#footer, #content').fadeOut(100);
templates.flush(); templates.flush();
templates.load_template(function() { templates.load_template(function () {
exec_body_scripts(content); exec_body_scripts(content);
if (callback) { if (callback) {
@ -78,7 +81,7 @@ var ajaxify = {};
app.process_page(); app.process_page();
jQuery('#content, #footer').stop(true, true).fadeIn(200, function() { jQuery('#content, #footer').stop(true, true).fadeIn(200, function () {
if (window.location.hash) if (window.location.hash)
hash = window.location.hash; hash = window.location.hash;
if (hash) if (hash)
@ -93,15 +96,15 @@ var ajaxify = {};
} }
return false; return false;
} };
$('document').ready(function() { $('document').ready(function () {
if (!window.history || !window.history.pushState) return; // no ajaxification for old browsers if (!window.history || !window.history.pushState) return; // no ajaxification for old browsers
content = content || document.getElementById('content'); content = content || document.getElementById('content');
// Enhancing all anchors to ajaxify... // Enhancing all anchors to ajaxify...
$(document.body).on('click', 'a', function(e) { $(document.body).on('click', 'a', function (e) {
function hrefEmpty(href) { function hrefEmpty(href) {
return href == 'javascript:;' || href == window.location.href + "#" || href.slice(-1) === "#"; return href == 'javascript:;' || href == window.location.href + "#" || href.slice(-1) === "#";
@ -127,7 +130,7 @@ var ajaxify = {};
function nodeName(elem, name) { function nodeName(elem, name) {
return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
}; }
function evalScript(elem) { function evalScript(elem) {
var data = (elem.text || elem.textContent || elem.innerHTML || ""), var data = (elem.text || elem.textContent || elem.innerHTML || ""),
@ -149,7 +152,7 @@ var ajaxify = {};
head.insertBefore(script, head.firstChild); head.insertBefore(script, head.firstChild);
//TODO: remove from head before inserting?, doing this breaks scripts in safari so commented out for now //TODO: remove from head before inserting?, doing this breaks scripts in safari so commented out for now
//head.removeChild(script); //head.removeChild(script);
}; }
var scripts = [], var scripts = [],
script, script,
@ -172,6 +175,6 @@ var ajaxify = {};
} }
evalScript(scripts[i]); evalScript(scripts[i]);
} }
}; }
}(jQuery)); }(jQuery));

@ -4,14 +4,14 @@ var socket,
API_URL = null; API_URL = null;
(function() { (function () {
var showWelcomeMessage = false; var showWelcomeMessage = false;
function loadConfig() { function loadConfig() {
$.ajax({ $.ajax({
url: RELATIVE_PATH + '/api/config', url: RELATIVE_PATH + '/api/config',
success: function(data) { success: function (data) {
API_URL = data.api_url; API_URL = data.api_url;
config = data; config = data;
@ -20,19 +20,19 @@ var socket,
var reconnecting = false; var reconnecting = false;
var reconnectTries = 0; var reconnectTries = 0;
socket.on('event:connect', function(data) { socket.on('event:connect', function (data) {
console.log('connected to nodebb socket: ', data); console.log('connected to nodebb socket: ', data);
app.username = data.username; app.username = data.username;
app.showLoginMessage(); app.showLoginMessage();
}); });
socket.on('event:alert', function(data) { socket.on('event:alert', function (data) {
app.alert(data); app.alert(data);
}); });
socket.on('connect', function(data) { socket.on('connect', function (data) {
if (reconnecting) { if (reconnecting) {
setTimeout(function() { setTimeout(function () {
app.alert({ app.alert({
alert_id: 'connection_alert', alert_id: 'connection_alert',
title: 'Connected', title: 'Connected',
@ -49,14 +49,14 @@ var socket,
} }
}); });
socket.on('reconnecting', function(data) { socket.on('reconnecting', function (data) {
function showDisconnectModal() { function showDisconnectModal() {
$('#disconnect-modal').modal({ $('#disconnect-modal').modal({
backdrop: 'static', backdrop: 'static',
show: true show: true
}); });
$('#reload-button').on('click', function() { $('#reload-button').on('click', function () {
$('#disconnect-modal').modal('hide'); $('#disconnect-modal').modal('hide');
window.location.reload(); window.location.reload();
}); });
@ -79,8 +79,8 @@ var socket,
}); });
}); });
socket.on('api:user.get_online_users', function(users) { socket.on('api:user.get_online_users', function (users) {
jQuery('a.username-field').each(function() { jQuery('a.username-field').each(function () {
if (this.processed === true) if (this.processed === true)
return; return;
@ -97,7 +97,7 @@ var socket,
el.processed = true; el.processed = true;
}); });
jQuery('button .username-field').each(function() { jQuery('button .username-field').each(function () {
//DRY FAIL //DRY FAIL
if (this.processed === true) if (this.processed === true)
return; return;
@ -124,17 +124,17 @@ var socket,
} }
// takes a string like 1000 and returns 1,000 // takes a string like 1000 and returns 1,000
app.addCommas = function(text) { app.addCommas = function (text) {
return text.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,"); return text.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
} }
// Willingly stolen from: http://phpjs.org/functions/strip_tags/ // Willingly stolen from: http://phpjs.org/functions/strip_tags/
app.strip_tags = function(input, allowed) { app.strip_tags = function (input, allowed) {
allowed = (((allowed || "") + "").toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join(''); // making sure the allowed arg is a string containing only tags in lowercase (<a><b><c>) allowed = (((allowed || "") + "").toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join(''); // making sure the allowed arg is a string containing only tags in lowercase (<a><b><c>)
var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi, var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi; commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
return input.replace(commentsAndPhpTags, '').replace(tags, function($0, $1) { return input.replace(commentsAndPhpTags, '').replace(tags, function ($0, $1) {
return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : ''; return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
}); });
} }
@ -145,14 +145,14 @@ var socket,
// message = alert message content // message = alert message content
// timeout default = permanent // timeout default = permanent
// location : alert_window (default) or content // location : alert_window (default) or content
app.alert = function(params) { app.alert = function (params) {
var alert_id = 'alert_button_' + ((params.alert_id) ? params.alert_id : new Date().getTime()); var alert_id = 'alert_button_' + ((params.alert_id) ? params.alert_id : new Date().getTime());
var alert = $('#' + alert_id); var alert = $('#' + alert_id);
function startTimeout(div, timeout) { function startTimeout(div, timeout) {
var timeoutId = setTimeout(function() { var timeoutId = setTimeout(function () {
$(div).fadeOut(1000, function() { $(div).fadeOut(1000, function () {
$(this).remove(); $(this).remove();
}); });
}, timeout); }, timeout);
@ -185,7 +185,7 @@ var socket,
button.className = 'close'; button.className = 'close';
button.innerHTML = '&times;'; button.innerHTML = '&times;';
button.onclick = function(ev) { button.onclick = function (ev) {
div.parentNode.removeChild(div); div.parentNode.removeChild(div);
} }
@ -199,9 +199,9 @@ var socket,
} }
if (params.clickfn) { if (params.clickfn) {
div.onclick = function() { div.onclick = function () {
params.clickfn(); params.clickfn();
jQuery(div).fadeOut(500, function() { jQuery(div).fadeOut(500, function () {
this.remove(); this.remove();
}); });
} }
@ -209,7 +209,7 @@ var socket,
} }
} }
app.alertSuccess = function(message, timeout) { app.alertSuccess = function (message, timeout) {
if (!timeout) if (!timeout)
timeout = 2000; timeout = 2000;
@ -221,7 +221,7 @@ var socket,
}); });
} }
app.alertError = function(message, timeout) { app.alertError = function (message, timeout) {
if (!timeout) if (!timeout)
timeout = 2000; timeout = 2000;
@ -234,7 +234,7 @@ var socket,
} }
app.current_room = null; app.current_room = null;
app.enter_room = function(room) { app.enter_room = function (room) {
if (socket) { if (socket) {
if (app.current_room === room) if (app.current_room === room)
return; return;
@ -248,20 +248,20 @@ var socket,
} }
}; };
app.populate_online_users = function() { app.populate_online_users = function () {
var uids = []; var uids = [];
jQuery('.post-row').each(function() { jQuery('.post-row').each(function () {
uids.push(this.getAttribute('data-uid')); uids.push(this.getAttribute('data-uid'));
}); });
socket.emit('api:user.get_online_users', uids); socket.emit('api:user.get_online_users', uids);
} }
app.process_page = function() { app.process_page = function () {
// here is where all modules' onNavigate should be called, I think. // here is where all modules' onNavigate should be called, I think.
require(['mobileMenu'], function(mobileMenu) { require(['mobileMenu'], function (mobileMenu) {
mobileMenu.onNavigate(); mobileMenu.onNavigate();
}); });
@ -273,9 +273,9 @@ var socket,
jQuery('#main-nav li').removeClass('active'); jQuery('#main-nav li').removeClass('active');
if (active) { if (active) {
jQuery('#main-nav li a').each(function() { jQuery('#main-nav li a').each(function () {
var href = this.getAttribute('href'); var href = this.getAttribute('href');
if (active == "sort-posts" || active == "sort-reputation" || active == "search" || active== "latest") if (active == "sort-posts" || active == "sort-reputation" || active == "search" || active == "latest")
active = 'users'; active = 'users';
if (href && href.match(active)) { if (href && href.match(active)) {
jQuery(this.parentNode).addClass('active'); jQuery(this.parentNode).addClass('active');
@ -286,12 +286,12 @@ var socket,
$('span.timeago').timeago(); $('span.timeago').timeago();
setTimeout(function() { setTimeout(function () {
window.scrollTo(0, 1); // rehide address bar on mobile after page load completes. window.scrollTo(0, 1); // rehide address bar on mobile after page load completes.
}, 100); }, 100);
} }
app.showLoginMessage = function() { app.showLoginMessage = function () {
function showAlert() { function showAlert() {
app.alert({ app.alert({
type: 'success', type: 'success',
@ -311,14 +311,14 @@ var socket,
} }
} }
app.addCommasToNumbers = function() { app.addCommasToNumbers = function () {
$('.formatted-number').each(function(index, element) { $('.formatted-number').each(function (index, element) {
$(element).html(app.addCommas($(element).html())); $(element).html(app.addCommas($(element).html()));
}); });
} }
app.openChat = function(username, touid) { app.openChat = function (username, touid) {
require(['chat'], function(chat) { require(['chat'], function (chat) {
var chatModal; var chatModal;
if (!chat.modalExists(touid)) { if (!chat.modalExists(touid)) {
chatModal = chat.createModal(username, touid); chatModal = chat.createModal(username, touid);
@ -329,7 +329,7 @@ var socket,
}); });
} }
app.createNewPosts = function(data) { app.createNewPosts = function (data) {
data.posts[0].display_moderator_tools = 'none'; data.posts[0].display_moderator_tools = 'none';
var html = templates.prepare(templates['topic'].blocks['posts']).parse(data), var html = templates.prepare(templates['topic'].blocks['posts']).parse(data),
uniqueid = new Date().getTime(), uniqueid = new Date().getTime(),
@ -353,7 +353,7 @@ var socket,
app.infiniteLoaderActive = false; app.infiniteLoaderActive = false;
app.loadMorePosts = function(tid, callback) { app.loadMorePosts = function (tid, callback) {
if (app.infiniteLoaderActive) if (app.infiniteLoaderActive)
return; return;
app.infiniteLoaderActive = true; app.infiniteLoaderActive = true;
@ -364,7 +364,7 @@ var socket,
socket.emit('api:topic.loadMore', { socket.emit('api:topic.loadMore', {
tid: tid, tid: tid,
after: document.querySelectorAll('#post-container li[data-pid]').length after: document.querySelectorAll('#post-container li[data-pid]').length
}, function(data) { }, function (data) {
app.infiniteLoaderActive = false; app.infiniteLoaderActive = false;
if (data.posts.length) { if (data.posts.length) {
$('#loading-indicator').attr('done', '0'); $('#loading-indicator').attr('done', '0');
@ -378,19 +378,19 @@ var socket,
}); });
} }
app.scrollToTop = function() { app.scrollToTop = function () {
$('body,html').animate({ $('body,html').animate({
scrollTop: 0 scrollTop: 0
}); });
}; };
app.scrollToBottom = function() { app.scrollToBottom = function () {
$('body,html').animate({ $('body,html').animate({
scrollTop: $('html').height() - 100 scrollTop: $('html').height() - 100
}); });
} }
app.scrollToPost = function(pid) { app.scrollToPost = function (pid) {
if (!pid) if (!pid)
return; return;
@ -407,8 +407,8 @@ var socket,
if (!scrollTo.length && tid) { if (!scrollTo.length && tid) {
var intervalID = setInterval(function() { var intervalID = setInterval(function () {
app.loadMorePosts(tid, function(posts) { app.loadMorePosts(tid, function (posts) {
scrollTo = $('#post_anchor_' + pid); scrollTo = $('#post_anchor_' + pid);
if (tid && scrollTo.length) { if (tid && scrollTo.length) {
@ -426,8 +426,10 @@ var socket,
} }
jQuery('document').ready(function() { jQuery('document').ready(function () {
$('#search-form').on('submit', function() { translator.load('global');
$('#search-form').on('submit', function () {
var input = $(this).find('input'); var input = $(this).find('input');
ajaxify.go("search/" + input.val(), null, "search"); ajaxify.go("search/" + input.val(), null, "search");
input.val(''); input.val('');

@ -2,33 +2,96 @@
"use strict"; "use strict";
/*global RELATIVE_PATH*/ /*global RELATIVE_PATH*/
/*
* TODO: language en is hardcoded while system is developed.
*/
var translator = {}, var translator = {},
loaded = {}; files = {
loaded: {},
loading: {},
callbacks: {}
};
module.exports = translator; module.exports = translator;
translator.load = function (filename, callback) {
translator.load = function (file, callback) { if (files.loaded[filename] && !files.loading[filename]) {
if (loaded[file]) { if (callback) {
callback(loaded[file]); callback(files.loaded[filename]);
}
} else if (files.loading[filename]) {
if (callback) {
files.callbacks[filename] = files.callbacks[filename] || [];
files.callbacks[filename].push(callback);
}
} else { } else {
var timestamp = new Date().getTime(); //debug var timestamp = new Date().getTime(); //debug
jQuery.getJSON(RELATIVE_PATH + '/language/en/' + file + '.json?v=' + timestamp, function (language) { files.loading[filename] = true;
loaded[file] = language;
jQuery.getJSON(RELATIVE_PATH + '/language/en/' + filename + '.json?v=' + timestamp, function (language) {
files.loaded[filename] = language;
if (callback) {
callback(language); callback(language);
}
while (files.callbacks[filename] && files.callbacks[filename].length) {
files.callbacks[filename].pop()(language);
}
files.loading[filename] = false;
}); });
} }
}; };
translator.loadAll = function (callback) {
var utils = require('./utils.js'),
path = require('path'),
fs = require('fs');
utils.walk(path.join(__dirname, '../../', 'public/language/en'), function (err, data) {
var loaded = data.length;
for (var d in data) {
if (data.hasOwnProperty(d)) {
(function (file) {
fs.readFile(file, function (err, json) {
files.loaded[path.basename(file).replace('json', '')] = json;
loaded--;
if (loaded === 0) {
callback();
}
});
}(data[d]));
}
}
});
};
/*
* TODO: DRY, see translator.translate. The hard part is to make sure both work node.js / js side
*/
translator.get = function (key) {
var parsedKey = key.split(':'),
languageFile = parsedKey[0];
parsedKey = parsedKey[1];
return files.loaded[languageFile][parsedKey];
};
/*
* TODO: Not fully converted to server side yet, ideally server should be able to parse whole templates on demand if necessary
* fix: translator.load should determine if server side and immediately return appropriate language file.
*/
translator.translate = function (data, callback) { translator.translate = function (data, callback) {
var keys = data.match(/\[\[.*?\]\]/g), var keys = data.match(/\[\[.*?\]\]/g),
loading = 0; loading = 0;
for (var key in keys) { for (var key in keys) {
if (keys.hasOwnProperty(key)) { if (keys.hasOwnProperty(key)) {
var parsedKey = keys[key].replace('[[', '').replace(']]', '').split(':'), var parsedKey = keys[key].replace('[[', '').replace(']]', '').split(':'),
@ -36,8 +99,8 @@
parsedKey = parsedKey[1]; parsedKey = parsedKey[1];
if (loaded[languageFile]) { if (files.loaded[languageFile]) {
data = data.replace(keys[key], loaded[file][parsedKey]); data = data.replace(keys[key], files.loaded[languageFile][parsedKey]);
} else { } else {
loading++; loading++;
@ -51,12 +114,11 @@
} }
} }
}
checkComplete(); checkComplete();
}
function checkComplete() { function checkComplete() {
if (loading === 0) { if (loading === 0) {
callback(data); callback(data);
} }

Loading…
Cancel
Save