Switched to spaces

This commit is contained in:
rr- 2015-06-28 10:07:11 +02:00
parent 79df9b56d3
commit 2702518e31
265 changed files with 14902 additions and 14902 deletions

View file

@ -2,130 +2,130 @@ var App = App || {};
App.API = function(_, jQuery, promise, appState) {
var baseUrl = '/api/';
var AJAX_UNSENT = 0;
var AJAX_OPENED = 1;
var AJAX_HEADERS_RECEIVED = 2;
var AJAX_LOADING = 3;
var AJAX_DONE = 4;
var baseUrl = '/api/';
var AJAX_UNSENT = 0;
var AJAX_OPENED = 1;
var AJAX_HEADERS_RECEIVED = 2;
var AJAX_LOADING = 3;
var AJAX_DONE = 4;
var cache = {};
var cache = {};
function get(url, data) {
return request('GET', url, data);
}
function get(url, data) {
return request('GET', url, data);
}
function post(url, data) {
return request('POST', url, data);
}
function post(url, data) {
return request('POST', url, data);
}
function put(url, data) {
return request('PUT', url, data);
}
function put(url, data) {
return request('PUT', url, data);
}
function _delete(url, data) {
return request('DELETE', url, data);
}
function _delete(url, data) {
return request('DELETE', url, data);
}
function getCacheKey(method, url, data) {
return JSON.stringify({method: method, url: url, data: data});
}
function getCacheKey(method, url, data) {
return JSON.stringify({method: method, url: url, data: data});
}
function clearCache() {
cache = {};
}
function clearCache() {
cache = {};
}
function request(method, url, data) {
if (method === 'GET') {
return requestWithCache(method, url, data);
}
clearCache();
return requestWithAjax(method, url, data);
}
function request(method, url, data) {
if (method === 'GET') {
return requestWithCache(method, url, data);
}
clearCache();
return requestWithAjax(method, url, data);
}
function requestWithCache(method, url, data) {
var cacheKey = getCacheKey(method, url, data);
if (_.has(cache, cacheKey)) {
return promise.make(function(resolve, reject) {
resolve(cache[cacheKey]);
});
}
function requestWithCache(method, url, data) {
var cacheKey = getCacheKey(method, url, data);
if (_.has(cache, cacheKey)) {
return promise.make(function(resolve, reject) {
resolve(cache[cacheKey]);
});
}
return promise.make(function(resolve, reject) {
promise.wait(requestWithAjax(method, url, data))
.then(function(response) {
setCache(method, url, data, response);
resolve(response);
}).fail(function(response) {
reject(response);
});
});
}
return promise.make(function(resolve, reject) {
promise.wait(requestWithAjax(method, url, data))
.then(function(response) {
setCache(method, url, data, response);
resolve(response);
}).fail(function(response) {
reject(response);
});
});
}
function setCache(method, url, data, response) {
var cacheKey = getCacheKey(method, url, data);
cache[cacheKey] = response;
}
function setCache(method, url, data, response) {
var cacheKey = getCacheKey(method, url, data);
cache[cacheKey] = response;
}
function requestWithAjax(method, url, data) {
var fullUrl = baseUrl + '/' + url;
fullUrl = fullUrl.replace(/\/{2,}/, '/');
function requestWithAjax(method, url, data) {
var fullUrl = baseUrl + '/' + url;
fullUrl = fullUrl.replace(/\/{2,}/, '/');
var xhr = null;
var apiPromise = promise.make(function(resolve, reject) {
var options = {
headers: {
'X-Authorization-Token': appState.get('loginToken') || '',
},
success: function(data, textStatus, xhr) {
resolve({
status: xhr.status,
json: stripMeta(data)});
},
error: function(xhr, textStatus, errorThrown) {
reject({
status: xhr.status,
json: xhr.responseJSON ?
stripMeta(xhr.responseJSON) :
{error: errorThrown}});
},
type: method,
url: fullUrl,
data: data,
cache: false,
};
if (data instanceof FormData) {
options.processData = false;
options.contentType = false;
}
xhr = jQuery.ajax(options);
});
apiPromise.xhr = xhr;
return apiPromise;
}
var xhr = null;
var apiPromise = promise.make(function(resolve, reject) {
var options = {
headers: {
'X-Authorization-Token': appState.get('loginToken') || '',
},
success: function(data, textStatus, xhr) {
resolve({
status: xhr.status,
json: stripMeta(data)});
},
error: function(xhr, textStatus, errorThrown) {
reject({
status: xhr.status,
json: xhr.responseJSON ?
stripMeta(xhr.responseJSON) :
{error: errorThrown}});
},
type: method,
url: fullUrl,
data: data,
cache: false,
};
if (data instanceof FormData) {
options.processData = false;
options.contentType = false;
}
xhr = jQuery.ajax(options);
});
apiPromise.xhr = xhr;
return apiPromise;
}
function stripMeta(data) {
var result = {};
_.each(data, function(v, k) {
if (!k.match(/^__/)) {
result[k] = v;
}
});
return result;
}
function stripMeta(data) {
var result = {};
_.each(data, function(v, k) {
if (!k.match(/^__/)) {
result[k] = v;
}
});
return result;
}
return {
get: get,
post: post,
put: put,
delete: _delete,
return {
get: get,
post: post,
put: put,
delete: _delete,
AJAX_UNSENT: AJAX_UNSENT,
AJAX_OPENED: AJAX_OPENED,
AJAX_HEADERS_RECEIVED: AJAX_HEADERS_RECEIVED,
AJAX_LOADING: AJAX_LOADING,
AJAX_DONE: AJAX_DONE,
};
AJAX_UNSENT: AJAX_UNSENT,
AJAX_OPENED: AJAX_OPENED,
AJAX_HEADERS_RECEIVED: AJAX_HEADERS_RECEIVED,
AJAX_LOADING: AJAX_LOADING,
AJAX_DONE: AJAX_DONE,
};
};

View file

@ -2,198 +2,198 @@ var App = App || {};
App.Auth = function(_, jQuery, util, api, appState, promise) {
var privileges = {
register: 'register',
listUsers: 'listUsers',
viewUsers: 'viewUsers',
viewAllAccessRanks: 'viewAllAccessRanks',
viewAllEmailAddresses: 'viewAllEmailAddresses',
changeAccessRank: 'changeAccessRank',
changeOwnAvatarStyle: 'changeOwnAvatarStyle',
changeOwnEmailAddress: 'changeOwnEmailAddress',
changeOwnName: 'changeOwnName',
changeOwnPassword: 'changeOwnPassword',
changeAllAvatarStyles: 'changeAllAvatarStyles',
changeAllEmailAddresses: 'changeAllEmailAddresses',
changeAllNames: 'changeAllNames',
changeAllPasswords: 'changeAllPasswords',
deleteOwnAccount: 'deleteOwnAccount',
deleteAllAccounts: 'deleteAllAccounts',
banUsers: 'banUsers',
var privileges = {
register: 'register',
listUsers: 'listUsers',
viewUsers: 'viewUsers',
viewAllAccessRanks: 'viewAllAccessRanks',
viewAllEmailAddresses: 'viewAllEmailAddresses',
changeAccessRank: 'changeAccessRank',
changeOwnAvatarStyle: 'changeOwnAvatarStyle',
changeOwnEmailAddress: 'changeOwnEmailAddress',
changeOwnName: 'changeOwnName',
changeOwnPassword: 'changeOwnPassword',
changeAllAvatarStyles: 'changeAllAvatarStyles',
changeAllEmailAddresses: 'changeAllEmailAddresses',
changeAllNames: 'changeAllNames',
changeAllPasswords: 'changeAllPasswords',
deleteOwnAccount: 'deleteOwnAccount',
deleteAllAccounts: 'deleteAllAccounts',
banUsers: 'banUsers',
listPosts: 'listPosts',
viewPosts: 'viewPosts',
uploadPosts: 'uploadPosts',
uploadPostsAnonymously: 'uploadPostsAnonymously',
deletePosts: 'deletePosts',
featurePosts: 'featurePosts',
changePostSafety: 'changePostSafety',
changePostSource: 'changePostSource',
changePostTags: 'changePostTags',
changePostContent: 'changePostContent',
changePostThumbnail: 'changePostThumbnail',
changePostRelations: 'changePostRelations',
changePostFlags: 'changePostFlags',
listPosts: 'listPosts',
viewPosts: 'viewPosts',
uploadPosts: 'uploadPosts',
uploadPostsAnonymously: 'uploadPostsAnonymously',
deletePosts: 'deletePosts',
featurePosts: 'featurePosts',
changePostSafety: 'changePostSafety',
changePostSource: 'changePostSource',
changePostTags: 'changePostTags',
changePostContent: 'changePostContent',
changePostThumbnail: 'changePostThumbnail',
changePostRelations: 'changePostRelations',
changePostFlags: 'changePostFlags',
addPostNotes: 'addPostNotes',
editPostNotes: 'editPostNotes',
deletePostNotes: 'deletePostNotes',
addPostNotes: 'addPostNotes',
editPostNotes: 'editPostNotes',
deletePostNotes: 'deletePostNotes',
listComments: 'listComments',
addComments: 'addComments',
editOwnComments: 'editOwnComments',
editAllComments: 'editAllComments',
deleteOwnComments: 'deleteOwnComments',
deleteAllComments: 'deleteAllComments',
deleteTags: 'deleteTags',
mergeTags: 'mergeTags',
listComments: 'listComments',
addComments: 'addComments',
editOwnComments: 'editOwnComments',
editAllComments: 'editAllComments',
deleteOwnComments: 'deleteOwnComments',
deleteAllComments: 'deleteAllComments',
deleteTags: 'deleteTags',
mergeTags: 'mergeTags',
listTags: 'listTags',
massTag: 'massTag',
changeTagName: 'changeTagName',
changeTagCategory: 'changeTagCategory',
changeTagImplications: 'changeTagImplications',
changeTagSuggestions: 'changeTagSuggestions',
banTags: 'banTags',
listTags: 'listTags',
massTag: 'massTag',
changeTagName: 'changeTagName',
changeTagCategory: 'changeTagCategory',
changeTagImplications: 'changeTagImplications',
changeTagSuggestions: 'changeTagSuggestions',
banTags: 'banTags',
viewHistory: 'viewHistory',
};
viewHistory: 'viewHistory',
};
function loginFromCredentials(userNameOrEmail, password, remember) {
return promise.make(function(resolve, reject) {
promise.wait(api.post('/login', {userNameOrEmail: userNameOrEmail, password: password}))
.then(function(response) {
updateAppState(response);
jQuery.cookie(
'auth',
response.json.token.name,
remember ? { expires: 365 } : {});
resolve(response);
}).fail(function(response) {
reject(response);
});
});
}
function loginFromCredentials(userNameOrEmail, password, remember) {
return promise.make(function(resolve, reject) {
promise.wait(api.post('/login', {userNameOrEmail: userNameOrEmail, password: password}))
.then(function(response) {
updateAppState(response);
jQuery.cookie(
'auth',
response.json.token.name,
remember ? { expires: 365 } : {});
resolve(response);
}).fail(function(response) {
reject(response);
});
});
}
function loginFromToken(token, isFromCookie) {
return promise.make(function(resolve, reject) {
var fd = {
token: token,
isFromCookie: isFromCookie
};
promise.wait(api.post('/login', fd))
.then(function(response) {
updateAppState(response);
resolve(response);
}).fail(function(response) {
reject(response);
});
});
}
function loginFromToken(token, isFromCookie) {
return promise.make(function(resolve, reject) {
var fd = {
token: token,
isFromCookie: isFromCookie
};
promise.wait(api.post('/login', fd))
.then(function(response) {
updateAppState(response);
resolve(response);
}).fail(function(response) {
reject(response);
});
});
}
function loginAnonymous() {
return promise.make(function(resolve, reject) {
promise.wait(api.post('/login'))
.then(function(response) {
updateAppState(response);
resolve(response);
}).fail(function(response) {
reject(response);
});
});
}
function loginAnonymous() {
return promise.make(function(resolve, reject) {
promise.wait(api.post('/login'))
.then(function(response) {
updateAppState(response);
resolve(response);
}).fail(function(response) {
reject(response);
});
});
}
function logout() {
return promise.make(function(resolve, reject) {
jQuery.removeCookie('auth');
appState.set('loginToken', null);
return promise.wait(loginAnonymous())
.then(resolve)
.fail(reject);
});
}
function logout() {
return promise.make(function(resolve, reject) {
jQuery.removeCookie('auth');
appState.set('loginToken', null);
return promise.wait(loginAnonymous())
.then(resolve)
.fail(reject);
});
}
function tryLoginFromCookie() {
return promise.make(function(resolve, reject) {
if (isLoggedIn()) {
resolve();
return;
}
function tryLoginFromCookie() {
return promise.make(function(resolve, reject) {
if (isLoggedIn()) {
resolve();
return;
}
var authCookie = jQuery.cookie('auth');
if (!authCookie) {
reject();
return;
}
var authCookie = jQuery.cookie('auth');
if (!authCookie) {
reject();
return;
}
promise.wait(loginFromToken(authCookie, true))
.then(function(response) {
resolve();
}).fail(function(response) {
jQuery.removeCookie('auth');
reject();
});
});
}
promise.wait(loginFromToken(authCookie, true))
.then(function(response) {
resolve();
}).fail(function(response) {
jQuery.removeCookie('auth');
reject();
});
});
}
function updateAppState(response) {
appState.set('privileges', response.json.privileges || []);
appState.set('loginToken', response.json.token && response.json.token.name);
appState.set('loggedIn', response.json.user && !!response.json.user.id);
appState.set('loggedInUser', response.json.user);
}
function updateAppState(response) {
appState.set('privileges', response.json.privileges || []);
appState.set('loginToken', response.json.token && response.json.token.name);
appState.set('loggedIn', response.json.user && !!response.json.user.id);
appState.set('loggedInUser', response.json.user);
}
function isLoggedIn(userName) {
if (!appState.get('loggedIn')) {
return false;
}
if (typeof(userName) !== 'undefined') {
if (getCurrentUser().name !== userName) {
return false;
}
}
return true;
}
function isLoggedIn(userName) {
if (!appState.get('loggedIn')) {
return false;
}
if (typeof(userName) !== 'undefined') {
if (getCurrentUser().name !== userName) {
return false;
}
}
return true;
}
function getCurrentUser() {
return appState.get('loggedInUser');
}
function getCurrentUser() {
return appState.get('loggedInUser');
}
function getCurrentPrivileges() {
return appState.get('privileges');
}
function getCurrentPrivileges() {
return appState.get('privileges');
}
function updateCurrentUser(user) {
if (user.id !== getCurrentUser().id) {
throw new Error('Cannot set current user to other user this way.');
}
appState.set('loggedInUser', user);
}
function updateCurrentUser(user) {
if (user.id !== getCurrentUser().id) {
throw new Error('Cannot set current user to other user this way.');
}
appState.set('loggedInUser', user);
}
function hasPrivilege(privilege) {
return _.contains(getCurrentPrivileges(), privilege);
}
function hasPrivilege(privilege) {
return _.contains(getCurrentPrivileges(), privilege);
}
function startObservingLoginChanges(listenerName, callback) {
appState.startObserving('loggedInUser', listenerName, callback);
}
function startObservingLoginChanges(listenerName, callback) {
appState.startObserving('loggedInUser', listenerName, callback);
}
return {
loginFromCredentials: loginFromCredentials,
loginFromToken: loginFromToken,
loginAnonymous: loginAnonymous,
tryLoginFromCookie: tryLoginFromCookie,
logout: logout,
return {
loginFromCredentials: loginFromCredentials,
loginFromToken: loginFromToken,
loginAnonymous: loginAnonymous,
tryLoginFromCookie: tryLoginFromCookie,
logout: logout,
startObservingLoginChanges: startObservingLoginChanges,
isLoggedIn: isLoggedIn,
getCurrentUser: getCurrentUser,
updateCurrentUser: updateCurrentUser,
getCurrentPrivileges: getCurrentPrivileges,
hasPrivilege: hasPrivilege,
startObservingLoginChanges: startObservingLoginChanges,
isLoggedIn: isLoggedIn,
getCurrentUser: getCurrentUser,
updateCurrentUser: updateCurrentUser,
getCurrentPrivileges: getCurrentPrivileges,
hasPrivilege: hasPrivilege,
privileges: privileges,
};
privileges: privileges,
};
};

View file

@ -2,29 +2,29 @@ var App = App || {};
App.Bootstrap = function(auth, router, promise, presenterManager) {
promise.wait(presenterManager.init())
.then(function() {
promise.wait(auth.tryLoginFromCookie())
.then(startRouting)
.fail(function(error) {
promise.wait(auth.loginAnonymous())
.then(startRouting)
.fail(function() {
console.log(arguments);
window.alert('Fatal authentication error');
});
});
}).fail(function() {
console.log(arguments);
});
promise.wait(presenterManager.init())
.then(function() {
promise.wait(auth.tryLoginFromCookie())
.then(startRouting)
.fail(function(error) {
promise.wait(auth.loginAnonymous())
.then(startRouting)
.fail(function() {
console.log(arguments);
window.alert('Fatal authentication error');
});
});
}).fail(function() {
console.log(arguments);
});
function startRouting() {
try {
router.start();
} catch (err) {
console.log(err);
}
}
function startRouting() {
try {
router.start();
} catch (err) {
console.log(err);
}
}
};

View file

@ -1,96 +1,96 @@
var App = App || {};
App.BrowsingSettings = function(
promise,
auth,
api) {
promise,
auth,
api) {
var settings = getDefaultSettings();
var settings = getDefaultSettings();
auth.startObservingLoginChanges('browsing-settings', loginStateChanged);
auth.startObservingLoginChanges('browsing-settings', loginStateChanged);
readFromLocalStorage();
if (auth.isLoggedIn()) {
loginStateChanged();
}
readFromLocalStorage();
if (auth.isLoggedIn()) {
loginStateChanged();
}
function setSettings(newSettings) {
settings = newSettings;
return save();
}
function setSettings(newSettings) {
settings = newSettings;
return save();
}
function getSettings() {
return settings;
}
function getSettings() {
return settings;
}
function getDefaultSettings() {
return {
hideDownvoted: true,
endlessScroll: false,
listPosts: {
safe: true,
sketchy: true,
unsafe: true,
},
keyboardShortcuts: true,
};
}
function getDefaultSettings() {
return {
hideDownvoted: true,
endlessScroll: false,
listPosts: {
safe: true,
sketchy: true,
unsafe: true,
},
keyboardShortcuts: true,
};
}
function loginStateChanged() {
readFromUser(auth.getCurrentUser());
}
function loginStateChanged() {
readFromUser(auth.getCurrentUser());
}
function readFromLocalStorage() {
readFromString(localStorage.getItem('browsingSettings'));
}
function readFromLocalStorage() {
readFromString(localStorage.getItem('browsingSettings'));
}
function readFromUser(user) {
readFromString(user.browsingSettings);
}
function readFromUser(user) {
readFromString(user.browsingSettings);
}
function readFromString(string) {
if (!string) {
return;
}
function readFromString(string) {
if (!string) {
return;
}
try {
if (typeof(string) === 'string' || string instanceof String) {
settings = JSON.parse(string);
} else {
settings = string;
}
} catch (e) {
}
}
try {
if (typeof(string) === 'string' || string instanceof String) {
settings = JSON.parse(string);
} else {
settings = string;
}
} catch (e) {
}
}
function saveToLocalStorage() {
localStorage.setItem('browsingSettings', JSON.stringify(settings));
}
function saveToLocalStorage() {
localStorage.setItem('browsingSettings', JSON.stringify(settings));
}
function saveToUser(user) {
var formData = {
browsingSettings: JSON.stringify(settings),
};
return api.post('/users/' + user.name, formData);
}
function saveToUser(user) {
var formData = {
browsingSettings: JSON.stringify(settings),
};
return api.post('/users/' + user.name, formData);
}
function save() {
return promise.make(function(resolve, reject) {
saveToLocalStorage();
if (auth.isLoggedIn()) {
promise.wait(saveToUser(auth.getCurrentUser()))
.then(resolve)
.fail(reject);
} else {
resolve();
}
});
}
function save() {
return promise.make(function(resolve, reject) {
saveToLocalStorage();
if (auth.isLoggedIn()) {
promise.wait(saveToUser(auth.getCurrentUser()))
.then(resolve)
.fail(reject);
} else {
resolve();
}
});
}
return {
getSettings: getSettings,
setSettings: setSettings,
};
return {
getSettings: getSettings,
setSettings: setSettings,
};
};

View file

@ -2,273 +2,273 @@ var App = App || {};
App.Controls = App.Controls || {};
App.Controls.AutoCompleteInput = function($input) {
var _ = App.DI.get('_');
var jQuery = App.DI.get('jQuery');
var tagList = App.DI.get('tagList');
var _ = App.DI.get('_');
var jQuery = App.DI.get('jQuery');
var tagList = App.DI.get('tagList');
var KEY_TAB = 9;
var KEY_RETURN = 13;
var KEY_DELETE = 46;
var KEY_ESCAPE = 27;
var KEY_UP = 38;
var KEY_DOWN = 40;
var KEY_TAB = 9;
var KEY_RETURN = 13;
var KEY_DELETE = 46;
var KEY_ESCAPE = 27;
var KEY_UP = 38;
var KEY_DOWN = 40;
var options = {
caseSensitive: false,
source: null,
maxResults: 15,
minLengthToArbitrarySearch: 3,
onApply: null,
onDelete: null,
onRender: null,
additionalFilter: null,
};
var showTimeout = null;
var cachedSource = null;
var results = [];
var activeResult = -1;
var monitorInputHidingInterval = null;
var options = {
caseSensitive: false,
source: null,
maxResults: 15,
minLengthToArbitrarySearch: 3,
onApply: null,
onDelete: null,
onRender: null,
additionalFilter: null,
};
var showTimeout = null;
var cachedSource = null;
var results = [];
var activeResult = -1;
var monitorInputHidingInterval = null;
if ($input.length === 0) {
throw new Error('Input element was not found');
}
if ($input.length > 1) {
throw new Error('Cannot add autocompletion to more than one element at once');
}
if ($input.attr('data-autocomplete')) {
throw new Error('Autocompletion was already added for this element');
}
$input.attr('data-autocomplete', true);
$input.attr('autocomplete', 'off');
if ($input.length === 0) {
throw new Error('Input element was not found');
}
if ($input.length > 1) {
throw new Error('Cannot add autocompletion to more than one element at once');
}
if ($input.attr('data-autocomplete')) {
throw new Error('Autocompletion was already added for this element');
}
$input.attr('data-autocomplete', true);
$input.attr('autocomplete', 'off');
var $div = jQuery('<div>');
var $list = jQuery('<ul>');
$div.addClass('autocomplete');
$div.append($list);
jQuery(document.body).append($div);
var $div = jQuery('<div>');
var $list = jQuery('<ul>');
$div.addClass('autocomplete');
$div.append($list);
jQuery(document.body).append($div);
function getSource() {
if (cachedSource) {
return cachedSource;
} else {
var source = tagList.getTags();
source = _.sortBy(source, function(a) { return -a.usages; });
source = _.filter(source, function(a) { return a.usages >= 0; });
source = _.map(source, function(a) {
return {
tag: a.name,
caption: a.name + ' (' + a.usages + ')',
};
});
cachedSource = source;
return source;
}
}
function getSource() {
if (cachedSource) {
return cachedSource;
} else {
var source = tagList.getTags();
source = _.sortBy(source, function(a) { return -a.usages; });
source = _.filter(source, function(a) { return a.usages >= 0; });
source = _.map(source, function(a) {
return {
tag: a.name,
caption: a.name + ' (' + a.usages + ')',
};
});
cachedSource = source;
return source;
}
}
$input.bind('keydown', function(e) {
var func = null;
if (isShown() && e.which === KEY_ESCAPE) {
func = hide;
} else if (isShown() && e.which === KEY_TAB) {
if (e.shiftKey) {
func = selectPrevious;
} else {
func = selectNext;
}
} else if (isShown() && e.which === KEY_DOWN) {
func = selectNext;
} else if (isShown() && e.which === KEY_UP) {
func = selectPrevious;
} else if (isShown() && e.which === KEY_RETURN && activeResult >= 0) {
func = function() { applyAutocomplete(); hide(); };
} else if (isShown() && e.which === KEY_DELETE && activeResult >= 0) {
func = function() { applyDelete(); hide(); };
}
$input.bind('keydown', function(e) {
var func = null;
if (isShown() && e.which === KEY_ESCAPE) {
func = hide;
} else if (isShown() && e.which === KEY_TAB) {
if (e.shiftKey) {
func = selectPrevious;
} else {
func = selectNext;
}
} else if (isShown() && e.which === KEY_DOWN) {
func = selectNext;
} else if (isShown() && e.which === KEY_UP) {
func = selectPrevious;
} else if (isShown() && e.which === KEY_RETURN && activeResult >= 0) {
func = function() { applyAutocomplete(); hide(); };
} else if (isShown() && e.which === KEY_DELETE && activeResult >= 0) {
func = function() { applyDelete(); hide(); };
}
if (func !== null) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
func();
} else {
window.clearTimeout(showTimeout);
showTimeout = window.setTimeout(showOrHide, 250);
}
});
if (func !== null) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
func();
} else {
window.clearTimeout(showTimeout);
showTimeout = window.setTimeout(showOrHide, 250);
}
});
$input.blur(function(e) {
window.clearTimeout(showTimeout);
window.setTimeout(function() { hide(); }, 50);
});
$input.blur(function(e) {
window.clearTimeout(showTimeout);
window.setTimeout(function() { hide(); }, 50);
});
function getSelectionStart(){
var input = $input.get(0);
if (!input) {
return;
}
if ('selectionStart' in input) {
return input.selectionStart;
} else if (document.selection) {
input.focus();
var sel = document.selection.createRange();
var selLen = document.selection.createRange().text.length;
sel.moveStart('character', -input.value.length);
return sel.text.length - selLen;
} else {
return 0;
}
}
function getSelectionStart(){
var input = $input.get(0);
if (!input) {
return;
}
if ('selectionStart' in input) {
return input.selectionStart;
} else if (document.selection) {
input.focus();
var sel = document.selection.createRange();
var selLen = document.selection.createRange().text.length;
sel.moveStart('character', -input.value.length);
return sel.text.length - selLen;
} else {
return 0;
}
}
function getTextToFind() {
var val = $input.val();
var start = getSelectionStart();
return val.substring(0, start).replace(/.*\s/, '');
}
function getTextToFind() {
var val = $input.val();
var start = getSelectionStart();
return val.substring(0, start).replace(/.*\s/, '');
}
function showOrHide() {
var textToFind = getTextToFind();
if (textToFind.length === 0) {
hide();
} else {
updateResults(textToFind);
refreshList();
}
}
function showOrHide() {
var textToFind = getTextToFind();
if (textToFind.length === 0) {
hide();
} else {
updateResults(textToFind);
refreshList();
}
}
function isShown() {
return $div.is(':visible');
}
function isShown() {
return $div.is(':visible');
}
function hide() {
$div.hide();
window.clearInterval(monitorInputHidingInterval);
}
function hide() {
$div.hide();
window.clearInterval(monitorInputHidingInterval);
}
function selectPrevious() {
select(activeResult === -1 ? results.length - 1 : activeResult - 1);
}
function selectPrevious() {
select(activeResult === -1 ? results.length - 1 : activeResult - 1);
}
function selectNext() {
select(activeResult === -1 ? 0 : activeResult + 1);
}
function selectNext() {
select(activeResult === -1 ? 0 : activeResult + 1);
}
function select(newActiveResult) {
if (newActiveResult >= 0 && newActiveResult < results.length) {
activeResult = newActiveResult;
refreshActiveResult();
} else {
activeResult = - 1;
refreshActiveResult();
}
}
function select(newActiveResult) {
if (newActiveResult >= 0 && newActiveResult < results.length) {
activeResult = newActiveResult;
refreshActiveResult();
} else {
activeResult = - 1;
refreshActiveResult();
}
}
function getResultsFilter(textToFind) {
if (textToFind.length < options.minLengthToArbitrarySearch) {
return options.caseSensitive ?
function(resultItem) { return resultItem.tag.indexOf(textToFind) === 0; } :
function(resultItem) { return resultItem.tag.toLowerCase().indexOf(textToFind.toLowerCase()) === 0; };
} else {
return options.caseSensitive ?
function(resultItem) { return resultItem.tag.indexOf(textToFind) >= 0; } :
function(resultItem) { return resultItem.tag.toLowerCase().indexOf(textToFind.toLowerCase()) >= 0; };
}
}
function getResultsFilter(textToFind) {
if (textToFind.length < options.minLengthToArbitrarySearch) {
return options.caseSensitive ?
function(resultItem) { return resultItem.tag.indexOf(textToFind) === 0; } :
function(resultItem) { return resultItem.tag.toLowerCase().indexOf(textToFind.toLowerCase()) === 0; };
} else {
return options.caseSensitive ?
function(resultItem) { return resultItem.tag.indexOf(textToFind) >= 0; } :
function(resultItem) { return resultItem.tag.toLowerCase().indexOf(textToFind.toLowerCase()) >= 0; };
}
}
function updateResults(textToFind) {
var oldResults = results.slice();
var source = getSource();
var filter = getResultsFilter(textToFind);
results = _.filter(source, filter);
if (options.additionalFilter) {
results = options.additionalFilter(results);
}
results = results.slice(0, options.maxResults);
if (!_.isEqual(oldResults, results)) {
activeResult = -1;
}
}
function updateResults(textToFind) {
var oldResults = results.slice();
var source = getSource();
var filter = getResultsFilter(textToFind);
results = _.filter(source, filter);
if (options.additionalFilter) {
results = options.additionalFilter(results);
}
results = results.slice(0, options.maxResults);
if (!_.isEqual(oldResults, results)) {
activeResult = -1;
}
}
function applyDelete() {
if (options.onDelete) {
options.onDelete(results[activeResult].tag);
}
}
function applyDelete() {
if (options.onDelete) {
options.onDelete(results[activeResult].tag);
}
}
function applyAutocomplete() {
if (options.onApply) {
options.onApply(results[activeResult].tag);
} else {
var val = $input.val();
var start = getSelectionStart();
var prefix = '';
var suffix = val.substring(start);
var middle = val.substring(0, start);
var index = middle.lastIndexOf(' ');
if (index !== -1) {
prefix = val.substring(0, index + 1);
middle = val.substring(index + 1);
}
$input.val(prefix + results[activeResult].tag + ' ' + suffix.trimLeft());
$input.focus();
}
}
function applyAutocomplete() {
if (options.onApply) {
options.onApply(results[activeResult].tag);
} else {
var val = $input.val();
var start = getSelectionStart();
var prefix = '';
var suffix = val.substring(start);
var middle = val.substring(0, start);
var index = middle.lastIndexOf(' ');
if (index !== -1) {
prefix = val.substring(0, index + 1);
middle = val.substring(index + 1);
}
$input.val(prefix + results[activeResult].tag + ' ' + suffix.trimLeft());
$input.focus();
}
}
function refreshList() {
if (results.length === 0) {
hide();
return;
}
function refreshList() {
if (results.length === 0) {
hide();
return;
}
$list.empty();
_.each(results, function(resultItem, resultIndex) {
var $listItem = jQuery('<li/>');
$listItem.text(resultItem.caption);
$listItem.attr('data-key', resultItem.tag);
$listItem.hover(function(e) {
e.preventDefault();
activeResult = resultIndex;
refreshActiveResult();
});
$listItem.mousedown(function(e) {
e.preventDefault();
activeResult = resultIndex;
applyAutocomplete();
hide();
});
$list.append($listItem);
});
if (options.onRender) {
options.onRender($list);
}
refreshActiveResult();
$list.empty();
_.each(results, function(resultItem, resultIndex) {
var $listItem = jQuery('<li/>');
$listItem.text(resultItem.caption);
$listItem.attr('data-key', resultItem.tag);
$listItem.hover(function(e) {
e.preventDefault();
activeResult = resultIndex;
refreshActiveResult();
});
$listItem.mousedown(function(e) {
e.preventDefault();
activeResult = resultIndex;
applyAutocomplete();
hide();
});
$list.append($listItem);
});
if (options.onRender) {
options.onRender($list);
}
refreshActiveResult();
var x = $input.offset().left;
var y = $input.offset().top + $input.outerHeight() - 2;
if (y + $div.height() > window.innerHeight) {
y = $input.offset().top - $div.height();
}
$div.css({
left: x + 'px',
top: y + 'px',
});
$div.show();
monitorInputHiding();
}
var x = $input.offset().left;
var y = $input.offset().top + $input.outerHeight() - 2;
if (y + $div.height() > window.innerHeight) {
y = $input.offset().top - $div.height();
}
$div.css({
left: x + 'px',
top: y + 'px',
});
$div.show();
monitorInputHiding();
}
function refreshActiveResult() {
$list.find('li.active').removeClass('active');
if (activeResult >= 0) {
$list.find('li').eq(activeResult).addClass('active');
}
}
function refreshActiveResult() {
$list.find('li.active').removeClass('active');
if (activeResult >= 0) {
$list.find('li').eq(activeResult).addClass('active');
}
}
function monitorInputHiding() {
monitorInputHidingInterval = window.setInterval(function() {
if (!$input.is(':visible')) {
hide();
}
}, 100);
}
function monitorInputHiding() {
monitorInputHidingInterval = window.setInterval(function() {
if (!$input.is(':visible')) {
hide();
}
}, 100);
}
return options;
return options;
};

View file

@ -2,64 +2,64 @@ var App = App || {};
App.Controls = App.Controls || {};
App.Controls.FileDropper = function($fileInput) {
var _ = App.DI.get('_');
var jQuery = App.DI.get('jQuery');
var _ = App.DI.get('_');
var jQuery = App.DI.get('jQuery');
var options = {
onChange: null,
setNames: false,
};
var options = {
onChange: null,
setNames: false,
};
var $dropDiv = jQuery('<button type="button" class="file-handler"></button>');
var allowMultiple = $fileInput.attr('multiple');
$dropDiv.html((allowMultiple ? 'Drop files here!' : 'Drop file here!') + '<br/>Or just click on this box.');
$dropDiv.insertBefore($fileInput);
$fileInput.attr('multiple', allowMultiple);
$fileInput.hide();
var $dropDiv = jQuery('<button type="button" class="file-handler"></button>');
var allowMultiple = $fileInput.attr('multiple');
$dropDiv.html((allowMultiple ? 'Drop files here!' : 'Drop file here!') + '<br/>Or just click on this box.');
$dropDiv.insertBefore($fileInput);
$fileInput.attr('multiple', allowMultiple);
$fileInput.hide();
$fileInput.change(function(e) {
addFiles(this.files);
});
$fileInput.change(function(e) {
addFiles(this.files);
});
$dropDiv.on('dragenter', function(e) {
$dropDiv.addClass('active');
}).on('dragleave', function(e) {
$dropDiv.removeClass('active');
}).on('dragover', function(e) {
e.preventDefault();
}).on('drop', function(e) {
e.preventDefault();
addFiles(e.originalEvent.dataTransfer.files);
}).on('click', function(e) {
$fileInput.show().focus().trigger('click').hide();
$dropDiv.addClass('active');
});
$dropDiv.on('dragenter', function(e) {
$dropDiv.addClass('active');
}).on('dragleave', function(e) {
$dropDiv.removeClass('active');
}).on('dragover', function(e) {
e.preventDefault();
}).on('drop', function(e) {
e.preventDefault();
addFiles(e.originalEvent.dataTransfer.files);
}).on('click', function(e) {
$fileInput.show().focus().trigger('click').hide();
$dropDiv.addClass('active');
});
function addFiles(files) {
$dropDiv.removeClass('active');
if (!allowMultiple && files.length > 1) {
window.alert('Cannot select multiple files.');
return;
}
if (typeof(options.onChange) !== 'undefined') {
options.onChange(files);
}
if (options.setNames && !allowMultiple) {
$dropDiv.text(files[0].name);
}
}
function addFiles(files) {
$dropDiv.removeClass('active');
if (!allowMultiple && files.length > 1) {
window.alert('Cannot select multiple files.');
return;
}
if (typeof(options.onChange) !== 'undefined') {
options.onChange(files);
}
if (options.setNames && !allowMultiple) {
$dropDiv.text(files[0].name);
}
}
function readAsDataURL(file, callback) {
var reader = new FileReader();
reader.onloadend = function() {
callback(reader.result);
};
reader.readAsDataURL(file);
}
function readAsDataURL(file, callback) {
var reader = new FileReader();
reader.onloadend = function() {
callback(reader.result);
};
reader.readAsDataURL(file);
}
_.extend(options, {
readAsDataURL: readAsDataURL,
});
_.extend(options, {
readAsDataURL: readAsDataURL,
});
return options;
return options;
};

View file

@ -2,419 +2,419 @@ var App = App || {};
App.Controls = App.Controls || {};
App.Controls.TagInput = function($underlyingInput) {
var _ = App.DI.get('_');
var jQuery = App.DI.get('jQuery');
var promise = App.DI.get('promise');
var api = App.DI.get('api');
var tagList = App.DI.get('tagList');
var _ = App.DI.get('_');
var jQuery = App.DI.get('jQuery');
var promise = App.DI.get('promise');
var api = App.DI.get('api');
var tagList = App.DI.get('tagList');
var KEY_RETURN = 13;
var KEY_SPACE = 32;
var KEY_BACKSPACE = 8;
var tagConfirmKeys = [KEY_RETURN, KEY_SPACE];
var inputConfirmKeys = [KEY_RETURN];
var KEY_RETURN = 13;
var KEY_SPACE = 32;
var KEY_BACKSPACE = 8;
var tagConfirmKeys = [KEY_RETURN, KEY_SPACE];
var inputConfirmKeys = [KEY_RETURN];
var SOURCE_INITIAL_TEXT = 1;
var SOURCE_AUTOCOMPLETION = 2;
var SOURCE_PASTE = 3;
var SOURCE_IMPLICATIONS = 4;
var SOURCE_INPUT_BLUR = 5;
var SOURCE_INPUT_ENTER = 6;
var SOURCE_SUGGESTIONS = 7;
var SOURCE_INITIAL_TEXT = 1;
var SOURCE_AUTOCOMPLETION = 2;
var SOURCE_PASTE = 3;
var SOURCE_IMPLICATIONS = 4;
var SOURCE_INPUT_BLUR = 5;
var SOURCE_INPUT_ENTER = 6;
var SOURCE_SUGGESTIONS = 7;
var tags = [];
var options = {
beforeTagAdded: null,
beforeTagRemoved: null,
inputConfirmed: null,
};
var tags = [];
var options = {
beforeTagAdded: null,
beforeTagRemoved: null,
inputConfirmed: null,
};
var $wrapper = jQuery('<div class="tag-input">');
var $tagList = jQuery('<ul class="tags">');
var tagInputId = 'tags' + Math.random();
var $label = jQuery('<label for="' + tagInputId + '" style="display: none">Tags:</label>');
var $input = jQuery('<input class="tag-real-input" type="text" id="' + tagInputId + '"/>');
var $siblings = jQuery('<div class="related-tags"><span>Sibling tags:</span><ul>');
var $suggestions = jQuery('<div class="related-tags"><span>Suggested tags:</span><ul>');
init();
render();
initAutoComplete();
var $wrapper = jQuery('<div class="tag-input">');
var $tagList = jQuery('<ul class="tags">');
var tagInputId = 'tags' + Math.random();
var $label = jQuery('<label for="' + tagInputId + '" style="display: none">Tags:</label>');
var $input = jQuery('<input class="tag-real-input" type="text" id="' + tagInputId + '"/>');
var $siblings = jQuery('<div class="related-tags"><span>Sibling tags:</span><ul>');
var $suggestions = jQuery('<div class="related-tags"><span>Suggested tags:</span><ul>');
init();
render();
initAutoComplete();
function init() {
if ($underlyingInput.length === 0) {
throw new Error('Tag input element was not found');
}
if ($underlyingInput.length > 1) {
throw new Error('Cannot set tag input to more than one element at once');
}
if ($underlyingInput.attr('data-tagged')) {
throw new Error('Tag input was already initialized for this element');
}
$underlyingInput.attr('data-tagged', true);
}
function init() {
if ($underlyingInput.length === 0) {
throw new Error('Tag input element was not found');
}
if ($underlyingInput.length > 1) {
throw new Error('Cannot set tag input to more than one element at once');
}
if ($underlyingInput.attr('data-tagged')) {
throw new Error('Tag input was already initialized for this element');
}
$underlyingInput.attr('data-tagged', true);
}
function render() {
$underlyingInput.hide();
$wrapper.append($tagList);
$wrapper.append($label);
$wrapper.append($input);
$wrapper.insertAfter($underlyingInput);
$wrapper.click(function(e) {
if (e.target.nodeName === 'LI') {
return;
}
e.preventDefault();
$input.focus();
});
$input.attr('placeholder', $underlyingInput.attr('placeholder'));
$siblings.insertAfter($wrapper);
$suggestions.insertAfter($wrapper);
function render() {
$underlyingInput.hide();
$wrapper.append($tagList);
$wrapper.append($label);
$wrapper.append($input);
$wrapper.insertAfter($underlyingInput);
$wrapper.click(function(e) {
if (e.target.nodeName === 'LI') {
return;
}
e.preventDefault();
$input.focus();
});
$input.attr('placeholder', $underlyingInput.attr('placeholder'));
$siblings.insertAfter($wrapper);
$suggestions.insertAfter($wrapper);
processText($underlyingInput.val(), SOURCE_INITIAL_TEXT);
processText($underlyingInput.val(), SOURCE_INITIAL_TEXT);
$underlyingInput.val('');
}
$underlyingInput.val('');
}
function initAutoComplete() {
var autoComplete = new App.Controls.AutoCompleteInput($input);
autoComplete.onDelete = function(text) {
removeTag(text);
$input.val('');
};
autoComplete.onApply = function(text) {
processText(text, SOURCE_AUTOCOMPLETION);
$input.val('');
};
autoComplete.additionalFilter = function(results) {
return _.filter(results, function(resultItem) {
return !_.contains(getTags(), resultItem[0]);
});
};
autoComplete.onRender = function($list) {
$list.find('li').each(function() {
var $li = jQuery(this);
if (isTaggedWith($li.attr('data-key'))) {
$li.css('opacity', '0.5');
}
});
};
}
function initAutoComplete() {
var autoComplete = new App.Controls.AutoCompleteInput($input);
autoComplete.onDelete = function(text) {
removeTag(text);
$input.val('');
};
autoComplete.onApply = function(text) {
processText(text, SOURCE_AUTOCOMPLETION);
$input.val('');
};
autoComplete.additionalFilter = function(results) {
return _.filter(results, function(resultItem) {
return !_.contains(getTags(), resultItem[0]);
});
};
autoComplete.onRender = function($list) {
$list.find('li').each(function() {
var $li = jQuery(this);
if (isTaggedWith($li.attr('data-key'))) {
$li.css('opacity', '0.5');
}
});
};
}
$input.bind('focus', function(e) {
$wrapper.addClass('focused');
});
$input.bind('blur', function(e) {
$wrapper.removeClass('focused');
var tagName = $input.val();
addTag(tagName, SOURCE_INPUT_BLUR);
$input.val('');
});
$input.bind('focus', function(e) {
$wrapper.addClass('focused');
});
$input.bind('blur', function(e) {
$wrapper.removeClass('focused');
var tagName = $input.val();
addTag(tagName, SOURCE_INPUT_BLUR);
$input.val('');
});
$input.bind('paste', function(e) {
e.preventDefault();
var pastedText;
if (window.clipboardData) {
pastedText = window.clipboardData.getData('Text');
} else {
pastedText = (e.originalEvent || e).clipboardData.getData('text/plain');
}
$input.bind('paste', function(e) {
e.preventDefault();
var pastedText;
if (window.clipboardData) {
pastedText = window.clipboardData.getData('Text');
} else {
pastedText = (e.originalEvent || e).clipboardData.getData('text/plain');
}
if (pastedText.length > 2000) {
window.alert('Pasted text is too long.');
return;
}
if (pastedText.length > 2000) {
window.alert('Pasted text is too long.');
return;
}
processTextWithoutLast(pastedText, SOURCE_PASTE);
});
processTextWithoutLast(pastedText, SOURCE_PASTE);
});
$input.bind('keydown', function(e) {
if (_.contains(inputConfirmKeys, e.which) && !$input.val()) {
e.preventDefault();
if (typeof(options.inputConfirmed) !== 'undefined') {
options.inputConfirmed();
}
} else if (_.contains(tagConfirmKeys, e.which)) {
var tagName = $input.val();
e.preventDefault();
$input.val('');
addTag(tagName, SOURCE_INPUT_ENTER);
} else if (e.which === KEY_BACKSPACE && jQuery(this).val().length === 0) {
e.preventDefault();
removeLastTag();
}
});
$input.bind('keydown', function(e) {
if (_.contains(inputConfirmKeys, e.which) && !$input.val()) {
e.preventDefault();
if (typeof(options.inputConfirmed) !== 'undefined') {
options.inputConfirmed();
}
} else if (_.contains(tagConfirmKeys, e.which)) {
var tagName = $input.val();
e.preventDefault();
$input.val('');
addTag(tagName, SOURCE_INPUT_ENTER);
} else if (e.which === KEY_BACKSPACE && jQuery(this).val().length === 0) {
e.preventDefault();
removeLastTag();
}
});
function explodeText(text) {
return _.filter(text.trim().split(/\s+/), function(item) {
return item.length > 0;
});
}
function explodeText(text) {
return _.filter(text.trim().split(/\s+/), function(item) {
return item.length > 0;
});
}
function processText(text, source) {
var tagNamesToAdd = explodeText(text);
_.map(tagNamesToAdd, function(tagName) { addTag(tagName, source); });
}
function processText(text, source) {
var tagNamesToAdd = explodeText(text);
_.map(tagNamesToAdd, function(tagName) { addTag(tagName, source); });
}
function processTextWithoutLast(text, source) {
var tagNamesToAdd = explodeText(text);
var lastTagName = tagNamesToAdd.pop();
_.map(tagNamesToAdd, function(tagName) { addTag(tagName, source); });
$input.val(lastTagName);
}
function processTextWithoutLast(text, source) {
var tagNamesToAdd = explodeText(text);
var lastTagName = tagNamesToAdd.pop();
_.map(tagNamesToAdd, function(tagName) { addTag(tagName, source); });
$input.val(lastTagName);
}
function addTag(tagName, source) {
tagName = tagName.trim();
if (tagName.length === 0) {
return;
}
function addTag(tagName, source) {
tagName = tagName.trim();
if (tagName.length === 0) {
return;
}
if (tagName.length > 64) {
//showing alert inside keydown event leads to mysterious behaviors
//in some browsers, hence the timeout
window.setTimeout(function() {
window.alert('Tag is too long.');
}, 10);
return;
}
if (tagName.length > 64) {
//showing alert inside keydown event leads to mysterious behaviors
//in some browsers, hence the timeout
window.setTimeout(function() {
window.alert('Tag is too long.');
}, 10);
return;
}
if (isTaggedWith(tagName)) {
flashTagRed(tagName);
} else {
beforeTagAdded(tagName, source);
if (isTaggedWith(tagName)) {
flashTagRed(tagName);
} else {
beforeTagAdded(tagName, source);
var exportedTag = getExportedTag(tagName);
if (!exportedTag || !exportedTag.banned) {
tags.push(tagName);
var $elem = createListElement(tagName);
$tagList.append($elem);
}
var exportedTag = getExportedTag(tagName);
if (!exportedTag || !exportedTag.banned) {
tags.push(tagName);
var $elem = createListElement(tagName);
$tagList.append($elem);
}
afterTagAdded(tagName, source);
}
}
afterTagAdded(tagName, source);
}
}
function beforeTagRemoved(tagName) {
if (typeof(options.beforeTagRemoved) === 'function') {
options.beforeTagRemoved(tagName);
}
}
function beforeTagRemoved(tagName) {
if (typeof(options.beforeTagRemoved) === 'function') {
options.beforeTagRemoved(tagName);
}
}
function afterTagRemoved(tagName) {
refreshShownSiblings();
}
function afterTagRemoved(tagName) {
refreshShownSiblings();
}
function beforeTagAdded(tagName, source) {
if (typeof(options.beforeTagAdded) === 'function') {
options.beforeTagAdded(tagName);
}
}
function beforeTagAdded(tagName, source) {
if (typeof(options.beforeTagAdded) === 'function') {
options.beforeTagAdded(tagName);
}
}
function afterTagAdded(tagName, source) {
if (source === SOURCE_IMPLICATIONS) {
flashTagYellow(tagName);
} else if (source !== SOURCE_INITIAL_TEXT) {
var tag = getExportedTag(tagName);
if (tag) {
_.each(tag.implications, function(impliedTagName) {
if (!isTaggedWith(impliedTagName)) {
addTag(impliedTagName, SOURCE_IMPLICATIONS);
}
});
if (source !== SOURCE_IMPLICATIONS && source !== SOURCE_SUGGESTIONS) {
showOrHideSuggestions(tagName);
refreshShownSiblings();
}
} else {
flashTagGreen(tagName);
}
}
}
function afterTagAdded(tagName, source) {
if (source === SOURCE_IMPLICATIONS) {
flashTagYellow(tagName);
} else if (source !== SOURCE_INITIAL_TEXT) {
var tag = getExportedTag(tagName);
if (tag) {
_.each(tag.implications, function(impliedTagName) {
if (!isTaggedWith(impliedTagName)) {
addTag(impliedTagName, SOURCE_IMPLICATIONS);
}
});
if (source !== SOURCE_IMPLICATIONS && source !== SOURCE_SUGGESTIONS) {
showOrHideSuggestions(tagName);
refreshShownSiblings();
}
} else {
flashTagGreen(tagName);
}
}
}
function getExportedTag(tagName) {
return _.first(_.filter(
tagList.getTags(),
function(t) {
return t.name.toLowerCase() === tagName.toLowerCase();
}));
}
function getExportedTag(tagName) {
return _.first(_.filter(
tagList.getTags(),
function(t) {
return t.name.toLowerCase() === tagName.toLowerCase();
}));
}
function removeTag(tagName) {
var oldTagNames = getTags();
var newTagNames = _.without(oldTagNames, tagName);
if (newTagNames.length !== oldTagNames.length) {
beforeTagRemoved(tagName);
setTags(newTagNames);
afterTagRemoved(tagName);
}
}
function removeTag(tagName) {
var oldTagNames = getTags();
var newTagNames = _.without(oldTagNames, tagName);
if (newTagNames.length !== oldTagNames.length) {
beforeTagRemoved(tagName);
setTags(newTagNames);
afterTagRemoved(tagName);
}
}
function isTaggedWith(tagName) {
var tagNames = _.map(getTags(), function(tagName) {
return tagName.toLowerCase();
});
return _.contains(tagNames, tagName.toLowerCase());
}
function isTaggedWith(tagName) {
var tagNames = _.map(getTags(), function(tagName) {
return tagName.toLowerCase();
});
return _.contains(tagNames, tagName.toLowerCase());
}
function removeLastTag() {
removeTag(_.last(getTags()));
}
function removeLastTag() {
removeTag(_.last(getTags()));
}
function flashTagRed(tagName) {
flashTag(tagName, 'rgba(255, 200, 200, 1)');
}
function flashTagRed(tagName) {
flashTag(tagName, 'rgba(255, 200, 200, 1)');
}
function flashTagYellow(tagName) {
flashTag(tagName, 'rgba(255, 255, 200, 1)');
}
function flashTagYellow(tagName) {
flashTag(tagName, 'rgba(255, 255, 200, 1)');
}
function flashTagGreen(tagName) {
flashTag(tagName, 'rgba(200, 255, 200, 1)');
}
function flashTagGreen(tagName) {
flashTag(tagName, 'rgba(200, 255, 200, 1)');
}
function flashTag(tagName, color) {
var $elem = getListElement(tagName);
$elem.css({backgroundColor: color});
}
function flashTag(tagName, color) {
var $elem = getListElement(tagName);
$elem.css({backgroundColor: color});
}
function getListElement(tagName) {
return $tagList.find('li[data-tag="' + tagName.toLowerCase() + '"]');
}
function getListElement(tagName) {
return $tagList.find('li[data-tag="' + tagName.toLowerCase() + '"]');
}
function setTags(newTagNames) {
tags = newTagNames.slice();
$tagList.empty();
$underlyingInput.val(newTagNames.join(' '));
_.each(newTagNames, function(tagName) {
var $elem = createListElement(tagName);
$tagList.append($elem);
});
}
function setTags(newTagNames) {
tags = newTagNames.slice();
$tagList.empty();
$underlyingInput.val(newTagNames.join(' '));
_.each(newTagNames, function(tagName) {
var $elem = createListElement(tagName);
$tagList.append($elem);
});
}
function createListElement(tagName) {
var $elem = jQuery('<li/>');
$elem.attr('data-tag', tagName.toLowerCase());
function createListElement(tagName) {
var $elem = jQuery('<li/>');
$elem.attr('data-tag', tagName.toLowerCase());
var $tagLink = jQuery('<a class="tag">');
$tagLink.text(tagName + ' ' /* for easy copying */);
$tagLink.click(function(e) {
e.preventDefault();
showOrHideSiblings(tagName);
showOrHideSuggestions(tagName);
});
$elem.append($tagLink);
var $tagLink = jQuery('<a class="tag">');
$tagLink.text(tagName + ' ' /* for easy copying */);
$tagLink.click(function(e) {
e.preventDefault();
showOrHideSiblings(tagName);
showOrHideSuggestions(tagName);
});
$elem.append($tagLink);
var $deleteButton = jQuery('<a class="close"><i class="fa fa-remove"></i></a>');
$deleteButton.click(function(e) {
e.preventDefault();
removeTag(tagName);
$input.focus();
});
$elem.append($deleteButton);
return $elem;
}
var $deleteButton = jQuery('<a class="close"><i class="fa fa-remove"></i></a>');
$deleteButton.click(function(e) {
e.preventDefault();
removeTag(tagName);
$input.focus();
});
$elem.append($deleteButton);
return $elem;
}
function showOrHideSuggestions(tagName) {
var tag = getExportedTag(tagName);
var suggestions = tag ? tag.suggestions : [];
updateSuggestions($suggestions, suggestions);
}
function showOrHideSuggestions(tagName) {
var tag = getExportedTag(tagName);
var suggestions = tag ? tag.suggestions : [];
updateSuggestions($suggestions, suggestions);
}
function showOrHideSiblings(tagName) {
if ($siblings.data('lastTag') === tagName && $siblings.is(':visible')) {
$siblings.slideUp('fast');
$siblings.data('lastTag', null);
return;
}
function showOrHideSiblings(tagName) {
if ($siblings.data('lastTag') === tagName && $siblings.is(':visible')) {
$siblings.slideUp('fast');
$siblings.data('lastTag', null);
return;
}
promise.wait(getSiblings(tagName), promise.make(function(resolve, reject) {
$siblings.slideUp('fast', resolve);
})).then(function(siblings) {
siblings = _.pluck(siblings, 'name');
$siblings.data('lastTag', tagName);
$siblings.data('siblings', siblings);
updateSuggestions($siblings, siblings);
}).fail(function() {
});
}
promise.wait(getSiblings(tagName), promise.make(function(resolve, reject) {
$siblings.slideUp('fast', resolve);
})).then(function(siblings) {
siblings = _.pluck(siblings, 'name');
$siblings.data('lastTag', tagName);
$siblings.data('siblings', siblings);
updateSuggestions($siblings, siblings);
}).fail(function() {
});
}
function refreshShownSiblings() {
updateSuggestions($siblings, $siblings.data('siblings'));
}
function refreshShownSiblings() {
updateSuggestions($siblings, $siblings.data('siblings'));
}
function updateSuggestions($target, suggestedTagNames) {
function filterSuggestions(sourceTagNames) {
if (!sourceTagNames) {
return [];
}
var tagNames = _.filter(sourceTagNames.slice(), function(tagName) {
return !isTaggedWith(tagName);
});
tagNames = tagNames.slice(0, 20);
return tagNames;
}
function updateSuggestions($target, suggestedTagNames) {
function filterSuggestions(sourceTagNames) {
if (!sourceTagNames) {
return [];
}
var tagNames = _.filter(sourceTagNames.slice(), function(tagName) {
return !isTaggedWith(tagName);
});
tagNames = tagNames.slice(0, 20);
return tagNames;
}
function attachTagsToSuggestionList($list, tagNames) {
$list.empty();
_.each(tagNames, function(tagName) {
var $li = jQuery('<li>');
var $a = jQuery('<a href="#/posts/query=' + tagName + '">');
$a.text(tagName);
$a.click(function(e) {
e.preventDefault();
addTag(tagName, SOURCE_SUGGESTIONS);
$li.fadeOut('fast', function() {
$li.remove();
if ($list.children().length === 0) {
$list.parent('div').slideUp('fast');
}
});
});
$li.append($a);
$list.append($li);
});
}
function attachTagsToSuggestionList($list, tagNames) {
$list.empty();
_.each(tagNames, function(tagName) {
var $li = jQuery('<li>');
var $a = jQuery('<a href="#/posts/query=' + tagName + '">');
$a.text(tagName);
$a.click(function(e) {
e.preventDefault();
addTag(tagName, SOURCE_SUGGESTIONS);
$li.fadeOut('fast', function() {
$li.remove();
if ($list.children().length === 0) {
$list.parent('div').slideUp('fast');
}
});
});
$li.append($a);
$list.append($li);
});
}
var suggestions = filterSuggestions(suggestedTagNames);
if (suggestions.length > 0) {
attachTagsToSuggestionList($target.find('ul'), suggestions);
$target.slideDown('fast');
} else {
$target.slideUp('fast');
}
}
var suggestions = filterSuggestions(suggestedTagNames);
if (suggestions.length > 0) {
attachTagsToSuggestionList($target.find('ul'), suggestions);
$target.slideDown('fast');
} else {
$target.slideUp('fast');
}
}
function getSiblings(tagName) {
return promise.make(function(resolve, reject) {
promise.wait(api.get('/tags/' + tagName + '/siblings'))
.then(function(response) {
resolve(response.json.data);
}).fail(function() {
reject();
});
});
}
function getSiblings(tagName) {
return promise.make(function(resolve, reject) {
promise.wait(api.get('/tags/' + tagName + '/siblings'))
.then(function(response) {
resolve(response.json.data);
}).fail(function() {
reject();
});
});
}
function getTags() {
return tags;
}
function getTags() {
return tags;
}
function focus() {
$input.focus();
}
function focus() {
$input.focus();
}
function hideSuggestions() {
$siblings.hide();
$suggestions.hide();
$siblings.data('siblings', []);
}
function hideSuggestions() {
$siblings.hide();
$suggestions.hide();
$siblings.data('siblings', []);
}
_.extend(options, {
setTags: setTags,
getTags: getTags,
removeTag: removeTag,
addTag: addTag,
focus: focus,
hideSuggestions: hideSuggestions,
});
return options;
_.extend(options, {
setTags: setTags,
getTags: getTags,
removeTag: removeTag,
addTag: addTag,
focus: focus,
hideSuggestions: hideSuggestions,
});
return options;
};

View file

@ -2,53 +2,53 @@ var App = App || {};
App.DI = (function() {
var factories = {};
var instances = {};
var factories = {};
var instances = {};
function get(key) {
var instance = instances[key];
if (!instance) {
var factory = factories[key];
if (!factory) {
throw new Error('Unregistered key: ' + key);
}
var objectInitializer = factory.initializer;
var singleton = factory.singleton;
var deps = resolveDependencies(objectInitializer, factory.dependencies);
instance = {};
instance = objectInitializer.apply(instance, deps);
if (singleton) {
instances[key] = instance;
}
}
return instance;
}
function get(key) {
var instance = instances[key];
if (!instance) {
var factory = factories[key];
if (!factory) {
throw new Error('Unregistered key: ' + key);
}
var objectInitializer = factory.initializer;
var singleton = factory.singleton;
var deps = resolveDependencies(objectInitializer, factory.dependencies);
instance = {};
instance = objectInitializer.apply(instance, deps);
if (singleton) {
instances[key] = instance;
}
}
return instance;
}
function resolveDependencies(objectIntializer, depKeys) {
var deps = [];
for (var i = 0; i < depKeys.length; i ++) {
deps[i] = get(depKeys[i]);
}
return deps;
}
function resolveDependencies(objectIntializer, depKeys) {
var deps = [];
for (var i = 0; i < depKeys.length; i ++) {
deps[i] = get(depKeys[i]);
}
return deps;
}
function register(key, dependencies, objectInitializer) {
factories[key] = {initializer: objectInitializer, singleton: false, dependencies: dependencies};
}
function register(key, dependencies, objectInitializer) {
factories[key] = {initializer: objectInitializer, singleton: false, dependencies: dependencies};
}
function registerSingleton(key, dependencies, objectInitializer) {
factories[key] = {initializer: objectInitializer, singleton: true, dependencies: dependencies};
}
function registerSingleton(key, dependencies, objectInitializer) {
factories[key] = {initializer: objectInitializer, singleton: true, dependencies: dependencies};
}
function registerManual(key, objectInitializer) {
instances[key] = objectInitializer();
}
function registerManual(key, objectInitializer) {
instances[key] = objectInitializer();
}
return {
get: get,
register: register,
registerManual: registerManual,
registerSingleton: registerSingleton,
};
return {
get: get,
register: register,
registerManual: registerManual,
registerSingleton: registerSingleton,
};
})();

View file

@ -2,60 +2,60 @@ var App = App || {};
App.Keyboard = function(jQuery, mousetrap, browsingSettings) {
var enabled = browsingSettings.getSettings().keyboardShortcuts;
var oldStopCallback = mousetrap.stopCallback;
mousetrap.stopCallback = function(e, element, combo, sequence) {
if (combo.indexOf('ctrl') === -1 && e.ctrlKey) {
return true;
}
if (combo.indexOf('alt') === -1 && e.altKey) {
return true;
}
if (combo.indexOf('ctrl') !== -1) {
return false;
}
var $focused = jQuery(':focus').eq(0);
if ($focused.length) {
if ($focused.prop('tagName').match(/embed|object/i)) {
return true;
}
if ($focused.prop('tagName').toLowerCase() === 'input' &&
$focused.attr('type').match(/checkbox|radio/i)) {
return false;
}
}
return oldStopCallback.apply(mousetrap, arguments);
};
var enabled = browsingSettings.getSettings().keyboardShortcuts;
var oldStopCallback = mousetrap.stopCallback;
mousetrap.stopCallback = function(e, element, combo, sequence) {
if (combo.indexOf('ctrl') === -1 && e.ctrlKey) {
return true;
}
if (combo.indexOf('alt') === -1 && e.altKey) {
return true;
}
if (combo.indexOf('ctrl') !== -1) {
return false;
}
var $focused = jQuery(':focus').eq(0);
if ($focused.length) {
if ($focused.prop('tagName').match(/embed|object/i)) {
return true;
}
if ($focused.prop('tagName').toLowerCase() === 'input' &&
$focused.attr('type').match(/checkbox|radio/i)) {
return false;
}
}
return oldStopCallback.apply(mousetrap, arguments);
};
function keyup(key, callback) {
unbind(key);
if (enabled) {
mousetrap.bind(key, callback, 'keyup');
}
}
function keyup(key, callback) {
unbind(key);
if (enabled) {
mousetrap.bind(key, callback, 'keyup');
}
}
function keydown(key, callback) {
unbind(key);
if (enabled) {
mousetrap.bind(key, callback);
}
}
function keydown(key, callback) {
unbind(key);
if (enabled) {
mousetrap.bind(key, callback);
}
}
function reset() {
mousetrap.reset();
}
function reset() {
mousetrap.reset();
}
function unbind(key) {
mousetrap.unbind(key, 'keyup');
mousetrap.unbind(key);
}
function unbind(key) {
mousetrap.unbind(key, 'keyup');
mousetrap.unbind(key);
}
return {
keydown: keydown,
keyup: keyup,
reset: reset,
unbind: unbind,
};
return {
keydown: keydown,
keyup: keyup,
reset: reset,
unbind: unbind,
};
};
App.DI.register('keyboard', ['jQuery', 'mousetrap', 'browsingSettings'], App.Keyboard);

View file

@ -1,142 +1,142 @@
var App = App || {};
App.Pager = function(
_,
promise,
api) {
_,
promise,
api) {
var totalPages;
var pageNumber;
var searchParams;
var url;
var cache = {};
var totalPages;
var pageNumber;
var searchParams;
var url;
var cache = {};
function init(args) {
url = args.url;
function init(args) {
url = args.url;
setSearchParams(args.searchParams);
if (typeof(args.page) !== 'undefined') {
setPage(args.page);
} else {
setPage(1);
}
}
setSearchParams(args.searchParams);
if (typeof(args.page) !== 'undefined') {
setPage(args.page);
} else {
setPage(1);
}
}
function getPage() {
return pageNumber;
}
function getPage() {
return pageNumber;
}
function getTotalPages() {
return totalPages;
}
function getTotalPages() {
return totalPages;
}
function prevPage() {
if (pageNumber > 1) {
setPage(pageNumber - 1);
return true;
}
return false;
}
function prevPage() {
if (pageNumber > 1) {
setPage(pageNumber - 1);
return true;
}
return false;
}
function nextPage() {
if (pageNumber < totalPages) {
setPage(pageNumber + 1);
return true;
}
return false;
}
function nextPage() {
if (pageNumber < totalPages) {
setPage(pageNumber + 1);
return true;
}
return false;
}
function setPage(newPageNumber) {
pageNumber = parseInt(newPageNumber);
if (!pageNumber || isNaN(pageNumber)) {
throw new Error('Trying to set page to a non-number (' + newPageNumber + ')');
}
}
function setPage(newPageNumber) {
pageNumber = parseInt(newPageNumber);
if (!pageNumber || isNaN(pageNumber)) {
throw new Error('Trying to set page to a non-number (' + newPageNumber + ')');
}
}
function getSearchParams() {
return searchParams;
}
function getSearchParams() {
return searchParams;
}
function setSearchParams(newSearchParams) {
setPage(1);
searchParams = _.extend({}, newSearchParams);
delete searchParams.page;
}
function setSearchParams(newSearchParams) {
setPage(1);
searchParams = _.extend({}, newSearchParams);
delete searchParams.page;
}
function retrieve() {
return promise.make(function(resolve, reject) {
promise.wait(api.get(url, _.extend({}, searchParams, {page: pageNumber})))
.then(function(response) {
var pageSize = response.json.pageSize;
var totalRecords = response.json.totalRecords;
totalPages = Math.ceil(totalRecords / pageSize);
function retrieve() {
return promise.make(function(resolve, reject) {
promise.wait(api.get(url, _.extend({}, searchParams, {page: pageNumber})))
.then(function(response) {
var pageSize = response.json.pageSize;
var totalRecords = response.json.totalRecords;
totalPages = Math.ceil(totalRecords / pageSize);
resolve({
entities: response.json.data,
totalRecords: totalRecords,
totalPages: totalPages});
resolve({
entities: response.json.data,
totalRecords: totalRecords,
totalPages: totalPages});
}).fail(function(response) {
reject(response);
});
});
}
}).fail(function(response) {
reject(response);
});
});
}
function retrieveCached() {
return promise.make(function(resolve, reject) {
var cacheKey = JSON.stringify(_.extend({}, searchParams, {url: url, page: getPage()}));
if (cacheKey in cache) {
resolve.apply(this, cache[cacheKey]);
} else {
promise.wait(retrieve())
.then(function() {
cache[cacheKey] = arguments;
resolve.apply(this, arguments);
}).fail(function() {
reject.apply(this, arguments);
});
}
});
}
function retrieveCached() {
return promise.make(function(resolve, reject) {
var cacheKey = JSON.stringify(_.extend({}, searchParams, {url: url, page: getPage()}));
if (cacheKey in cache) {
resolve.apply(this, cache[cacheKey]);
} else {
promise.wait(retrieve())
.then(function() {
cache[cacheKey] = arguments;
resolve.apply(this, arguments);
}).fail(function() {
reject.apply(this, arguments);
});
}
});
}
function resetCache() {
cache = {};
}
function resetCache() {
cache = {};
}
function getVisiblePages() {
var pages = [1, totalPages || 1];
var pagesAroundCurrent = 2;
for (var i = -pagesAroundCurrent; i <= pagesAroundCurrent; i ++) {
if (pageNumber + i >= 1 && pageNumber + i <= totalPages) {
pages.push(pageNumber + i);
}
}
if (pageNumber - pagesAroundCurrent - 1 === 2) {
pages.push(2);
}
if (pageNumber + pagesAroundCurrent + 1 === totalPages - 1) {
pages.push(totalPages - 1);
}
function getVisiblePages() {
var pages = [1, totalPages || 1];
var pagesAroundCurrent = 2;
for (var i = -pagesAroundCurrent; i <= pagesAroundCurrent; i ++) {
if (pageNumber + i >= 1 && pageNumber + i <= totalPages) {
pages.push(pageNumber + i);
}
}
if (pageNumber - pagesAroundCurrent - 1 === 2) {
pages.push(2);
}
if (pageNumber + pagesAroundCurrent + 1 === totalPages - 1) {
pages.push(totalPages - 1);
}
return pages.sort(function(a, b) { return a - b; }).filter(function(item, pos) {
return !pos || item !== pages[pos - 1];
});
}
return pages.sort(function(a, b) { return a - b; }).filter(function(item, pos) {
return !pos || item !== pages[pos - 1];
});
}
return {
init: init,
getPage: getPage,
getTotalPages: getTotalPages,
prevPage: prevPage,
nextPage: nextPage,
setPage: setPage,
getSearchParams: getSearchParams,
setSearchParams: setSearchParams,
retrieve: retrieve,
retrieveCached: retrieveCached,
getVisiblePages: getVisiblePages,
resetCache: resetCache,
};
return {
init: init,
getPage: getPage,
getTotalPages: getTotalPages,
prevPage: prevPage,
nextPage: nextPage,
setPage: setPage,
getSearchParams: getSearchParams,
setSearchParams: setSearchParams,
retrieve: retrieve,
retrieveCached: retrieveCached,
getVisiblePages: getVisiblePages,
resetCache: resetCache,
};
};

View file

@ -2,53 +2,53 @@ var App = App || {};
App.PresenterManager = function(jQuery, promise, topNavigationPresenter, keyboard) {
var lastContentPresenter = null;
var lastContentPresenter = null;
function init() {
return promise.make(function(resolve, reject) {
initPresenter(topNavigationPresenter, [], resolve);
});
}
function init() {
return promise.make(function(resolve, reject) {
initPresenter(topNavigationPresenter, [], resolve);
});
}
function initPresenter(presenter, args, loaded) {
presenter.init.call(presenter, args, loaded);
}
function initPresenter(presenter, args, loaded) {
presenter.init.call(presenter, args, loaded);
}
function switchContentPresenter(presenter, args) {
if (lastContentPresenter === null || lastContentPresenter.name !== presenter.name) {
if (lastContentPresenter !== null && lastContentPresenter.deinit) {
lastContentPresenter.deinit();
}
keyboard.reset();
topNavigationPresenter.changeTitle(null);
topNavigationPresenter.focus();
presenter.init.call(presenter, args, function() {});
lastContentPresenter = presenter;
} else if (lastContentPresenter.reinit) {
lastContentPresenter.reinit.call(lastContentPresenter, args, function() {});
}
}
function switchContentPresenter(presenter, args) {
if (lastContentPresenter === null || lastContentPresenter.name !== presenter.name) {
if (lastContentPresenter !== null && lastContentPresenter.deinit) {
lastContentPresenter.deinit();
}
keyboard.reset();
topNavigationPresenter.changeTitle(null);
topNavigationPresenter.focus();
presenter.init.call(presenter, args, function() {});
lastContentPresenter = presenter;
} else if (lastContentPresenter.reinit) {
lastContentPresenter.reinit.call(lastContentPresenter, args, function() {});
}
}
function initPresenters(options, loaded) {
var count = 0;
var subPresenterLoaded = function() {
count ++;
if (count === options.length) {
loaded();
}
};
function initPresenters(options, loaded) {
var count = 0;
var subPresenterLoaded = function() {
count ++;
if (count === options.length) {
loaded();
}
};
for (var i = 0; i < options.length; i ++) {
initPresenter(options[i][0], options[i][1], subPresenterLoaded);
}
}
for (var i = 0; i < options.length; i ++) {
initPresenter(options[i][0], options[i][1], subPresenterLoaded);
}
}
return {
init: init,
initPresenter: initPresenter,
initPresenters: initPresenters,
switchContentPresenter: switchContentPresenter,
};
return {
init: init,
initPresenter: initPresenter,
initPresenters: initPresenters,
switchContentPresenter: switchContentPresenter,
};
};

View file

@ -2,230 +2,230 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.CommentListPresenter = function(
_,
jQuery,
util,
promise,
api,
auth,
topNavigationPresenter,
messagePresenter) {
_,
jQuery,
util,
promise,
api,
auth,
topNavigationPresenter,
messagePresenter) {
var $el;
var privileges;
var templates = {};
var $el;
var privileges;
var templates = {};
var post;
var comments = [];
var post;
var comments = [];
function init(params, loaded) {
$el = params.$target;
post = params.post;
comments = params.comments || [];
function init(params, loaded) {
$el = params.$target;
post = params.post;
comments = params.comments || [];
privileges = {
canListComments: auth.hasPrivilege(auth.privileges.listComments),
canAddComments: auth.hasPrivilege(auth.privileges.addComments),
canEditOwnComments: auth.hasPrivilege(auth.privileges.editOwnComments),
canEditAllComments: auth.hasPrivilege(auth.privileges.editAllComments),
canDeleteOwnComments: auth.hasPrivilege(auth.privileges.deleteOwnComments),
canDeleteAllComments: auth.hasPrivilege(auth.privileges.deleteAllComments),
canViewUsers: auth.hasPrivilege(auth.privileges.viewUsers),
canViewPosts: auth.hasPrivilege(auth.privileges.viewPosts),
};
privileges = {
canListComments: auth.hasPrivilege(auth.privileges.listComments),
canAddComments: auth.hasPrivilege(auth.privileges.addComments),
canEditOwnComments: auth.hasPrivilege(auth.privileges.editOwnComments),
canEditAllComments: auth.hasPrivilege(auth.privileges.editAllComments),
canDeleteOwnComments: auth.hasPrivilege(auth.privileges.deleteOwnComments),
canDeleteAllComments: auth.hasPrivilege(auth.privileges.deleteAllComments),
canViewUsers: auth.hasPrivilege(auth.privileges.viewUsers),
canViewPosts: auth.hasPrivilege(auth.privileges.viewPosts),
};
promise.wait(
util.promiseTemplate('comment-list'),
util.promiseTemplate('comment-list-item'),
util.promiseTemplate('comment-form'))
.then(function(
commentListTemplate,
commentListItemTemplate,
commentFormTemplate)
{
templates.commentList = commentListTemplate;
templates.commentListItem = commentListItemTemplate;
templates.commentForm = commentFormTemplate;
promise.wait(
util.promiseTemplate('comment-list'),
util.promiseTemplate('comment-list-item'),
util.promiseTemplate('comment-form'))
.then(function(
commentListTemplate,
commentListItemTemplate,
commentFormTemplate)
{
templates.commentList = commentListTemplate;
templates.commentListItem = commentListItemTemplate;
templates.commentForm = commentFormTemplate;
render();
loaded();
render();
loaded();
if (comments.length === 0) {
promise.wait(api.get('/comments/' + params.post.id))
.then(function(response) {
comments = response.json.data;
render();
}).fail(function() {
console.log(arguments);
});
}
})
.fail(function() {
console.log(arguments);
loaded();
});
}
if (comments.length === 0) {
promise.wait(api.get('/comments/' + params.post.id))
.then(function(response) {
comments = response.json.data;
render();
}).fail(function() {
console.log(arguments);
});
}
})
.fail(function() {
console.log(arguments);
loaded();
});
}
function render() {
$el.html(templates.commentList(
_.extend(
{
commentListItemTemplate: templates.commentListItem,
commentFormTemplate: templates.commentForm,
util: util,
comments: comments,
post: post,
},
privileges)));
function render() {
$el.html(templates.commentList(
_.extend(
{
commentListItemTemplate: templates.commentListItem,
commentFormTemplate: templates.commentForm,
util: util,
comments: comments,
post: post,
},
privileges)));
$el.find('.comment-add form button[type=submit]').click(function(e) { commentFormSubmitted(e, null); });
renderComments(comments);
}
$el.find('.comment-add form button[type=submit]').click(function(e) { commentFormSubmitted(e, null); });
renderComments(comments);
}
function renderComments(comments) {
var $target = $el.find('.comments');
var $targetList = $el.find('ul');
function renderComments(comments) {
var $target = $el.find('.comments');
var $targetList = $el.find('ul');
if (comments.length > 0) {
$target.show();
} else {
$target.hide();
}
if (comments.length > 0) {
$target.show();
} else {
$target.hide();
}
$targetList.empty();
_.each(comments, function(comment) {
renderComment($targetList, comment);
});
}
$targetList.empty();
_.each(comments, function(comment) {
renderComment($targetList, comment);
});
}
function renderComment($targetList, comment) {
var $item = jQuery('<li>' + templates.commentListItem({
comment: comment,
util: util,
canVote: auth.isLoggedIn(),
canEditComment: auth.isLoggedIn(comment.user.name) ? privileges.canEditOwnComments : privileges.canEditAllComments,
canDeleteComment: auth.isLoggedIn(comment.user.name) ? privileges.canDeleteOwnComments : privileges.canDeleteAllComments,
canViewUsers: privileges.canViewUsers,
canViewPosts: privileges.canViewPosts,
}) + '</li>');
util.loadImagesNicely($item.find('img'));
$targetList.append($item);
function renderComment($targetList, comment) {
var $item = jQuery('<li>' + templates.commentListItem({
comment: comment,
util: util,
canVote: auth.isLoggedIn(),
canEditComment: auth.isLoggedIn(comment.user.name) ? privileges.canEditOwnComments : privileges.canEditAllComments,
canDeleteComment: auth.isLoggedIn(comment.user.name) ? privileges.canDeleteOwnComments : privileges.canDeleteAllComments,
canViewUsers: privileges.canViewUsers,
canViewPosts: privileges.canViewPosts,
}) + '</li>');
util.loadImagesNicely($item.find('img'));
$targetList.append($item);
$item.find('a.edit').click(function(e) {
e.preventDefault();
editCommentStart($item, comment);
});
$item.find('a.edit').click(function(e) {
e.preventDefault();
editCommentStart($item, comment);
});
$item.find('a.delete').click(function(e) {
e.preventDefault();
deleteComment(comment);
});
$item.find('a.delete').click(function(e) {
e.preventDefault();
deleteComment(comment);
});
$item.find('a.score-up').click(function(e) {
e.preventDefault();
score(comment, jQuery(this).hasClass('active') ? 0 : 1);
});
$item.find('a.score-up').click(function(e) {
e.preventDefault();
score(comment, jQuery(this).hasClass('active') ? 0 : 1);
});
$item.find('a.score-down').click(function(e) {
e.preventDefault();
score(comment, jQuery(this).hasClass('active') ? 0 : -1);
});
}
$item.find('a.score-down').click(function(e) {
e.preventDefault();
score(comment, jQuery(this).hasClass('active') ? 0 : -1);
});
}
function commentFormSubmitted(e, comment) {
e.preventDefault();
var $button = jQuery(e.target);
var $form = $button.parents('form');
var sender = $button.val();
if (sender === 'preview') {
previewComment($form);
} else {
submitComment($form, comment);
}
}
function commentFormSubmitted(e, comment) {
e.preventDefault();
var $button = jQuery(e.target);
var $form = $button.parents('form');
var sender = $button.val();
if (sender === 'preview') {
previewComment($form);
} else {
submitComment($form, comment);
}
}
function previewComment($form) {
var $preview = $form.find('.preview');
$preview.slideUp('fast', function() {
$preview.html(util.formatMarkdown($form.find('textarea').val()));
$preview.slideDown('fast');
});
}
function previewComment($form) {
var $preview = $form.find('.preview');
$preview.slideUp('fast', function() {
$preview.html(util.formatMarkdown($form.find('textarea').val()));
$preview.slideDown('fast');
});
}
function updateComment(comment) {
comments = _.map(comments, function(c) { return c.id === comment.id ? comment : c; });
render();
}
function updateComment(comment) {
comments = _.map(comments, function(c) { return c.id === comment.id ? comment : c; });
render();
}
function addComment(comment) {
comments.push(comment);
render();
}
function addComment(comment) {
comments.push(comment);
render();
}
function submitComment($form, commentToEdit) {
$form.find('.preview').slideUp();
var $textarea = $form.find('textarea');
function submitComment($form, commentToEdit) {
$form.find('.preview').slideUp();
var $textarea = $form.find('textarea');
var data = {text: $textarea.val()};
var p;
if (commentToEdit) {
p = promise.wait(api.put('/comments/' + commentToEdit.id, data));
} else {
p = promise.wait(api.post('/comments/' + post.id, data));
}
var data = {text: $textarea.val()};
var p;
if (commentToEdit) {
p = promise.wait(api.put('/comments/' + commentToEdit.id, data));
} else {
p = promise.wait(api.post('/comments/' + post.id, data));
}
p.then(function(response) {
$textarea.val('');
var comment = response.json;
p.then(function(response) {
$textarea.val('');
var comment = response.json;
if (commentToEdit) {
$form.slideUp(function() {
$form.remove();
});
updateComment(comment);
} else {
addComment(comment);
}
}).fail(showGenericError);
}
if (commentToEdit) {
$form.slideUp(function() {
$form.remove();
});
updateComment(comment);
} else {
addComment(comment);
}
}).fail(showGenericError);
}
function editCommentStart($item, comment) {
if ($item.find('.comment-form').length > 0) {
return;
}
var $form = jQuery(templates.commentForm({title: 'Edit comment', text: comment.text}));
$item.find('.body').append($form);
$item.find('form button[type=submit]').click(function(e) { commentFormSubmitted(e, comment); });
}
function editCommentStart($item, comment) {
if ($item.find('.comment-form').length > 0) {
return;
}
var $form = jQuery(templates.commentForm({title: 'Edit comment', text: comment.text}));
$item.find('.body').append($form);
$item.find('form button[type=submit]').click(function(e) { commentFormSubmitted(e, comment); });
}
function deleteComment(comment) {
if (!window.confirm('Are you sure you want to delete this comment?')) {
return;
}
promise.wait(api.delete('/comments/' + comment.id))
.then(function(response) {
comments = _.filter(comments, function(c) { return c.id !== comment.id; });
renderComments(comments);
}).fail(showGenericError);
}
function deleteComment(comment) {
if (!window.confirm('Are you sure you want to delete this comment?')) {
return;
}
promise.wait(api.delete('/comments/' + comment.id))
.then(function(response) {
comments = _.filter(comments, function(c) { return c.id !== comment.id; });
renderComments(comments);
}).fail(showGenericError);
}
function score(comment, scoreValue) {
promise.wait(api.post('/comments/' + comment.id + '/score', {score: scoreValue}))
.then(function(response) {
comment.score = parseInt(response.json.score);
comment.ownScore = parseInt(response.json.ownScore);
updateComment(comment);
}).fail(showGenericError);
}
function score(comment, scoreValue) {
promise.wait(api.post('/comments/' + comment.id + '/score', {score: scoreValue}))
.then(function(response) {
comment.score = parseInt(response.json.score);
comment.ownScore = parseInt(response.json.ownScore);
updateComment(comment);
}).fail(showGenericError);
}
function showGenericError(response) {
window.alert(response.json && response.json.error || response);
}
function showGenericError(response) {
window.alert(response.json && response.json.error || response);
}
return {
init: init,
render: render,
};
return {
init: init,
render: render,
};
};

View file

@ -2,103 +2,103 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.GlobalCommentListPresenter = function(
_,
jQuery,
util,
auth,
promise,
pagerPresenter,
topNavigationPresenter) {
_,
jQuery,
util,
auth,
promise,
pagerPresenter,
topNavigationPresenter) {
var $el;
var privileges;
var templates = {};
var $el;
var privileges;
var templates = {};
function init(params, loaded) {
$el = jQuery('#content');
topNavigationPresenter.select('comments');
function init(params, loaded) {
$el = jQuery('#content');
topNavigationPresenter.select('comments');
privileges = {
canViewPosts: auth.hasPrivilege(auth.privileges.viewPosts),
};
privileges = {
canViewPosts: auth.hasPrivilege(auth.privileges.viewPosts),
};
promise.wait(
util.promiseTemplate('global-comment-list'),
util.promiseTemplate('global-comment-list-item'),
util.promiseTemplate('post-list-item'))
.then(function(listTemplate, listItemTemplate, postTemplate) {
templates.list = listTemplate;
templates.listItem = listItemTemplate;
templates.post = postTemplate;
promise.wait(
util.promiseTemplate('global-comment-list'),
util.promiseTemplate('global-comment-list-item'),
util.promiseTemplate('post-list-item'))
.then(function(listTemplate, listItemTemplate, postTemplate) {
templates.list = listTemplate;
templates.listItem = listItemTemplate;
templates.post = postTemplate;
render();
loaded();
render();
loaded();
pagerPresenter.init({
baseUri: '#/comments',
backendUri: '/comments',
$target: $el.find('.pagination-target'),
updateCallback: function($page, data) {
renderComments($page, data.entities);
},
},
function() {
reinit(params, function() {});
});
}).fail(function() {
console.log(arguments);
loaded();
});
}
pagerPresenter.init({
baseUri: '#/comments',
backendUri: '/comments',
$target: $el.find('.pagination-target'),
updateCallback: function($page, data) {
renderComments($page, data.entities);
},
},
function() {
reinit(params, function() {});
});
}).fail(function() {
console.log(arguments);
loaded();
});
}
function reinit(params, loaded) {
pagerPresenter.reinit({query: params.query || {}});
loaded();
}
function reinit(params, loaded) {
pagerPresenter.reinit({query: params.query || {}});
loaded();
}
function deinit() {
pagerPresenter.deinit();
}
function deinit() {
pagerPresenter.deinit();
}
function render() {
$el.html(templates.list());
}
function render() {
$el.html(templates.list());
}
function renderComments($page, data) {
var $target = $page.find('.posts');
_.each(data, function(data) {
var post = data.post;
var comments = data.comments;
function renderComments($page, data) {
var $target = $page.find('.posts');
_.each(data, function(data) {
var post = data.post;
var comments = data.comments;
var $post = jQuery('<li>' + templates.listItem({
util: util,
post: post,
postTemplate: templates.post,
canViewPosts: privileges.canViewPosts,
}) + '</li>');
var $post = jQuery('<li>' + templates.listItem({
util: util,
post: post,
postTemplate: templates.post,
canViewPosts: privileges.canViewPosts,
}) + '</li>');
util.loadImagesNicely($post.find('img'));
var presenter = App.DI.get('commentListPresenter');
util.loadImagesNicely($post.find('img'));
var presenter = App.DI.get('commentListPresenter');
presenter.init({
post: post,
comments: comments,
$target: $post.find('.post-comments-target'),
}, function() {
presenter.render();
});
presenter.init({
post: post,
comments: comments,
$target: $post.find('.post-comments-target'),
}, function() {
presenter.render();
});
$target.append($post);
});
}
$target.append($post);
});
}
return {
init: init,
reinit: reinit,
deinit: deinit,
render: render,
};
return {
init: init,
reinit: reinit,
deinit: deinit,
render: render,
};
};

View file

@ -2,48 +2,48 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.HelpPresenter = function(
jQuery,
promise,
util,
topNavigationPresenter) {
jQuery,
promise,
util,
topNavigationPresenter) {
var $el = jQuery('#content');
var templates = {};
var activeTab;
var $el = jQuery('#content');
var templates = {};
var activeTab;
function init(params, loaded) {
topNavigationPresenter.select('help');
topNavigationPresenter.changeTitle('Help');
function init(params, loaded) {
topNavigationPresenter.select('help');
topNavigationPresenter.changeTitle('Help');
promise.wait(util.promiseTemplate('help'))
.then(function(template) {
templates.help = template;
reinit(params, loaded);
}).fail(function() {
console.log(arguments);
loaded();
});
}
promise.wait(util.promiseTemplate('help'))
.then(function(template) {
templates.help = template;
reinit(params, loaded);
}).fail(function() {
console.log(arguments);
loaded();
});
}
function reinit(params, loaded) {
activeTab = params.tab || 'about';
render();
loaded();
}
function reinit(params, loaded) {
activeTab = params.tab || 'about';
render();
loaded();
}
function render() {
$el.html(templates.help({title: topNavigationPresenter.getBaseTitle() }));
$el.find('.big-button').removeClass('active');
$el.find('.big-button[href*="' + activeTab + '"]').addClass('active');
$el.find('div[data-tab]').hide();
$el.find('div[data-tab*="' + activeTab + '"]').show();
}
function render() {
$el.html(templates.help({title: topNavigationPresenter.getBaseTitle() }));
$el.find('.big-button').removeClass('active');
$el.find('.big-button[href*="' + activeTab + '"]').addClass('active');
$el.find('div[data-tab]').hide();
$el.find('div[data-tab*="' + activeTab + '"]').show();
}
return {
init: init,
reinit: reinit,
render: render,
};
return {
init: init,
reinit: reinit,
render: render,
};
};

View file

@ -2,76 +2,76 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.HistoryPresenter = function(
_,
jQuery,
util,
promise,
auth,
pagerPresenter,
topNavigationPresenter) {
_,
jQuery,
util,
promise,
auth,
pagerPresenter,
topNavigationPresenter) {
var $el = jQuery('#content');
var templates = {};
var params;
var $el = jQuery('#content');
var templates = {};
var params;
function init(params, loaded) {
topNavigationPresenter.changeTitle('History');
function init(params, loaded) {
topNavigationPresenter.changeTitle('History');
promise.wait(
util.promiseTemplate('global-history'),
util.promiseTemplate('history'))
.then(function(historyWrapperTemplate, historyTemplate) {
templates.historyWrapper = historyWrapperTemplate;
templates.history = historyTemplate;
promise.wait(
util.promiseTemplate('global-history'),
util.promiseTemplate('history'))
.then(function(historyWrapperTemplate, historyTemplate) {
templates.historyWrapper = historyWrapperTemplate;
templates.history = historyTemplate;
render();
loaded();
render();
loaded();
pagerPresenter.init({
baseUri: '#/history',
backendUri: '/history',
$target: $el.find('.pagination-target'),
updateCallback: function($page, data) {
renderHistory($page, data.entities);
},
},
function() {
reinit(params, function() {});
});
}).fail(function() {
console.log(arguments);
loaded();
});
}
pagerPresenter.init({
baseUri: '#/history',
backendUri: '/history',
$target: $el.find('.pagination-target'),
updateCallback: function($page, data) {
renderHistory($page, data.entities);
},
},
function() {
reinit(params, function() {});
});
}).fail(function() {
console.log(arguments);
loaded();
});
}
function reinit(_params, loaded) {
params = _params;
params.query = params.query || {};
function reinit(_params, loaded) {
params = _params;
params.query = params.query || {};
pagerPresenter.reinit({query: params.query});
loaded();
}
pagerPresenter.reinit({query: params.query});
loaded();
}
function deinit() {
pagerPresenter.deinit();
}
function deinit() {
pagerPresenter.deinit();
}
function render() {
$el.html(templates.historyWrapper());
}
function render() {
$el.html(templates.historyWrapper());
}
function renderHistory($page, historyItems) {
$page.append(templates.history({
util: util,
history: historyItems}));
}
function renderHistory($page, historyItems) {
$page.append(templates.history({
util: util,
history: historyItems}));
}
return {
init: init,
reinit: reinit,
deinit: deinit,
render: render,
};
return {
init: init,
reinit: reinit,
deinit: deinit,
render: render,
};
};

View file

@ -2,90 +2,90 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.HomePresenter = function(
jQuery,
util,
promise,
api,
auth,
presenterManager,
postContentPresenter,
topNavigationPresenter,
messagePresenter) {
jQuery,
util,
promise,
api,
auth,
presenterManager,
postContentPresenter,
topNavigationPresenter,
messagePresenter) {
var $el = jQuery('#content');
var templates = {};
var globals;
var post;
var user;
var $el = jQuery('#content');
var templates = {};
var globals;
var post;
var user;
function init(params, loaded) {
topNavigationPresenter.select('home');
topNavigationPresenter.changeTitle('Home');
function init(params, loaded) {
topNavigationPresenter.select('home');
topNavigationPresenter.changeTitle('Home');
promise.wait(
util.promiseTemplate('home'),
api.get('/globals'),
api.get('/posts/featured'))
.then(function(
homeTemplate,
globalsResponse,
featuredPostResponse) {
templates.home = homeTemplate;
promise.wait(
util.promiseTemplate('home'),
api.get('/globals'),
api.get('/posts/featured'))
.then(function(
homeTemplate,
globalsResponse,
featuredPostResponse) {
templates.home = homeTemplate;
globals = globalsResponse.json;
post = featuredPostResponse.json.post;
user = featuredPostResponse.json.user;
render();
loaded();
globals = globalsResponse.json;
post = featuredPostResponse.json.post;
user = featuredPostResponse.json.user;
render();
loaded();
if ($el.find('#post-content-target').length > 0) {
presenterManager.initPresenters([
[postContentPresenter, {post: post, $target: $el.find('#post-content-target')}]],
function() {
var $wrapper = $el.find('.object-wrapper');
$wrapper.css({
maxWidth: $wrapper.attr('data-width') + 'px',
width: 'auto',
margin: '0 auto'});
postContentPresenter.updatePostNotesSize();
});
}
if ($el.find('#post-content-target').length > 0) {
presenterManager.initPresenters([
[postContentPresenter, {post: post, $target: $el.find('#post-content-target')}]],
function() {
var $wrapper = $el.find('.object-wrapper');
$wrapper.css({
maxWidth: $wrapper.attr('data-width') + 'px',
width: 'auto',
margin: '0 auto'});
postContentPresenter.updatePostNotesSize();
});
}
}).fail(function(response) {
messagePresenter.showError($el, response.json && response.json.error || response);
loaded();
});
}
}).fail(function(response) {
messagePresenter.showError($el, response.json && response.json.error || response);
loaded();
});
}
function render() {
$el.html(templates.home({
post: post,
user: user,
globals: globals,
title: topNavigationPresenter.getBaseTitle(),
canViewUsers: auth.hasPrivilege(auth.privileges.viewUsers),
canViewPosts: auth.hasPrivilege(auth.privileges.viewPosts),
util: util,
version: jQuery('head').attr('data-version'),
buildTime: jQuery('head').attr('data-build-time'),
}));
}
function render() {
$el.html(templates.home({
post: post,
user: user,
globals: globals,
title: topNavigationPresenter.getBaseTitle(),
canViewUsers: auth.hasPrivilege(auth.privileges.viewUsers),
canViewPosts: auth.hasPrivilege(auth.privileges.viewPosts),
util: util,
version: jQuery('head').attr('data-version'),
buildTime: jQuery('head').attr('data-build-time'),
}));
}
return {
init: init,
render: render,
};
return {
init: init,
render: render,
};
};
App.DI.register('homePresenter', [
'jQuery',
'util',
'promise',
'api',
'auth',
'presenterManager',
'postContentPresenter',
'topNavigationPresenter',
'messagePresenter'],
App.Presenters.HomePresenter);
'jQuery',
'util',
'promise',
'api',
'auth',
'presenterManager',
'postContentPresenter',
'topNavigationPresenter',
'messagePresenter'],
App.Presenters.HomePresenter);

View file

@ -2,46 +2,46 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.HttpErrorPresenter = function(
jQuery,
promise,
util,
topNavigationPresenter) {
jQuery,
promise,
util,
topNavigationPresenter) {
var $el = jQuery('#content');
var templates = {};
var $el = jQuery('#content');
var templates = {};
function init(params, loaded) {
topNavigationPresenter.changeTitle('Error ' + params.error);
function init(params, loaded) {
topNavigationPresenter.changeTitle('Error ' + params.error);
if (params.error === 404) {
promise.wait(util.promiseTemplate('404'))
.then(function(template) {
templates.errorPage = template;
reinit(params, loaded);
}).fail(function() {
console.log(arguments);
loaded();
});
} else {
console.log('Not supported.');
loaded();
}
}
if (params.error === 404) {
promise.wait(util.promiseTemplate('404'))
.then(function(template) {
templates.errorPage = template;
reinit(params, loaded);
}).fail(function() {
console.log(arguments);
loaded();
});
} else {
console.log('Not supported.');
loaded();
}
}
function reinit(params, loaded) {
render();
loaded();
}
function reinit(params, loaded) {
render();
loaded();
}
function render() {
$el.html(templates.errorPage());
}
function render() {
$el.html(templates.errorPage());
}
return {
init: init,
reinit: reinit,
render: render,
};
return {
init: init,
reinit: reinit,
render: render,
};
};

View file

@ -2,84 +2,84 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.LoginPresenter = function(
jQuery,
util,
promise,
router,
auth,
topNavigationPresenter,
messagePresenter) {
jQuery,
util,
promise,
router,
auth,
topNavigationPresenter,
messagePresenter) {
var $el = jQuery('#content');
var $messages;
var templates = {};
var previousLocation;
var $el = jQuery('#content');
var $messages;
var templates = {};
var previousLocation;
function init(params, loaded) {
topNavigationPresenter.select('login');
topNavigationPresenter.changeTitle('Login');
previousLocation = params.previousLocation;
promise.wait(util.promiseTemplate('login-form'))
.then(function(template) {
templates.login = template;
if (auth.isLoggedIn()) {
finishLogin();
} else {
render();
$el.find('input:eq(0)').focus();
}
loaded();
}).fail(function() {
console.log(arguments);
loaded();
});
}
function init(params, loaded) {
topNavigationPresenter.select('login');
topNavigationPresenter.changeTitle('Login');
previousLocation = params.previousLocation;
promise.wait(util.promiseTemplate('login-form'))
.then(function(template) {
templates.login = template;
if (auth.isLoggedIn()) {
finishLogin();
} else {
render();
$el.find('input:eq(0)').focus();
}
loaded();
}).fail(function() {
console.log(arguments);
loaded();
});
}
function render() {
$el.html(templates.login());
$el.find('form').submit(loginFormSubmitted);
$messages = $el.find('.messages');
$messages.width($el.find('form').width());
}
function render() {
$el.html(templates.login());
$el.find('form').submit(loginFormSubmitted);
$messages = $el.find('.messages');
$messages.width($el.find('form').width());
}
function loginFormSubmitted(e) {
e.preventDefault();
messagePresenter.hideMessages($messages);
function loginFormSubmitted(e) {
e.preventDefault();
messagePresenter.hideMessages($messages);
var userNameOrEmail = $el.find('[name=user]').val();
var password = $el.find('[name=password]').val();
var remember = $el.find('[name=remember]').is(':checked');
var userNameOrEmail = $el.find('[name=user]').val();
var password = $el.find('[name=password]').val();
var remember = $el.find('[name=remember]').is(':checked');
if (userNameOrEmail.length === 0) {
messagePresenter.showError($messages, 'User name cannot be empty.');
return false;
}
if (userNameOrEmail.length === 0) {
messagePresenter.showError($messages, 'User name cannot be empty.');
return false;
}
if (password.length === 0) {
messagePresenter.showError($messages, 'Password cannot be empty.');
return false;
}
if (password.length === 0) {
messagePresenter.showError($messages, 'Password cannot be empty.');
return false;
}
promise.wait(auth.loginFromCredentials(userNameOrEmail, password, remember))
.then(function(response) {
finishLogin();
}).fail(function(response) {
messagePresenter.showError($messages, response.json && response.json.error || response);
});
}
promise.wait(auth.loginFromCredentials(userNameOrEmail, password, remember))
.then(function(response) {
finishLogin();
}).fail(function(response) {
messagePresenter.showError($messages, response.json && response.json.error || response);
});
}
function finishLogin() {
if (previousLocation && !previousLocation.match(/logout|password-reset|activate|register/)) {
router.navigate(previousLocation);
} else {
router.navigateToMainPage();
}
}
function finishLogin() {
if (previousLocation && !previousLocation.match(/logout|password-reset|activate|register/)) {
router.navigate(previousLocation);
} else {
router.navigateToMainPage();
}
}
return {
init: init,
render: render,
};
return {
init: init,
render: render,
};
};

View file

@ -2,38 +2,38 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.LogoutPresenter = function(
jQuery,
promise,
router,
auth,
topNavigationPresenter,
messagePresenter) {
jQuery,
promise,
router,
auth,
topNavigationPresenter,
messagePresenter) {
var $messages = jQuery('#content');
var $messages = jQuery('#content');
function init(params, loaded) {
topNavigationPresenter.select('logout');
topNavigationPresenter.changeTitle('Logout');
promise.wait(auth.logout())
.then(function() {
loaded();
$messages.empty();
var $messageDiv = messagePresenter.showInfo($messages, 'Logged out. <a href="">Back to main page</a>');
$messageDiv.find('a').click(mainPageLinkClicked);
}).fail(function(response) {
messagePresenter.showError(($messages, response.json && response.json.error || response) + '<br/>Reload the page to continue.');
loaded();
});
}
function init(params, loaded) {
topNavigationPresenter.select('logout');
topNavigationPresenter.changeTitle('Logout');
promise.wait(auth.logout())
.then(function() {
loaded();
$messages.empty();
var $messageDiv = messagePresenter.showInfo($messages, 'Logged out. <a href="">Back to main page</a>');
$messageDiv.find('a').click(mainPageLinkClicked);
}).fail(function(response) {
messagePresenter.showError(($messages, response.json && response.json.error || response) + '<br/>Reload the page to continue.');
loaded();
});
}
function mainPageLinkClicked(e) {
e.preventDefault();
router.navigateToMainPage();
}
function mainPageLinkClicked(e) {
e.preventDefault();
router.navigateToMainPage();
}
return {
init: init
};
return {
init: init
};
};

View file

@ -3,51 +3,51 @@ App.Presenters = App.Presenters || {};
App.Presenters.MessagePresenter = function(_, jQuery) {
var options = {
instant: false
};
var options = {
instant: false
};
function showInfo($el, message) {
return showMessage($el, 'info', message);
}
function showInfo($el, message) {
return showMessage($el, 'info', message);
}
function showError($el, message) {
return showMessage($el, 'error', message);
}
function showError($el, message) {
return showMessage($el, 'error', message);
}
function hideMessages($el) {
var $messages = $el.children('.message');
if (options.instant) {
$messages.each(function() {
jQuery(this).slideUp('fast', function() {
jQuery(this).remove();
});
});
} else {
$messages.remove();
}
}
function hideMessages($el) {
var $messages = $el.children('.message');
if (options.instant) {
$messages.each(function() {
jQuery(this).slideUp('fast', function() {
jQuery(this).remove();
});
});
} else {
$messages.remove();
}
}
function showMessage($el, className, message) {
var $messageDiv = jQuery('<div>');
$messageDiv.addClass('message');
$messageDiv.addClass(className);
$messageDiv.html(message);
if (!options.instant) {
$messageDiv.hide();
}
$el.append($messageDiv);
if (!options.instant) {
$messageDiv.slideDown('fast');
}
return $messageDiv;
}
function showMessage($el, className, message) {
var $messageDiv = jQuery('<div>');
$messageDiv.addClass('message');
$messageDiv.addClass(className);
$messageDiv.html(message);
if (!options.instant) {
$messageDiv.hide();
}
$el.append($messageDiv);
if (!options.instant) {
$messageDiv.slideDown('fast');
}
return $messageDiv;
}
return _.extend(options, {
showInfo: showInfo,
showError: showError,
hideMessages: hideMessages,
});
return _.extend(options, {
showInfo: showInfo,
showError: showError,
hideMessages: hideMessages,
});
};

View file

@ -2,267 +2,267 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.PagerPresenter = function(
_,
jQuery,
util,
promise,
keyboard,
router,
pager,
messagePresenter,
browsingSettings,
progress) {
_,
jQuery,
util,
promise,
keyboard,
router,
pager,
messagePresenter,
browsingSettings,
progress) {
var $target;
var $pageList;
var $messages;
var targetContent;
var endlessScroll = browsingSettings.getSettings().endlessScroll;
var scrollInterval;
var templates = {};
var forceClear = !endlessScroll;
var $target;
var $pageList;
var $messages;
var targetContent;
var endlessScroll = browsingSettings.getSettings().endlessScroll;
var scrollInterval;
var templates = {};
var forceClear = !endlessScroll;
var baseUri;
var updateCallback;
var baseUri;
var updateCallback;
function init(params, loaded) {
baseUri = params.baseUri;
updateCallback = params.updateCallback;
function init(params, loaded) {
baseUri = params.baseUri;
updateCallback = params.updateCallback;
messagePresenter.instant = true;
messagePresenter.instant = true;
$target = params.$target;
targetContent = jQuery(params.$target).html();
$target = params.$target;
targetContent = jQuery(params.$target).html();
pager.init({url: params.backendUri});
setQuery(params.query);
if (forceClear) {
clearContent();
}
pager.init({url: params.backendUri});
setQuery(params.query);
if (forceClear) {
clearContent();
}
promise.wait(util.promiseTemplate('pager'))
.then(function(template) {
templates.pager = template;
render();
loaded();
}).fail(function() {
console.log(arguments);
loaded();
});
}
promise.wait(util.promiseTemplate('pager'))
.then(function(template) {
templates.pager = template;
render();
loaded();
}).fail(function() {
console.log(arguments);
loaded();
});
}
function reinit(params, loaded) {
setQuery(params.query);
if (forceClear) {
clearContent();
}
function reinit(params, loaded) {
setQuery(params.query);
if (forceClear) {
clearContent();
}
promise.wait(retrieve())
.then(loaded)
.fail(loaded);
promise.wait(retrieve())
.then(loaded)
.fail(loaded);
if (!endlessScroll) {
keyboard.keydown('a', navigateToPrevPage);
keyboard.keydown('d', navigateToNextPage);
}
}
if (!endlessScroll) {
keyboard.keydown('a', navigateToPrevPage);
keyboard.keydown('d', navigateToNextPage);
}
}
function deinit() {
detachNextPageLoader();
}
function deinit() {
detachNextPageLoader();
}
function getUrl(options) {
return util.appendComplexRouteParam(
baseUri,
util.simplifySearchQuery(
_.extend(
{},
pager.getSearchParams(),
{page: pager.getPage()},
options)));
}
function getUrl(options) {
return util.appendComplexRouteParam(
baseUri,
util.simplifySearchQuery(
_.extend(
{},
pager.getSearchParams(),
{page: pager.getPage()},
options)));
}
function syncUrl(options) {
router.navigate(getUrl(options));
}
function syncUrl(options) {
router.navigate(getUrl(options));
}
function syncUrlInplace(options) {
router.navigateInplace(getUrl(options));
}
function syncUrlInplace(options) {
router.navigateInplace(getUrl(options));
}
function retrieve() {
messagePresenter.hideMessages($messages);
progress.start();
function retrieve() {
messagePresenter.hideMessages($messages);
progress.start();
return promise.make(function(resolve, reject) {
hidePageList();
return promise.make(function(resolve, reject) {
hidePageList();
promise.wait(pager.retrieve())
.then(function(response) {
progress.done();
promise.wait(pager.retrieve())
.then(function(response) {
progress.done();
if (forceClear) {
clearContent();
window.scrollTo(0, 0);
}
var $page = jQuery('<div class="page">');
if (endlessScroll && pager.getTotalPages() > 1) {
$page.append('<p>Page ' + pager.getPage() + ' of ' + pager.getTotalPages() + '</p>');
}
$page.append(targetContent);
$target.find('.pagination-content').append($page);
updateCallback($page, response);
if (forceClear) {
clearContent();
window.scrollTo(0, 0);
}
var $page = jQuery('<div class="page">');
if (endlessScroll && pager.getTotalPages() > 1) {
$page.append('<p>Page ' + pager.getPage() + ' of ' + pager.getTotalPages() + '</p>');
}
$page.append(targetContent);
$target.find('.pagination-content').append($page);
updateCallback($page, response);
refreshPageList();
if (!response.entities.length) {
messagePresenter.showInfo($messages, 'No data to show');
if (pager.getVisiblePages().length === 1) {
hidePageList();
} else {
showPageList();
}
} else {
showPageList();
}
refreshPageList();
if (!response.entities.length) {
messagePresenter.showInfo($messages, 'No data to show');
if (pager.getVisiblePages().length === 1) {
hidePageList();
} else {
showPageList();
}
} else {
showPageList();
}
if (pager.getPage() < response.totalPages) {
attachNextPageLoader();
}
if (pager.getPage() < response.totalPages) {
attachNextPageLoader();
}
resolve();
}).fail(function(response) {
progress.done();
clearContent();
hidePageList();
messagePresenter.showError($messages, response.json && response.json.error || response);
resolve();
}).fail(function(response) {
progress.done();
clearContent();
hidePageList();
messagePresenter.showError($messages, response.json && response.json.error || response);
reject();
});
});
}
reject();
});
});
}
function clearContent() {
detachNextPageLoader();
$target.find('.pagination-content').empty();
}
function clearContent() {
detachNextPageLoader();
$target.find('.pagination-content').empty();
}
function attachNextPageLoader() {
if (!endlessScroll) {
return;
}
function attachNextPageLoader() {
if (!endlessScroll) {
return;
}
detachNextPageLoader();
scrollInterval = window.setInterval(function() {
var myScrollInterval = scrollInterval;
var baseLine = $target.offset().top + $target.innerHeight();
var scrollY = jQuery(window).scrollTop() + jQuery(window).height();
if (scrollY > baseLine) {
syncUrlInplace({page: pager.getPage() + 1});
window.clearInterval(myScrollInterval);
}
}, 100);
}
detachNextPageLoader();
scrollInterval = window.setInterval(function() {
var myScrollInterval = scrollInterval;
var baseLine = $target.offset().top + $target.innerHeight();
var scrollY = jQuery(window).scrollTop() + jQuery(window).height();
if (scrollY > baseLine) {
syncUrlInplace({page: pager.getPage() + 1});
window.clearInterval(myScrollInterval);
}
}, 100);
}
function detachNextPageLoader() {
window.clearInterval(scrollInterval);
}
function detachNextPageLoader() {
window.clearInterval(scrollInterval);
}
function showPageList() {
$pageList.show();
}
function showPageList() {
$pageList.show();
}
function hidePageList() {
$pageList.hide();
}
function hidePageList() {
$pageList.hide();
}
function navigateToPrevPage() {
console.log('!');
if (pager.prevPage()) {
syncUrl({page: pager.getPage()});
}
}
function navigateToPrevPage() {
console.log('!');
if (pager.prevPage()) {
syncUrl({page: pager.getPage()});
}
}
function navigateToNextPage() {
if (pager.nextPage()) {
syncUrl({page: pager.getPage()});
}
}
function navigateToNextPage() {
if (pager.nextPage()) {
syncUrl({page: pager.getPage()});
}
}
function refreshPageList() {
var $lastItem = $pageList.find('li:last-child');
var currentPage = pager.getPage();
var pages = pager.getVisiblePages();
$pageList.find('li.page').remove();
var lastPage = 0;
_.each(pages, function(page) {
if (page - lastPage > 1) {
jQuery('<li class="page ellipsis"><a>&hellip;</a></li>').insertBefore($lastItem);
}
lastPage = page;
function refreshPageList() {
var $lastItem = $pageList.find('li:last-child');
var currentPage = pager.getPage();
var pages = pager.getVisiblePages();
$pageList.find('li.page').remove();
var lastPage = 0;
_.each(pages, function(page) {
if (page - lastPage > 1) {
jQuery('<li class="page ellipsis"><a>&hellip;</a></li>').insertBefore($lastItem);
}
lastPage = page;
var $a = jQuery('<a href="#"/>');
$a.click(function(e) {
e.preventDefault();
syncUrl({page: page});
});
$a.addClass('big-button');
$a.text(page);
if (page === currentPage) {
$a.addClass('active');
}
jQuery('<li class="page"/>').append($a).insertBefore($lastItem);
});
var $a = jQuery('<a href="#"/>');
$a.click(function(e) {
e.preventDefault();
syncUrl({page: page});
});
$a.addClass('big-button');
$a.text(page);
if (page === currentPage) {
$a.addClass('active');
}
jQuery('<li class="page"/>').append($a).insertBefore($lastItem);
});
$pageList.find('li.next a').unbind('click').bind('click', function(e) {
e.preventDefault();
navigateToNextPage();
});
$pageList.find('li.prev a').unbind('click').bind('click', function(e) {
e.preventDefault();
navigateToPrevPage();
});
}
$pageList.find('li.next a').unbind('click').bind('click', function(e) {
e.preventDefault();
navigateToNextPage();
});
$pageList.find('li.prev a').unbind('click').bind('click', function(e) {
e.preventDefault();
navigateToPrevPage();
});
}
function render() {
$target.html(templates.pager());
$messages = $target.find('.pagination-content');
$pageList = $target.find('.page-list');
if (endlessScroll) {
$pageList.remove();
} else {
refreshPageList();
}
}
function render() {
$target.html(templates.pager());
$messages = $target.find('.pagination-content');
$pageList = $target.find('.page-list');
if (endlessScroll) {
$pageList.remove();
} else {
refreshPageList();
}
}
function setQuery(query) {
if (!query) {
return;
}
query.page = parseInt(query.page) || 1;
var page = query.page;
query = _.extend({}, query);
delete query.page;
forceClear =
query.query !== pager.getSearchParams().query ||
query.order !== pager.getSearchParams().order ||
parseInt(page) !== pager.getPage() + 1 ||
!endlessScroll;
pager.setSearchParams(query);
pager.setPage(page);
}
function setQuery(query) {
if (!query) {
return;
}
query.page = parseInt(query.page) || 1;
var page = query.page;
query = _.extend({}, query);
delete query.page;
forceClear =
query.query !== pager.getSearchParams().query ||
query.order !== pager.getSearchParams().order ||
parseInt(page) !== pager.getPage() + 1 ||
!endlessScroll;
pager.setSearchParams(query);
pager.setPage(page);
}
function setQueryAndSyncUrl(query) {
setQuery(query);
syncUrl();
}
function setQueryAndSyncUrl(query) {
setQuery(query);
syncUrl();
}
return {
init: init,
reinit: reinit,
deinit: deinit,
syncUrl: syncUrl,
setQuery: setQueryAndSyncUrl,
};
return {
init: init,
reinit: reinit,
deinit: deinit,
syncUrl: syncUrl,
setQuery: setQueryAndSyncUrl,
};
};

View file

@ -2,76 +2,76 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.PostContentPresenter = function(
jQuery,
util,
promise,
presenterManager,
postNotesPresenter) {
jQuery,
util,
promise,
presenterManager,
postNotesPresenter) {
var post;
var templates = {};
var $target;
var post;
var templates = {};
var $target;
function init(params, loaded) {
$target = params.$target;
post = params.post;
function init(params, loaded) {
$target = params.$target;
post = params.post;
promise.wait(util.promiseTemplate('post-content'))
.then(function(postContentTemplate) {
templates.postContent = postContentTemplate;
render();
loaded();
}).fail(function() {
console.log(arguments);
loaded();
});
}
promise.wait(util.promiseTemplate('post-content'))
.then(function(postContentTemplate) {
templates.postContent = postContentTemplate;
render();
loaded();
}).fail(function() {
console.log(arguments);
loaded();
});
}
function render() {
$target.html(templates.postContent({post: post}));
function render() {
$target.html(templates.postContent({post: post}));
if (post.contentType === 'image') {
loadPostNotes();
updatePostNotesSize();
}
if (post.contentType === 'image') {
loadPostNotes();
updatePostNotesSize();
}
jQuery(window).resize(updatePostNotesSize);
}
jQuery(window).resize(updatePostNotesSize);
}
function loadPostNotes() {
presenterManager.initPresenters([
[postNotesPresenter, {post: post, notes: post.notes, $target: $target.find('.post-notes-target')}]],
function() {});
}
function loadPostNotes() {
presenterManager.initPresenters([
[postNotesPresenter, {post: post, notes: post.notes, $target: $target.find('.post-notes-target')}]],
function() {});
}
function updatePostNotesSize() {
var $postNotes = $target.find('.post-notes-target');
var $objectWrapper = $target.find('.object-wrapper');
$postNotes.css({
width: $objectWrapper.outerWidth() + 'px',
height: $objectWrapper.outerHeight() + 'px',
left: ($objectWrapper.offset().left - $objectWrapper.parent().offset().left) + 'px',
top: ($objectWrapper.offset().top - $objectWrapper.parent().offset().top) + 'px',
});
}
function updatePostNotesSize() {
var $postNotes = $target.find('.post-notes-target');
var $objectWrapper = $target.find('.object-wrapper');
$postNotes.css({
width: $objectWrapper.outerWidth() + 'px',
height: $objectWrapper.outerHeight() + 'px',
left: ($objectWrapper.offset().left - $objectWrapper.parent().offset().left) + 'px',
top: ($objectWrapper.offset().top - $objectWrapper.parent().offset().top) + 'px',
});
}
function addNewPostNote() {
postNotesPresenter.addNewPostNote();
}
function addNewPostNote() {
postNotesPresenter.addNewPostNote();
}
return {
init: init,
render: render,
addNewPostNote: addNewPostNote,
updatePostNotesSize: updatePostNotesSize,
};
return {
init: init,
render: render,
addNewPostNote: addNewPostNote,
updatePostNotesSize: updatePostNotesSize,
};
};
App.DI.register('postContentPresenter', [
'jQuery',
'util',
'promise',
'presenterManager',
'postNotesPresenter'],
App.Presenters.PostContentPresenter);
'jQuery',
'util',
'promise',
'presenterManager',
'postNotesPresenter'],
App.Presenters.PostContentPresenter);

View file

@ -2,154 +2,154 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.PostEditPresenter = function(
jQuery,
util,
promise,
api,
auth,
tagList) {
jQuery,
util,
promise,
api,
auth,
tagList) {
var $target;
var post;
var updateCallback;
var privileges = {};
var templates = {};
var $target;
var post;
var updateCallback;
var privileges = {};
var templates = {};
var tagInput;
var postContentFileDropper;
var postThumbnailFileDropper;
var postContent;
var postThumbnail;
var tagInput;
var postContentFileDropper;
var postThumbnailFileDropper;
var postContent;
var postThumbnail;
privileges.canChangeSafety = auth.hasPrivilege(auth.privileges.changePostSafety);
privileges.canChangeSource = auth.hasPrivilege(auth.privileges.changePostSource);
privileges.canChangeTags = auth.hasPrivilege(auth.privileges.changePostTags);
privileges.canChangeContent = auth.hasPrivilege(auth.privileges.changePostContent);
privileges.canChangeThumbnail = auth.hasPrivilege(auth.privileges.changePostThumbnail);
privileges.canChangeRelations = auth.hasPrivilege(auth.privileges.changePostRelations);
privileges.canChangeFlags = auth.hasPrivilege(auth.privileges.changePostFlags);
privileges.canChangeSafety = auth.hasPrivilege(auth.privileges.changePostSafety);
privileges.canChangeSource = auth.hasPrivilege(auth.privileges.changePostSource);
privileges.canChangeTags = auth.hasPrivilege(auth.privileges.changePostTags);
privileges.canChangeContent = auth.hasPrivilege(auth.privileges.changePostContent);
privileges.canChangeThumbnail = auth.hasPrivilege(auth.privileges.changePostThumbnail);
privileges.canChangeRelations = auth.hasPrivilege(auth.privileges.changePostRelations);
privileges.canChangeFlags = auth.hasPrivilege(auth.privileges.changePostFlags);
function init(params, loaded) {
post = params.post;
function init(params, loaded) {
post = params.post;
updateCallback = params.updateCallback;
$target = params.$target;
updateCallback = params.updateCallback;
$target = params.$target;
promise.wait(util.promiseTemplate('post-edit'))
.then(function(postEditTemplate) {
templates.postEdit = postEditTemplate;
render();
loaded();
}).fail(function() {
console.log(arguments);
loaded();
});
}
promise.wait(util.promiseTemplate('post-edit'))
.then(function(postEditTemplate) {
templates.postEdit = postEditTemplate;
render();
loaded();
}).fail(function() {
console.log(arguments);
loaded();
});
}
function render() {
$target.html(templates.postEdit({post: post, privileges: privileges}));
function render() {
$target.html(templates.postEdit({post: post, privileges: privileges}));
postContentFileDropper = new App.Controls.FileDropper($target.find('form [name=content]'));
postContentFileDropper.onChange = postContentChanged;
postContentFileDropper.setNames = true;
postThumbnailFileDropper = new App.Controls.FileDropper($target.find('form [name=thumbnail]'));
postThumbnailFileDropper.onChange = postThumbnailChanged;
postThumbnailFileDropper.setNames = true;
postContentFileDropper = new App.Controls.FileDropper($target.find('form [name=content]'));
postContentFileDropper.onChange = postContentChanged;
postContentFileDropper.setNames = true;
postThumbnailFileDropper = new App.Controls.FileDropper($target.find('form [name=thumbnail]'));
postThumbnailFileDropper.onChange = postThumbnailChanged;
postThumbnailFileDropper.setNames = true;
if (privileges.canChangeTags) {
tagInput = new App.Controls.TagInput($target.find('form [name=tags]'));
tagInput.inputConfirmed = editPost;
}
if (privileges.canChangeTags) {
tagInput = new App.Controls.TagInput($target.find('form [name=tags]'));
tagInput.inputConfirmed = editPost;
}
$target.find('form').submit(editFormSubmitted);
}
$target.find('form').submit(editFormSubmitted);
}
function focus() {
if (tagInput) {
tagInput.focus();
}
}
function focus() {
if (tagInput) {
tagInput.focus();
}
}
function editFormSubmitted(e) {
e.preventDefault();
editPost();
}
function editFormSubmitted(e) {
e.preventDefault();
editPost();
}
function postContentChanged(files) {
postContent = files[0];
}
function postContentChanged(files) {
postContent = files[0];
}
function postThumbnailChanged(files) {
postThumbnail = files[0];
}
function postThumbnailChanged(files) {
postThumbnail = files[0];
}
function getPrivileges() {
return privileges;
}
function getPrivileges() {
return privileges;
}
function editPost() {
var $form = $target.find('form');
var formData = new FormData();
formData.append('seenEditTime', post.lastEditTime);
function editPost() {
var $form = $target.find('form');
var formData = new FormData();
formData.append('seenEditTime', post.lastEditTime);
if (privileges.canChangeContent && postContent) {
formData.append('content', postContent);
}
if (privileges.canChangeContent && postContent) {
formData.append('content', postContent);
}
if (privileges.canChangeThumbnail && postThumbnail) {
formData.append('thumbnail', postThumbnail);
}
if (privileges.canChangeThumbnail && postThumbnail) {
formData.append('thumbnail', postThumbnail);
}
if (privileges.canChangeSource) {
formData.append('source', $form.find('[name=source]').val());
}
if (privileges.canChangeSource) {
formData.append('source', $form.find('[name=source]').val());
}
if (privileges.canChangeSafety) {
formData.append('safety', $form.find('[name=safety]:checked').val());
}
if (privileges.canChangeSafety) {
formData.append('safety', $form.find('[name=safety]:checked').val());
}
if (privileges.canChangeTags) {
formData.append('tags', tagInput.getTags().join(' '));
}
if (privileges.canChangeTags) {
formData.append('tags', tagInput.getTags().join(' '));
}
if (privileges.canChangeRelations) {
formData.append('relations', $form.find('[name=relations]').val());
}
if (privileges.canChangeRelations) {
formData.append('relations', $form.find('[name=relations]').val());
}
if (privileges.canChangeFlags) {
if (post.contentType === 'video') {
formData.append('loop', $form.find('[name=loop]').is(':checked') ? 1 : 0);
}
}
if (privileges.canChangeFlags) {
if (post.contentType === 'video') {
formData.append('loop', $form.find('[name=loop]').is(':checked') ? 1 : 0);
}
}
if (post.tags.length === 0) {
showEditError('No tags set.');
return;
}
if (post.tags.length === 0) {
showEditError('No tags set.');
return;
}
jQuery(document.activeElement).blur();
jQuery(document.activeElement).blur();
promise.wait(api.post('/posts/' + post.id, formData))
.then(function(response) {
tagList.refreshTags();
if (typeof(updateCallback) !== 'undefined') {
updateCallback(post = response.json);
}
}).fail(function(response) {
showEditError(response);
});
}
promise.wait(api.post('/posts/' + post.id, formData))
.then(function(response) {
tagList.refreshTags();
if (typeof(updateCallback) !== 'undefined') {
updateCallback(post = response.json);
}
}).fail(function(response) {
showEditError(response);
});
}
function showEditError(response) {
window.alert(response.json && response.json.error || response);
}
function showEditError(response) {
window.alert(response.json && response.json.error || response);
}
return {
init: init,
render: render,
getPrivileges: getPrivileges,
focus: focus,
};
return {
init: init,
render: render,
getPrivileges: getPrivileges,
focus: focus,
};
};

View file

@ -2,264 +2,264 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.PostListPresenter = function(
_,
jQuery,
util,
promise,
auth,
api,
keyboard,
pagerPresenter,
browsingSettings,
topNavigationPresenter) {
_,
jQuery,
util,
promise,
auth,
api,
keyboard,
pagerPresenter,
browsingSettings,
topNavigationPresenter) {
var KEY_RETURN = 13;
var KEY_RETURN = 13;
var templates = {};
var $el = jQuery('#content');
var $searchInput;
var privileges = {};
var templates = {};
var $el = jQuery('#content');
var $searchInput;
var privileges = {};
var params;
var params;
function init(_params, loaded) {
topNavigationPresenter.select('posts');
topNavigationPresenter.changeTitle('Posts');
params = _params;
params.query = params.query || {};
function init(_params, loaded) {
topNavigationPresenter.select('posts');
topNavigationPresenter.changeTitle('Posts');
params = _params;
params.query = params.query || {};
privileges.canMassTag = auth.hasPrivilege(auth.privileges.massTag);
privileges.canViewPosts = auth.hasPrivilege(auth.privileges.viewPosts);
privileges.canMassTag = auth.hasPrivilege(auth.privileges.massTag);
privileges.canViewPosts = auth.hasPrivilege(auth.privileges.viewPosts);
promise.wait(
util.promiseTemplate('post-list'),
util.promiseTemplate('post-list-item'))
.then(function(listTemplate, listItemTemplate) {
templates.list = listTemplate;
templates.listItem = listItemTemplate;
promise.wait(
util.promiseTemplate('post-list'),
util.promiseTemplate('post-list-item'))
.then(function(listTemplate, listItemTemplate) {
templates.list = listTemplate;
templates.listItem = listItemTemplate;
render();
loaded();
render();
loaded();
pagerPresenter.init({
baseUri: '#/posts',
backendUri: '/posts',
$target: $el.find('.pagination-target'),
updateCallback: function($page, data) {
renderPosts($page, data.entities);
},
},
function() {
reinit(params, function() {});
});
}).fail(function() {
console.log(arguments);
loaded();
});
pagerPresenter.init({
baseUri: '#/posts',
backendUri: '/posts',
$target: $el.find('.pagination-target'),
updateCallback: function($page, data) {
renderPosts($page, data.entities);
},
},
function() {
reinit(params, function() {});
});
}).fail(function() {
console.log(arguments);
loaded();
});
jQuery(window).on('resize', windowResized);
}
jQuery(window).on('resize', windowResized);
}
function reinit(_params, loaded) {
params = _params;
params.query = params.query || {};
pagerPresenter.reinit({query: params.query});
loaded();
softRender();
}
function reinit(_params, loaded) {
params = _params;
params.query = params.query || {};
pagerPresenter.reinit({query: params.query});
loaded();
softRender();
}
function deinit() {
pagerPresenter.deinit();
jQuery(window).off('resize', windowResized);
}
function deinit() {
pagerPresenter.deinit();
jQuery(window).off('resize', windowResized);
}
function render() {
$el.html(templates.list({
massTag: params.query.massTag,
privileges: privileges,
browsingSettings: browsingSettings.getSettings()}));
$searchInput = $el.find('input[name=query]');
App.Controls.AutoCompleteInput($searchInput);
function render() {
$el.html(templates.list({
massTag: params.query.massTag,
privileges: privileges,
browsingSettings: browsingSettings.getSettings()}));
$searchInput = $el.find('input[name=query]');
App.Controls.AutoCompleteInput($searchInput);
$searchInput.val(params.query.query);
$searchInput.keydown(searchInputKeyPressed);
$el.find('form').submit(searchFormSubmitted);
$el.find('[name=mass-tag]').click(massTagButtonClicked);
$el.find('.safety button').click(safetyButtonClicked);
$searchInput.val(params.query.query);
$searchInput.keydown(searchInputKeyPressed);
$el.find('form').submit(searchFormSubmitted);
$el.find('[name=mass-tag]').click(massTagButtonClicked);
$el.find('.safety button').click(safetyButtonClicked);
keyboard.keyup('p', function() {
$el.find('.posts li a').eq(0).focus();
});
keyboard.keyup('p', function() {
$el.find('.posts li a').eq(0).focus();
});
keyboard.keyup('q', function() {
$searchInput.eq(0).focus().select();
});
keyboard.keyup('q', function() {
$searchInput.eq(0).focus().select();
});
windowResized();
}
windowResized();
}
function safetyButtonClicked(e) {
e.preventDefault();
var settings = browsingSettings.getSettings();
var buttonClass = jQuery(e.currentTarget).attr('class').split(' ')[0];
var enabled = jQuery(e.currentTarget).hasClass('disabled');
jQuery(e.currentTarget).toggleClass('disabled');
if (buttonClass === 'safety-unsafe') {
settings.listPosts.unsafe = enabled;
} else if (buttonClass === 'safety-sketchy') {
settings.listPosts.sketchy = enabled;
} else if (buttonClass === 'safety-safe') {
settings.listPosts.safe = enabled;
}
promise.wait(browsingSettings.setSettings(settings))
.then(function() {
reinit(params, function() {});
}).fail(function() {
console.log(arguments);
});
}
function safetyButtonClicked(e) {
e.preventDefault();
var settings = browsingSettings.getSettings();
var buttonClass = jQuery(e.currentTarget).attr('class').split(' ')[0];
var enabled = jQuery(e.currentTarget).hasClass('disabled');
jQuery(e.currentTarget).toggleClass('disabled');
if (buttonClass === 'safety-unsafe') {
settings.listPosts.unsafe = enabled;
} else if (buttonClass === 'safety-sketchy') {
settings.listPosts.sketchy = enabled;
} else if (buttonClass === 'safety-safe') {
settings.listPosts.safe = enabled;
}
promise.wait(browsingSettings.setSettings(settings))
.then(function() {
reinit(params, function() {});
}).fail(function() {
console.log(arguments);
});
}
function softRender() {
$searchInput.val(params.query.query);
function softRender() {
$searchInput.val(params.query.query);
var $massTagInfo = $el.find('.mass-tag-info');
if (params.query.massTag) {
$massTagInfo.show();
$massTagInfo.find('span').text(params.query.massTag);
} else {
$massTagInfo.hide();
}
_.map($el.find('.posts .post-small'), function(postNode) { softRenderPost(jQuery(postNode).parents('li')); });
}
var $massTagInfo = $el.find('.mass-tag-info');
if (params.query.massTag) {
$massTagInfo.show();
$massTagInfo.find('span').text(params.query.massTag);
} else {
$massTagInfo.hide();
}
_.map($el.find('.posts .post-small'), function(postNode) { softRenderPost(jQuery(postNode).parents('li')); });
}
function renderPosts($page, posts) {
var $target = $page.find('.posts');
_.each(posts, function(post) {
if (!shouldSkipPost(post)) {
var $post = renderPost(post);
softRenderPost($post);
$target.append($post);
}
});
windowResized();
}
function renderPosts($page, posts) {
var $target = $page.find('.posts');
_.each(posts, function(post) {
if (!shouldSkipPost(post)) {
var $post = renderPost(post);
softRenderPost($post);
$target.append($post);
}
});
windowResized();
}
function shouldSkipPost(post) {
var settings = browsingSettings.getSettings();
if (post.ownScore < 0 && settings.hideDownvoted) {
return true;
}
if (settings.listPosts) {
if (post.safety === 'safe' && !settings.listPosts.safe) {
return true;
} else if (post.safety === 'sketchy' && !settings.listPosts.sketchy) {
return true;
} else if (post.safety === 'unsafe' && !settings.listPosts.unsafe) {
return true;
}
}
return false;
}
function shouldSkipPost(post) {
var settings = browsingSettings.getSettings();
if (post.ownScore < 0 && settings.hideDownvoted) {
return true;
}
if (settings.listPosts) {
if (post.safety === 'safe' && !settings.listPosts.safe) {
return true;
} else if (post.safety === 'sketchy' && !settings.listPosts.sketchy) {
return true;
} else if (post.safety === 'unsafe' && !settings.listPosts.unsafe) {
return true;
}
}
return false;
}
function renderPost(post) {
var $post = jQuery('<li>' + templates.listItem({
util: util,
query: params.query,
post: post,
canViewPosts: privileges.canViewPosts,
}) + '</li>');
$post.data('post', post);
util.loadImagesNicely($post.find('img'));
return $post;
}
function renderPost(post) {
var $post = jQuery('<li>' + templates.listItem({
util: util,
query: params.query,
post: post,
canViewPosts: privileges.canViewPosts,
}) + '</li>');
$post.data('post', post);
util.loadImagesNicely($post.find('img'));
return $post;
}
function softRenderPost($post) {
var classes = [];
if (params.query.massTag) {
var post = $post.data('post');
if (_.contains(_.map(post.tags, function(tag) { return tag.name.toLowerCase(); }), params.query.massTag.toLowerCase())) {
classes.push('tagged');
} else {
classes.push('untagged');
}
}
$post.toggleClass('tagged', _.contains(classes, 'tagged'));
$post.toggleClass('untagged', _.contains(classes, 'untagged'));
$post.find('.action').toggle(_.any(classes));
$post.find('.action button').text(_.contains(classes, 'tagged') ? 'Tagged' : 'Untagged').unbind('click').click(postTagButtonClicked);
}
function softRenderPost($post) {
var classes = [];
if (params.query.massTag) {
var post = $post.data('post');
if (_.contains(_.map(post.tags, function(tag) { return tag.name.toLowerCase(); }), params.query.massTag.toLowerCase())) {
classes.push('tagged');
} else {
classes.push('untagged');
}
}
$post.toggleClass('tagged', _.contains(classes, 'tagged'));
$post.toggleClass('untagged', _.contains(classes, 'untagged'));
$post.find('.action').toggle(_.any(classes));
$post.find('.action button').text(_.contains(classes, 'tagged') ? 'Tagged' : 'Untagged').unbind('click').click(postTagButtonClicked);
}
function windowResized() {
var $list = $el.find('ul.posts');
var $posts = $list.find('.post-small');
var $firstPost = $posts.eq(0);
var $lastPost = $firstPost;
for (var i = 1; i < $posts.length; i ++) {
$lastPost = $posts.eq(i-1);
if ($posts.eq(i).offset().left < $lastPost.offset().left) {
break;
}
}
if ($firstPost.length === 0) {
return;
}
$el.find('.search').width($lastPost.offset().left + $lastPost.width() - $firstPost.offset().left);
}
function windowResized() {
var $list = $el.find('ul.posts');
var $posts = $list.find('.post-small');
var $firstPost = $posts.eq(0);
var $lastPost = $firstPost;
for (var i = 1; i < $posts.length; i ++) {
$lastPost = $posts.eq(i-1);
if ($posts.eq(i).offset().left < $lastPost.offset().left) {
break;
}
}
if ($firstPost.length === 0) {
return;
}
$el.find('.search').width($lastPost.offset().left + $lastPost.width() - $firstPost.offset().left);
}
function postTagButtonClicked(e) {
e.preventDefault();
var $post = jQuery(e.target).parents('li');
var post = $post.data('post');
var tags = _.pluck(post.tags, 'name');
if (_.contains(_.map(tags, function(tag) { return tag.toLowerCase(); }), params.query.massTag.toLowerCase())) {
tags = _.filter(tags, function(tag) { return tag.toLowerCase() !== params.query.massTag.toLowerCase(); });
} else {
tags.push(params.query.massTag);
}
var formData = {};
formData.seenEditTime = post.lastEditTime;
formData.tags = tags.join(' ');
promise.wait(api.post('/posts/' + post.id, formData))
.then(function(response) {
post = response.json;
$post.data('post', post);
softRenderPost($post);
}).fail(function(response) {
window.alert(response.json && response.json.error || response);
});
}
function postTagButtonClicked(e) {
e.preventDefault();
var $post = jQuery(e.target).parents('li');
var post = $post.data('post');
var tags = _.pluck(post.tags, 'name');
if (_.contains(_.map(tags, function(tag) { return tag.toLowerCase(); }), params.query.massTag.toLowerCase())) {
tags = _.filter(tags, function(tag) { return tag.toLowerCase() !== params.query.massTag.toLowerCase(); });
} else {
tags.push(params.query.massTag);
}
var formData = {};
formData.seenEditTime = post.lastEditTime;
formData.tags = tags.join(' ');
promise.wait(api.post('/posts/' + post.id, formData))
.then(function(response) {
post = response.json;
$post.data('post', post);
softRenderPost($post);
}).fail(function(response) {
window.alert(response.json && response.json.error || response);
});
}
function searchInputKeyPressed(e) {
if (e.which !== KEY_RETURN) {
return;
}
updateSearch();
}
function searchInputKeyPressed(e) {
if (e.which !== KEY_RETURN) {
return;
}
updateSearch();
}
function massTagButtonClicked(e) {
e.preventDefault();
params.query.massTag = window.prompt('Enter tag to tag with:');
pagerPresenter.setQuery(params.query);
}
function massTagButtonClicked(e) {
e.preventDefault();
params.query.massTag = window.prompt('Enter tag to tag with:');
pagerPresenter.setQuery(params.query);
}
function searchFormSubmitted(e) {
e.preventDefault();
updateSearch();
}
function searchFormSubmitted(e) {
e.preventDefault();
updateSearch();
}
function updateSearch() {
$searchInput.blur();
params.query.query = $searchInput.val().trim();
params.query.page = 1;
pagerPresenter.setQuery(params.query);
}
function updateSearch() {
$searchInput.blur();
params.query.query = $searchInput.val().trim();
params.query.page = 1;
pagerPresenter.setQuery(params.query);
}
return {
init: init,
reinit: reinit,
deinit: deinit,
render: render,
};
return {
init: init,
reinit: reinit,
deinit: deinit,
render: render,
};
};

View file

@ -2,192 +2,192 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.PostNotesPresenter = function(
jQuery,
util,
promise,
api,
auth,
draggable,
resizable) {
jQuery,
util,
promise,
api,
auth,
draggable,
resizable) {
var post;
var notes;
var templates = {};
var $target;
var $form;
var privileges = {};
var post;
var notes;
var templates = {};
var $target;
var $form;
var privileges = {};
function init(params, loaded) {
$target = params.$target;
post = params.post;
notes = params.notes || [];
function init(params, loaded) {
$target = params.$target;
post = params.post;
notes = params.notes || [];
privileges.canDeletePostNotes = auth.hasPrivilege(auth.privileges.deletePostNotes);
privileges.canEditPostNotes = auth.hasPrivilege(auth.privileges.editPostNotes);
privileges.canDeletePostNotes = auth.hasPrivilege(auth.privileges.deletePostNotes);
privileges.canEditPostNotes = auth.hasPrivilege(auth.privileges.editPostNotes);
promise.wait(util.promiseTemplate('post-notes'))
.then(function(postNotesTemplate) {
templates.postNotes = postNotesTemplate;
render();
loaded();
}).fail(function() {
console.log(arguments);
loaded();
});
}
promise.wait(util.promiseTemplate('post-notes'))
.then(function(postNotesTemplate) {
templates.postNotes = postNotesTemplate;
render();
loaded();
}).fail(function() {
console.log(arguments);
loaded();
});
}
function addNewPostNote() {
notes.push({left: 10.0, top: 10.0, width: 10.0, height: 10.0, text: '…'});
}
function addNewPostNote() {
notes.push({left: 10.0, top: 10.0, width: 10.0, height: 10.0, text: '…'});
}
function addNewPostNoteAndRender() {
addNewPostNote();
render();
}
function addNewPostNoteAndRender() {
addNewPostNote();
render();
}
function render() {
$target.html(templates.postNotes({
privileges: privileges,
post: post,
notes: notes,
util: util}));
function render() {
$target.html(templates.postNotes({
privileges: privileges,
post: post,
notes: notes,
util: util}));
$form = $target.find('.post-note-edit');
var $postNotes = $target.find('.post-note');
$form = $target.find('.post-note-edit');
var $postNotes = $target.find('.post-note');
$postNotes.each(function(i) {
var postNote = notes[i];
var $postNote = jQuery(this);
$postNote.data('postNote', postNote);
$postNote.find('.text-wrapper').click(postNoteClicked);
postNote.$element = $postNote;
draggable.makeDraggable($postNote, draggable.relativeDragStrategy, true);
resizable.makeResizable($postNote, true);
});
$postNotes.each(function(i) {
var postNote = notes[i];
var $postNote = jQuery(this);
$postNote.data('postNote', postNote);
$postNote.find('.text-wrapper').click(postNoteClicked);
postNote.$element = $postNote;
draggable.makeDraggable($postNote, draggable.relativeDragStrategy, true);
resizable.makeResizable($postNote, true);
});
$form.find('button').click(formSubmitted);
}
$form.find('button').click(formSubmitted);
}
function formSubmitted(e) {
e.preventDefault();
var $button = jQuery(e.target);
var sender = $button.val();
function formSubmitted(e) {
e.preventDefault();
var $button = jQuery(e.target);
var sender = $button.val();
var postNote = $form.data('postNote');
postNote.left = (postNote.$element.offset().left - $target.offset().left) * 100.0 / $target.outerWidth();
postNote.top = (postNote.$element.offset().top - $target.offset().top) * 100.0 / $target.outerHeight();
postNote.width = postNote.$element.width() * 100.0 / $target.outerWidth();
postNote.height = postNote.$element.height() * 100.0 / $target.outerHeight();
postNote.text = $form.find('textarea').val();
var postNote = $form.data('postNote');
postNote.left = (postNote.$element.offset().left - $target.offset().left) * 100.0 / $target.outerWidth();
postNote.top = (postNote.$element.offset().top - $target.offset().top) * 100.0 / $target.outerHeight();
postNote.width = postNote.$element.width() * 100.0 / $target.outerWidth();
postNote.height = postNote.$element.height() * 100.0 / $target.outerHeight();
postNote.text = $form.find('textarea').val();
if (sender === 'cancel') {
hideForm();
} else if (sender === 'remove') {
removePostNote(postNote);
} else if (sender === 'save') {
savePostNote(postNote);
} else if (sender === 'preview') {
previewPostNote(postNote);
}
}
if (sender === 'cancel') {
hideForm();
} else if (sender === 'remove') {
removePostNote(postNote);
} else if (sender === 'save') {
savePostNote(postNote);
} else if (sender === 'preview') {
previewPostNote(postNote);
}
}
function removePostNote(postNote) {
if (postNote.id) {
if (window.confirm('Are you sure you want to delete this note?')) {
promise.wait(api.delete('/notes/' + postNote.id))
.then(function() {
hideForm();
postNote.$element.remove();
}).fail(function(response) {
window.alert(response.json && response.json.error || response);
});
}
} else {
postNote.$element.remove();
hideForm();
}
}
function removePostNote(postNote) {
if (postNote.id) {
if (window.confirm('Are you sure you want to delete this note?')) {
promise.wait(api.delete('/notes/' + postNote.id))
.then(function() {
hideForm();
postNote.$element.remove();
}).fail(function(response) {
window.alert(response.json && response.json.error || response);
});
}
} else {
postNote.$element.remove();
hideForm();
}
}
function savePostNote(postNote) {
if (window.confirm('Are you sure you want to save this note?')) {
var formData = {
left: postNote.left,
top: postNote.top,
width: postNote.width,
height: postNote.height,
text: postNote.text,
};
function savePostNote(postNote) {
if (window.confirm('Are you sure you want to save this note?')) {
var formData = {
left: postNote.left,
top: postNote.top,
width: postNote.width,
height: postNote.height,
text: postNote.text,
};
var p = postNote.id ?
api.put('/notes/' + postNote.id, formData) :
api.post('/notes/' + post.id, formData);
var p = postNote.id ?
api.put('/notes/' + postNote.id, formData) :
api.post('/notes/' + post.id, formData);
promise.wait(p)
.then(function(response) {
hideForm();
postNote.id = response.json.id;
postNote.$element.data('postNote', postNote);
render();
}).fail(function(response) {
window.alert(response.json && response.json.error || response);
});
}
}
promise.wait(p)
.then(function(response) {
hideForm();
postNote.id = response.json.id;
postNote.$element.data('postNote', postNote);
render();
}).fail(function(response) {
window.alert(response.json && response.json.error || response);
});
}
}
function previewPostNote(postNote) {
var previewText = $form.find('textarea').val();
postNote.$element.find('.text').html(util.formatMarkdown(previewText));
showPostNoteText(postNote);
}
function previewPostNote(postNote) {
var previewText = $form.find('textarea').val();
postNote.$element.find('.text').html(util.formatMarkdown(previewText));
showPostNoteText(postNote);
}
function showPostNoteText(postNote) {
postNote.$element.find('.text-wrapper').show();
}
function showPostNoteText(postNote) {
postNote.$element.find('.text-wrapper').show();
}
function hidePostNoteText(postNote) {
postNote.$element.find('.text-wrapper').css('display', '');
}
function hidePostNoteText(postNote) {
postNote.$element.find('.text-wrapper').css('display', '');
}
function postNoteClicked(e) {
e.preventDefault();
var $postNote = jQuery(e.currentTarget).parents('.post-note');
if ($postNote.hasClass('resizing') || $postNote.hasClass('dragging')) {
return;
}
showFormForPostNote($postNote);
}
function postNoteClicked(e) {
e.preventDefault();
var $postNote = jQuery(e.currentTarget).parents('.post-note');
if ($postNote.hasClass('resizing') || $postNote.hasClass('dragging')) {
return;
}
showFormForPostNote($postNote);
}
function showFormForPostNote($postNote) {
hideForm();
var postNote = $postNote.data('postNote');
$form.data('postNote', postNote);
$form.find('textarea').val(postNote.text);
$form.show();
draggable.makeDraggable($form, draggable.absoluteDragStrategy, false);
}
function showFormForPostNote($postNote) {
hideForm();
var postNote = $postNote.data('postNote');
$form.data('postNote', postNote);
$form.find('textarea').val(postNote.text);
$form.show();
draggable.makeDraggable($form, draggable.absoluteDragStrategy, false);
}
function hideForm() {
var previousPostNote = $form.data('post-note');
if (previousPostNote) {
hidePostNoteText(previousPostNote);
}
$form.hide();
}
function hideForm() {
var previousPostNote = $form.data('post-note');
if (previousPostNote) {
hidePostNoteText(previousPostNote);
}
$form.hide();
}
return {
init: init,
render: render,
addNewPostNote: addNewPostNoteAndRender,
};
return {
init: init,
render: render,
addNewPostNote: addNewPostNoteAndRender,
};
};
App.DI.register('postNotesPresenter', [
'jQuery',
'util',
'promise',
'api',
'auth',
'draggable',
'resizable'],
App.Presenters.PostNotesPresenter);
'jQuery',
'util',
'promise',
'api',
'auth',
'draggable',
'resizable'],
App.Presenters.PostNotesPresenter);

View file

@ -2,349 +2,349 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.PostPresenter = function(
_,
jQuery,
util,
promise,
api,
auth,
router,
keyboard,
presenterManager,
postsAroundCalculator,
postEditPresenter,
postContentPresenter,
commentListPresenter,
topNavigationPresenter,
messagePresenter) {
_,
jQuery,
util,
promise,
api,
auth,
router,
keyboard,
presenterManager,
postsAroundCalculator,
postEditPresenter,
postContentPresenter,
commentListPresenter,
topNavigationPresenter,
messagePresenter) {
var $el = jQuery('#content');
var $messages = $el;
var $el = jQuery('#content');
var $messages = $el;
var templates = {};
var params;
var templates = {};
var params;
var postNameOrId;
var post;
var postNameOrId;
var post;
var privileges = {};
var privileges = {};
function init(params, loaded) {
topNavigationPresenter.select('posts');
postsAroundCalculator.resetCache();
function init(params, loaded) {
topNavigationPresenter.select('posts');
postsAroundCalculator.resetCache();
privileges.canDeletePosts = auth.hasPrivilege(auth.privileges.deletePosts);
privileges.canFeaturePosts = auth.hasPrivilege(auth.privileges.featurePosts);
privileges.canViewHistory = auth.hasPrivilege(auth.privileges.viewHistory);
privileges.canAddPostNotes = auth.hasPrivilege(auth.privileges.addPostNotes);
privileges.canDeletePosts = auth.hasPrivilege(auth.privileges.deletePosts);
privileges.canFeaturePosts = auth.hasPrivilege(auth.privileges.featurePosts);
privileges.canViewHistory = auth.hasPrivilege(auth.privileges.viewHistory);
privileges.canAddPostNotes = auth.hasPrivilege(auth.privileges.addPostNotes);
promise.wait(
util.promiseTemplate('post'),
util.promiseTemplate('history'))
.then(function(
postTemplate,
historyTemplate) {
templates.post = postTemplate;
templates.history = historyTemplate;
promise.wait(
util.promiseTemplate('post'),
util.promiseTemplate('history'))
.then(function(
postTemplate,
historyTemplate) {
templates.post = postTemplate;
templates.history = historyTemplate;
reinit(params, loaded);
}).fail(function(response) {
showGenericError(response);
loaded();
});
}
reinit(params, loaded);
}).fail(function(response) {
showGenericError(response);
loaded();
});
}
function reinit(_params, loaded) {
params = _params;
params.query = params.query || {};
params.query.page = parseInt(params.query.page) || 1;
function reinit(_params, loaded) {
params = _params;
params.query = params.query || {};
params.query.page = parseInt(params.query.page) || 1;
postNameOrId = params.postNameOrId;
postNameOrId = params.postNameOrId;
promise.wait(refreshPost())
.then(function() {
topNavigationPresenter.changeTitle('@' + post.id);
render();
loaded();
promise.wait(refreshPost())
.then(function() {
topNavigationPresenter.changeTitle('@' + post.id);
render();
loaded();
presenterManager.initPresenters([
[postContentPresenter, {post: post, $target: $el.find('#post-content-target')}],
[postEditPresenter, {post: post, $target: $el.find('#post-edit-target'), updateCallback: postEdited}],
[commentListPresenter, {post: post, $target: $el.find('#post-comments-target')}]],
function() { });
presenterManager.initPresenters([
[postContentPresenter, {post: post, $target: $el.find('#post-content-target')}],
[postEditPresenter, {post: post, $target: $el.find('#post-edit-target'), updateCallback: postEdited}],
[commentListPresenter, {post: post, $target: $el.find('#post-comments-target')}]],
function() { });
}).fail(function() {
console.log(arguments);
loaded();
});
}).fail(function() {
console.log(arguments);
loaded();
});
}
}
function attachLinksToPostsAround() {
promise.wait(postsAroundCalculator.getLinksToPostsAround(params.query, post.id))
.then(function(nextPostUrl, prevPostUrl) {
var $prevPost = $el.find('#post-current-search .right a');
var $nextPost = $el.find('#post-current-search .left a');
function attachLinksToPostsAround() {
promise.wait(postsAroundCalculator.getLinksToPostsAround(params.query, post.id))
.then(function(nextPostUrl, prevPostUrl) {
var $prevPost = $el.find('#post-current-search .right a');
var $nextPost = $el.find('#post-current-search .left a');
if (nextPostUrl) {
$nextPost.addClass('enabled');
$nextPost.attr('href', nextPostUrl);
keyboard.keyup('a', function() {
router.navigate(nextPostUrl);
});
} else {
$nextPost.removeClass('enabled');
$nextPost.removeAttr('href');
keyboard.unbind('a');
}
if (nextPostUrl) {
$nextPost.addClass('enabled');
$nextPost.attr('href', nextPostUrl);
keyboard.keyup('a', function() {
router.navigate(nextPostUrl);
});
} else {
$nextPost.removeClass('enabled');
$nextPost.removeAttr('href');
keyboard.unbind('a');
}
if (prevPostUrl) {
$prevPost.addClass('enabled');
$prevPost.attr('href', prevPostUrl);
keyboard.keyup('d', function() {
router.navigate(prevPostUrl);
});
} else {
$prevPost.removeClass('enabled');
$prevPost.removeAttr('href');
keyboard.unbind('d');
}
}).fail(function() {
});
}
if (prevPostUrl) {
$prevPost.addClass('enabled');
$prevPost.attr('href', prevPostUrl);
keyboard.keyup('d', function() {
router.navigate(prevPostUrl);
});
} else {
$prevPost.removeClass('enabled');
$prevPost.removeAttr('href');
keyboard.unbind('d');
}
}).fail(function() {
});
}
function refreshPost() {
return promise.make(function(resolve, reject) {
promise.wait(api.get('/posts/' + postNameOrId))
.then(function(postResponse) {
post = postResponse.json;
resolve();
}).fail(function(response) {
showGenericError(response);
reject();
});
});
}
function refreshPost() {
return promise.make(function(resolve, reject) {
promise.wait(api.get('/posts/' + postNameOrId))
.then(function(postResponse) {
post = postResponse.json;
resolve();
}).fail(function(response) {
showGenericError(response);
reject();
});
});
}
function render() {
$el.html(renderPostTemplate());
$messages = $el.find('.messages');
function render() {
$el.html(renderPostTemplate());
$messages = $el.find('.messages');
keyboard.keyup('e', function() {
editButtonClicked(null);
});
keyboard.keyup('e', function() {
editButtonClicked(null);
});
keyboard.keyup('f', function() {
var $wrapper = $el.find('.object-wrapper');
if ($wrapper.data('full')) {
$wrapper.css({maxWidth: $wrapper.attr('data-width') + 'px', width: 'auto'});
$wrapper.data('full', false);
} else {
$wrapper.css({maxWidth: null, width: $wrapper.attr('data-width')});
$wrapper.data('full', true);
}
postContentPresenter.updatePostNotesSize();
});
keyboard.keyup('f', function() {
var $wrapper = $el.find('.object-wrapper');
if ($wrapper.data('full')) {
$wrapper.css({maxWidth: $wrapper.attr('data-width') + 'px', width: 'auto'});
$wrapper.data('full', false);
} else {
$wrapper.css({maxWidth: null, width: $wrapper.attr('data-width')});
$wrapper.data('full', true);
}
postContentPresenter.updatePostNotesSize();
});
attachSidebarEvents();
attachSidebarEvents();
attachLinksToPostsAround();
}
attachLinksToPostsAround();
}
function postEdited(newPost) {
post = newPost;
hideEditForm();
softRender();
}
function postEdited(newPost) {
post = newPost;
hideEditForm();
softRender();
}
function softRender() {
renderSidebar();
$el.find('video').prop('loop', post.flags.loop);
}
function softRender() {
renderSidebar();
$el.find('video').prop('loop', post.flags.loop);
}
function renderSidebar() {
$el.find('#sidebar').html(jQuery(renderPostTemplate()).find('#sidebar').html());
attachSidebarEvents();
}
function renderSidebar() {
$el.find('#sidebar').html(jQuery(renderPostTemplate()).find('#sidebar').html());
attachSidebarEvents();
}
function renderPostTemplate() {
return templates.post({
query: params.query,
post: post,
ownScore: post.ownScore,
postFavorites: post.favorites,
postHistory: post.history,
function renderPostTemplate() {
return templates.post({
query: params.query,
post: post,
ownScore: post.ownScore,
postFavorites: post.favorites,
postHistory: post.history,
util: util,
util: util,
historyTemplate: templates.history,
historyTemplate: templates.history,
hasFav: _.any(post.favorites, function(favUser) { return favUser.id === auth.getCurrentUser().id; }),
isLoggedIn: auth.isLoggedIn(),
privileges: privileges,
editPrivileges: postEditPresenter.getPrivileges(),
});
}
hasFav: _.any(post.favorites, function(favUser) { return favUser.id === auth.getCurrentUser().id; }),
isLoggedIn: auth.isLoggedIn(),
privileges: privileges,
editPrivileges: postEditPresenter.getPrivileges(),
});
}
function attachSidebarEvents() {
$el.find('#sidebar .delete').click(deleteButtonClicked);
$el.find('#sidebar .feature').click(featureButtonClicked);
$el.find('#sidebar .edit').click(editButtonClicked);
$el.find('#sidebar .history').click(historyButtonClicked);
$el.find('#sidebar .add-favorite').click(addFavoriteButtonClicked);
$el.find('#sidebar .delete-favorite').click(deleteFavoriteButtonClicked);
$el.find('#sidebar .score-up').click(scoreUpButtonClicked);
$el.find('#sidebar .score-down').click(scoreDownButtonClicked);
$el.find('#sidebar .add-note').click(addNoteButtonClicked);
}
function attachSidebarEvents() {
$el.find('#sidebar .delete').click(deleteButtonClicked);
$el.find('#sidebar .feature').click(featureButtonClicked);
$el.find('#sidebar .edit').click(editButtonClicked);
$el.find('#sidebar .history').click(historyButtonClicked);
$el.find('#sidebar .add-favorite').click(addFavoriteButtonClicked);
$el.find('#sidebar .delete-favorite').click(deleteFavoriteButtonClicked);
$el.find('#sidebar .score-up').click(scoreUpButtonClicked);
$el.find('#sidebar .score-down').click(scoreDownButtonClicked);
$el.find('#sidebar .add-note').click(addNoteButtonClicked);
}
function addNoteButtonClicked(e) {
e.preventDefault();
postContentPresenter.addNewPostNote();
}
function addNoteButtonClicked(e) {
e.preventDefault();
postContentPresenter.addNewPostNote();
}
function deleteButtonClicked(e) {
e.preventDefault();
messagePresenter.hideMessages($messages);
if (window.confirm('Do you really want to delete this post?')) {
deletePost();
}
}
function deleteButtonClicked(e) {
e.preventDefault();
messagePresenter.hideMessages($messages);
if (window.confirm('Do you really want to delete this post?')) {
deletePost();
}
}
function deletePost() {
promise.wait(api.delete('/posts/' + post.id))
.then(function(response) {
router.navigate('#/posts');
}).fail(showGenericError);
}
function deletePost() {
promise.wait(api.delete('/posts/' + post.id))
.then(function(response) {
router.navigate('#/posts');
}).fail(showGenericError);
}
function featureButtonClicked(e) {
e.preventDefault();
messagePresenter.hideMessages($messages);
if (window.confirm('Do you want to feature this post on the front page?')) {
featurePost();
}
}
function featureButtonClicked(e) {
e.preventDefault();
messagePresenter.hideMessages($messages);
if (window.confirm('Do you want to feature this post on the front page?')) {
featurePost();
}
}
function featurePost() {
promise.wait(api.post('/posts/' + post.id + '/feature'))
.then(function(response) {
router.navigate('#/home');
}).fail(showGenericError);
}
function featurePost() {
promise.wait(api.post('/posts/' + post.id + '/feature'))
.then(function(response) {
router.navigate('#/home');
}).fail(showGenericError);
}
function editButtonClicked(e) {
if (e) {
e.preventDefault();
}
messagePresenter.hideMessages($messages);
if ($el.find('#post-edit-target').is(':visible')) {
hideEditForm();
} else {
showEditForm();
}
}
function editButtonClicked(e) {
if (e) {
e.preventDefault();
}
messagePresenter.hideMessages($messages);
if ($el.find('#post-edit-target').is(':visible')) {
hideEditForm();
} else {
showEditForm();
}
}
function showEditForm() {
$el.find('#post-edit-target').slideDown('fast');
util.enableExitConfirmation();
postEditPresenter.focus();
}
function showEditForm() {
$el.find('#post-edit-target').slideDown('fast');
util.enableExitConfirmation();
postEditPresenter.focus();
}
function hideEditForm() {
$el.find('#post-edit-target').slideUp('fast');
util.disableExitConfirmation();
}
function hideEditForm() {
$el.find('#post-edit-target').slideUp('fast');
util.disableExitConfirmation();
}
function historyButtonClicked(e) {
e.preventDefault();
if ($el.find('.post-history-wrapper').is(':visible')) {
hideHistory();
} else {
showHistory();
}
}
function historyButtonClicked(e) {
e.preventDefault();
if ($el.find('.post-history-wrapper').is(':visible')) {
hideHistory();
} else {
showHistory();
}
}
function hideHistory() {
$el.find('.post-history-wrapper').slideUp('slow');
}
function hideHistory() {
$el.find('.post-history-wrapper').slideUp('slow');
}
function showHistory() {
$el.find('.post-history-wrapper').slideDown('slow');
}
function showHistory() {
$el.find('.post-history-wrapper').slideDown('slow');
}
function addFavoriteButtonClicked(e) {
e.preventDefault();
addFavorite();
}
function addFavoriteButtonClicked(e) {
e.preventDefault();
addFavorite();
}
function deleteFavoriteButtonClicked(e) {
e.preventDefault();
deleteFavorite();
}
function deleteFavoriteButtonClicked(e) {
e.preventDefault();
deleteFavorite();
}
function addFavorite() {
promise.wait(api.post('/posts/' + post.id + '/favorites'))
.then(function(response) {
promise.wait(refreshPost()).then(softRender);
}).fail(showGenericError);
}
function addFavorite() {
promise.wait(api.post('/posts/' + post.id + '/favorites'))
.then(function(response) {
promise.wait(refreshPost()).then(softRender);
}).fail(showGenericError);
}
function deleteFavorite() {
promise.wait(api.delete('/posts/' + post.id + '/favorites'))
.then(function(response) {
promise.wait(refreshPost()).then(softRender);
}).fail(showGenericError);
}
function deleteFavorite() {
promise.wait(api.delete('/posts/' + post.id + '/favorites'))
.then(function(response) {
promise.wait(refreshPost()).then(softRender);
}).fail(showGenericError);
}
function scoreUpButtonClicked(e) {
e.preventDefault();
var $target = jQuery(this);
score($target.hasClass('active') ? 0 : 1);
}
function scoreUpButtonClicked(e) {
e.preventDefault();
var $target = jQuery(this);
score($target.hasClass('active') ? 0 : 1);
}
function scoreDownButtonClicked(e) {
e.preventDefault();
var $target = jQuery(this);
score($target.hasClass('active') ? 0 : -1);
}
function scoreDownButtonClicked(e) {
e.preventDefault();
var $target = jQuery(this);
score($target.hasClass('active') ? 0 : -1);
}
function score(scoreValue) {
promise.wait(api.post('/posts/' + post.id + '/score', {score: scoreValue}))
.then(function() {
promise.wait(refreshPost()).then(softRender);
}).fail(showGenericError);
}
function score(scoreValue) {
promise.wait(api.post('/posts/' + post.id + '/score', {score: scoreValue}))
.then(function() {
promise.wait(refreshPost()).then(softRender);
}).fail(showGenericError);
}
function showGenericError(response) {
if ($messages === $el) {
$el.empty();
}
messagePresenter.showError($messages, response.json && response.json.error || response);
}
function showGenericError(response) {
if ($messages === $el) {
$el.empty();
}
messagePresenter.showError($messages, response.json && response.json.error || response);
}
return {
init: init,
reinit: reinit,
render: render
};
return {
init: init,
reinit: reinit,
render: render
};
};
App.DI.register('postPresenter', [
'_',
'jQuery',
'util',
'promise',
'api',
'auth',
'router',
'keyboard',
'presenterManager',
'postsAroundCalculator',
'postEditPresenter',
'postContentPresenter',
'commentListPresenter',
'topNavigationPresenter',
'messagePresenter'],
App.Presenters.PostPresenter);
'_',
'jQuery',
'util',
'promise',
'api',
'auth',
'router',
'keyboard',
'presenterManager',
'postsAroundCalculator',
'postEditPresenter',
'postContentPresenter',
'commentListPresenter',
'topNavigationPresenter',
'messagePresenter'],
App.Presenters.PostPresenter);

File diff suppressed because it is too large Load diff

View file

@ -2,43 +2,43 @@ var App = App || {};
App.Controls = App.Controls || {};
App.Presenters.ProgressPresenter = function(nprogress) {
var nesting = 0;
var nesting = 0;
function start() {
nesting ++;
function start() {
nesting ++;
if (nesting === 1) {
nprogress.start();
}
}
if (nesting === 1) {
nprogress.start();
}
}
function reset() {
nesting = 0;
}
function reset() {
nesting = 0;
}
function done() {
if (nesting) {
nesting --;
}
function done() {
if (nesting) {
nesting --;
}
if (nesting <= 0) {
nprogress.done();
} else {
nprogress.inc();
}
}
if (nesting <= 0) {
nprogress.done();
} else {
nprogress.inc();
}
}
window.setInterval(function() {
if (nesting <= 0) {
nprogress.done();
}
}, 1000);
window.setInterval(function() {
if (nesting <= 0) {
nprogress.done();
}
}, 1000);
return {
start: start,
done: done,
reset: reset,
};
return {
start: start,
done: done,
reset: reset,
};
};

View file

@ -2,100 +2,100 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.RegistrationPresenter = function(
jQuery,
util,
promise,
api,
topNavigationPresenter,
messagePresenter) {
jQuery,
util,
promise,
api,
topNavigationPresenter,
messagePresenter) {
var $el = jQuery('#content');
var templates = {};
var $messages;
var $el = jQuery('#content');
var templates = {};
var $messages;
function init(params, loaded) {
topNavigationPresenter.select('register');
topNavigationPresenter.changeTitle('Registration');
promise.wait(util.promiseTemplate('registration-form'))
.then(function(template) {
templates.registration = template;
render();
loaded();
}).fail(function() {
console.log(arguments);
loaded();
});
}
function init(params, loaded) {
topNavigationPresenter.select('register');
topNavigationPresenter.changeTitle('Registration');
promise.wait(util.promiseTemplate('registration-form'))
.then(function(template) {
templates.registration = template;
render();
loaded();
}).fail(function() {
console.log(arguments);
loaded();
});
}
function render() {
$el.html(templates.registration());
$el.find('form').submit(registrationFormSubmitted);
$messages = $el.find('.messages');
$messages.width($el.find('form').width());
}
function render() {
$el.html(templates.registration());
$el.find('form').submit(registrationFormSubmitted);
$messages = $el.find('.messages');
$messages.width($el.find('form').width());
}
function registrationFormSubmitted(e) {
e.preventDefault();
messagePresenter.hideMessages($messages);
function registrationFormSubmitted(e) {
e.preventDefault();
messagePresenter.hideMessages($messages);
var formData = {
userName: $el.find('[name=userName]').val(),
password: $el.find('[name=password]').val(),
passwordConfirmation: $el.find('[name=passwordConfirmation]').val(),
email: $el.find('[name=email]').val(),
};
var formData = {
userName: $el.find('[name=userName]').val(),
password: $el.find('[name=password]').val(),
passwordConfirmation: $el.find('[name=passwordConfirmation]').val(),
email: $el.find('[name=email]').val(),
};
if (!validateRegistrationFormData(formData)) {
return;
}
if (!validateRegistrationFormData(formData)) {
return;
}
promise.wait(api.post('/users', formData))
.then(function(response) {
registrationSuccess(response);
}).fail(function(response) {
registrationFailure(response);
});
}
promise.wait(api.post('/users', formData))
.then(function(response) {
registrationSuccess(response);
}).fail(function(response) {
registrationFailure(response);
});
}
function registrationSuccess(apiResponse) {
$el.find('form').slideUp(function() {
var message = 'Registration complete! ';
if (!apiResponse.json.confirmed) {
message += '<br/>Check your inbox for activation e-mail.<br/>If e-mail doesn\'t show up, check your spam folder.';
} else {
message += '<a href="#/login">Click here</a> to login.';
}
messagePresenter.showInfo($messages, message);
});
}
function registrationSuccess(apiResponse) {
$el.find('form').slideUp(function() {
var message = 'Registration complete! ';
if (!apiResponse.json.confirmed) {
message += '<br/>Check your inbox for activation e-mail.<br/>If e-mail doesn\'t show up, check your spam folder.';
} else {
message += '<a href="#/login">Click here</a> to login.';
}
messagePresenter.showInfo($messages, message);
});
}
function registrationFailure(apiResponse) {
messagePresenter.showError($messages, apiResponse.json && apiResponse.json.error || apiResponse);
}
function registrationFailure(apiResponse) {
messagePresenter.showError($messages, apiResponse.json && apiResponse.json.error || apiResponse);
}
function validateRegistrationFormData(formData) {
if (formData.userName.length === 0) {
messagePresenter.showError($messages, 'User name cannot be empty.');
return false;
}
function validateRegistrationFormData(formData) {
if (formData.userName.length === 0) {
messagePresenter.showError($messages, 'User name cannot be empty.');
return false;
}
if (formData.password.length === 0) {
messagePresenter.showError($messages, 'Password cannot be empty.');
return false;
}
if (formData.password.length === 0) {
messagePresenter.showError($messages, 'Password cannot be empty.');
return false;
}
if (formData.password !== formData.passwordConfirmation) {
messagePresenter.showError($messages, 'Passwords must be the same.');
return false;
}
if (formData.password !== formData.passwordConfirmation) {
messagePresenter.showError($messages, 'Passwords must be the same.');
return false;
}
return true;
}
return true;
}
return {
init: init,
render: render,
};
return {
init: init,
render: render,
};
};

View file

@ -2,124 +2,124 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.TagListPresenter = function(
_,
jQuery,
util,
promise,
keyboard,
pagerPresenter,
topNavigationPresenter) {
_,
jQuery,
util,
promise,
keyboard,
pagerPresenter,
topNavigationPresenter) {
var $el = jQuery('#content');
var $searchInput;
var templates = {};
var $el = jQuery('#content');
var $searchInput;
var templates = {};
var params;
var params;
function init(_params, loaded) {
topNavigationPresenter.select('tags');
topNavigationPresenter.changeTitle('Tags');
params = _params;
params.query = params.query || {};
function init(_params, loaded) {
topNavigationPresenter.select('tags');
topNavigationPresenter.changeTitle('Tags');
params = _params;
params.query = params.query || {};
promise.wait(
util.promiseTemplate('tag-list'),
util.promiseTemplate('tag-list-item'))
.then(function(listTemplate, listItemTemplate) {
templates.list = listTemplate;
templates.listItem = listItemTemplate;
promise.wait(
util.promiseTemplate('tag-list'),
util.promiseTemplate('tag-list-item'))
.then(function(listTemplate, listItemTemplate) {
templates.list = listTemplate;
templates.listItem = listItemTemplate;
render();
loaded();
render();
loaded();
pagerPresenter.init({
baseUri: '#/tags',
backendUri: '/tags',
$target: $el.find('.pagination-target'),
updateCallback: function($page, data) {
renderTags($page, data.entities);
},
},
function() {
reinit(params, function() {});
});
}).fail(function() {
console.log(arguments);
loaded();
});
}
pagerPresenter.init({
baseUri: '#/tags',
backendUri: '/tags',
$target: $el.find('.pagination-target'),
updateCallback: function($page, data) {
renderTags($page, data.entities);
},
},
function() {
reinit(params, function() {});
});
}).fail(function() {
console.log(arguments);
loaded();
});
}
function reinit(_params, loaded) {
params = _params;
params.query = params.query || {};
params.query.order = params.query.order || 'name,asc';
updateActiveOrder(params.query.order);
function reinit(_params, loaded) {
params = _params;
params.query = params.query || {};
params.query.order = params.query.order || 'name,asc';
updateActiveOrder(params.query.order);
pagerPresenter.reinit({query: params.query});
pagerPresenter.reinit({query: params.query});
keyboard.keyup('p', function() {
$el.find('table a').eq(0).focus();
});
keyboard.keyup('p', function() {
$el.find('table a').eq(0).focus();
});
keyboard.keyup('q', function() {
$searchInput.eq(0).focus().select();
});
keyboard.keyup('q', function() {
$searchInput.eq(0).focus().select();
});
loaded();
softRender();
}
loaded();
softRender();
}
function deinit() {
pagerPresenter.deinit();
}
function deinit() {
pagerPresenter.deinit();
}
function render() {
$el.html(templates.list());
$searchInput = $el.find('input[name=query]');
$el.find('form').submit(searchFormSubmitted);
App.Controls.AutoCompleteInput($searchInput);
softRender();
}
function render() {
$el.html(templates.list());
$searchInput = $el.find('input[name=query]');
$el.find('form').submit(searchFormSubmitted);
App.Controls.AutoCompleteInput($searchInput);
softRender();
}
function softRender() {
$searchInput.val(params.query.query);
}
function softRender() {
$searchInput.val(params.query.query);
}
function searchFormSubmitted(e) {
e.preventDefault();
updateSearch();
}
function searchFormSubmitted(e) {
e.preventDefault();
updateSearch();
}
function updateSearch() {
$searchInput.blur();
params.query.query = $searchInput.val().trim();
params.query.page = 1;
pagerPresenter.setQuery(params.query);
}
function updateSearch() {
$searchInput.blur();
params.query.query = $searchInput.val().trim();
params.query.page = 1;
pagerPresenter.setQuery(params.query);
}
function updateActiveOrder(activeOrder) {
$el.find('.order li a.active').removeClass('active');
$el.find('.order [href*="' + activeOrder + '"]').addClass('active');
}
function updateActiveOrder(activeOrder) {
$el.find('.order li a.active').removeClass('active');
$el.find('.order [href*="' + activeOrder + '"]').addClass('active');
}
function renderTags($page, tags) {
var $target = $page.find('tbody');
_.each(tags, function(tag) {
var $item = jQuery(templates.listItem({
tag: tag,
util: util,
}));
$target.append($item);
});
}
function renderTags($page, tags) {
var $target = $page.find('tbody');
_.each(tags, function(tag) {
var $item = jQuery(templates.listItem({
tag: tag,
util: util,
}));
$target.append($item);
});
}
return {
init: init,
reinit: reinit,
deinit: deinit,
render: render,
};
return {
init: init,
reinit: reinit,
deinit: deinit,
render: render,
};
};

View file

@ -2,199 +2,199 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.TagPresenter = function(
_,
jQuery,
util,
promise,
auth,
api,
tagList,
router,
keyboard,
topNavigationPresenter,
messagePresenter) {
_,
jQuery,
util,
promise,
auth,
api,
tagList,
router,
keyboard,
topNavigationPresenter,
messagePresenter) {
var $el = jQuery('#content');
var $messages = $el;
var templates = {};
var implicationsTagInput;
var suggestionsTagInput;
var $el = jQuery('#content');
var $messages = $el;
var templates = {};
var implicationsTagInput;
var suggestionsTagInput;
var tag;
var posts;
var siblings;
var tag;
var posts;
var siblings;
var privileges = {};
var privileges = {};
function init(params, loaded) {
topNavigationPresenter.select('tags');
topNavigationPresenter.changeTitle('Tags');
function init(params, loaded) {
topNavigationPresenter.select('tags');
topNavigationPresenter.changeTitle('Tags');
privileges.canChangeName = auth.hasPrivilege(auth.privileges.changeTagName);
privileges.canChangeCategory = auth.hasPrivilege(auth.privileges.changeTagCategory);
privileges.canChangeImplications = auth.hasPrivilege(auth.privileges.changeTagImplications);
privileges.canChangeSuggestions = auth.hasPrivilege(auth.privileges.changeTagSuggestions);
privileges.canBan = auth.hasPrivilege(auth.privileges.banTags);
privileges.canViewHistory = auth.hasPrivilege(auth.privileges.viewHistory);
privileges.canDelete = auth.hasPrivilege(auth.privileges.deleteTags);
privileges.canMerge = auth.hasPrivilege(auth.privileges.mergeTags);
privileges.canViewPosts = auth.hasPrivilege(auth.privileges.viewPosts);
privileges.canChangeName = auth.hasPrivilege(auth.privileges.changeTagName);
privileges.canChangeCategory = auth.hasPrivilege(auth.privileges.changeTagCategory);
privileges.canChangeImplications = auth.hasPrivilege(auth.privileges.changeTagImplications);
privileges.canChangeSuggestions = auth.hasPrivilege(auth.privileges.changeTagSuggestions);
privileges.canBan = auth.hasPrivilege(auth.privileges.banTags);
privileges.canViewHistory = auth.hasPrivilege(auth.privileges.viewHistory);
privileges.canDelete = auth.hasPrivilege(auth.privileges.deleteTags);
privileges.canMerge = auth.hasPrivilege(auth.privileges.mergeTags);
privileges.canViewPosts = auth.hasPrivilege(auth.privileges.viewPosts);
promise.wait(
util.promiseTemplate('tag'),
util.promiseTemplate('post-list-item'),
util.promiseTemplate('history'))
.then(function(tagTemplate, postListItemTemplate, historyTemplate) {
templates.tag = tagTemplate;
templates.postListItem = postListItemTemplate;
templates.history = historyTemplate;
promise.wait(
util.promiseTemplate('tag'),
util.promiseTemplate('post-list-item'),
util.promiseTemplate('history'))
.then(function(tagTemplate, postListItemTemplate, historyTemplate) {
templates.tag = tagTemplate;
templates.postListItem = postListItemTemplate;
templates.history = historyTemplate;
reinit(params, loaded);
}).fail(function() {
console.log(arguments);
loaded();
});
}
reinit(params, loaded);
}).fail(function() {
console.log(arguments);
loaded();
});
}
function reinit(params, loaded) {
var tagName = params.tagName;
function reinit(params, loaded) {
var tagName = params.tagName;
messagePresenter.hideMessages($messages);
messagePresenter.hideMessages($messages);
promise.wait(
api.get('tags/' + tagName),
api.get('tags/' + tagName + '/siblings'),
api.get('posts', {query: tagName}))
.then(function(tagResponse, siblingsResponse, postsResponse) {
tag = tagResponse.json;
siblings = siblingsResponse.json.data;
posts = postsResponse.json.data;
posts = posts.slice(0, 8);
promise.wait(
api.get('tags/' + tagName),
api.get('tags/' + tagName + '/siblings'),
api.get('posts', {query: tagName}))
.then(function(tagResponse, siblingsResponse, postsResponse) {
tag = tagResponse.json;
siblings = siblingsResponse.json.data;
posts = postsResponse.json.data;
posts = posts.slice(0, 8);
render();
loaded();
render();
loaded();
renderPosts(posts);
}).fail(function(tagResponse, siblingsResponse, postsResponse) {
messagePresenter.showError($messages, tagResponse.json.error || siblingsResponse.json.error || postsResponse.json.error);
loaded();
});
}
renderPosts(posts);
}).fail(function(tagResponse, siblingsResponse, postsResponse) {
messagePresenter.showError($messages, tagResponse.json.error || siblingsResponse.json.error || postsResponse.json.error);
loaded();
});
}
function render() {
$el.html(templates.tag({
privileges: privileges,
tag: tag,
siblings: siblings,
tagCategories: JSON.parse(jQuery('head').attr('data-tag-categories')),
util: util,
historyTemplate: templates.history,
}));
$el.find('.post-list').hide();
$el.find('form').submit(function(e) { e.preventDefault(); });
$el.find('form button[name=update]').click(updateButtonClicked);
$el.find('form button[name=delete]').click(deleteButtonClicked);
$el.find('form button[name=merge]').click(mergeButtonClicked);
implicationsTagInput = App.Controls.TagInput($el.find('[name=implications]'));
suggestionsTagInput = App.Controls.TagInput($el.find('[name=suggestions]'));
}
function render() {
$el.html(templates.tag({
privileges: privileges,
tag: tag,
siblings: siblings,
tagCategories: JSON.parse(jQuery('head').attr('data-tag-categories')),
util: util,
historyTemplate: templates.history,
}));
$el.find('.post-list').hide();
$el.find('form').submit(function(e) { e.preventDefault(); });
$el.find('form button[name=update]').click(updateButtonClicked);
$el.find('form button[name=delete]').click(deleteButtonClicked);
$el.find('form button[name=merge]').click(mergeButtonClicked);
implicationsTagInput = App.Controls.TagInput($el.find('[name=implications]'));
suggestionsTagInput = App.Controls.TagInput($el.find('[name=suggestions]'));
}
function updateButtonClicked(e) {
e.preventDefault();
var $form = $el.find('form');
var formData = {};
function updateButtonClicked(e) {
e.preventDefault();
var $form = $el.find('form');
var formData = {};
if (privileges.canChangeName) {
formData.name = $form.find('[name=name]').val();
}
if (privileges.canChangeName) {
formData.name = $form.find('[name=name]').val();
}
if (privileges.canChangeCategory) {
formData.category = $form.find('[name=category]:checked').val();
}
if (privileges.canChangeCategory) {
formData.category = $form.find('[name=category]:checked').val();
}
if (privileges.canBan) {
formData.banned = $form.find('[name=ban]').is(':checked') ? 1 : 0;
}
if (privileges.canBan) {
formData.banned = $form.find('[name=ban]').is(':checked') ? 1 : 0;
}
if (privileges.canChangeImplications) {
formData.implications = implicationsTagInput.getTags().join(' ');
}
if (privileges.canChangeImplications) {
formData.implications = implicationsTagInput.getTags().join(' ');
}
if (privileges.canChangeSuggestions) {
formData.suggestions = suggestionsTagInput.getTags().join(' ');
}
if (privileges.canChangeSuggestions) {
formData.suggestions = suggestionsTagInput.getTags().join(' ');
}
promise.wait(api.put('/tags/' + tag.name, formData))
.then(function(response) {
router.navigateInplace('#/tag/' + response.json.name);
tagList.refreshTags();
}).fail(function(response) {
window.alert(response.json && response.json.error || 'An error occured.');
});
}
promise.wait(api.put('/tags/' + tag.name, formData))
.then(function(response) {
router.navigateInplace('#/tag/' + response.json.name);
tagList.refreshTags();
}).fail(function(response) {
window.alert(response.json && response.json.error || 'An error occured.');
});
}
function deleteButtonClicked(e) {
if (!window.confirm('Are you sure you want to delete this tag?')) {
return;
}
promise.wait(api.delete('/tags/' + tag.name))
.then(function(response) {
router.navigate('#/tags');
tagList.refreshTags();
}).fail(function(response) {
window.alert(response.json && response.json.error || 'An error occured.');
});
}
function deleteButtonClicked(e) {
if (!window.confirm('Are you sure you want to delete this tag?')) {
return;
}
promise.wait(api.delete('/tags/' + tag.name))
.then(function(response) {
router.navigate('#/tags');
tagList.refreshTags();
}).fail(function(response) {
window.alert(response.json && response.json.error || 'An error occured.');
});
}
function mergeButtonClicked(e) {
var targetTag = window.prompt('What tag should this be merged to?');
if (targetTag) {
promise.wait(api.put('/tags/' + tag.name + '/merge', {targetTag: targetTag}))
.then(function(response) {
router.navigate('#/tags');
tagList.refreshTags();
}).fail(function(response) {
window.alert(response.json && response.json.error || 'An error occured.');
});
}
}
function mergeButtonClicked(e) {
var targetTag = window.prompt('What tag should this be merged to?');
if (targetTag) {
promise.wait(api.put('/tags/' + tag.name + '/merge', {targetTag: targetTag}))
.then(function(response) {
router.navigate('#/tags');
tagList.refreshTags();
}).fail(function(response) {
window.alert(response.json && response.json.error || 'An error occured.');
});
}
}
function renderPosts(posts) {
var $target = $el.find('.post-list ul');
_.each(posts, function(post) {
var $post = jQuery('<li>' + templates.postListItem({
util: util,
post: post,
query: {query: tag.name},
canViewPosts: privileges.canViewPosts,
}) + '</li>');
$target.append($post);
});
if (posts.length > 0) {
$el.find('.post-list').fadeIn();
keyboard.keyup('p', function() {
$el.find('.post-list a').eq(0).focus();
});
}
}
function renderPosts(posts) {
var $target = $el.find('.post-list ul');
_.each(posts, function(post) {
var $post = jQuery('<li>' + templates.postListItem({
util: util,
post: post,
query: {query: tag.name},
canViewPosts: privileges.canViewPosts,
}) + '</li>');
$target.append($post);
});
if (posts.length > 0) {
$el.find('.post-list').fadeIn();
keyboard.keyup('p', function() {
$el.find('.post-list a').eq(0).focus();
});
}
}
return {
init: init,
reinit: reinit,
};
return {
init: init,
reinit: reinit,
};
};
App.DI.register('tagPresenter', [
'_',
'jQuery',
'util',
'promise',
'auth',
'api',
'tagList',
'router',
'keyboard',
'topNavigationPresenter',
'messagePresenter'],
'_',
'jQuery',
'util',
'promise',
'auth',
'api',
'tagList',
'router',
'keyboard',
'topNavigationPresenter',
'messagePresenter'],
App.Presenters.TagPresenter);

View file

@ -2,78 +2,78 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.TopNavigationPresenter = function(
jQuery,
util,
promise,
auth) {
jQuery,
util,
promise,
auth) {
var selectedElement = null;
var $el = jQuery('#top-navigation');
var templates = {};
var baseTitle = document.title;
var selectedElement = null;
var $el = jQuery('#top-navigation');
var templates = {};
var baseTitle = document.title;
function init(params, loaded) {
promise.wait(util.promiseTemplate('top-navigation'))
.then(function(template) {
templates.topNavigation = template;
render();
loaded();
auth.startObservingLoginChanges('top-navigation', loginStateChanged);
}).fail(function() {
loaded();
});
}
function init(params, loaded) {
promise.wait(util.promiseTemplate('top-navigation'))
.then(function(template) {
templates.topNavigation = template;
render();
loaded();
auth.startObservingLoginChanges('top-navigation', loginStateChanged);
}).fail(function() {
loaded();
});
}
function select(newSelectedElement) {
selectedElement = newSelectedElement;
$el.find('li a').removeClass('active');
$el.find('li.' + selectedElement).find('a').addClass('active');
}
function select(newSelectedElement) {
selectedElement = newSelectedElement;
$el.find('li a').removeClass('active');
$el.find('li.' + selectedElement).find('a').addClass('active');
}
function loginStateChanged() {
render();
}
function loginStateChanged() {
render();
}
function render() {
$el.html(templates.topNavigation({
loggedIn: auth.isLoggedIn(),
user: auth.getCurrentUser(),
canListUsers: auth.hasPrivilege(auth.privileges.listUsers),
canListPosts: auth.hasPrivilege(auth.privileges.listPosts),
canListComments: auth.hasPrivilege(auth.privileges.listComments),
canListTags: auth.hasPrivilege(auth.privileges.listTags),
canUploadPosts: auth.hasPrivilege(auth.privileges.uploadPosts),
}));
$el.find('li.' + selectedElement).find('a').addClass('active');
}
function render() {
$el.html(templates.topNavigation({
loggedIn: auth.isLoggedIn(),
user: auth.getCurrentUser(),
canListUsers: auth.hasPrivilege(auth.privileges.listUsers),
canListPosts: auth.hasPrivilege(auth.privileges.listPosts),
canListComments: auth.hasPrivilege(auth.privileges.listComments),
canListTags: auth.hasPrivilege(auth.privileges.listTags),
canUploadPosts: auth.hasPrivilege(auth.privileges.uploadPosts),
}));
$el.find('li.' + selectedElement).find('a').addClass('active');
}
function focus() {
var $tmp = jQuery('<a href="#"> </a>');
$el.prepend($tmp);
$tmp.focus();
$tmp.remove();
}
function focus() {
var $tmp = jQuery('<a href="#"> </a>');
$el.prepend($tmp);
$tmp.focus();
$tmp.remove();
}
function getBaseTitle() {
return baseTitle;
}
function getBaseTitle() {
return baseTitle;
}
function changeTitle(subTitle) {
var newTitle = baseTitle;
if (subTitle) {
newTitle += ' - ' + subTitle;
}
document.title = newTitle;
}
function changeTitle(subTitle) {
var newTitle = baseTitle;
if (subTitle) {
newTitle += ' - ' + subTitle;
}
document.title = newTitle;
}
return {
init: init,
render: render,
select: select,
focus: focus,
getBaseTitle: getBaseTitle,
changeTitle: changeTitle,
};
return {
init: init,
render: render,
select: select,
focus: focus,
getBaseTitle: getBaseTitle,
changeTitle: changeTitle,
};
};

View file

@ -2,80 +2,80 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.UserAccountRemovalPresenter = function(
jQuery,
util,
promise,
api,
auth,
router,
messagePresenter) {
jQuery,
util,
promise,
api,
auth,
router,
messagePresenter) {
var target;
var templates = {};
var user;
var privileges = {};
var target;
var templates = {};
var user;
var privileges = {};
function init(params, loaded) {
user = params.user;
target = params.target;
function init(params, loaded) {
user = params.user;
target = params.target;
privileges.canDeleteAccount =
auth.hasPrivilege(auth.privileges.deleteAllAccounts) ||
(auth.hasPrivilege(auth.privileges.deleteOwnAccount) && auth.isLoggedIn(user.name));
privileges.canDeleteAccount =
auth.hasPrivilege(auth.privileges.deleteAllAccounts) ||
(auth.hasPrivilege(auth.privileges.deleteOwnAccount) && auth.isLoggedIn(user.name));
promise.wait(util.promiseTemplate('account-removal'))
.then(function(template) {
templates.accountRemoval = template;
render();
loaded();
}).fail(function() {
console.log(arguments);
loaded();
});
}
promise.wait(util.promiseTemplate('account-removal'))
.then(function(template) {
templates.accountRemoval = template;
render();
loaded();
}).fail(function() {
console.log(arguments);
loaded();
});
}
function render() {
var $el = jQuery(target);
$el.html(templates.accountRemoval({
user: user,
canDeleteAccount: privileges.canDeleteAccount}));
function render() {
var $el = jQuery(target);
$el.html(templates.accountRemoval({
user: user,
canDeleteAccount: privileges.canDeleteAccount}));
$el.find('form').submit(accountRemovalFormSubmitted);
}
$el.find('form').submit(accountRemovalFormSubmitted);
}
function getPrivileges() {
return privileges;
}
function getPrivileges() {
return privileges;
}
function accountRemovalFormSubmitted(e) {
e.preventDefault();
var $el = jQuery(target);
var $messages = $el.find('.messages');
messagePresenter.hideMessages($messages);
if (!$el.find('input[name=confirmation]:visible').prop('checked')) {
messagePresenter.showError($messages, 'Must confirm to proceed.');
return;
}
promise.wait(api.delete('/users/' + user.name))
.then(function() {
auth.logout();
var $messageDiv = messagePresenter.showInfo($messages, 'Account deleted. <a href="">Back to main page</a>');
$messageDiv.find('a').click(mainPageLinkClicked);
}).fail(function(response) {
messagePresenter.showError($messages, response.json && response.json.error || response);
});
}
function accountRemovalFormSubmitted(e) {
e.preventDefault();
var $el = jQuery(target);
var $messages = $el.find('.messages');
messagePresenter.hideMessages($messages);
if (!$el.find('input[name=confirmation]:visible').prop('checked')) {
messagePresenter.showError($messages, 'Must confirm to proceed.');
return;
}
promise.wait(api.delete('/users/' + user.name))
.then(function() {
auth.logout();
var $messageDiv = messagePresenter.showInfo($messages, 'Account deleted. <a href="">Back to main page</a>');
$messageDiv.find('a').click(mainPageLinkClicked);
}).fail(function(response) {
messagePresenter.showError($messages, response.json && response.json.error || response);
});
}
function mainPageLinkClicked(e) {
e.preventDefault();
router.navigateToMainPage();
}
function mainPageLinkClicked(e) {
e.preventDefault();
router.navigateToMainPage();
}
return {
init: init,
render: render,
getPrivileges: getPrivileges
};
return {
init: init,
render: render,
getPrivileges: getPrivileges
};
};

View file

@ -2,162 +2,162 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.UserAccountSettingsPresenter = function(
_,
jQuery,
util,
promise,
api,
auth,
messagePresenter) {
_,
jQuery,
util,
promise,
api,
auth,
messagePresenter) {
var target;
var templates = {};
var user;
var privileges;
var avatarContent;
var fileDropper;
var target;
var templates = {};
var user;
var privileges;
var avatarContent;
var fileDropper;
function init(params, loaded) {
user = params.user;
target = params.target;
function init(params, loaded) {
user = params.user;
target = params.target;
privileges = {
canBan:
auth.hasPrivilege(auth.privileges.banUsers),
canChangeAccessRank:
auth.hasPrivilege(auth.privileges.changeAccessRank),
canChangeAvatarStyle:
auth.hasPrivilege(auth.privileges.changeAllAvatarStyles) ||
(auth.hasPrivilege(auth.privileges.changeOwnAvatarStyle) && auth.isLoggedIn(user.name)),
canChangeName:
auth.hasPrivilege(auth.privileges.changeAllNames) ||
(auth.hasPrivilege(auth.privileges.changeOwnName) && auth.isLoggedIn(user.name)),
canChangeEmailAddress:
auth.hasPrivilege(auth.privileges.changeAllEmailAddresses) ||
(auth.hasPrivilege(auth.privileges.changeOwnEmailAddress) && auth.isLoggedIn(user.name)),
canChangePassword:
auth.hasPrivilege(auth.privileges.changeAllPasswords) ||
(auth.hasPrivilege(auth.privileges.changeOwnPassword) && auth.isLoggedIn(user.name)),
};
privileges = {
canBan:
auth.hasPrivilege(auth.privileges.banUsers),
canChangeAccessRank:
auth.hasPrivilege(auth.privileges.changeAccessRank),
canChangeAvatarStyle:
auth.hasPrivilege(auth.privileges.changeAllAvatarStyles) ||
(auth.hasPrivilege(auth.privileges.changeOwnAvatarStyle) && auth.isLoggedIn(user.name)),
canChangeName:
auth.hasPrivilege(auth.privileges.changeAllNames) ||
(auth.hasPrivilege(auth.privileges.changeOwnName) && auth.isLoggedIn(user.name)),
canChangeEmailAddress:
auth.hasPrivilege(auth.privileges.changeAllEmailAddresses) ||
(auth.hasPrivilege(auth.privileges.changeOwnEmailAddress) && auth.isLoggedIn(user.name)),
canChangePassword:
auth.hasPrivilege(auth.privileges.changeAllPasswords) ||
(auth.hasPrivilege(auth.privileges.changeOwnPassword) && auth.isLoggedIn(user.name)),
};
promise.wait(util.promiseTemplate('account-settings'))
.then(function(template) {
templates.accountRemoval = template;
render();
loaded();
}).fail(function() {
console.log(arguments);
loaded();
});
}
promise.wait(util.promiseTemplate('account-settings'))
.then(function(template) {
templates.accountRemoval = template;
render();
loaded();
}).fail(function() {
console.log(arguments);
loaded();
});
}
function render() {
var $el = jQuery(target);
$el.html(templates.accountRemoval(_.extend({user: user}, privileges)));
$el.find('form').submit(accountSettingsFormSubmitted);
$el.find('form [name=avatar-style]').change(avatarStyleChanged);
avatarStyleChanged();
fileDropper = new App.Controls.FileDropper($el.find('[name=avatar-content]'));
fileDropper.onChange = avatarContentChanged;
fileDropper.setNames = true;
}
function render() {
var $el = jQuery(target);
$el.html(templates.accountRemoval(_.extend({user: user}, privileges)));
$el.find('form').submit(accountSettingsFormSubmitted);
$el.find('form [name=avatar-style]').change(avatarStyleChanged);
avatarStyleChanged();
fileDropper = new App.Controls.FileDropper($el.find('[name=avatar-content]'));
fileDropper.onChange = avatarContentChanged;
fileDropper.setNames = true;
}
function getPrivileges() {
return privileges;
}
function getPrivileges() {
return privileges;
}
function avatarStyleChanged(e) {
var $el = jQuery(target);
var $target = $el.find('.avatar-content .file-handler');
if ($el.find('[name=avatar-style]:checked').val() === 'manual') {
$target.show();
} else {
$target.hide();
}
}
function avatarStyleChanged(e) {
var $el = jQuery(target);
var $target = $el.find('.avatar-content .file-handler');
if ($el.find('[name=avatar-style]:checked').val() === 'manual') {
$target.show();
} else {
$target.hide();
}
}
function avatarContentChanged(files) {
avatarContent = files[0];
}
function avatarContentChanged(files) {
avatarContent = files[0];
}
function accountSettingsFormSubmitted(e) {
e.preventDefault();
var $el = jQuery(target);
var $messages = jQuery(target).find('.messages');
messagePresenter.hideMessages($messages);
var formData = new FormData();
function accountSettingsFormSubmitted(e) {
e.preventDefault();
var $el = jQuery(target);
var $messages = jQuery(target).find('.messages');
messagePresenter.hideMessages($messages);
var formData = new FormData();
if (privileges.canChangeAvatarStyle) {
formData.append('avatarStyle', $el.find('[name=avatar-style]:checked').val());
if (avatarContent) {
formData.append('avatarContent', avatarContent);
}
}
if (privileges.canChangeName) {
formData.append('userName', $el.find('[name=userName]').val());
}
if (privileges.canChangeAvatarStyle) {
formData.append('avatarStyle', $el.find('[name=avatar-style]:checked').val());
if (avatarContent) {
formData.append('avatarContent', avatarContent);
}
}
if (privileges.canChangeName) {
formData.append('userName', $el.find('[name=userName]').val());
}
if (privileges.canChangeEmailAddress) {
formData.append('email', $el.find('[name=email]').val());
}
if (privileges.canChangeEmailAddress) {
formData.append('email', $el.find('[name=email]').val());
}
if (privileges.canChangePassword) {
var password = $el.find('[name=password]').val();
var passwordConfirmation = $el.find('[name=passwordConfirmation]').val();
if (privileges.canChangePassword) {
var password = $el.find('[name=password]').val();
var passwordConfirmation = $el.find('[name=passwordConfirmation]').val();
if (password) {
if (password !== passwordConfirmation) {
messagePresenter.showError($messages, 'Passwords must be the same.');
return;
}
if (password) {
if (password !== passwordConfirmation) {
messagePresenter.showError($messages, 'Passwords must be the same.');
return;
}
formData.append('password', password);
}
}
formData.append('password', password);
}
}
if (privileges.canChangeAccessRank) {
formData.append('accessRank', $el.find('[name=access-rank]:checked').val());
}
if (privileges.canChangeAccessRank) {
formData.append('accessRank', $el.find('[name=access-rank]:checked').val());
}
if (privileges.canBan) {
formData.append('banned', $el.find('[name=ban]').is(':checked') ? 1 : 0);
}
if (privileges.canBan) {
formData.append('banned', $el.find('[name=ban]').is(':checked') ? 1 : 0);
}
promise.wait(api.post('/users/' + user.name, formData))
.then(function(response) {
editSuccess(response);
}).fail(function(response) {
editFailure(response);
});
}
promise.wait(api.post('/users/' + user.name, formData))
.then(function(response) {
editSuccess(response);
}).fail(function(response) {
editFailure(response);
});
}
function editSuccess(apiResponse) {
var wasLoggedIn = auth.isLoggedIn(user.name);
user = apiResponse.json;
if (wasLoggedIn) {
auth.updateCurrentUser(user);
}
function editSuccess(apiResponse) {
var wasLoggedIn = auth.isLoggedIn(user.name);
user = apiResponse.json;
if (wasLoggedIn) {
auth.updateCurrentUser(user);
}
render();
render();
var $messages = jQuery(target).find('.messages');
var message = 'Account settings updated!';
if (!apiResponse.json.confirmed) {
message += '<br/>Check your inbox for activation e-mail.<br/>If e-mail doesn\'t show up, check your spam folder.';
}
messagePresenter.showInfo($messages, message);
}
var $messages = jQuery(target).find('.messages');
var message = 'Account settings updated!';
if (!apiResponse.json.confirmed) {
message += '<br/>Check your inbox for activation e-mail.<br/>If e-mail doesn\'t show up, check your spam folder.';
}
messagePresenter.showInfo($messages, message);
}
function editFailure(apiResponse) {
var $messages = jQuery(target).find('.messages');
messagePresenter.showError($messages, apiResponse.json && apiResponse.json.error || apiResponse);
}
function editFailure(apiResponse) {
var $messages = jQuery(target).find('.messages');
messagePresenter.showError($messages, apiResponse.json && apiResponse.json.error || apiResponse);
}
return {
init: init,
render: render,
getPrivileges: getPrivileges,
};
return {
init: init,
render: render,
getPrivileges: getPrivileges,
};
};

View file

@ -2,117 +2,117 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.UserActivationPresenter = function(
jQuery,
promise,
util,
auth,
api,
router,
topNavigationPresenter,
messagePresenter) {
jQuery,
promise,
util,
auth,
api,
router,
topNavigationPresenter,
messagePresenter) {
var $el = jQuery('#content');
var $messages = $el;
var templates = {};
var formHidden = false;
var operation;
var $el = jQuery('#content');
var $messages = $el;
var templates = {};
var formHidden = false;
var operation;
function init(params, loaded) {
topNavigationPresenter.select('login');
topNavigationPresenter.changeTitle('Account recovery');
reinit(params, loaded);
}
function init(params, loaded) {
topNavigationPresenter.select('login');
topNavigationPresenter.changeTitle('Account recovery');
reinit(params, loaded);
}
function reinit(params, loaded) {
operation = params.operation;
promise.wait(util.promiseTemplate('user-query-form'))
.then(function(template) {
templates.userQuery = template;
if (params.token) {
hideForm();
confirmToken(params.token);
} else {
showForm();
}
render();
loaded();
}).fail(function() {
console.log(arguments);
loaded();
});
}
function reinit(params, loaded) {
operation = params.operation;
promise.wait(util.promiseTemplate('user-query-form'))
.then(function(template) {
templates.userQuery = template;
if (params.token) {
hideForm();
confirmToken(params.token);
} else {
showForm();
}
render();
loaded();
}).fail(function() {
console.log(arguments);
loaded();
});
}
function render() {
$el.html(templates.userQuery());
$messages = $el.find('.messages');
if (formHidden) {
$el.find('form').hide();
}
$el.find('form').submit(userQueryFormSubmitted);
}
function render() {
$el.html(templates.userQuery());
$messages = $el.find('.messages');
if (formHidden) {
$el.find('form').hide();
}
$el.find('form').submit(userQueryFormSubmitted);
}
function hideForm() {
formHidden = true;
}
function hideForm() {
formHidden = true;
}
function showForm() {
formHidden = false;
}
function showForm() {
formHidden = false;
}
function userQueryFormSubmitted(e) {
e.preventDefault();
messagePresenter.hideMessages($messages);
function userQueryFormSubmitted(e) {
e.preventDefault();
messagePresenter.hideMessages($messages);
var userNameOrEmail = $el.find('form input[name=user]').val();
if (userNameOrEmail.length === 0) {
messagePresenter.showError($messages, 'Field cannot be blank.');
return;
}
var url = operation === 'passwordReset' ?
'/password-reset/' + userNameOrEmail :
'/activation/' + userNameOrEmail;
var userNameOrEmail = $el.find('form input[name=user]').val();
if (userNameOrEmail.length === 0) {
messagePresenter.showError($messages, 'Field cannot be blank.');
return;
}
var url = operation === 'passwordReset' ?
'/password-reset/' + userNameOrEmail :
'/activation/' + userNameOrEmail;
promise.wait(api.post(url))
.then(function(response) {
var message = operation === 'passwordReset' ?
'Password reset request sent.' :
'Activation e-mail resent.';
message += ' Check your inbox.<br/>If e-mail doesn\'t show up, check your spam folder.';
promise.wait(api.post(url))
.then(function(response) {
var message = operation === 'passwordReset' ?
'Password reset request sent.' :
'Activation e-mail resent.';
message += ' Check your inbox.<br/>If e-mail doesn\'t show up, check your spam folder.';
$el.find('#user-query-form').slideUp(function() {
messagePresenter.showInfo($messages, message);
});
}).fail(function(response) {
messagePresenter.showError($messages, response.json && response.json.error || response);
});
}
$el.find('#user-query-form').slideUp(function() {
messagePresenter.showInfo($messages, message);
});
}).fail(function(response) {
messagePresenter.showError($messages, response.json && response.json.error || response);
});
}
function confirmToken(token) {
messagePresenter.hideMessages($messages);
function confirmToken(token) {
messagePresenter.hideMessages($messages);
var url = operation === 'passwordReset' ?
'/finish-password-reset/' + token :
'/finish-activation/' + token;
var url = operation === 'passwordReset' ?
'/finish-password-reset/' + token :
'/finish-activation/' + token;
promise.wait(api.post(url))
.then(function(response) {
var message = operation === 'passwordReset' ?
'Your new password is <strong>' + response.json.newPassword + '</strong>.' :
'E-mail activation successful.';
promise.wait(api.post(url))
.then(function(response) {
var message = operation === 'passwordReset' ?
'Your new password is <strong>' + response.json.newPassword + '</strong>.' :
'E-mail activation successful.';
$el.find('#user-query-form').slideUp(function() {
messagePresenter.showInfo($messages, message);
});
}).fail(function(response) {
messagePresenter.showError($messages, response.json && response.json.error || response);
});
}
$el.find('#user-query-form').slideUp(function() {
messagePresenter.showInfo($messages, message);
});
}).fail(function(response) {
messagePresenter.showError($messages, response.json && response.json.error || response);
});
}
return {
init: init,
reinit: reinit,
render: render,
};
return {
init: init,
reinit: reinit,
render: render,
};
};

View file

@ -2,75 +2,75 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.UserBrowsingSettingsPresenter = function(
jQuery,
util,
promise,
auth,
browsingSettings,
messagePresenter) {
jQuery,
util,
promise,
auth,
browsingSettings,
messagePresenter) {
var target;
var templates = {};
var user;
var privileges = {};
var target;
var templates = {};
var user;
var privileges = {};
function init(params, loaded) {
user = params.user;
target = params.target;
function init(params, loaded) {
user = params.user;
target = params.target;
privileges.canChangeBrowsingSettings = auth.isLoggedIn(user.name) && user.name === auth.getCurrentUser().name;
privileges.canChangeBrowsingSettings = auth.isLoggedIn(user.name) && user.name === auth.getCurrentUser().name;
promise.wait(util.promiseTemplate('browsing-settings'))
.then(function(template) {
templates.browsingSettings = template;
render();
loaded();
}).fail(function() {
console.log(arguments);
loaded();
});
}
promise.wait(util.promiseTemplate('browsing-settings'))
.then(function(template) {
templates.browsingSettings = template;
render();
loaded();
}).fail(function() {
console.log(arguments);
loaded();
});
}
function render() {
var $el = jQuery(target);
$el.html(templates.browsingSettings({user: user, settings: browsingSettings.getSettings()}));
$el.find('form').submit(browsingSettingsFormSubmitted);
}
function render() {
var $el = jQuery(target);
$el.html(templates.browsingSettings({user: user, settings: browsingSettings.getSettings()}));
$el.find('form').submit(browsingSettingsFormSubmitted);
}
function browsingSettingsFormSubmitted(e) {
e.preventDefault();
var $el = jQuery(target);
var $messages = $el.find('.messages');
messagePresenter.hideMessages($messages);
function browsingSettingsFormSubmitted(e) {
e.preventDefault();
var $el = jQuery(target);
var $messages = $el.find('.messages');
messagePresenter.hideMessages($messages);
var newSettings = {
endlessScroll: $el.find('[name=endlessScroll]').is(':checked'),
hideDownvoted: $el.find('[name=hideDownvoted]').is(':checked'),
listPosts: {
safe: $el.find('[name=listSafePosts]').is(':checked'),
sketchy: $el.find('[name=listSketchyPosts]').is(':checked'),
unsafe: $el.find('[name=listUnsafePosts]').is(':checked'),
},
keyboardShortcuts: $el.find('[name=keyboardShortcuts]').is(':checked'),
};
var newSettings = {
endlessScroll: $el.find('[name=endlessScroll]').is(':checked'),
hideDownvoted: $el.find('[name=hideDownvoted]').is(':checked'),
listPosts: {
safe: $el.find('[name=listSafePosts]').is(':checked'),
sketchy: $el.find('[name=listSketchyPosts]').is(':checked'),
unsafe: $el.find('[name=listUnsafePosts]').is(':checked'),
},
keyboardShortcuts: $el.find('[name=keyboardShortcuts]').is(':checked'),
};
promise.wait(browsingSettings.setSettings(newSettings))
.then(function() {
messagePresenter.showInfo($messages, 'Browsing settings updated!');
}).fail(function() {
console.log(arguments);
});
}
promise.wait(browsingSettings.setSettings(newSettings))
.then(function() {
messagePresenter.showInfo($messages, 'Browsing settings updated!');
}).fail(function() {
console.log(arguments);
});
}
function getPrivileges() {
return privileges;
}
function getPrivileges() {
return privileges;
}
return {
init: init,
render: render,
getPrivileges: getPrivileges,
};
return {
init: init,
render: render,
getPrivileges: getPrivileges,
};
};

View file

@ -2,93 +2,93 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.UserListPresenter = function(
_,
jQuery,
util,
promise,
auth,
pagerPresenter,
topNavigationPresenter) {
_,
jQuery,
util,
promise,
auth,
pagerPresenter,
topNavigationPresenter) {
var $el = jQuery('#content');
var templates = {};
var params;
var privileges = {};
var $el = jQuery('#content');
var templates = {};
var params;
var privileges = {};
function init(params, loaded) {
topNavigationPresenter.select('users');
topNavigationPresenter.changeTitle('Users');
function init(params, loaded) {
topNavigationPresenter.select('users');
topNavigationPresenter.changeTitle('Users');
privileges.canViewUsers = auth.hasPrivilege(auth.privileges.viewUsers);
privileges.canViewUsers = auth.hasPrivilege(auth.privileges.viewUsers);
promise.wait(
util.promiseTemplate('user-list'),
util.promiseTemplate('user-list-item'))
.then(function(listTemplate, listItemTemplate) {
templates.list = listTemplate;
templates.listItem = listItemTemplate;
promise.wait(
util.promiseTemplate('user-list'),
util.promiseTemplate('user-list-item'))
.then(function(listTemplate, listItemTemplate) {
templates.list = listTemplate;
templates.listItem = listItemTemplate;
render();
loaded();
render();
loaded();
pagerPresenter.init({
baseUri: '#/users',
backendUri: '/users',
$target: $el.find('.pagination-target'),
updateCallback: function($page, data) {
renderUsers($page, data.entities);
},
},
function() {
reinit(params, function() {});
});
}).fail(function() {
console.log(arguments);
loaded();
});
}
pagerPresenter.init({
baseUri: '#/users',
backendUri: '/users',
$target: $el.find('.pagination-target'),
updateCallback: function($page, data) {
renderUsers($page, data.entities);
},
},
function() {
reinit(params, function() {});
});
}).fail(function() {
console.log(arguments);
loaded();
});
}
function reinit(_params, loaded) {
params = _params;
params.query = params.query || {};
params.query.order = params.query.order || 'name,asc';
updateActiveOrder(params.query.order);
function reinit(_params, loaded) {
params = _params;
params.query = params.query || {};
params.query.order = params.query.order || 'name,asc';
updateActiveOrder(params.query.order);
pagerPresenter.reinit({query: params.query});
loaded();
}
pagerPresenter.reinit({query: params.query});
loaded();
}
function deinit() {
pagerPresenter.deinit();
}
function deinit() {
pagerPresenter.deinit();
}
function render() {
$el.html(templates.list(privileges));
}
function render() {
$el.html(templates.list(privileges));
}
function updateActiveOrder(activeOrder) {
$el.find('.order li a.active').removeClass('active');
$el.find('.order [href*="' + activeOrder + '"]').addClass('active');
}
function updateActiveOrder(activeOrder) {
$el.find('.order li a.active').removeClass('active');
$el.find('.order [href*="' + activeOrder + '"]').addClass('active');
}
function renderUsers($page, users) {
var $target = $page.find('.users');
_.each(users, function(user) {
var $item = jQuery('<li>' + templates.listItem(_.extend({
user: user,
util: util,
}, privileges)) + '</li>');
$target.append($item);
});
_.map(_.map($target.find('img'), jQuery), util.loadImagesNicely);
}
function renderUsers($page, users) {
var $target = $page.find('.users');
_.each(users, function(user) {
var $item = jQuery('<li>' + templates.listItem(_.extend({
user: user,
util: util,
}, privileges)) + '</li>');
$target.append($item);
});
_.map(_.map($target.find('img'), jQuery), util.loadImagesNicely);
}
return {
init: init,
reinit: reinit,
deinit: deinit,
render: render,
};
return {
init: init,
reinit: reinit,
deinit: deinit,
render: render,
};
};

View file

@ -2,105 +2,105 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.UserPresenter = function(
_,
jQuery,
util,
promise,
api,
auth,
topNavigationPresenter,
presenterManager,
userBrowsingSettingsPresenter,
userAccountSettingsPresenter,
userAccountRemovalPresenter,
messagePresenter) {
_,
jQuery,
util,
promise,
api,
auth,
topNavigationPresenter,
presenterManager,
userBrowsingSettingsPresenter,
userAccountSettingsPresenter,
userAccountRemovalPresenter,
messagePresenter) {
var $el = jQuery('#content');
var $messages = $el;
var templates = {};
var user;
var userName = null;
var activeTab;
var $el = jQuery('#content');
var $messages = $el;
var templates = {};
var user;
var userName = null;
var activeTab;
function init(params, loaded) {
promise.wait(util.promiseTemplate('user'))
.then(function(template) {
templates.user = template;
reinit(params, loaded);
}).fail(function() {
console.log(arguments);
loaded();
});
}
function init(params, loaded) {
promise.wait(util.promiseTemplate('user'))
.then(function(template) {
templates.user = template;
reinit(params, loaded);
}).fail(function() {
console.log(arguments);
loaded();
});
}
function reinit(params, loaded) {
if (params.userName !== userName) {
userName = params.userName;
topNavigationPresenter.select(auth.isLoggedIn(userName) ? 'my-account' : 'users');
topNavigationPresenter.changeTitle(userName);
function reinit(params, loaded) {
if (params.userName !== userName) {
userName = params.userName;
topNavigationPresenter.select(auth.isLoggedIn(userName) ? 'my-account' : 'users');
topNavigationPresenter.changeTitle(userName);
promise.wait(api.get('/users/' + userName))
.then(function(response) {
user = response.json;
var extendedContext = _.extend(params, {user: user});
promise.wait(api.get('/users/' + userName))
.then(function(response) {
user = response.json;
var extendedContext = _.extend(params, {user: user});
presenterManager.initPresenters([
[userBrowsingSettingsPresenter, _.extend({}, extendedContext, {target: '#browsing-settings-target'})],
[userAccountSettingsPresenter, _.extend({}, extendedContext, {target: '#account-settings-target'})],
[userAccountRemovalPresenter, _.extend({}, extendedContext, {target: '#account-removal-target'})]],
function() {
initTabs(params);
loaded();
});
presenterManager.initPresenters([
[userBrowsingSettingsPresenter, _.extend({}, extendedContext, {target: '#browsing-settings-target'})],
[userAccountSettingsPresenter, _.extend({}, extendedContext, {target: '#account-settings-target'})],
[userAccountRemovalPresenter, _.extend({}, extendedContext, {target: '#account-removal-target'})]],
function() {
initTabs(params);
loaded();
});
}).fail(function(response) {
$el.empty();
messagePresenter.showError($messages, response.json && response.json.error || response);
loaded();
});
}).fail(function(response) {
$el.empty();
messagePresenter.showError($messages, response.json && response.json.error || response);
loaded();
});
} else {
initTabs(params);
loaded();
}
}
} else {
initTabs(params);
loaded();
}
}
function initTabs(params) {
activeTab = params.tab || 'basic-info';
render();
}
function initTabs(params) {
activeTab = params.tab || 'basic-info';
render();
}
function render() {
$el.html(templates.user({
user: user,
isLoggedIn: auth.isLoggedIn(user.name),
util: util,
canChangeBrowsingSettings: userBrowsingSettingsPresenter.getPrivileges().canChangeBrowsingSettings,
canChangeAccountSettings: _.any(userAccountSettingsPresenter.getPrivileges()),
canDeleteAccount: userAccountRemovalPresenter.getPrivileges().canDeleteAccount}));
$messages = $el.find('.messages');
util.loadImagesNicely($el.find('img'));
userBrowsingSettingsPresenter.render();
userAccountSettingsPresenter.render();
userAccountRemovalPresenter.render();
changeTab(activeTab);
}
function render() {
$el.html(templates.user({
user: user,
isLoggedIn: auth.isLoggedIn(user.name),
util: util,
canChangeBrowsingSettings: userBrowsingSettingsPresenter.getPrivileges().canChangeBrowsingSettings,
canChangeAccountSettings: _.any(userAccountSettingsPresenter.getPrivileges()),
canDeleteAccount: userAccountRemovalPresenter.getPrivileges().canDeleteAccount}));
$messages = $el.find('.messages');
util.loadImagesNicely($el.find('img'));
userBrowsingSettingsPresenter.render();
userAccountSettingsPresenter.render();
userAccountRemovalPresenter.render();
changeTab(activeTab);
}
function changeTab(targetTab) {
var $link = $el.find('a[data-tab=' + targetTab + ']');
var $links = $link.closest('ul').find('a[data-tab]');
var $tabs = $el.find('.tab-wrapper').find('.tab');
$links.removeClass('active');
$link.addClass('active');
$tabs.removeClass('active');
$tabs.filter('[data-tab=' + targetTab + ']').addClass('active');
}
function changeTab(targetTab) {
var $link = $el.find('a[data-tab=' + targetTab + ']');
var $links = $link.closest('ul').find('a[data-tab]');
var $tabs = $el.find('.tab-wrapper').find('.tab');
$links.removeClass('active');
$link.addClass('active');
$tabs.removeClass('active');
$tabs.filter('[data-tab=' + targetTab + ']').addClass('active');
}
return {
init: init,
reinit: reinit,
render: render
};
return {
init: init,
reinit: reinit,
render: render
};
};

View file

@ -2,84 +2,84 @@ var App = App || {};
App.Promise = function(_, jQuery, progress) {
function BrokenPromiseError(promiseId) {
this.name = 'BrokenPromiseError';
this.message = 'Broken promise (promise ID: ' + promiseId + ')';
}
BrokenPromiseError.prototype = new Error();
function BrokenPromiseError(promiseId) {
this.name = 'BrokenPromiseError';
this.message = 'Broken promise (promise ID: ' + promiseId + ')';
}
BrokenPromiseError.prototype = new Error();
var active = [];
var promiseId = 0;
var active = [];
var promiseId = 0;
function make(callback, useProgress) {
var deferred = jQuery.Deferred();
var promise = deferred.promise();
promise.promiseId = ++ promiseId;
function make(callback, useProgress) {
var deferred = jQuery.Deferred();
var promise = deferred.promise();
promise.promiseId = ++ promiseId;
if (useProgress === true) {
progress.start();
}
callback(function() {
try {
deferred.resolve.apply(deferred, arguments);
active = _.without(active, promise.promiseId);
progress.done();
} catch (e) {
if (!(e instanceof BrokenPromiseError)) {
console.log(e);
}
progress.reset();
}
}, function() {
try {
deferred.reject.apply(deferred, arguments);
active = _.without(active, promise.promiseId);
progress.done();
} catch (e) {
if (!(e instanceof BrokenPromiseError)) {
console.log(e);
}
progress.reset();
}
});
if (useProgress === true) {
progress.start();
}
callback(function() {
try {
deferred.resolve.apply(deferred, arguments);
active = _.without(active, promise.promiseId);
progress.done();
} catch (e) {
if (!(e instanceof BrokenPromiseError)) {
console.log(e);
}
progress.reset();
}
}, function() {
try {
deferred.reject.apply(deferred, arguments);
active = _.without(active, promise.promiseId);
progress.done();
} catch (e) {
if (!(e instanceof BrokenPromiseError)) {
console.log(e);
}
progress.reset();
}
});
active.push(promise.promiseId);
active.push(promise.promiseId);
promise.always(function() {
if (!_.contains(active, promise.promiseId)) {
throw new BrokenPromiseError(promise.promiseId);
}
});
promise.always(function() {
if (!_.contains(active, promise.promiseId)) {
throw new BrokenPromiseError(promise.promiseId);
}
});
return promise;
}
return promise;
}
function wait() {
var promises = arguments;
var deferred = jQuery.Deferred();
return jQuery.when.apply(jQuery, promises)
.then(function() {
return deferred.resolve.apply(deferred, arguments);
}).fail(function() {
return deferred.reject.apply(deferred, arguments);
});
}
function wait() {
var promises = arguments;
var deferred = jQuery.Deferred();
return jQuery.when.apply(jQuery, promises)
.then(function() {
return deferred.resolve.apply(deferred, arguments);
}).fail(function() {
return deferred.reject.apply(deferred, arguments);
});
}
function abortAll() {
active = [];
}
function abortAll() {
active = [];
}
function getActive() {
return active.length;
}
function getActive() {
return active.length;
}
return {
make: function(callback) { return make(callback, true); },
makeSilent: function(callback) { return make(callback, false); },
wait: wait,
getActive: getActive,
abortAll: abortAll,
};
return {
make: function(callback) { return make(callback, true); },
makeSilent: function(callback) { return make(callback, false); },
wait: wait,
getActive: getActive,
abortAll: abortAll,
};
};

View file

@ -2,184 +2,184 @@ var App = App || {};
App.Router = function(_, jQuery, promise, util, appState, presenterManager) {
var root = '#/';
var previousLocation = window.location.href;
var routes = [];
var root = '#/';
var previousLocation = window.location.href;
var routes = [];
injectRoutes();
injectRoutes();
function injectRoutes() {
inject('', 'homePresenter');
inject('#/', 'homePresenter');
inject('#/404', 'httpErrorPresenter', {error: 404});
inject('#/home', 'homePresenter');
inject('#/login', 'loginPresenter');
inject('#/logout', 'logoutPresenter');
inject('#/register', 'registrationPresenter');
inject('#/upload', 'postUploadPresenter');
inject('#/password-reset(/:token)', 'userActivationPresenter', {operation: 'passwordReset'});
inject('#/activate(/:token)', 'userActivationPresenter', {operation: 'activation'});
inject('#/users(/:!query)', 'userListPresenter');
inject('#/user/:userName(/:tab)', 'userPresenter');
inject('#/posts(/:!query)', 'postListPresenter');
inject('#/post/:postNameOrId(/:!query)', 'postPresenter');
inject('#/comments(/:!query)', 'globalCommentListPresenter');
inject('#/tags(/:!query)', 'tagListPresenter');
inject('#/tag/:tagName', 'tagPresenter');
inject('#/help(/:tab)', 'helpPresenter');
inject('#/history(/:!query)', 'historyPresenter');
}
function injectRoutes() {
inject('', 'homePresenter');
inject('#/', 'homePresenter');
inject('#/404', 'httpErrorPresenter', {error: 404});
inject('#/home', 'homePresenter');
inject('#/login', 'loginPresenter');
inject('#/logout', 'logoutPresenter');
inject('#/register', 'registrationPresenter');
inject('#/upload', 'postUploadPresenter');
inject('#/password-reset(/:token)', 'userActivationPresenter', {operation: 'passwordReset'});
inject('#/activate(/:token)', 'userActivationPresenter', {operation: 'activation'});
inject('#/users(/:!query)', 'userListPresenter');
inject('#/user/:userName(/:tab)', 'userPresenter');
inject('#/posts(/:!query)', 'postListPresenter');
inject('#/post/:postNameOrId(/:!query)', 'postPresenter');
inject('#/comments(/:!query)', 'globalCommentListPresenter');
inject('#/tags(/:!query)', 'tagListPresenter');
inject('#/tag/:tagName', 'tagPresenter');
inject('#/help(/:tab)', 'helpPresenter');
inject('#/history(/:!query)', 'historyPresenter');
}
function navigate(url, useBrowserDispatcher) {
if (('pushState' in history) && !useBrowserDispatcher) {
history.pushState('', '', url);
dispatch();
} else {
window.location.href = url;
}
}
function navigate(url, useBrowserDispatcher) {
if (('pushState' in history) && !useBrowserDispatcher) {
history.pushState('', '', url);
dispatch();
} else {
window.location.href = url;
}
}
function navigateToMainPage() {
navigate(root);
}
function navigateToMainPage() {
navigate(root);
}
function navigateInplace(url, useBrowserDispatcher) {
if ('replaceState' in history) {
history.replaceState('', '', url);
if (!useBrowserDispatcher) {
dispatch();
} else {
location.reload();
}
} else {
navigate(url, useBrowserDispatcher);
}
}
function navigateInplace(url, useBrowserDispatcher) {
if ('replaceState' in history) {
history.replaceState('', '', url);
if (!useBrowserDispatcher) {
dispatch();
} else {
location.reload();
}
} else {
navigate(url, useBrowserDispatcher);
}
}
function start() {
if ('onhashchange' in window) {
window.onhashchange = dispatch;
} else {
window.onpopstate = dispatch;
}
dispatch();
}
function start() {
if ('onhashchange' in window) {
window.onhashchange = dispatch;
} else {
window.onpopstate = dispatch;
}
dispatch();
}
function inject(definition, presenterName, additionalParams) {
routes.push(new Route(definition, function(params) {
if (util.isExitConfirmationEnabled()) {
if (window.location.href === previousLocation) {
return;
} else {
if (window.confirm('Are you sure you want to leave this page? Data will be lost.')) {
util.disableExitConfirmation();
} else {
window.location.href = previousLocation;
return;
}
}
}
function inject(definition, presenterName, additionalParams) {
routes.push(new Route(definition, function(params) {
if (util.isExitConfirmationEnabled()) {
if (window.location.href === previousLocation) {
return;
} else {
if (window.confirm('Are you sure you want to leave this page? Data will be lost.')) {
util.disableExitConfirmation();
} else {
window.location.href = previousLocation;
return;
}
}
}
params = _.extend({}, params, additionalParams, {previousLocation: previousLocation});
params = _.extend({}, params, additionalParams, {previousLocation: previousLocation});
//abort every operation that can be executed
promise.abortAll();
previousLocation = window.location.href;
//abort every operation that can be executed
promise.abortAll();
previousLocation = window.location.href;
var presenter = App.DI.get(presenterName);
presenter.name = presenterName;
presenterManager.switchContentPresenter(presenter, params);
}));
}
var presenter = App.DI.get(presenterName);
presenter.name = presenterName;
presenterManager.switchContentPresenter(presenter, params);
}));
}
function dispatch() {
var url = document.location.hash;
for (var i = 0; i < routes.length; i ++) {
var route = routes[i];
if (route.match(url)) {
route.callback(route.params);
return true;
}
}
navigateInplace('#/404', true);
return false;
}
function dispatch() {
var url = document.location.hash;
for (var i = 0; i < routes.length; i ++) {
var route = routes[i];
if (route.match(url)) {
route.callback(route.params);
return true;
}
}
navigateInplace('#/404', true);
return false;
}
function parseComplexParamValue(value) {
var result = {};
var params = (value || '').split(/;/);
for (var i = 0; i < params.length; i ++) {
var param = params[i];
if (!param) {
continue;
}
var kv = param.split(/=/);
result[kv[0]] = kv[1];
}
return result;
}
function parseComplexParamValue(value) {
var result = {};
var params = (value || '').split(/;/);
for (var i = 0; i < params.length; i ++) {
var param = params[i];
if (!param) {
continue;
}
var kv = param.split(/=/);
result[kv[0]] = kv[1];
}
return result;
}
function Route(definition, callback) {
var possibleRoutes = getPossibleRoutes(definition);
function Route(definition, callback) {
var possibleRoutes = getPossibleRoutes(definition);
function getPossibleRoutes(routeDefinition) {
var parts = [];
var re = new RegExp('\\(([^}]+?)\\)', 'g');
while (true) {
var text = re.exec(routeDefinition);
if (!text) {
break;
}
parts.push(text[1]);
}
var possibleRoutes = [routeDefinition.split('(')[0]];
for (var i = 0; i < parts.length; i ++) {
possibleRoutes.push(possibleRoutes[possibleRoutes.length - 1] + parts[i]);
}
return possibleRoutes;
}
function getPossibleRoutes(routeDefinition) {
var parts = [];
var re = new RegExp('\\(([^}]+?)\\)', 'g');
while (true) {
var text = re.exec(routeDefinition);
if (!text) {
break;
}
parts.push(text[1]);
}
var possibleRoutes = [routeDefinition.split('(')[0]];
for (var i = 0; i < parts.length; i ++) {
possibleRoutes.push(possibleRoutes[possibleRoutes.length - 1] + parts[i]);
}
return possibleRoutes;
}
function match(url) {
var params = {};
for (var i = 0; i < possibleRoutes.length; i ++) {
var possibleRoute = possibleRoutes[i];
var compare = url;
var possibleRouteParts = possibleRoute.split('/');
var compareParts = compare.split('/');
if (possibleRoute.search(':') > 0) {
for (var j = 0; j < possibleRouteParts.length; j ++) {
if ((j < compareParts.length) && (possibleRouteParts[j].charAt(0) === ':')) {
var key = possibleRouteParts[j].substring(1);
var value = compareParts[j];
if (key.charAt(0) === '!') {
key = key.substring(1);
value = parseComplexParamValue(value);
}
params[key] = value;
compareParts[j] = possibleRouteParts[j];
compare = compareParts.join('/');
}
}
}
if (possibleRoute === compare) {
this.params = params;
return true;
}
}
return false;
}
function match(url) {
var params = {};
for (var i = 0; i < possibleRoutes.length; i ++) {
var possibleRoute = possibleRoutes[i];
var compare = url;
var possibleRouteParts = possibleRoute.split('/');
var compareParts = compare.split('/');
if (possibleRoute.search(':') > 0) {
for (var j = 0; j < possibleRouteParts.length; j ++) {
if ((j < compareParts.length) && (possibleRouteParts[j].charAt(0) === ':')) {
var key = possibleRouteParts[j].substring(1);
var value = compareParts[j];
if (key.charAt(0) === '!') {
key = key.substring(1);
value = parseComplexParamValue(value);
}
params[key] = value;
compareParts[j] = possibleRouteParts[j];
compare = compareParts.join('/');
}
}
}
if (possibleRoute === compare) {
this.params = params;
return true;
}
}
return false;
}
this.match = match;
this.callback = callback;
}
this.match = match;
this.callback = callback;
}
return {
start: start,
navigate: navigate,
navigateInplace: navigateInplace,
navigateToMainPage: navigateToMainPage,
};
return {
start: start,
navigate: navigate,
navigateInplace: navigateInplace,
navigateToMainPage: navigateToMainPage,
};
};
App.DI.registerSingleton('router', ['_', 'jQuery', 'promise', 'util', 'appState', 'presenterManager'], App.Router);

View file

@ -3,83 +3,83 @@ App.Services = App.Services || {};
App.Services.PostsAroundCalculator = function(_, promise, util, pager) {
pager.init({url: '/posts'});
pager.init({url: '/posts'});
function resetCache() {
pager.resetCache();
}
function resetCache() {
pager.resetCache();
}
function getLinksToPostsAround(query, postId) {
return promise.make(function(resolve, reject) {
pager.setSearchParams(query);
pager.setPage(query.page);
promise.wait(pager.retrieveCached())
.then(function(response) {
var postIds = _.pluck(response.entities, 'id');
var position = _.indexOf(postIds, postId);
function getLinksToPostsAround(query, postId) {
return promise.make(function(resolve, reject) {
pager.setSearchParams(query);
pager.setPage(query.page);
promise.wait(pager.retrieveCached())
.then(function(response) {
var postIds = _.pluck(response.entities, 'id');
var position = _.indexOf(postIds, postId);
if (position === -1) {
resolve(null, null);
}
if (position === -1) {
resolve(null, null);
}
promise.wait(
getLinkToPostAround(postIds, position, query.page, -1),
getLinkToPostAround(postIds, position, query.page, 1))
.then(function(nextPostUrl, prevPostUrl) {
resolve(nextPostUrl, prevPostUrl);
}).fail(function() {
reject();
});
}).fail(function() {
reject();
});
});
}
promise.wait(
getLinkToPostAround(postIds, position, query.page, -1),
getLinkToPostAround(postIds, position, query.page, 1))
.then(function(nextPostUrl, prevPostUrl) {
resolve(nextPostUrl, prevPostUrl);
}).fail(function() {
reject();
});
}).fail(function() {
reject();
});
});
}
function getLinkToPostAround(postIds, position, page, direction) {
return promise.make(function(resolve, reject) {
if (position + direction >= 0 && position + direction < postIds.length) {
var url = util.appendComplexRouteParam(
'#/post/' + postIds[position + direction],
util.simplifySearchQuery(
_.extend(
{page: page},
pager.getSearchParams())));
function getLinkToPostAround(postIds, position, page, direction) {
return promise.make(function(resolve, reject) {
if (position + direction >= 0 && position + direction < postIds.length) {
var url = util.appendComplexRouteParam(
'#/post/' + postIds[position + direction],
util.simplifySearchQuery(
_.extend(
{page: page},
pager.getSearchParams())));
resolve(url);
} else if (page + direction >= 1) {
pager.setPage(page + direction);
promise.wait(pager.retrieveCached())
.then(function(response) {
if (response.entities.length) {
var post = direction === - 1 ?
_.last(response.entities) :
_.first(response.entities);
resolve(url);
} else if (page + direction >= 1) {
pager.setPage(page + direction);
promise.wait(pager.retrieveCached())
.then(function(response) {
if (response.entities.length) {
var post = direction === - 1 ?
_.last(response.entities) :
_.first(response.entities);
var url = util.appendComplexRouteParam(
'#/post/' + post.id,
util.simplifySearchQuery(
_.extend(
{page: page + direction},
pager.getSearchParams())));
var url = util.appendComplexRouteParam(
'#/post/' + post.id,
util.simplifySearchQuery(
_.extend(
{page: page + direction},
pager.getSearchParams())));
resolve(url);
} else {
resolve(null);
}
}).fail(function() {
reject();
});
} else {
resolve(null);
}
});
}
resolve(url);
} else {
resolve(null);
}
}).fail(function() {
reject();
});
} else {
resolve(null);
}
});
}
return {
resetCache: resetCache,
getLinksToPostsAround: getLinksToPostsAround,
};
return {
resetCache: resetCache,
getLinksToPostsAround: getLinksToPostsAround,
};
};
App.DI.register('postsAroundCalculator', ['_', 'promise', 'util', 'pager'], App.Services.PostsAroundCalculator);

View file

@ -2,31 +2,31 @@ var App = App || {};
App.Services = App.Services || {};
App.Services.TagList = function(jQuery) {
var tags = [];
var tags = [];
function refreshTags() {
jQuery.ajax({
success: function(data, textStatus, xhr) {
tags = data;
},
error: function(xhr, textStatus, errorThrown) {
console.log(new Error(errorThrown));
},
type: 'GET',
url: '/data/tags.json',
});
}
function refreshTags() {
jQuery.ajax({
success: function(data, textStatus, xhr) {
tags = data;
},
error: function(xhr, textStatus, errorThrown) {
console.log(new Error(errorThrown));
},
type: 'GET',
url: '/data/tags.json',
});
}
function getTags() {
return tags;
}
function getTags() {
return tags;
}
refreshTags();
refreshTags();
return {
refreshTags: refreshTags,
getTags: getTags,
};
return {
refreshTags: refreshTags,
getTags: getTags,
};
};
App.DI.registerSingleton('tagList', ['jQuery'], App.Services.TagList);

View file

@ -2,50 +2,50 @@ var App = App || {};
App.State = function() {
var properties = {};
var observers = {};
var properties = {};
var observers = {};
function get(key) {
return properties[key];
}
function get(key) {
return properties[key];
}
function set(key, value) {
properties[key] = value;
if (key in observers) {
for (var observerName in observers[key]) {
if (observers[key].hasOwnProperty(observerName)) {
observers[key][observerName](key, value);
}
}
}
}
function set(key, value) {
properties[key] = value;
if (key in observers) {
for (var observerName in observers[key]) {
if (observers[key].hasOwnProperty(observerName)) {
observers[key][observerName](key, value);
}
}
}
}
function startObserving(key, observerName, callback) {
if (!(key in observers)) {
observers[key] = {};
}
if (!(observerName in observers[key])) {
observers[key][observerName] = {};
}
observers[key][observerName] = callback;
}
function startObserving(key, observerName, callback) {
if (!(key in observers)) {
observers[key] = {};
}
if (!(observerName in observers[key])) {
observers[key][observerName] = {};
}
observers[key][observerName] = callback;
}
function stopObserving(key, observerName) {
if (!(key in observers)) {
return;
}
if (!(observerName in observers[key])) {
return;
}
delete observers[key][observerName];
}
function stopObserving(key, observerName) {
if (!(key in observers)) {
return;
}
if (!(observerName in observers[key])) {
return;
}
delete observers[key][observerName];
}
return {
get: get,
set: set,
startObserving: startObserving,
stopObserving: stopObserving,
};
return {
get: get,
set: set,
startObserving: startObserving,
stopObserving: stopObserving,
};
};

View file

@ -2,146 +2,146 @@ var App = App || {};
App.Util = App.Util || {};
App.Util.Draggable = function(jQuery) {
var KEY_LEFT = 37;
var KEY_UP = 38;
var KEY_RIGHT = 39;
var KEY_DOWN = 40;
var KEY_LEFT = 37;
var KEY_UP = 38;
var KEY_RIGHT = 39;
var KEY_DOWN = 40;
function relativeDragStrategy($element) {
var $parent = $element.parent();
var delta;
var x = $element.offset().left - $parent.offset().left;
var y = $element.offset().top - $parent.offset().top;
function relativeDragStrategy($element) {
var $parent = $element.parent();
var delta;
var x = $element.offset().left - $parent.offset().left;
var y = $element.offset().top - $parent.offset().top;
var getPosition = function() {
return {x: x, y: y};
};
var getPosition = function() {
return {x: x, y: y};
};
var setPosition = function(newX, newY) {
x = newX;
y = newY;
var screenX = Math.min(Math.max(newX, 0), $parent.outerWidth() - $element.outerWidth());
var screenY = Math.min(Math.max(newY, 0), $parent.outerHeight() - $element.outerHeight());
screenX *= 100.0 / $parent.outerWidth();
screenY *= 100.0 / $parent.outerHeight();
$element.css({
left: screenX + '%',
top: screenY + '%'});
};
var setPosition = function(newX, newY) {
x = newX;
y = newY;
var screenX = Math.min(Math.max(newX, 0), $parent.outerWidth() - $element.outerWidth());
var screenY = Math.min(Math.max(newY, 0), $parent.outerHeight() - $element.outerHeight());
screenX *= 100.0 / $parent.outerWidth();
screenY *= 100.0 / $parent.outerHeight();
$element.css({
left: screenX + '%',
top: screenY + '%'});
};
return {
mouseClicked: function(e) {
delta = {
x: $element.offset().left - e.clientX,
y: $element.offset().top - e.clientY,
};
},
return {
mouseClicked: function(e) {
delta = {
x: $element.offset().left - e.clientX,
y: $element.offset().top - e.clientY,
};
},
mouseMoved: function(e) {
setPosition(
e.clientX + delta.x - $parent.offset().left,
e.clientY + delta.y - $parent.offset().top);
},
mouseMoved: function(e) {
setPosition(
e.clientX + delta.x - $parent.offset().left,
e.clientY + delta.y - $parent.offset().top);
},
getPosition: getPosition,
setPosition: setPosition,
};
}
getPosition: getPosition,
setPosition: setPosition,
};
}
function absoluteDragStrategy($element) {
var delta;
var x = $element.offset().left;
var y = $element.offset().top;
function absoluteDragStrategy($element) {
var delta;
var x = $element.offset().left;
var y = $element.offset().top;
var getPosition = function() {
return {x: x, y: y};
};
var getPosition = function() {
return {x: x, y: y};
};
var setPosition = function(newX, newY) {
x = newX;
y = newY;
$element.css({
left: x + 'px',
top: y + 'px'});
};
var setPosition = function(newX, newY) {
x = newX;
y = newY;
$element.css({
left: x + 'px',
top: y + 'px'});
};
return {
mouseClicked: function(e) {
delta = {
x: $element.position().left - e.clientX,
y: $element.position().top - e.clientY,
};
},
return {
mouseClicked: function(e) {
delta = {
x: $element.position().left - e.clientX,
y: $element.position().top - e.clientY,
};
},
mouseMoved: function(e) {
setPosition(e.clientX + delta.x, e.clientY + delta.y);
},
mouseMoved: function(e) {
setPosition(e.clientX + delta.x, e.clientY + delta.y);
},
getPosition: getPosition,
setPosition: setPosition,
};
}
getPosition: getPosition,
setPosition: setPosition,
};
}
function makeDraggable($element, dragStrategy, enableHotkeys) {
var strategy = dragStrategy($element);
$element.data('drag-strategy', strategy);
function makeDraggable($element, dragStrategy, enableHotkeys) {
var strategy = dragStrategy($element);
$element.data('drag-strategy', strategy);
$element.addClass('draggable');
$element.addClass('draggable');
$element.mousedown(function(e) {
if (e.target !== $element.get(0)) {
return;
}
e.preventDefault();
$element.focus();
$element.addClass('dragging');
$element.mousedown(function(e) {
if (e.target !== $element.get(0)) {
return;
}
e.preventDefault();
$element.focus();
$element.addClass('dragging');
strategy.mouseClicked(e);
jQuery(window).bind('mousemove.elemmove', function(e) {
strategy.mouseMoved(e);
}).bind('mouseup.elemmove', function(e) {
e.preventDefault();
strategy.mouseMoved(e);
$element.removeClass('dragging');
jQuery(window).unbind('mousemove.elemmove');
jQuery(window).unbind('mouseup.elemmove');
});
});
strategy.mouseClicked(e);
jQuery(window).bind('mousemove.elemmove', function(e) {
strategy.mouseMoved(e);
}).bind('mouseup.elemmove', function(e) {
e.preventDefault();
strategy.mouseMoved(e);
$element.removeClass('dragging');
jQuery(window).unbind('mousemove.elemmove');
jQuery(window).unbind('mouseup.elemmove');
});
});
if (enableHotkeys) {
$element.keydown(function(e) {
var position = strategy.getPosition();
var oldPosition = {x: position.x, y: position.y};
if (e.shiftKey) {
return;
}
if (enableHotkeys) {
$element.keydown(function(e) {
var position = strategy.getPosition();
var oldPosition = {x: position.x, y: position.y};
if (e.shiftKey) {
return;
}
var delta = e.ctrlKey ? 10 : 1;
if (e.which === KEY_LEFT) {
position.x -= delta;
} else if (e.which === KEY_RIGHT) {
position.x += delta;
} else if (e.which === KEY_UP) {
position.y -= delta;
} else if (e.which === KEY_DOWN) {
position.y += delta;
}
var delta = e.ctrlKey ? 10 : 1;
if (e.which === KEY_LEFT) {
position.x -= delta;
} else if (e.which === KEY_RIGHT) {
position.x += delta;
} else if (e.which === KEY_UP) {
position.y -= delta;
} else if (e.which === KEY_DOWN) {
position.y += delta;
}
if (position.x !== oldPosition.x || position.y !== oldPosition.y) {
e.stopPropagation();
e.stopImmediatePropagation();
e.preventDefault();
strategy.setPosition(position.x, position.y);
}
});
}
}
if (position.x !== oldPosition.x || position.y !== oldPosition.y) {
e.stopPropagation();
e.stopImmediatePropagation();
e.preventDefault();
strategy.setPosition(position.x, position.y);
}
});
}
}
return {
makeDraggable: makeDraggable,
absoluteDragStrategy: absoluteDragStrategy,
relativeDragStrategy: relativeDragStrategy,
};
return {
makeDraggable: makeDraggable,
absoluteDragStrategy: absoluteDragStrategy,
relativeDragStrategy: relativeDragStrategy,
};
};

View file

@ -3,265 +3,265 @@ App.Util = App.Util || {};
App.Util.Misc = function(_, jQuery, marked, promise) {
var exitConfirmationEnabled = false;
var exitConfirmationEnabled = false;
function transparentPixel() {
return 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
}
function transparentPixel() {
return 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
}
function enableExitConfirmation() {
exitConfirmationEnabled = true;
jQuery(window).bind('beforeunload', function(e) {
return 'There are unsaved changes.';
});
}
function enableExitConfirmation() {
exitConfirmationEnabled = true;
jQuery(window).bind('beforeunload', function(e) {
return 'There are unsaved changes.';
});
}
function disableExitConfirmation() {
exitConfirmationEnabled = false;
jQuery(window).unbind('beforeunload');
}
function disableExitConfirmation() {
exitConfirmationEnabled = false;
jQuery(window).unbind('beforeunload');
}
function isExitConfirmationEnabled() {
return exitConfirmationEnabled;
}
function isExitConfirmationEnabled() {
return exitConfirmationEnabled;
}
function loadImagesNicely($img) {
if (!$img.get(0).complete) {
$img.addClass('loading');
$img.css({opacity: 0});
var $div = jQuery('<div>Loading ' + $img.attr('alt') + '&hellip;</div>');
var width = $img.width();
var height = $img.height();
if (width > 50 && height > 50) {
$div.css({
position: 'absolute',
width: width + 'px',
height: height + 'px',
color: 'rgba(0, 0, 0, 0.15)',
zIndex: -1,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
textAlign: 'center'});
$div.insertBefore($img);
$div.offset($img.offset());
}
$img.bind('load', function() {
$img.animate({opacity: 1}, 'fast');
$img.removeClass('loading');
$div.fadeOut($div.remove);
});
}
}
function loadImagesNicely($img) {
if (!$img.get(0).complete) {
$img.addClass('loading');
$img.css({opacity: 0});
var $div = jQuery('<div>Loading ' + $img.attr('alt') + '&hellip;</div>');
var width = $img.width();
var height = $img.height();
if (width > 50 && height > 50) {
$div.css({
position: 'absolute',
width: width + 'px',
height: height + 'px',
color: 'rgba(0, 0, 0, 0.15)',
zIndex: -1,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
textAlign: 'center'});
$div.insertBefore($img);
$div.offset($img.offset());
}
$img.bind('load', function() {
$img.animate({opacity: 1}, 'fast');
$img.removeClass('loading');
$div.fadeOut($div.remove);
});
}
}
function promiseTemplate(templateName) {
return promiseTemplateFromDOM(templateName) ||
promiseTemplateWithAJAX(templateName);
}
function promiseTemplate(templateName) {
return promiseTemplateFromDOM(templateName) ||
promiseTemplateWithAJAX(templateName);
}
function promiseTemplateFromDOM(templateName) {
var $template = jQuery('#' + templateName + '-template');
if ($template.length) {
return promise.make(function(resolve, reject) {
resolve(_.template($template.html()));
});
}
return null;
}
function promiseTemplateFromDOM(templateName) {
var $template = jQuery('#' + templateName + '-template');
if ($template.length) {
return promise.make(function(resolve, reject) {
resolve(_.template($template.html()));
});
}
return null;
}
function promiseTemplateWithAJAX(templateName) {
return promise.make(function(resolve, reject) {
var templatesDir = '/templates';
var templateUrl = templatesDir + '/' + templateName + '.tpl';
function promiseTemplateWithAJAX(templateName) {
return promise.make(function(resolve, reject) {
var templatesDir = '/templates';
var templateUrl = templatesDir + '/' + templateName + '.tpl';
jQuery.ajax({
url: templateUrl,
method: 'GET',
success: function(data, textStatus, xhr) {
resolve(_.template(data));
},
error: function(xhr, textStatus, errorThrown) {
console.log(new Error('Error while loading template ' + templateName + ': ' + errorThrown));
reject();
},
});
});
}
jQuery.ajax({
url: templateUrl,
method: 'GET',
success: function(data, textStatus, xhr) {
resolve(_.template(data));
},
error: function(xhr, textStatus, errorThrown) {
console.log(new Error('Error while loading template ' + templateName + ': ' + errorThrown));
reject();
},
});
});
}
function formatRelativeTime(timeString) {
if (!timeString) {
return 'never';
}
function formatRelativeTime(timeString) {
if (!timeString) {
return 'never';
}
var then = Date.parse(timeString);
var now = Date.now();
var difference = Math.abs(now - then);
var future = now < then;
var then = Date.parse(timeString);
var now = Date.now();
var difference = Math.abs(now - then);
var future = now < then;
var text = (function(difference) {
var mul = 1000;
var prevMul;
var text = (function(difference) {
var mul = 1000;
var prevMul;
mul *= 60;
if (difference < mul) {
return 'a few seconds';
} else if (difference < mul * 2) {
return 'a minute';
}
mul *= 60;
if (difference < mul) {
return 'a few seconds';
} else if (difference < mul * 2) {
return 'a minute';
}
prevMul = mul; mul *= 60;
if (difference < mul) {
return Math.round(difference / prevMul) + ' minutes';
} else if (difference < mul * 2) {
return 'an hour';
}
prevMul = mul; mul *= 60;
if (difference < mul) {
return Math.round(difference / prevMul) + ' minutes';
} else if (difference < mul * 2) {
return 'an hour';
}
prevMul = mul; mul *= 24;
if (difference < mul) {
return Math.round(difference / prevMul) + ' hours';
} else if (difference < mul * 2) {
return 'a day';
}
prevMul = mul; mul *= 24;
if (difference < mul) {
return Math.round(difference / prevMul) + ' hours';
} else if (difference < mul * 2) {
return 'a day';
}
prevMul = mul; mul *= 30.42;
if (difference < mul) {
return Math.round(difference / prevMul) + ' days';
} else if (difference < mul * 2) {
return 'a month';
}
prevMul = mul; mul *= 30.42;
if (difference < mul) {
return Math.round(difference / prevMul) + ' days';
} else if (difference < mul * 2) {
return 'a month';
}
prevMul = mul; mul *= 12;
if (difference < mul) {
return Math.round(difference / prevMul) + ' months';
} else if (difference < mul * 2) {
return 'a year';
}
prevMul = mul; mul *= 12;
if (difference < mul) {
return Math.round(difference / prevMul) + ' months';
} else if (difference < mul * 2) {
return 'a year';
}
return Math.round(difference / mul) + ' years';
})(difference);
return Math.round(difference / mul) + ' years';
})(difference);
if (text === 'a day') {
return future ? 'tomorrow' : 'yesterday';
}
return future ? 'in ' + text : text + ' ago';
}
if (text === 'a day') {
return future ? 'tomorrow' : 'yesterday';
}
return future ? 'in ' + text : text + ' ago';
}
function formatAbsoluteTime(timeString) {
var time = new Date(Date.parse(timeString));
return time.toString();
}
function formatAbsoluteTime(timeString) {
var time = new Date(Date.parse(timeString));
return time.toString();
}
function formatUnits(number, base, suffixes, callback) {
if (!number && number !== 0) {
return NaN;
}
number *= 1.0;
function formatUnits(number, base, suffixes, callback) {
if (!number && number !== 0) {
return NaN;
}
number *= 1.0;
var suffix = suffixes.shift();
while (number >= base && suffixes.length > 0) {
suffix = suffixes.shift();
number /= base;
}
var suffix = suffixes.shift();
while (number >= base && suffixes.length > 0) {
suffix = suffixes.shift();
number /= base;
}
if (typeof(callback) === 'undefined') {
callback = function(number, suffix) {
return suffix ? number.toFixed(1) + suffix : number;
};
}
if (typeof(callback) === 'undefined') {
callback = function(number, suffix) {
return suffix ? number.toFixed(1) + suffix : number;
};
}
return callback(number, suffix);
}
return callback(number, suffix);
}
function formatFileSize(fileSize) {
return formatUnits(
fileSize,
1024,
['B', 'K', 'M', 'G'],
function(number, suffix) {
var decimalPlaces = number < 20 && suffix !== 'B' ? 1 : 0;
return number.toFixed(decimalPlaces) + suffix;
});
}
function formatFileSize(fileSize) {
return formatUnits(
fileSize,
1024,
['B', 'K', 'M', 'G'],
function(number, suffix) {
var decimalPlaces = number < 20 && suffix !== 'B' ? 1 : 0;
return number.toFixed(decimalPlaces) + suffix;
});
}
function formatMarkdown(text) {
var renderer = new marked.Renderer();
function formatMarkdown(text) {
var renderer = new marked.Renderer();
var options = {
renderer: renderer,
breaks: true,
sanitize: true,
smartypants: true,
};
var options = {
renderer: renderer,
breaks: true,
sanitize: true,
smartypants: true,
};
var preDecorator = function(text) {
//prevent ^#... from being treated as headers, due to tag permalinks
text = text.replace(/^#/g, '%%%#');
//fix \ before ~ being stripped away
text = text.replace(/\\~/g, '%%%T');
return text;
};
var preDecorator = function(text) {
//prevent ^#... from being treated as headers, due to tag permalinks
text = text.replace(/^#/g, '%%%#');
//fix \ before ~ being stripped away
text = text.replace(/\\~/g, '%%%T');
return text;
};
var postDecorator = function(text) {
//restore fixes
text = text.replace(/%%%T/g, '\\~');
text = text.replace(/%%%#/g, '#');
var postDecorator = function(text) {
//restore fixes
text = text.replace(/%%%T/g, '\\~');
text = text.replace(/%%%#/g, '#');
//search permalinks
text = text.replace(/\[search\]((?:[^\[]|\[(?!\/?search\]))+)\[\/search\]/ig, '<a href="#/posts/query=$1"><code>$1</code></a>');
//spoilers
text = text.replace(/\[spoiler\]((?:[^\[]|\[(?!\/?spoiler\]))+)\[\/spoiler\]/ig, '<span class="spoiler">$1</span>');
//[small]
text = text.replace(/\[small\]((?:[^\[]|\[(?!\/?small\]))+)\[\/small\]/ig, '<small>$1</small>');
//strike-through
text = text.replace(/(^|[^\\])(~~|~)([^~]+)\2/g, '$1<del>$3</del>');
text = text.replace(/\\~/g, '~');
//post premalinks
text = text.replace(/(^|[\s<>\(\)\[\]])@(\d+)/g, '$1<a href="#/post/$2"><code>@$2</code></a>');
//user permalinks
text = text.replace(/(^|[\s<>\(\)\[\]])\+([a-zA-Z0-9_-]+)/g, '$1<a href="#/user/$2"><code>+$2</code></a>');
//tag permalinks
text = text.replace(/(^|[\s<>\(\)\[\]])\#([^\s<>/\\]+)/g, '$1<a href="#/posts/query=$2"><code>#$2</code></a>');
return text;
};
//search permalinks
text = text.replace(/\[search\]((?:[^\[]|\[(?!\/?search\]))+)\[\/search\]/ig, '<a href="#/posts/query=$1"><code>$1</code></a>');
//spoilers
text = text.replace(/\[spoiler\]((?:[^\[]|\[(?!\/?spoiler\]))+)\[\/spoiler\]/ig, '<span class="spoiler">$1</span>');
//[small]
text = text.replace(/\[small\]((?:[^\[]|\[(?!\/?small\]))+)\[\/small\]/ig, '<small>$1</small>');
//strike-through
text = text.replace(/(^|[^\\])(~~|~)([^~]+)\2/g, '$1<del>$3</del>');
text = text.replace(/\\~/g, '~');
//post premalinks
text = text.replace(/(^|[\s<>\(\)\[\]])@(\d+)/g, '$1<a href="#/post/$2"><code>@$2</code></a>');
//user permalinks
text = text.replace(/(^|[\s<>\(\)\[\]])\+([a-zA-Z0-9_-]+)/g, '$1<a href="#/user/$2"><code>+$2</code></a>');
//tag permalinks
text = text.replace(/(^|[\s<>\(\)\[\]])\#([^\s<>/\\]+)/g, '$1<a href="#/posts/query=$2"><code>#$2</code></a>');
return text;
};
return postDecorator(marked(preDecorator(text), options));
}
return postDecorator(marked(preDecorator(text), options));
}
function appendComplexRouteParam(baseUri, params) {
var result = baseUri + '/';
_.each(params, function(v, k) {
if (typeof(v) !== 'undefined') {
result += k + '=' + v + ';';
}
});
return result.slice(0, -1);
}
function appendComplexRouteParam(baseUri, params) {
var result = baseUri + '/';
_.each(params, function(v, k) {
if (typeof(v) !== 'undefined') {
result += k + '=' + v + ';';
}
});
return result.slice(0, -1);
}
function simplifySearchQuery(query) {
if (typeof(query) === 'undefined') {
return {};
}
if (query.page === 1) {
delete query.page;
}
query = _.pick(query, _.identity); //remove falsy values
return query;
}
function simplifySearchQuery(query) {
if (typeof(query) === 'undefined') {
return {};
}
if (query.page === 1) {
delete query.page;
}
query = _.pick(query, _.identity); //remove falsy values
return query;
}
return {
promiseTemplate: promiseTemplate,
formatRelativeTime: formatRelativeTime,
formatAbsoluteTime: formatAbsoluteTime,
formatFileSize: formatFileSize,
formatMarkdown: formatMarkdown,
enableExitConfirmation: enableExitConfirmation,
disableExitConfirmation: disableExitConfirmation,
isExitConfirmationEnabled: isExitConfirmationEnabled,
transparentPixel: transparentPixel,
loadImagesNicely: loadImagesNicely,
appendComplexRouteParam: appendComplexRouteParam,
simplifySearchQuery: simplifySearchQuery,
};
return {
promiseTemplate: promiseTemplate,
formatRelativeTime: formatRelativeTime,
formatAbsoluteTime: formatAbsoluteTime,
formatFileSize: formatFileSize,
formatMarkdown: formatMarkdown,
enableExitConfirmation: enableExitConfirmation,
disableExitConfirmation: disableExitConfirmation,
isExitConfirmationEnabled: isExitConfirmationEnabled,
transparentPixel: transparentPixel,
loadImagesNicely: loadImagesNicely,
appendComplexRouteParam: appendComplexRouteParam,
simplifySearchQuery: simplifySearchQuery,
};
};

View file

@ -2,108 +2,108 @@ var App = App || {};
App.Util = App.Util || {};
App.Util.Resizable = function(jQuery) {
var KEY_LEFT = 37;
var KEY_UP = 38;
var KEY_RIGHT = 39;
var KEY_DOWN = 40;
var KEY_LEFT = 37;
var KEY_UP = 38;
var KEY_RIGHT = 39;
var KEY_DOWN = 40;
function relativeResizeStrategy($element) {
var $parent = $element.parent();
var delta;
var width = $element.width();
var height = $element.height();
function relativeResizeStrategy($element) {
var $parent = $element.parent();
var delta;
var width = $element.width();
var height = $element.height();
var getSize = function() {
return {width: width, height: height};
};
var getSize = function() {
return {width: width, height: height};
};
var setSize = function(newWidth, newHeight) {
width = newWidth;
height = newHeight;
var screenWidth = Math.min(Math.max(width, 20), $parent.outerWidth() + $parent.offset().left - $element.offset().left);
var screenHeight = Math.min(Math.max(height, 20), $parent.outerHeight() + $parent.offset().top - $element.offset().top);
screenWidth *= 100.0 / $parent.outerWidth();
screenHeight *= 100.0 / $parent.outerHeight();
$element.css({
width: screenWidth + '%',
height: screenHeight + '%'});
};
var setSize = function(newWidth, newHeight) {
width = newWidth;
height = newHeight;
var screenWidth = Math.min(Math.max(width, 20), $parent.outerWidth() + $parent.offset().left - $element.offset().left);
var screenHeight = Math.min(Math.max(height, 20), $parent.outerHeight() + $parent.offset().top - $element.offset().top);
screenWidth *= 100.0 / $parent.outerWidth();
screenHeight *= 100.0 / $parent.outerHeight();
$element.css({
width: screenWidth + '%',
height: screenHeight + '%'});
};
return {
mouseClicked: function(e) {
delta = {
x: $element.width() - e.clientX,
y: $element.height() - e.clientY,
};
},
return {
mouseClicked: function(e) {
delta = {
x: $element.width() - e.clientX,
y: $element.height() - e.clientY,
};
},
mouseMoved: function(e) {
setSize(
e.clientX + delta.x,
e.clientY + delta.y);
},
mouseMoved: function(e) {
setSize(
e.clientX + delta.x,
e.clientY + delta.y);
},
getSize: getSize,
setSize: setSize,
};
}
getSize: getSize,
setSize: setSize,
};
}
function makeResizable($element, enableHotkeys) {
var $resizer = jQuery('<div class="resizer"></div>');
var strategy = relativeResizeStrategy($element);
$element.append($resizer);
function makeResizable($element, enableHotkeys) {
var $resizer = jQuery('<div class="resizer"></div>');
var strategy = relativeResizeStrategy($element);
$element.append($resizer);
$resizer.mousedown(function(e) {
e.preventDefault();
e.stopPropagation();
$element.focus();
$element.addClass('resizing');
$resizer.mousedown(function(e) {
e.preventDefault();
e.stopPropagation();
$element.focus();
$element.addClass('resizing');
strategy.mouseClicked(e);
strategy.mouseClicked(e);
jQuery(window).bind('mousemove.elemsize', function(e) {
strategy.mouseMoved(e);
}).bind('mouseup.elemsize', function(e) {
e.preventDefault();
strategy.mouseMoved(e);
$element.removeClass('resizing');
jQuery(window).unbind('mousemove.elemsize');
jQuery(window).unbind('mouseup.elemsize');
});
});
jQuery(window).bind('mousemove.elemsize', function(e) {
strategy.mouseMoved(e);
}).bind('mouseup.elemsize', function(e) {
e.preventDefault();
strategy.mouseMoved(e);
$element.removeClass('resizing');
jQuery(window).unbind('mousemove.elemsize');
jQuery(window).unbind('mouseup.elemsize');
});
});
if (enableHotkeys) {
$element.keydown(function(e) {
var size = strategy.getSize();
var oldSize = {width: size.width, height: size.height};
if (!e.shiftKey) {
return;
}
if (enableHotkeys) {
$element.keydown(function(e) {
var size = strategy.getSize();
var oldSize = {width: size.width, height: size.height};
if (!e.shiftKey) {
return;
}
var delta = e.ctrlKey ? 10 : 1;
if (e.which === KEY_LEFT) {
size.width -= delta;
} else if (e.which === KEY_RIGHT) {
size.width += delta;
} else if (e.which === KEY_UP) {
size.height -= delta;
} else if (e.which === KEY_DOWN) {
size.height += delta;
}
var delta = e.ctrlKey ? 10 : 1;
if (e.which === KEY_LEFT) {
size.width -= delta;
} else if (e.which === KEY_RIGHT) {
size.width += delta;
} else if (e.which === KEY_UP) {
size.height -= delta;
} else if (e.which === KEY_DOWN) {
size.height += delta;
}
if (size.width !== oldSize.width || size.height !== oldSize.height) {
e.stopPropagation();
e.stopImmediatePropagation();
e.preventDefault();
strategy.setSize(size.width, size.height);
}
});
}
}
if (size.width !== oldSize.width || size.height !== oldSize.height) {
e.stopPropagation();
e.stopImmediatePropagation();
e.preventDefault();
strategy.setSize(size.width, size.height);
}
});
}
}
return {
makeResizable: makeResizable,
};
return {
makeResizable: makeResizable,
};
};

View file

@ -5,42 +5,42 @@ $startTime = microtime(true);
final class Bootstrap
{
private static $startTime;
private static $startTime;
public static function init($startTime)
{
self::$startTime = $startTime;
self::setTimezone();
self::turnErrorsIntoExceptions();
self::initAutoloader();
}
public static function init($startTime)
{
self::$startTime = $startTime;
self::setTimezone();
self::turnErrorsIntoExceptions();
self::initAutoloader();
}
public static function getStartTime()
{
return self::$startTime;
}
public static function getStartTime()
{
return self::$startTime;
}
private static function setTimezone()
{
date_default_timezone_set('UTC');
}
private static function setTimezone()
{
date_default_timezone_set('UTC');
}
private static function initAutoloader()
{
require(__DIR__
. DIRECTORY_SEPARATOR . '..'
. DIRECTORY_SEPARATOR . 'vendor'
. DIRECTORY_SEPARATOR . 'autoload.php');
}
private static function initAutoloader()
{
require(__DIR__
. DIRECTORY_SEPARATOR . '..'
. DIRECTORY_SEPARATOR . 'vendor'
. DIRECTORY_SEPARATOR . 'autoload.php');
}
private static function turnErrorsIntoExceptions()
{
set_error_handler(
function($errno, $errstr, $errfile, $errline, array $errcontext)
{
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
});
}
private static function turnErrorsIntoExceptions()
{
set_error_handler(
function($errno, $errstr, $errfile, $errline, array $errcontext)
{
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
});
}
}
Bootstrap::init($startTime);

View file

@ -3,79 +3,79 @@ namespace Szurubooru;
class Config extends \ArrayObject
{
private $dataDirectory;
private $publicDataDirectory;
private $dataDirectory;
private $publicDataDirectory;
public function __construct($dataDirectory, $publicDataDirectory)
{
$this->setFlags($this->getArrayObjectFlags());
$this->dataDirectory = $dataDirectory;
$this->publicDataDirectory = $publicDataDirectory;
$this->tryLoadFromIni([
$dataDirectory . DIRECTORY_SEPARATOR . 'config.ini',
$dataDirectory . DIRECTORY_SEPARATOR . 'local.ini']);
}
public function __construct($dataDirectory, $publicDataDirectory)
{
$this->setFlags($this->getArrayObjectFlags());
$this->dataDirectory = $dataDirectory;
$this->publicDataDirectory = $publicDataDirectory;
$this->tryLoadFromIni([
$dataDirectory . DIRECTORY_SEPARATOR . 'config.ini',
$dataDirectory . DIRECTORY_SEPARATOR . 'local.ini']);
}
public function tryLoadFromIni($configPaths)
{
if (!is_array($configPaths))
$configPaths = [$configPaths];
public function tryLoadFromIni($configPaths)
{
if (!is_array($configPaths))
$configPaths = [$configPaths];
foreach ($configPaths as $configPath)
{
if (file_exists($configPath))
$this->loadFromIni($configPath);
}
}
foreach ($configPaths as $configPath)
{
if (file_exists($configPath))
$this->loadFromIni($configPath);
}
}
public function getDataDirectory()
{
return $this->dataDirectory;
}
public function getDataDirectory()
{
return $this->dataDirectory;
}
public function getPublicDataDirectory()
{
return $this->publicDataDirectory;
}
public function getPublicDataDirectory()
{
return $this->publicDataDirectory;
}
public function offsetGet($index)
{
if (!parent::offsetExists($index))
return null;
return parent::offsetGet($index);
}
public function offsetGet($index)
{
if (!parent::offsetExists($index))
return null;
return parent::offsetGet($index);
}
public function loadFromIni($configPath)
{
$array = parse_ini_file($configPath, true, INI_SCANNER_RAW);
public function loadFromIni($configPath)
{
$array = parse_ini_file($configPath, true, INI_SCANNER_RAW);
foreach ($array as $key => $value)
{
if (!is_array($value))
{
$this->offsetSet($key, $value);
}
else
{
$section = $key;
$ptr = $this;
foreach ($array as $key => $value)
{
if (!is_array($value))
{
$this->offsetSet($key, $value);
}
else
{
$section = $key;
$ptr = $this;
foreach (explode('.', $section) as $subSection)
{
if (!$ptr->offsetExists($subSection))
$ptr->offsetSet($subSection, new \ArrayObject([], $this->getArrayObjectFlags()));
foreach (explode('.', $section) as $subSection)
{
if (!$ptr->offsetExists($subSection))
$ptr->offsetSet($subSection, new \ArrayObject([], $this->getArrayObjectFlags()));
$ptr = $ptr->$subSection;
}
$ptr = $ptr->$subSection;
}
foreach ($value as $sectionKey => $sectionValue)
$ptr->offsetSet($sectionKey, $sectionValue);
}
}
}
foreach ($value as $sectionKey => $sectionValue)
$ptr->offsetSet($sectionKey, $sectionValue);
}
}
}
private function getArrayObjectFlags()
{
return parent::ARRAY_AS_PROPS | parent::STD_PROP_LIST;
}
private function getArrayObjectFlags()
{
return parent::ARRAY_AS_PROPS | parent::STD_PROP_LIST;
}
}

View file

@ -12,300 +12,300 @@ use Szurubooru\Search\Result;
abstract class AbstractDao implements ICrudDao, IBatchDao
{
protected $pdo;
protected $tableName;
protected $entityConverter;
protected $driver;
protected $pdo;
protected $tableName;
protected $entityConverter;
protected $driver;
public function __construct(
DatabaseConnection $databaseConnection,
$tableName,
IEntityConverter $entityConverter)
{
$this->setDatabaseConnection($databaseConnection);
$this->tableName = $tableName;
$this->entityConverter = $entityConverter;
$this->entityConverter->setEntityDecorator(function($entity)
{
$this->afterLoad($entity);
});
}
public function __construct(
DatabaseConnection $databaseConnection,
$tableName,
IEntityConverter $entityConverter)
{
$this->setDatabaseConnection($databaseConnection);
$this->tableName = $tableName;
$this->entityConverter = $entityConverter;
$this->entityConverter->setEntityDecorator(function($entity)
{
$this->afterLoad($entity);
});
}
public function getTableName()
{
return $this->tableName;
}
public function getTableName()
{
return $this->tableName;
}
public function getEntityConverter()
{
return $this->entityConverter;
}
public function getEntityConverter()
{
return $this->entityConverter;
}
public function save(&$entity)
{
$entity = $this->upsert($entity);
$this->afterSave($entity);
$this->afterBatchSave([$entity]);
return $entity;
}
public function save(&$entity)
{
$entity = $this->upsert($entity);
$this->afterSave($entity);
$this->afterBatchSave([$entity]);
return $entity;
}
public function batchSave(array $entities)
{
foreach ($entities as $key => $entity)
{
$entities[$key] = $this->upsert($entity);
$this->afterSave($entity);
}
if (count($entities) > 0)
$this->afterBatchSave([$entity]);
return $entities;
}
public function batchSave(array $entities)
{
foreach ($entities as $key => $entity)
{
$entities[$key] = $this->upsert($entity);
$this->afterSave($entity);
}
if (count($entities) > 0)
$this->afterBatchSave([$entity]);
return $entities;
}
public function findAll()
{
$query = $this->pdo->from($this->tableName);
return $this->arrayToEntities($query);
}
public function findAll()
{
$query = $this->pdo->from($this->tableName);
return $this->arrayToEntities($query);
}
public function findById($entityId)
{
return $this->findOneBy($this->getIdColumn(), $entityId);
}
public function findById($entityId)
{
return $this->findOneBy($this->getIdColumn(), $entityId);
}
public function findByIds($entityIds)
{
return $this->findBy($this->getIdColumn(), $entityIds);
}
public function findByIds($entityIds)
{
return $this->findBy($this->getIdColumn(), $entityIds);
}
public function findFiltered(IFilter $searchFilter)
{
$query = $this->pdo->from($this->tableName);
public function findFiltered(IFilter $searchFilter)
{
$query = $this->pdo->from($this->tableName);
$orderByString = self::compileOrderBy($searchFilter->getOrder());
if ($orderByString)
$query->orderBy($orderByString);
$orderByString = self::compileOrderBy($searchFilter->getOrder());
if ($orderByString)
$query->orderBy($orderByString);
$this->decorateQueryFromFilter($query, $searchFilter);
if ($searchFilter->getPageSize() > 0)
{
$query->limit($searchFilter->getPageSize());
$query->offset($searchFilter->getPageSize() * max(0, $searchFilter->getPageNumber() - 1));
}
$entities = $this->arrayToEntities(iterator_to_array($query));
$this->decorateQueryFromFilter($query, $searchFilter);
if ($searchFilter->getPageSize() > 0)
{
$query->limit($searchFilter->getPageSize());
$query->offset($searchFilter->getPageSize() * max(0, $searchFilter->getPageNumber() - 1));
}
$entities = $this->arrayToEntities(iterator_to_array($query));
$query = $this->pdo->from($this->tableName);
$this->decorateQueryFromFilter($query, $searchFilter);
$totalRecords = count($query);
$query = $this->pdo->from($this->tableName);
$this->decorateQueryFromFilter($query, $searchFilter);
$totalRecords = count($query);
$searchResult = new Result();
$searchResult->setSearchFilter($searchFilter);
$searchResult->setEntities($entities);
$searchResult->setTotalRecords($totalRecords);
$searchResult->setPageNumber($searchFilter->getPageNumber());
$searchResult->setPageSize($searchFilter->getPageSize());
return $searchResult;
}
$searchResult = new Result();
$searchResult->setSearchFilter($searchFilter);
$searchResult->setEntities($entities);
$searchResult->setTotalRecords($totalRecords);
$searchResult->setPageNumber($searchFilter->getPageNumber());
$searchResult->setPageSize($searchFilter->getPageSize());
return $searchResult;
}
public function deleteAll()
{
foreach ($this->findAll() as $entity)
{
$this->beforeDelete($entity);
}
$this->pdo->deleteFrom($this->tableName)->execute();
}
public function deleteAll()
{
foreach ($this->findAll() as $entity)
{
$this->beforeDelete($entity);
}
$this->pdo->deleteFrom($this->tableName)->execute();
}
public function deleteById($entityId)
{
return $this->deleteBy($this->getIdColumn(), $entityId);
}
public function deleteById($entityId)
{
return $this->deleteBy($this->getIdColumn(), $entityId);
}
public function update(Entity $entity)
{
$arrayEntity = $this->entityConverter->toArray($entity);
unset($arrayEntity['id']);
$this->pdo->update($this->tableName)->set($arrayEntity)->where($this->getIdColumn(), $entity->getId())->execute();
return $entity;
}
public function update(Entity $entity)
{
$arrayEntity = $this->entityConverter->toArray($entity);
unset($arrayEntity['id']);
$this->pdo->update($this->tableName)->set($arrayEntity)->where($this->getIdColumn(), $entity->getId())->execute();
return $entity;
}
public function create(Entity $entity)
{
$sql = 'UPDATE sequencer SET lastUsedId = (@lastUsedId := (lastUsedId + 1)) WHERE tableName = :tableName';
$query = $this->pdo->prepare($sql);
$query->bindValue(':tableName', $this->tableName);
$query->execute();
$lastUsedId = $this->pdo->query('SELECT @lastUsedId')->fetchColumn();
public function create(Entity $entity)
{
$sql = 'UPDATE sequencer SET lastUsedId = (@lastUsedId := (lastUsedId + 1)) WHERE tableName = :tableName';
$query = $this->pdo->prepare($sql);
$query->bindValue(':tableName', $this->tableName);
$query->execute();
$lastUsedId = $this->pdo->query('SELECT @lastUsedId')->fetchColumn();
$entity->setId(intval($lastUsedId));
$arrayEntity = $this->entityConverter->toArray($entity);
$this->pdo->insertInto($this->tableName)->values($arrayEntity)->execute();
return $entity;
}
$entity->setId(intval($lastUsedId));
$arrayEntity = $this->entityConverter->toArray($entity);
$this->pdo->insertInto($this->tableName)->values($arrayEntity)->execute();
return $entity;
}
protected function getIdColumn()
{
return 'id';
}
protected function getIdColumn()
{
return 'id';
}
protected function hasAnyRecords()
{
return count(iterator_to_array($this->pdo->from($this->tableName)->limit(1))) > 0;
}
protected function hasAnyRecords()
{
return count(iterator_to_array($this->pdo->from($this->tableName)->limit(1))) > 0;
}
protected function findBy($columnName, $value)
{
if (is_array($value) && empty($value))
return [];
$query = $this->pdo->from($this->tableName)->where($columnName, $value);
$arrayEntities = iterator_to_array($query);
return $this->arrayToEntities($arrayEntities);
}
protected function findBy($columnName, $value)
{
if (is_array($value) && empty($value))
return [];
$query = $this->pdo->from($this->tableName)->where($columnName, $value);
$arrayEntities = iterator_to_array($query);
return $this->arrayToEntities($arrayEntities);
}
protected function findOneBy($columnName, $value)
{
$entities = $this->findBy($columnName, $value);
if (!$entities)
return null;
return array_shift($entities);
}
protected function findOneBy($columnName, $value)
{
$entities = $this->findBy($columnName, $value);
if (!$entities)
return null;
return array_shift($entities);
}
protected function deleteBy($columnName, $value)
{
foreach ($this->findBy($columnName, $value) as $entity)
{
$this->beforeDelete($entity);
}
$this->pdo->deleteFrom($this->tableName)->where($columnName, $value)->execute();
}
protected function deleteBy($columnName, $value)
{
foreach ($this->findBy($columnName, $value) as $entity)
{
$this->beforeDelete($entity);
}
$this->pdo->deleteFrom($this->tableName)->where($columnName, $value)->execute();
}
protected function afterLoad(Entity $entity)
{
}
protected function afterLoad(Entity $entity)
{
}
protected function afterSave(Entity $entity)
{
}
protected function afterSave(Entity $entity)
{
}
protected function afterBatchSave(array $entities)
{
}
protected function afterBatchSave(array $entities)
{
}
protected function beforeDelete(Entity $entity)
{
}
protected function beforeDelete(Entity $entity)
{
}
protected function decorateQueryFromRequirement($query, Requirement $requirement)
{
$value = $requirement->getValue();
$sqlColumn = $requirement->getType();
protected function decorateQueryFromRequirement($query, Requirement $requirement)
{
$value = $requirement->getValue();
$sqlColumn = $requirement->getType();
if ($value instanceof RequirementCompositeValue)
{
$sql = $sqlColumn;
$bindings = $value->getValues();
if ($value instanceof RequirementCompositeValue)
{
$sql = $sqlColumn;
$bindings = $value->getValues();
if ($requirement->isNegated())
$sql = 'NOT ' . $sql;
}
if ($requirement->isNegated())
$sql = 'NOT ' . $sql;
}
else if ($value instanceof RequirementRangedValue)
{
if ($value->getMinValue() && $value->getMaxValue())
{
$sql = $sqlColumn . ' >= ? AND ' . $sqlColumn . ' <= ?';
$bindings = [$value->getMinValue(), $value->getMaxValue()];
}
elseif ($value->getMinValue())
{
$sql = $sqlColumn . ' >= ?';
$bindings = [$value->getMinValue()];
}
elseif ($value->getMaxValue())
{
$sql = $sqlColumn . ' <= ?';
$bindings = [$value->getMaxValue()];
}
else
throw new \RuntimeException('Neither min or max value was supplied');
else if ($value instanceof RequirementRangedValue)
{
if ($value->getMinValue() && $value->getMaxValue())
{
$sql = $sqlColumn . ' >= ? AND ' . $sqlColumn . ' <= ?';
$bindings = [$value->getMinValue(), $value->getMaxValue()];
}
elseif ($value->getMinValue())
{
$sql = $sqlColumn . ' >= ?';
$bindings = [$value->getMinValue()];
}
elseif ($value->getMaxValue())
{
$sql = $sqlColumn . ' <= ?';
$bindings = [$value->getMaxValue()];
}
else
throw new \RuntimeException('Neither min or max value was supplied');
if ($requirement->isNegated())
$sql = 'NOT (' . $sql . ')';
}
if ($requirement->isNegated())
$sql = 'NOT (' . $sql . ')';
}
else if ($value instanceof RequirementSingleValue)
{
$sql = $sqlColumn;
$bindings = [$value->getValue()];
else if ($value instanceof RequirementSingleValue)
{
$sql = $sqlColumn;
$bindings = [$value->getValue()];
if ($requirement->isNegated())
$sql = 'NOT ' . $sql;
}
if ($requirement->isNegated())
$sql = 'NOT ' . $sql;
}
else
throw new \Exception('Bad value: ' . get_class($value));
else
throw new \Exception('Bad value: ' . get_class($value));
$query->where($sql, $bindings);
}
$query->where($sql, $bindings);
}
protected function arrayToEntities($arrayEntities, $entityConverter = null)
{
if ($entityConverter === null)
$entityConverter = $this->entityConverter;
protected function arrayToEntities($arrayEntities, $entityConverter = null)
{
if ($entityConverter === null)
$entityConverter = $this->entityConverter;
$entities = [];
foreach ($arrayEntities as $arrayEntity)
{
$entity = $entityConverter->toEntity($arrayEntity);
$entities[$entity->getId()] = $entity;
}
return $entities;
}
$entities = [];
foreach ($arrayEntities as $arrayEntity)
{
$entity = $entityConverter->toEntity($arrayEntity);
$entities[$entity->getId()] = $entity;
}
return $entities;
}
private function setDatabaseConnection(DatabaseConnection $databaseConnection)
{
$this->pdo = $databaseConnection->getPDO();
$this->driver = $databaseConnection->getDriver();
}
private function setDatabaseConnection(DatabaseConnection $databaseConnection)
{
$this->pdo = $databaseConnection->getPDO();
$this->driver = $databaseConnection->getDriver();
}
private function decorateQueryFromFilter($query, IFilter $filter)
{
foreach ($filter->getRequirements() as $requirement)
{
$this->decorateQueryFromRequirement($query, $requirement);
}
}
private function decorateQueryFromFilter($query, IFilter $filter)
{
foreach ($filter->getRequirements() as $requirement)
{
$this->decorateQueryFromRequirement($query, $requirement);
}
}
private function compileOrderBy($order)
{
$orderByString = '';
foreach ($order as $orderColumn => $orderDir)
{
if ($orderColumn === IFilter::ORDER_RANDOM)
{
$driver = $this->driver;
if ($driver === 'sqlite')
{
$orderColumn = 'RANDOM()';
}
else
{
$orderColumn = 'RAND()';
}
}
$orderByString .= $orderColumn . ' ' . ($orderDir === IFilter::ORDER_DESC ? 'DESC' : 'ASC') . ', ';
}
return substr($orderByString, 0, -2);
}
private function compileOrderBy($order)
{
$orderByString = '';
foreach ($order as $orderColumn => $orderDir)
{
if ($orderColumn === IFilter::ORDER_RANDOM)
{
$driver = $this->driver;
if ($driver === 'sqlite')
{
$orderColumn = 'RANDOM()';
}
else
{
$orderColumn = 'RAND()';
}
}
$orderByString .= $orderColumn . ' ' . ($orderDir === IFilter::ORDER_DESC ? 'DESC' : 'ASC') . ', ';
}
return substr($orderByString, 0, -2);
}
private function upsert(Entity $entity)
{
if ($entity->getId())
{
return $this->update($entity);
}
else
{
return $this->create($entity);
}
}
private function upsert(Entity $entity)
{
if ($entity->getId())
{
return $this->update($entity);
}
else
{
return $this->create($entity);
}
}
}

View file

@ -10,42 +10,42 @@ use Szurubooru\Entities\Post;
class CommentDao extends AbstractDao implements ICrudDao
{
private $userDao;
private $postDao;
private $userDao;
private $postDao;
public function __construct(
DatabaseConnection $databaseConnection,
UserDao $userDao,
PostDao $postDao)
{
parent::__construct(
$databaseConnection,
'comments',
new CommentEntityConverter());
public function __construct(
DatabaseConnection $databaseConnection,
UserDao $userDao,
PostDao $postDao)
{
parent::__construct(
$databaseConnection,
'comments',
new CommentEntityConverter());
$this->userDao = $userDao;
$this->postDao = $postDao;
}
$this->userDao = $userDao;
$this->postDao = $postDao;
}
public function findByPost(Post $post)
{
return $this->findBy('postId', $post->getId());
}
public function findByPost(Post $post)
{
return $this->findBy('postId', $post->getId());
}
protected function afterLoad(Entity $comment)
{
$comment->setLazyLoader(
Comment::LAZY_LOADER_USER,
function (Comment $comment)
{
return $this->userDao->findById($comment->getUserId());
});
protected function afterLoad(Entity $comment)
{
$comment->setLazyLoader(
Comment::LAZY_LOADER_USER,
function (Comment $comment)
{
return $this->userDao->findById($comment->getUserId());
});
$comment->setLazyLoader(
Comment::LAZY_LOADER_POST,
function (Comment $comment)
{
return $this->postDao->findById($comment->getPostId());
});
}
$comment->setLazyLoader(
Comment::LAZY_LOADER_POST,
function (Comment $comment)
{
return $this->postDao->findById($comment->getPostId());
});
}
}

View file

@ -5,43 +5,43 @@ use Szurubooru\Entities\Entity;
abstract class AbstractEntityConverter implements IEntityConverter
{
private $entityDecorator = null;
private $entityDecorator = null;
public function setEntityDecorator(callable $entityDecorator)
{
$this->entityDecorator = $entityDecorator;
}
public function setEntityDecorator(callable $entityDecorator)
{
$this->entityDecorator = $entityDecorator;
}
public function toEntity(array $array)
{
$entity = $this->toBasicEntity($array);
$func = $this->entityDecorator;
if ($func !== null)
$func($entity);
return $entity;
}
public function toEntity(array $array)
{
$entity = $this->toBasicEntity($array);
$func = $this->entityDecorator;
if ($func !== null)
$func($entity);
return $entity;
}
public function toArray(Entity $entity)
{
$array = $this->toBasicArray($entity);
if ($entity->getId() !== null)
$array['id'] = $entity->getId();
return $array;
}
public function toArray(Entity $entity)
{
$array = $this->toBasicArray($entity);
if ($entity->getId() !== null)
$array['id'] = $entity->getId();
return $array;
}
protected abstract function toBasicEntity(array $array);
protected abstract function toBasicEntity(array $array);
protected abstract function toBasicArray(Entity $entity);
protected abstract function toBasicArray(Entity $entity);
protected function dbTimeToEntityTime($time)
{
if ($time === null)
return null;
return date('c', strtotime($time));
}
protected function dbTimeToEntityTime($time)
{
if ($time === null)
return null;
return date('c', strtotime($time));
}
protected function entityTimeToDbTime($time)
{
return $time === null ? null : date('Y-m-d H:i:s', strtotime($time));
}
protected function entityTimeToDbTime($time)
{
return $time === null ? null : date('Y-m-d H:i:s', strtotime($time));
}
}

View file

@ -5,27 +5,27 @@ use Szurubooru\Entities\Entity;
class CommentEntityConverter extends AbstractEntityConverter implements IEntityConverter
{
public function toBasicArray(Entity $entity)
{
return
[
'userId' => $entity->getUserId(),
'postId' => $entity->getPostId(),
'text' => $entity->getText(),
'creationTime' => $this->entityTimeToDbTime($entity->getCreationTime()),
'lastEditTime' => $this->entityTimeToDbTime($entity->getLastEditTime()),
];
}
public function toBasicArray(Entity $entity)
{
return
[
'userId' => $entity->getUserId(),
'postId' => $entity->getPostId(),
'text' => $entity->getText(),
'creationTime' => $this->entityTimeToDbTime($entity->getCreationTime()),
'lastEditTime' => $this->entityTimeToDbTime($entity->getLastEditTime()),
];
}
public function toBasicEntity(array $array)
{
$entity = new Comment(intval($array['id']));
$entity->setUserId($array['userId']);
$entity->setPostId($array['postId']);
$entity->setText($array['text']);
$entity->setCreationTime($this->dbTimeToEntityTime($array['creationTime']));
$entity->setLastEditTime($this->dbTimeToEntityTime($array['lastEditTime']));
$entity->setMeta(Comment::META_SCORE, intval($array['score']));
return $entity;
}
public function toBasicEntity(array $array)
{
$entity = new Comment(intval($array['id']));
$entity->setUserId($array['userId']);
$entity->setPostId($array['postId']);
$entity->setText($array['text']);
$entity->setCreationTime($this->dbTimeToEntityTime($array['creationTime']));
$entity->setLastEditTime($this->dbTimeToEntityTime($array['lastEditTime']));
$entity->setMeta(Comment::META_SCORE, intval($array['score']));
return $entity;
}
}

View file

@ -5,22 +5,22 @@ use Szurubooru\Entities\Favorite;
class FavoriteEntityConverter extends AbstractEntityConverter implements IEntityConverter
{
public function toBasicArray(Entity $entity)
{
return
[
'userId' => $entity->getUserId(),
'postId' => $entity->getPostId(),
'time' => $this->entityTimeToDbTime($entity->getTime()),
];
}
public function toBasicArray(Entity $entity)
{
return
[
'userId' => $entity->getUserId(),
'postId' => $entity->getPostId(),
'time' => $this->entityTimeToDbTime($entity->getTime()),
];
}
public function toBasicEntity(array $array)
{
$entity = new Favorite(intval($array['id']));
$entity->setUserId($array['userId']);
$entity->setPostId($array['postId']);
$entity->setTime($this->dbTimeToEntityTime($array['time']));
return $entity;
}
public function toBasicEntity(array $array)
{
$entity = new Favorite(intval($array['id']));
$entity->setUserId($array['userId']);
$entity->setPostId($array['postId']);
$entity->setTime($this->dbTimeToEntityTime($array['time']));
return $entity;
}
}

View file

@ -5,20 +5,20 @@ use Szurubooru\Entities\GlobalParam;
class GlobalParamEntityConverter extends AbstractEntityConverter implements IEntityConverter
{
public function toBasicArray(Entity $entity)
{
return
[
'dataKey' => $entity->getKey(),
'dataValue' => $entity->getValue(),
];
}
public function toBasicArray(Entity $entity)
{
return
[
'dataKey' => $entity->getKey(),
'dataValue' => $entity->getValue(),
];
}
public function toBasicEntity(array $array)
{
$entity = new GlobalParam(intval($array['id']));
$entity->setKey($array['dataKey']);
$entity->setValue($array['dataValue']);
return $entity;
}
public function toBasicEntity(array $array)
{
$entity = new GlobalParam(intval($array['id']));
$entity->setKey($array['dataKey']);
$entity->setValue($array['dataValue']);
return $entity;
}
}

View file

@ -4,7 +4,7 @@ use Szurubooru\Entities\Entity;
interface IEntityConverter
{
public function toArray(Entity $entity);
public function toArray(Entity $entity);
public function toEntity(array $array);
public function toEntity(array $array);
}

View file

@ -5,52 +5,52 @@ use Szurubooru\Entities\Post;
class PostEntityConverter extends AbstractEntityConverter implements IEntityConverter
{
public function toBasicArray(Entity $entity)
{
return
[
'name' => $entity->getName(),
'userId' => $entity->getUserId(),
'uploadTime' => $this->entityTimeToDbTime($entity->getUploadTime()),
'lastEditTime' => $this->entityTimeToDbTime($entity->getLastEditTime()),
'safety' => $entity->getSafety(),
'contentType' => $entity->getContentType(),
'contentChecksum' => $entity->getContentChecksum(),
'contentMimeType' => $entity->getContentMimeType(),
'source' => $entity->getSource(),
'imageWidth' => $entity->getImageWidth(),
'imageHeight' => $entity->getImageHeight(),
'originalFileSize' => $entity->getOriginalFileSize(),
'originalFileName' => $entity->getOriginalFileName(),
'featureCount' => $entity->getFeatureCount(),
'lastFeatureTime' => $this->entityTimeToDbTime($entity->getLastFeatureTime()),
'flags' => $entity->getFlags(),
];
}
public function toBasicArray(Entity $entity)
{
return
[
'name' => $entity->getName(),
'userId' => $entity->getUserId(),
'uploadTime' => $this->entityTimeToDbTime($entity->getUploadTime()),
'lastEditTime' => $this->entityTimeToDbTime($entity->getLastEditTime()),
'safety' => $entity->getSafety(),
'contentType' => $entity->getContentType(),
'contentChecksum' => $entity->getContentChecksum(),
'contentMimeType' => $entity->getContentMimeType(),
'source' => $entity->getSource(),
'imageWidth' => $entity->getImageWidth(),
'imageHeight' => $entity->getImageHeight(),
'originalFileSize' => $entity->getOriginalFileSize(),
'originalFileName' => $entity->getOriginalFileName(),
'featureCount' => $entity->getFeatureCount(),
'lastFeatureTime' => $this->entityTimeToDbTime($entity->getLastFeatureTime()),
'flags' => $entity->getFlags(),
];
}
public function toBasicEntity(array $array)
{
$entity = new Post(intval($array['id']));
$entity->setName($array['name']);
$entity->setUserId($array['userId']);
$entity->setUploadTime($this->dbTimeToEntityTime($array['uploadTime']));
$entity->setLastEditTime($this->dbTimeToEntityTime($array['lastEditTime']));
$entity->setSafety(intval($array['safety']));
$entity->setContentType(intval($array['contentType']));
$entity->setContentChecksum($array['contentChecksum']);
$entity->setContentMimeType($array['contentMimeType']);
$entity->setSource($array['source']);
$entity->setImageWidth($array['imageWidth']);
$entity->setImageHeight($array['imageHeight']);
$entity->setOriginalFileSize($array['originalFileSize']);
$entity->setOriginalFileName($array['originalFileName']);
$entity->setFeatureCount(intval($array['featureCount']));
$entity->setLastFeatureTime($this->dbTimeToEntityTime($array['lastFeatureTime']));
$entity->setFlags(intval($array['flags']));
$entity->setMeta(Post::META_TAG_COUNT, intval($array['tagCount']));
$entity->setMeta(Post::META_FAV_COUNT, intval($array['favCount']));
$entity->setMeta(Post::META_COMMENT_COUNT, intval($array['commentCount']));
$entity->setMeta(Post::META_SCORE, intval($array['score']));
return $entity;
}
public function toBasicEntity(array $array)
{
$entity = new Post(intval($array['id']));
$entity->setName($array['name']);
$entity->setUserId($array['userId']);
$entity->setUploadTime($this->dbTimeToEntityTime($array['uploadTime']));
$entity->setLastEditTime($this->dbTimeToEntityTime($array['lastEditTime']));
$entity->setSafety(intval($array['safety']));
$entity->setContentType(intval($array['contentType']));
$entity->setContentChecksum($array['contentChecksum']);
$entity->setContentMimeType($array['contentMimeType']);
$entity->setSource($array['source']);
$entity->setImageWidth($array['imageWidth']);
$entity->setImageHeight($array['imageHeight']);
$entity->setOriginalFileSize($array['originalFileSize']);
$entity->setOriginalFileName($array['originalFileName']);
$entity->setFeatureCount(intval($array['featureCount']));
$entity->setLastFeatureTime($this->dbTimeToEntityTime($array['lastFeatureTime']));
$entity->setFlags(intval($array['flags']));
$entity->setMeta(Post::META_TAG_COUNT, intval($array['tagCount']));
$entity->setMeta(Post::META_FAV_COUNT, intval($array['favCount']));
$entity->setMeta(Post::META_COMMENT_COUNT, intval($array['commentCount']));
$entity->setMeta(Post::META_SCORE, intval($array['score']));
return $entity;
}
}

View file

@ -5,28 +5,28 @@ use Szurubooru\Entities\PostNote;
class PostNoteEntityConverter extends AbstractEntityConverter implements IEntityConverter
{
public function toBasicArray(Entity $entity)
{
return
[
'postId' => $entity->getPostId(),
'x' => $entity->getLeft(),
'y' => $entity->getTop(),
'width' => $entity->getWidth(),
'height' => $entity->getHeight(),
'text' => $entity->getText(),
];
}
public function toBasicArray(Entity $entity)
{
return
[
'postId' => $entity->getPostId(),
'x' => $entity->getLeft(),
'y' => $entity->getTop(),
'width' => $entity->getWidth(),
'height' => $entity->getHeight(),
'text' => $entity->getText(),
];
}
public function toBasicEntity(array $array)
{
$entity = new PostNote(intval($array['id']));
$entity->setPostId($array['postId']);
$entity->setLeft(floatval($array['x']));
$entity->setTop(floatval($array['y']));
$entity->setWidth(floatval($array['width']));
$entity->setHeight(floatval($array['height']));
$entity->setText($array['text']);
return $entity;
}
public function toBasicEntity(array $array)
{
$entity = new PostNote(intval($array['id']));
$entity->setPostId($array['postId']);
$entity->setLeft(floatval($array['x']));
$entity->setTop(floatval($array['y']));
$entity->setWidth(floatval($array['width']));
$entity->setHeight(floatval($array['height']));
$entity->setText($array['text']);
return $entity;
}
}

View file

@ -5,26 +5,26 @@ use Szurubooru\Entities\Score;
class ScoreEntityConverter extends AbstractEntityConverter implements IEntityConverter
{
public function toBasicArray(Entity $entity)
{
return
[
'userId' => $entity->getUserId(),
'postId' => $entity->getPostId(),
'commentId' => $entity->getCommentId(),
'time' => $this->entityTimeToDbTime($entity->getTime()),
'score' => $entity->getScore(),
];
}
public function toBasicArray(Entity $entity)
{
return
[
'userId' => $entity->getUserId(),
'postId' => $entity->getPostId(),
'commentId' => $entity->getCommentId(),
'time' => $this->entityTimeToDbTime($entity->getTime()),
'score' => $entity->getScore(),
];
}
public function toBasicEntity(array $array)
{
$entity = new Score(intval($array['id']));
$entity->setUserId($array['userId']);
$entity->setPostId($array['postId']);
$entity->setCommentId($array['commentId']);
$entity->setTime($this->dbTimeToEntityTime($array['time']));
$entity->setScore(intval($array['score']));
return $entity;
}
public function toBasicEntity(array $array)
{
$entity = new Score(intval($array['id']));
$entity->setUserId($array['userId']);
$entity->setPostId($array['postId']);
$entity->setCommentId($array['commentId']);
$entity->setTime($this->dbTimeToEntityTime($array['time']));
$entity->setScore(intval($array['score']));
return $entity;
}
}

View file

@ -5,30 +5,30 @@ use Szurubooru\Entities\Snapshot;
class SnapshotEntityConverter extends AbstractEntityConverter implements IEntityConverter
{
public function toBasicArray(Entity $entity)
{
return
[
'time' => $this->entityTimeToDbTime($entity->getTime()),
'type' => $entity->getType(),
'primaryKey' => $entity->getPrimaryKey(),
'userId' => $entity->getUserId(),
'operation' => $entity->getOperation(),
'data' => gzdeflate(json_encode($entity->getData())),
'dataDifference' => gzdeflate(json_encode($entity->getDataDifference())),
];
}
public function toBasicArray(Entity $entity)
{
return
[
'time' => $this->entityTimeToDbTime($entity->getTime()),
'type' => $entity->getType(),
'primaryKey' => $entity->getPrimaryKey(),
'userId' => $entity->getUserId(),
'operation' => $entity->getOperation(),
'data' => gzdeflate(json_encode($entity->getData())),
'dataDifference' => gzdeflate(json_encode($entity->getDataDifference())),
];
}
public function toBasicEntity(array $array)
{
$entity = new Snapshot(intval($array['id']));
$entity->setTime($this->dbTimeToEntityTime($array['time']));
$entity->setType(intval($array['type']));
$entity->setPrimaryKey($array['primaryKey']);
$entity->setUserId(intval($array['userId']));
$entity->setOperation($array['operation']);
$entity->setData(json_decode(gzinflate($array['data']), true));
$entity->setDataDifference(json_decode(gzinflate($array['dataDifference']), true));
return $entity;
}
public function toBasicEntity(array $array)
{
$entity = new Snapshot(intval($array['id']));
$entity->setTime($this->dbTimeToEntityTime($array['time']));
$entity->setType(intval($array['type']));
$entity->setPrimaryKey($array['primaryKey']);
$entity->setUserId(intval($array['userId']));
$entity->setOperation($array['operation']);
$entity->setData(json_decode(gzinflate($array['data']), true));
$entity->setDataDifference(json_decode(gzinflate($array['dataDifference']), true));
return $entity;
}
}

View file

@ -5,25 +5,25 @@ use Szurubooru\Entities\Tag;
class TagEntityConverter extends AbstractEntityConverter implements IEntityConverter
{
public function toBasicArray(Entity $entity)
{
return
[
'name' => $entity->getName(),
'creationTime' => $this->entityTimeToDbTime($entity->getCreationTime()),
'banned' => intval($entity->isBanned()),
'category' => $entity->getCategory(),
];
}
public function toBasicArray(Entity $entity)
{
return
[
'name' => $entity->getName(),
'creationTime' => $this->entityTimeToDbTime($entity->getCreationTime()),
'banned' => intval($entity->isBanned()),
'category' => $entity->getCategory(),
];
}
public function toBasicEntity(array $array)
{
$entity = new Tag(intval($array['id']));
$entity->setName($array['name']);
$entity->setCreationTime($this->dbTimeToEntityTime($array['creationTime']));
$entity->setMeta(Tag::META_USAGES, intval($array['usages']));
$entity->setBanned($array['banned']);
$entity->setCategory($array['category']);
return $entity;
}
public function toBasicEntity(array $array)
{
$entity = new Tag(intval($array['id']));
$entity->setName($array['name']);
$entity->setCreationTime($this->dbTimeToEntityTime($array['creationTime']));
$entity->setMeta(Tag::META_USAGES, intval($array['usages']));
$entity->setBanned($array['banned']);
$entity->setCategory($array['category']);
return $entity;
}
}

View file

@ -5,22 +5,22 @@ use Szurubooru\Entities\Token;
class TokenEntityConverter extends AbstractEntityConverter implements IEntityConverter
{
public function toBasicArray(Entity $entity)
{
return
[
'name' => $entity->getName(),
'purpose' => $entity->getPurpose(),
'additionalData' => $entity->getAdditionalData(),
];
}
public function toBasicArray(Entity $entity)
{
return
[
'name' => $entity->getName(),
'purpose' => $entity->getPurpose(),
'additionalData' => $entity->getAdditionalData(),
];
}
public function toBasicEntity(array $array)
{
$entity = new Token(intval($array['id']));
$entity->setName($array['name']);
$entity->setPurpose($array['purpose']);
$entity->setAdditionalData($array['additionalData']);
return $entity;
}
public function toBasicEntity(array $array)
{
$entity = new Token(intval($array['id']));
$entity->setName($array['name']);
$entity->setPurpose($array['purpose']);
$entity->setAdditionalData($array['additionalData']);
return $entity;
}
}

View file

@ -5,40 +5,40 @@ use Szurubooru\Entities\User;
class UserEntityConverter extends AbstractEntityConverter implements IEntityConverter
{
public function toBasicArray(Entity $entity)
{
return
[
'name' => $entity->getName(),
'email' => $entity->getEmail(),
'emailUnconfirmed' => $entity->getEmailUnconfirmed(),
'passwordHash' => $entity->getPasswordHash(),
'passwordSalt' => $entity->getPasswordSalt(),
'accessRank' => $entity->getAccessRank(),
'registrationTime' => $this->entityTimeToDbTime($entity->getRegistrationTime()),
'lastLoginTime' => $this->entityTimeToDbTime($entity->getLastLoginTime()),
'avatarStyle' => $entity->getAvatarStyle(),
'browsingSettings' => json_encode($entity->getBrowsingSettings()),
'accountConfirmed' => intval($entity->isAccountConfirmed()),
'banned' => intval($entity->isBanned()),
];
}
public function toBasicArray(Entity $entity)
{
return
[
'name' => $entity->getName(),
'email' => $entity->getEmail(),
'emailUnconfirmed' => $entity->getEmailUnconfirmed(),
'passwordHash' => $entity->getPasswordHash(),
'passwordSalt' => $entity->getPasswordSalt(),
'accessRank' => $entity->getAccessRank(),
'registrationTime' => $this->entityTimeToDbTime($entity->getRegistrationTime()),
'lastLoginTime' => $this->entityTimeToDbTime($entity->getLastLoginTime()),
'avatarStyle' => $entity->getAvatarStyle(),
'browsingSettings' => json_encode($entity->getBrowsingSettings()),
'accountConfirmed' => intval($entity->isAccountConfirmed()),
'banned' => intval($entity->isBanned()),
];
}
public function toBasicEntity(array $array)
{
$entity = new User(intval($array['id']));
$entity->setName($array['name']);
$entity->setEmail($array['email']);
$entity->setEmailUnconfirmed($array['emailUnconfirmed']);
$entity->setPasswordHash($array['passwordHash']);
$entity->setPasswordSalt($array['passwordSalt']);
$entity->setAccessRank(intval($array['accessRank']));
$entity->setRegistrationTime($this->dbTimeToEntityTime($array['registrationTime']));
$entity->setLastLoginTime($this->dbTimeToEntityTime($array['lastLoginTime']));
$entity->setAvatarStyle(intval($array['avatarStyle']));
$entity->setBrowsingSettings(json_decode($array['browsingSettings']));
$entity->setAccountConfirmed($array['accountConfirmed']);
$entity->setBanned($array['banned']);
return $entity;
}
public function toBasicEntity(array $array)
{
$entity = new User(intval($array['id']));
$entity->setName($array['name']);
$entity->setEmail($array['email']);
$entity->setEmailUnconfirmed($array['emailUnconfirmed']);
$entity->setPasswordHash($array['passwordHash']);
$entity->setPasswordSalt($array['passwordSalt']);
$entity->setAccessRank(intval($array['accessRank']));
$entity->setRegistrationTime($this->dbTimeToEntityTime($array['registrationTime']));
$entity->setLastLoginTime($this->dbTimeToEntityTime($array['lastLoginTime']));
$entity->setAvatarStyle(intval($array['avatarStyle']));
$entity->setBrowsingSettings(json_decode($array['browsingSettings']));
$entity->setAccountConfirmed($array['accountConfirmed']);
$entity->setBanned($array['banned']);
return $entity;
}
}

View file

@ -10,65 +10,65 @@ use Szurubooru\Services\TimeService;
class FavoritesDao extends AbstractDao implements ICrudDao
{
private $timeService;
private $timeService;
public function __construct(
DatabaseConnection $databaseConnection,
TimeService $timeService)
{
parent::__construct(
$databaseConnection,
'favorites',
new FavoriteEntityConverter());
public function __construct(
DatabaseConnection $databaseConnection,
TimeService $timeService)
{
parent::__construct(
$databaseConnection,
'favorites',
new FavoriteEntityConverter());
$this->timeService = $timeService;
}
$this->timeService = $timeService;
}
public function findByEntity(Entity $entity)
{
if ($entity instanceof Post)
return $this->findBy('postId', $entity->getId());
else
throw new \InvalidArgumentException();
}
public function findByEntity(Entity $entity)
{
if ($entity instanceof Post)
return $this->findBy('postId', $entity->getId());
else
throw new \InvalidArgumentException();
}
public function set(User $user, Entity $entity)
{
$favorite = $this->get($user, $entity);
if (!$favorite)
{
$favorite = new Favorite();
$favorite->setTime($this->timeService->getCurrentTime());
$favorite->setUserId($user->getId());
public function set(User $user, Entity $entity)
{
$favorite = $this->get($user, $entity);
if (!$favorite)
{
$favorite = new Favorite();
$favorite->setTime($this->timeService->getCurrentTime());
$favorite->setUserId($user->getId());
if ($entity instanceof Post)
$favorite->setPostId($entity->getId());
else
throw new \InvalidArgumentException();
if ($entity instanceof Post)
$favorite->setPostId($entity->getId());
else
throw new \InvalidArgumentException();
$this->save($favorite);
}
return $favorite;
}
$this->save($favorite);
}
return $favorite;
}
public function delete(User $user, Entity $entity)
{
$favorite = $this->get($user, $entity);
if ($favorite)
$this->deleteById($favorite->getId());
}
public function delete(User $user, Entity $entity)
{
$favorite = $this->get($user, $entity);
if ($favorite)
$this->deleteById($favorite->getId());
}
private function get(User $user, Entity $entity)
{
$query = $this->pdo->from($this->tableName)->where('userId', $user->getId());
private function get(User $user, Entity $entity)
{
$query = $this->pdo->from($this->tableName)->where('userId', $user->getId());
if ($entity instanceof Post)
$query->where('postId', $entity->getId());
else
throw new \InvalidArgumentException();
if ($entity instanceof Post)
$query->where('postId', $entity->getId());
else
throw new \InvalidArgumentException();
$arrayEntities = iterator_to_array($query);
$entities = $this->arrayToEntities($arrayEntities);
return array_shift($entities);
}
$arrayEntities = iterator_to_array($query);
$entities = $this->arrayToEntities($arrayEntities);
return array_shift($entities);
}
}

View file

@ -4,93 +4,93 @@ use Szurubooru\Dao\IFileDao;
class FileDao implements IFileDao
{
private $directory;
private $directory;
public function __construct($directory)
{
$this->directory = $directory;
}
public function __construct($directory)
{
$this->directory = $directory;
}
public function load($fileName)
{
$fullPath = $this->getFullPath($fileName);
return file_exists($fullPath)
? file_get_contents($fullPath)
: null;
}
public function load($fileName)
{
$fullPath = $this->getFullPath($fileName);
return file_exists($fullPath)
? file_get_contents($fullPath)
: null;
}
public function save($fileName, $data)
{
$fullPath = $this->getFullPath($fileName);
$this->createFolders($fileName);
file_put_contents($fullPath, $data);
}
public function save($fileName, $data)
{
$fullPath = $this->getFullPath($fileName);
$this->createFolders($fileName);
file_put_contents($fullPath, $data);
}
public function delete($fileName)
{
$fullPath = $this->getFullPath($fileName);
if (file_exists($fullPath))
unlink($fullPath);
}
public function delete($fileName)
{
$fullPath = $this->getFullPath($fileName);
if (file_exists($fullPath))
unlink($fullPath);
}
public function exists($fileName)
{
$fullPath = $this->getFullPath($fileName);
return file_exists($fullPath);
}
public function exists($fileName)
{
$fullPath = $this->getFullPath($fileName);
return file_exists($fullPath);
}
public function getFullPath($fileName)
{
return $this->directory . DIRECTORY_SEPARATOR . $fileName;
}
public function getFullPath($fileName)
{
return $this->directory . DIRECTORY_SEPARATOR . $fileName;
}
public function listAll()
{
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory));
$files = [];
foreach ($iterator as $path)
{
if (!$path->isDir())
$files[] = $this->getRelativePath($this->directory, $path->getPathName());
}
return $files;
}
public function listAll()
{
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory));
$files = [];
foreach ($iterator as $path)
{
if (!$path->isDir())
$files[] = $this->getRelativePath($this->directory, $path->getPathName());
}
return $files;
}
private function createFolders($fileName)
{
$fullPath = dirname($this->getFullPath($fileName));
if (!file_exists($fullPath))
mkdir($fullPath, 0777, true);
}
private function createFolders($fileName)
{
$fullPath = dirname($this->getFullPath($fileName));
if (!file_exists($fullPath))
mkdir($fullPath, 0777, true);
}
private function getRelativePath($from, $to)
{
$from = is_dir($from) ? rtrim($from, '\/') . '/' : $from;
$to = is_dir($to) ? rtrim($to, '\/') . '/' : $to;
$from = explode('/', str_replace('\\', '/', $from));
$to = explode('/', str_replace('\\', '/', $to));
$relPath = $to;
foreach($from as $depth => $dir)
{
if($dir === $to[$depth])
{
array_shift($relPath);
}
else
{
$remaining = count($from) - $depth;
if ($remaining > 1)
{
$padLength = (count($relPath) + $remaining - 1) * -1;
$relPath = array_pad($relPath, $padLength, '..');
break;
}
else
{
$relPath[0] = $relPath[0];
}
}
}
return implode('/', $relPath);
}
private function getRelativePath($from, $to)
{
$from = is_dir($from) ? rtrim($from, '\/') . '/' : $from;
$to = is_dir($to) ? rtrim($to, '\/') . '/' : $to;
$from = explode('/', str_replace('\\', '/', $from));
$to = explode('/', str_replace('\\', '/', $to));
$relPath = $to;
foreach($from as $depth => $dir)
{
if($dir === $to[$depth])
{
array_shift($relPath);
}
else
{
$remaining = count($from) - $depth;
if ($remaining > 1)
{
$padLength = (count($relPath) + $remaining - 1) * -1;
$relPath = array_pad($relPath, $padLength, '..');
break;
}
else
{
$relPath[0] = $relPath[0];
}
}
}
return implode('/', $relPath);
}
}

View file

@ -5,32 +5,32 @@ use Szurubooru\DatabaseConnection;
class GlobalParamDao extends AbstractDao implements ICrudDao
{
public function __construct(DatabaseConnection $databaseConnection)
{
parent::__construct(
$databaseConnection,
'globals',
new GlobalParamEntityConverter());
}
public function __construct(DatabaseConnection $databaseConnection)
{
parent::__construct(
$databaseConnection,
'globals',
new GlobalParamEntityConverter());
}
public function save(&$entity)
{
if (!$entity->getId())
{
$otherEntityWithThisKey = $this->findByKey($entity->getKey());
if ($otherEntityWithThisKey)
$entity->setId($otherEntityWithThisKey->getId());
}
parent::save($entity);
}
public function save(&$entity)
{
if (!$entity->getId())
{
$otherEntityWithThisKey = $this->findByKey($entity->getKey());
if ($otherEntityWithThisKey)
$entity->setId($otherEntityWithThisKey->getId());
}
parent::save($entity);
}
public function findByKey($key)
{
return $this->findOneBy('dataKey', $key);
}
public function findByKey($key)
{
return $this->findOneBy('dataKey', $key);
}
public function deleteByKey($key)
{
return $this->deleteBy('dataKey', $key);
}
public function deleteByKey($key)
{
return $this->deleteBy('dataKey', $key);
}
}

View file

@ -3,9 +3,9 @@ namespace Szurubooru\Dao;
interface IBatchDao
{
public function findAll();
public function findAll();
public function deleteAll();
public function deleteAll();
public function batchSave(array $objects);
public function batchSave(array $objects);
}

View file

@ -3,9 +3,9 @@ namespace Szurubooru\Dao;
interface ICrudDao
{
public function findById($objectId);
public function findById($objectId);
public function save(&$object);
public function save(&$object);
public function deleteById($objectId);
public function deleteById($objectId);
}

View file

@ -3,11 +3,11 @@ namespace Szurubooru\Dao;
interface IFileDao
{
public function load($fileName);
public function load($fileName);
public function save($fileName, $contents);
public function save($fileName, $contents);
public function delete($fileName);
public function delete($fileName);
public function exists($fileName);
public function exists($fileName);
}

View file

@ -13,295 +13,295 @@ use Szurubooru\Services\ThumbnailService;
class PostDao extends AbstractDao implements ICrudDao
{
private $tagDao;
private $userDao;
private $fileDao;
private $thumbnailService;
private $tagDao;
private $userDao;
private $fileDao;
private $thumbnailService;
public function __construct(
DatabaseConnection $databaseConnection,
TagDao $tagDao,
UserDao $userDao,
PublicFileDao $fileDao,
ThumbnailService $thumbnailService)
{
parent::__construct(
$databaseConnection,
'posts',
new PostEntityConverter());
public function __construct(
DatabaseConnection $databaseConnection,
TagDao $tagDao,
UserDao $userDao,
PublicFileDao $fileDao,
ThumbnailService $thumbnailService)
{
parent::__construct(
$databaseConnection,
'posts',
new PostEntityConverter());
$this->tagDao = $tagDao;
$this->userDao = $userDao;
$this->fileDao = $fileDao;
$this->thumbnailService = $thumbnailService;
}
$this->tagDao = $tagDao;
$this->userDao = $userDao;
$this->fileDao = $fileDao;
$this->thumbnailService = $thumbnailService;
}
public function getCount()
{
return count($this->pdo->from($this->tableName));
}
public function getCount()
{
return count($this->pdo->from($this->tableName));
}
public function getTotalFileSize()
{
$query = $this->pdo->from($this->tableName)->select('SUM(originalFileSize) AS __sum');
return iterator_to_array($query)[0]['__sum'];
}
public function getTotalFileSize()
{
$query = $this->pdo->from($this->tableName)->select('SUM(originalFileSize) AS __sum');
return iterator_to_array($query)[0]['__sum'];
}
public function findByName($name)
{
return $this->findOneBy('name', $name);
}
public function findByName($name)
{
return $this->findOneBy('name', $name);
}
public function findByTagName($tagName)
{
$query = $this->pdo->from('posts')
->innerJoin('postTags', 'postTags.postId = posts.id')
->innerJoin('tags', 'postTags.tagId = tags.id')
->where('tags.name', $tagName);
$arrayEntities = iterator_to_array($query);
return $this->arrayToEntities($arrayEntities);
}
public function findByTagName($tagName)
{
$query = $this->pdo->from('posts')
->innerJoin('postTags', 'postTags.postId = posts.id')
->innerJoin('tags', 'postTags.tagId = tags.id')
->where('tags.name', $tagName);
$arrayEntities = iterator_to_array($query);
return $this->arrayToEntities($arrayEntities);
}
public function findByContentChecksum($checksum)
{
return $this->findOneBy('contentChecksum', $checksum);
}
public function findByContentChecksum($checksum)
{
return $this->findOneBy('contentChecksum', $checksum);
}
protected function afterLoad(Entity $post)
{
$post->setLazyLoader(
Post::LAZY_LOADER_CONTENT,
function (Post $post)
{
return $this->fileDao->load($post->getContentPath());
});
protected function afterLoad(Entity $post)
{
$post->setLazyLoader(
Post::LAZY_LOADER_CONTENT,
function (Post $post)
{
return $this->fileDao->load($post->getContentPath());
});
$post->setLazyLoader(
Post::LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT,
function (Post $post)
{
return $this->fileDao->load($post->getThumbnailSourceContentPath());
});
$post->setLazyLoader(
Post::LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT,
function (Post $post)
{
return $this->fileDao->load($post->getThumbnailSourceContentPath());
});
$post->setLazyLoader(
Post::LAZY_LOADER_USER,
function (Post $post)
{
return $this->getUser($post);
});
$post->setLazyLoader(
Post::LAZY_LOADER_USER,
function (Post $post)
{
return $this->getUser($post);
});
$post->setLazyLoader(
Post::LAZY_LOADER_TAGS,
function (Post $post)
{
return $this->getTags($post);
});
$post->setLazyLoader(
Post::LAZY_LOADER_TAGS,
function (Post $post)
{
return $this->getTags($post);
});
$post->setLazyLoader(
Post::LAZY_LOADER_RELATED_POSTS,
function (Post $post)
{
return $this->getRelatedPosts($post);
});
}
$post->setLazyLoader(
Post::LAZY_LOADER_RELATED_POSTS,
function (Post $post)
{
return $this->getRelatedPosts($post);
});
}
protected function afterSave(Entity $post)
{
$this->syncContent($post);
$this->syncThumbnailSourceContent($post);
$this->syncTags($post);
$this->syncPostRelations($post);
}
protected function afterSave(Entity $post)
{
$this->syncContent($post);
$this->syncThumbnailSourceContent($post);
$this->syncTags($post);
$this->syncPostRelations($post);
}
protected function decorateQueryFromRequirement($query, Requirement $requirement)
{
if ($requirement->getType() === PostFilter::REQUIREMENT_TAG)
{
$tagName = $requirement->getValue()->getValue();
$tag = $this->tagDao->findByName($tagName);
if (!$tag)
throw new \DomainException('Invalid tag: "' . $tagName . '"');
protected function decorateQueryFromRequirement($query, Requirement $requirement)
{
if ($requirement->getType() === PostFilter::REQUIREMENT_TAG)
{
$tagName = $requirement->getValue()->getValue();
$tag = $this->tagDao->findByName($tagName);
if (!$tag)
throw new \DomainException('Invalid tag: "' . $tagName . '"');
$sql = 'EXISTS (
SELECT 1 FROM postTags
WHERE postTags.postId = posts.id
AND postTags.tagId = ?)';
$sql = 'EXISTS (
SELECT 1 FROM postTags
WHERE postTags.postId = posts.id
AND postTags.tagId = ?)';
if ($requirement->isNegated())
$sql = 'NOT ' . $sql;
if ($requirement->isNegated())
$sql = 'NOT ' . $sql;
$query->where($sql, $tag->getId());
return;
}
$query->where($sql, $tag->getId());
return;
}
elseif ($requirement->getType() === PostFilter::REQUIREMENT_FAVORITE)
{
foreach ($requirement->getValue()->getValues() as $userName)
{
$sql = 'EXISTS (
SELECT 1 FROM favorites f
WHERE f.postId = posts.id
AND f.userId = (SELECT id FROM users WHERE name = ?))';
if ($requirement->isNegated())
$sql = 'NOT ' . $sql;
$query->where($sql, [$userName]);
}
return;
}
elseif ($requirement->getType() === PostFilter::REQUIREMENT_FAVORITE)
{
foreach ($requirement->getValue()->getValues() as $userName)
{
$sql = 'EXISTS (
SELECT 1 FROM favorites f
WHERE f.postId = posts.id
AND f.userId = (SELECT id FROM users WHERE name = ?))';
if ($requirement->isNegated())
$sql = 'NOT ' . $sql;
$query->where($sql, [$userName]);
}
return;
}
elseif ($requirement->getType() === PostFilter::REQUIREMENT_COMMENT_AUTHOR)
{
foreach ($requirement->getValue()->getValues() as $userName)
{
$sql = 'EXISTS (
SELECT 1 FROM comments c
WHERE c.postId = posts.id
AND c.userId = (SELECT id FROM users WHERE name = ?))';
if ($requirement->isNegated())
$sql = 'NOT ' . $sql;
$query->where($sql, [$userName]);
}
return;
}
elseif ($requirement->getType() === PostFilter::REQUIREMENT_COMMENT_AUTHOR)
{
foreach ($requirement->getValue()->getValues() as $userName)
{
$sql = 'EXISTS (
SELECT 1 FROM comments c
WHERE c.postId = posts.id
AND c.userId = (SELECT id FROM users WHERE name = ?))';
if ($requirement->isNegated())
$sql = 'NOT ' . $sql;
$query->where($sql, [$userName]);
}
return;
}
elseif ($requirement->getType() === PostFilter::REQUIREMENT_UPLOADER)
{
foreach ($requirement->getValue()->getValues() as $userName)
{
$alias = 'u' . uniqid();
$query->innerJoin('users ' . $alias, $alias . '.id = posts.userId');
$sql = $alias . '.name = ?';
if ($requirement->isNegated())
$sql = 'NOT ' . $sql;
$query->where($sql, [$userName]);
}
return;
}
elseif ($requirement->getType() === PostFilter::REQUIREMENT_UPLOADER)
{
foreach ($requirement->getValue()->getValues() as $userName)
{
$alias = 'u' . uniqid();
$query->innerJoin('users ' . $alias, $alias . '.id = posts.userId');
$sql = $alias . '.name = ?';
if ($requirement->isNegated())
$sql = 'NOT ' . $sql;
$query->where($sql, [$userName]);
}
return;
}
elseif ($requirement->getType() === PostFilter::REQUIREMENT_USER_SCORE)
{
$values = $requirement->getValue()->getValues();
$userName = $values[0];
$score = $values[1];
$sql = 'EXISTS (
SELECT 1 FROM scores
WHERE scores.postId = posts.id
AND scores.userId = (SELECT id FROM users WHERE name = ?)
AND scores.score = ?)';
if ($requirement->isNegated())
$sql = 'NOT ' . $sql;
$query->where($sql, [$userName, $score]);
return;
}
elseif ($requirement->getType() === PostFilter::REQUIREMENT_USER_SCORE)
{
$values = $requirement->getValue()->getValues();
$userName = $values[0];
$score = $values[1];
$sql = 'EXISTS (
SELECT 1 FROM scores
WHERE scores.postId = posts.id
AND scores.userId = (SELECT id FROM users WHERE name = ?)
AND scores.score = ?)';
if ($requirement->isNegated())
$sql = 'NOT ' . $sql;
$query->where($sql, [$userName, $score]);
return;
}
parent::decorateQueryFromRequirement($query, $requirement);
}
parent::decorateQueryFromRequirement($query, $requirement);
}
private function getTags(Post $post)
{
return $this->tagDao->findByPostId($post->getId());
}
private function getTags(Post $post)
{
return $this->tagDao->findByPostId($post->getId());
}
private function getUser(Post $post)
{
return $this->userDao->findById($post->getUserId());
}
private function getUser(Post $post)
{
return $this->userDao->findById($post->getUserId());
}
private function getRelatedPosts(Post $post)
{
$relatedPostIds = [];
private function getRelatedPosts(Post $post)
{
$relatedPostIds = [];
foreach ($this->pdo->from('postRelations')->where('post1id', $post->getId()) as $arrayEntity)
{
$postId = intval($arrayEntity['post2id']);
if ($postId !== $post->getId())
$relatedPostIds[] = $postId;
}
foreach ($this->pdo->from('postRelations')->where('post1id', $post->getId()) as $arrayEntity)
{
$postId = intval($arrayEntity['post2id']);
if ($postId !== $post->getId())
$relatedPostIds[] = $postId;
}
foreach ($this->pdo->from('postRelations')->where('post2id', $post->getId()) as $arrayEntity)
{
$postId = intval($arrayEntity['post1id']);
if ($postId !== $post->getId())
$relatedPostIds[] = $postId;
}
foreach ($this->pdo->from('postRelations')->where('post2id', $post->getId()) as $arrayEntity)
{
$postId = intval($arrayEntity['post1id']);
if ($postId !== $post->getId())
$relatedPostIds[] = $postId;
}
return $this->findByIds($relatedPostIds);
}
return $this->findByIds($relatedPostIds);
}
private function syncContent(Post $post)
{
$targetPath = $post->getContentPath();
$content = $post->getContent();
if ($content)
$this->fileDao->save($targetPath, $content);
else
$this->fileDao->delete($targetPath, $content);
$this->thumbnailService->deleteUsedThumbnails($targetPath);
}
private function syncContent(Post $post)
{
$targetPath = $post->getContentPath();
$content = $post->getContent();
if ($content)
$this->fileDao->save($targetPath, $content);
else
$this->fileDao->delete($targetPath, $content);
$this->thumbnailService->deleteUsedThumbnails($targetPath);
}
private function syncThumbnailSourceContent(Post $post)
{
$targetPath = $post->getThumbnailSourceContentPath();
$content = $post->getThumbnailSourceContent();
if ($content)
$this->fileDao->save($targetPath, $content);
else
$this->fileDao->delete($targetPath);
$this->thumbnailService->deleteUsedThumbnails($targetPath);
}
private function syncThumbnailSourceContent(Post $post)
{
$targetPath = $post->getThumbnailSourceContentPath();
$content = $post->getThumbnailSourceContent();
if ($content)
$this->fileDao->save($targetPath, $content);
else
$this->fileDao->delete($targetPath);
$this->thumbnailService->deleteUsedThumbnails($targetPath);
}
private function syncTags(Post $post)
{
$tagIds = array_map(
function ($tag)
{
if (!$tag->getId())
throw new \RuntimeException('Unsaved entities found');
return $tag->getId();
},
$post->getTags());
private function syncTags(Post $post)
{
$tagIds = array_map(
function ($tag)
{
if (!$tag->getId())
throw new \RuntimeException('Unsaved entities found');
return $tag->getId();
},
$post->getTags());
$existingTagRelationIds = array_map(
function ($arrayEntity)
{
return $arrayEntity['tagId'];
},
iterator_to_array($this->pdo->from('postTags')->where('postId', $post->getId())));
$existingTagRelationIds = array_map(
function ($arrayEntity)
{
return $arrayEntity['tagId'];
},
iterator_to_array($this->pdo->from('postTags')->where('postId', $post->getId())));
$tagRelationsToInsert = array_diff($tagIds, $existingTagRelationIds);
$tagRelationsToDelete = array_diff($existingTagRelationIds, $tagIds);
$tagRelationsToInsert = array_diff($tagIds, $existingTagRelationIds);
$tagRelationsToDelete = array_diff($existingTagRelationIds, $tagIds);
foreach ($tagRelationsToInsert as $tagId)
{
$this->pdo->insertInto('postTags')->values(['postId' => $post->getId(), 'tagId' => $tagId])->execute();
}
foreach ($tagRelationsToDelete as $tagId)
{
$this->pdo->deleteFrom('postTags')->where('postId', $post->getId())->where('tagId', $tagId)->execute();
}
}
foreach ($tagRelationsToInsert as $tagId)
{
$this->pdo->insertInto('postTags')->values(['postId' => $post->getId(), 'tagId' => $tagId])->execute();
}
foreach ($tagRelationsToDelete as $tagId)
{
$this->pdo->deleteFrom('postTags')->where('postId', $post->getId())->where('tagId', $tagId)->execute();
}
}
private function syncPostRelations(Post $post)
{
$relatedPostIds = array_filter(array_unique(array_map(
function ($post)
{
if (!$post->getId())
throw new \RuntimeException('Unsaved entities found');
return $post->getId();
},
$post->getRelatedPosts())));
private function syncPostRelations(Post $post)
{
$relatedPostIds = array_filter(array_unique(array_map(
function ($post)
{
if (!$post->getId())
throw new \RuntimeException('Unsaved entities found');
return $post->getId();
},
$post->getRelatedPosts())));
$this->pdo->deleteFrom('postRelations')->where('post1id', $post->getId())->execute();
$this->pdo->deleteFrom('postRelations')->where('post2id', $post->getId())->execute();
foreach ($relatedPostIds as $postId)
{
$this->pdo
->insertInto('postRelations')
->values([
'post1id' => $post->getId(),
'post2id' => $postId])
->execute();
}
}
$this->pdo->deleteFrom('postRelations')->where('post1id', $post->getId())->execute();
$this->pdo->deleteFrom('postRelations')->where('post2id', $post->getId())->execute();
foreach ($relatedPostIds as $postId)
{
$this->pdo
->insertInto('postRelations')
->values([
'post1id' => $post->getId(),
'post2id' => $postId])
->execute();
}
}
}

View file

@ -8,32 +8,32 @@ use Szurubooru\Entities\PostNote;
class PostNoteDao extends AbstractDao implements ICrudDao
{
private $postDao;
private $postDao;
public function __construct(
DatabaseConnection $databaseConnection,
PostDao $postDao)
{
parent::__construct(
$databaseConnection,
'postNotes',
new PostNoteEntityConverter());
public function __construct(
DatabaseConnection $databaseConnection,
PostDao $postDao)
{
parent::__construct(
$databaseConnection,
'postNotes',
new PostNoteEntityConverter());
$this->postDao = $postDao;
}
$this->postDao = $postDao;
}
public function findByPostId($postId)
{
return $this->findBy('postId', $postId);
}
public function findByPostId($postId)
{
return $this->findBy('postId', $postId);
}
protected function afterLoad(Entity $postNote)
{
$postNote->setLazyLoader(
PostNote::LAZY_LOADER_POST,
function (PostNote $postNote)
{
return $this->postDao->findById($postNote->getPostId());
});
}
protected function afterLoad(Entity $postNote)
{
$postNote->setLazyLoader(
PostNote::LAZY_LOADER_POST,
function (PostNote $postNote)
{
return $this->postDao->findById($postNote->getPostId());
});
}
}

View file

@ -6,8 +6,8 @@ use Szurubooru\Dao\IFileDao;
class PublicFileDao extends FileDao implements IFileDao
{
public function __construct(Config $config)
{
parent::__construct($config->getPublicDataDirectory());
}
public function __construct(Config $config)
{
parent::__construct($config->getPublicDataDirectory());
}
}

View file

@ -11,70 +11,70 @@ use Szurubooru\Services\TimeService;
class ScoreDao extends AbstractDao implements ICrudDao
{
private $timeService;
private $timeService;
public function __construct(
DatabaseConnection $databaseConnection,
TimeService $timeService)
{
parent::__construct(
$databaseConnection,
'scores',
new ScoreEntityConverter());
public function __construct(
DatabaseConnection $databaseConnection,
TimeService $timeService)
{
parent::__construct(
$databaseConnection,
'scores',
new ScoreEntityConverter());
$this->timeService = $timeService;
}
$this->timeService = $timeService;
}
public function getScoreValue(Entity $entity)
{
$query = $this->getBaseQuery($entity);
$query->select(null);
$query->select('SUM(score) AS score');
return iterator_to_array($query)[0]['score'];
}
public function getScoreValue(Entity $entity)
{
$query = $this->getBaseQuery($entity);
$query->select(null);
$query->select('SUM(score) AS score');
return iterator_to_array($query)[0]['score'];
}
public function getUserScore(User $user, Entity $entity)
{
$query = $this->getBaseQuery($entity);
$query->where('userId', $user->getId());
public function getUserScore(User $user, Entity $entity)
{
$query = $this->getBaseQuery($entity);
$query->where('userId', $user->getId());
$arrayEntities = iterator_to_array($query);
$entities = $this->arrayToEntities($arrayEntities);
return array_shift($entities);
}
$arrayEntities = iterator_to_array($query);
$entities = $this->arrayToEntities($arrayEntities);
return array_shift($entities);
}
public function setUserScore(User $user, Entity $entity, $scoreValue)
{
$score = $this->getUserScore($user, $entity);
if (!$score)
{
$score = new Score();
$score->setTime($this->timeService->getCurrentTime());
$score->setUserId($user->getId());
public function setUserScore(User $user, Entity $entity, $scoreValue)
{
$score = $this->getUserScore($user, $entity);
if (!$score)
{
$score = new Score();
$score->setTime($this->timeService->getCurrentTime());
$score->setUserId($user->getId());
if ($entity instanceof Post)
$score->setPostId($entity->getId());
elseif ($entity instanceof Comment)
$score->setCommentId($entity->getId());
else
throw new \InvalidArgumentException();
}
$score->setScore($scoreValue);
$this->save($score);
return $score;
}
if ($entity instanceof Post)
$score->setPostId($entity->getId());
elseif ($entity instanceof Comment)
$score->setCommentId($entity->getId());
else
throw new \InvalidArgumentException();
}
$score->setScore($scoreValue);
$this->save($score);
return $score;
}
private function getBaseQuery($entity)
{
$query = $this->pdo->from($this->tableName);
private function getBaseQuery($entity)
{
$query = $this->pdo->from($this->tableName);
if ($entity instanceof Post)
$query->where('postId', $entity->getId());
elseif ($entity instanceof Comment)
$query->where('commentId', $entity->getId());
else
throw new \InvalidArgumentException();
if ($entity instanceof Post)
$query->where('postId', $entity->getId());
elseif ($entity instanceof Comment)
$query->where('commentId', $entity->getId());
else
throw new \InvalidArgumentException();
return $query;
}
return $query;
}
}

View file

@ -8,47 +8,47 @@ use Szurubooru\Entities\Snapshot;
class SnapshotDao extends AbstractDao
{
private $userDao;
private $userDao;
public function __construct(
DatabaseConnection $databaseConnection,
UserDao $userDao)
{
parent::__construct(
$databaseConnection,
'snapshots',
new SnapshotEntityConverter());
public function __construct(
DatabaseConnection $databaseConnection,
UserDao $userDao)
{
parent::__construct(
$databaseConnection,
'snapshots',
new SnapshotEntityConverter());
$this->userDao = $userDao;
}
$this->userDao = $userDao;
}
public function findEarlierSnapshots(Snapshot $snapshot)
{
$query = $this->pdo
->from($this->tableName)
->where('type', $snapshot->getType())
->where('primaryKey', $snapshot->getPrimaryKey())
->orderBy('time DESC');
public function findEarlierSnapshots(Snapshot $snapshot)
{
$query = $this->pdo
->from($this->tableName)
->where('type', $snapshot->getType())
->where('primaryKey', $snapshot->getPrimaryKey())
->orderBy('time DESC');
if ($snapshot->getId())
$query->where('id < ?', $snapshot->getId());
if ($snapshot->getId())
$query->where('id < ?', $snapshot->getId());
return $this->arrayToEntities(iterator_to_array($query));
}
return $this->arrayToEntities(iterator_to_array($query));
}
public function afterLoad(Entity $snapshot)
{
$snapshot->setLazyLoader(
Snapshot::LAZY_LOADER_USER,
function (Snapshot $snapshot)
{
return $this->getUser($snapshot);
});
}
public function afterLoad(Entity $snapshot)
{
$snapshot->setLazyLoader(
Snapshot::LAZY_LOADER_USER,
function (Snapshot $snapshot)
{
return $this->getUser($snapshot);
});
}
private function getUser(Snapshot $snapshot)
{
$userId = $snapshot->getUserId();
return $this->userDao->findById($userId);
}
private function getUser(Snapshot $snapshot)
{
$userId = $snapshot->getUserId();
return $this->userDao->findById($userId);
}
}

View file

@ -10,213 +10,213 @@ use Szurubooru\Search\Requirements\Requirement;
class TagDao extends AbstractDao implements ICrudDao
{
const TAG_RELATION_IMPLICATION = 1;
const TAG_RELATION_SUGGESTION = 2;
const TAG_RELATION_IMPLICATION = 1;
const TAG_RELATION_SUGGESTION = 2;
public function __construct(DatabaseConnection $databaseConnection)
{
parent::__construct(
$databaseConnection,
'tags',
new TagEntityConverter());
}
public function __construct(DatabaseConnection $databaseConnection)
{
parent::__construct(
$databaseConnection,
'tags',
new TagEntityConverter());
}
public function findByName($tagName)
{
return $this->findOneBy('name', $tagName);
}
public function findByName($tagName)
{
return $this->findOneBy('name', $tagName);
}
public function findByNames($tagNames)
{
return $this->findBy('name', $tagNames);
}
public function findByNames($tagNames)
{
return $this->findBy('name', $tagNames);
}
public function findByPostId($postId)
{
return $this->findByPostIds([$postId]);
}
public function findByPostId($postId)
{
return $this->findByPostIds([$postId]);
}
public function findByPostIds($postIds)
{
$query = $this->pdo->from($this->tableName)
->innerJoin('postTags', 'postTags.tagId = tags.id')
->where('postTags.postId', $postIds);
$arrayEntities = iterator_to_array($query);
return $this->arrayToEntities($arrayEntities);
}
public function findByPostIds($postIds)
{
$query = $this->pdo->from($this->tableName)
->innerJoin('postTags', 'postTags.tagId = tags.id')
->where('postTags.postId', $postIds);
$arrayEntities = iterator_to_array($query);
return $this->arrayToEntities($arrayEntities);
}
public function findSiblings($tagName)
{
$tag = $this->findByName($tagName);
if (!$tag)
return [];
$tagId = $tag->getId();
$query = $this->pdo->from($this->tableName)
->select('COUNT(pt2.postId) AS postCount')
->innerJoin('postTags pt1', 'pt1.tagId = tags.id')
->innerJoin('postTags pt2', 'pt2.postId = pt1.postId')
->where('pt2.tagId', $tagId)
->groupBy('tags.id')
->orderBy('postCount DESC, name ASC');
public function findSiblings($tagName)
{
$tag = $this->findByName($tagName);
if (!$tag)
return [];
$tagId = $tag->getId();
$query = $this->pdo->from($this->tableName)
->select('COUNT(pt2.postId) AS postCount')
->innerJoin('postTags pt1', 'pt1.tagId = tags.id')
->innerJoin('postTags pt2', 'pt2.postId = pt1.postId')
->where('pt2.tagId', $tagId)
->groupBy('tags.id')
->orderBy('postCount DESC, name ASC');
$arrayEntities = array_filter(
iterator_to_array($query),
function($arrayEntity) use ($tagName)
{
return strcasecmp($arrayEntity['name'], $tagName) !== 0;
});
$arrayEntities = array_filter(
iterator_to_array($query),
function($arrayEntity) use ($tagName)
{
return strcasecmp($arrayEntity['name'], $tagName) !== 0;
});
return $this->arrayToEntities($arrayEntities);
}
return $this->arrayToEntities($arrayEntities);
}
public function export()
{
$exported = [];
foreach ($this->pdo->from($this->tableName) as $arrayEntity)
{
$exported[$arrayEntity['id']] = [
'name' => $arrayEntity['name'],
'usages' => intval($arrayEntity['usages']),
'banned' => boolval($arrayEntity['banned'])
];
}
public function export()
{
$exported = [];
foreach ($this->pdo->from($this->tableName) as $arrayEntity)
{
$exported[$arrayEntity['id']] = [
'name' => $arrayEntity['name'],
'usages' => intval($arrayEntity['usages']),
'banned' => boolval($arrayEntity['banned'])
];
}
//upgrades on old databases
try
{
$relations = iterator_to_array($this->pdo->from('tagRelations'));
}
catch (\Exception $e)
{
$relations = [];
}
//upgrades on old databases
try
{
$relations = iterator_to_array($this->pdo->from('tagRelations'));
}
catch (\Exception $e)
{
$relations = [];
}
foreach ($relations as $arrayEntity)
{
$key1 = $arrayEntity['tag1id'];
$key2 = $arrayEntity['tag2id'];
$type = intval($arrayEntity['type']);
if ($type === self::TAG_RELATION_IMPLICATION)
$target = 'implications';
elseif ($type === self::TAG_RELATION_SUGGESTION)
$target = 'suggestions';
else
continue;
foreach ($relations as $arrayEntity)
{
$key1 = $arrayEntity['tag1id'];
$key2 = $arrayEntity['tag2id'];
$type = intval($arrayEntity['type']);
if ($type === self::TAG_RELATION_IMPLICATION)
$target = 'implications';
elseif ($type === self::TAG_RELATION_SUGGESTION)
$target = 'suggestions';
else
continue;
if (!isset($exported[$key1]) || !isset($exported[$key2]))
continue;
if (!isset($exported[$key1]) || !isset($exported[$key2]))
continue;
if (!isset($exported[$key1][$target]))
$exported[$key1][$target] = [];
if (!isset($exported[$key1][$target]))
$exported[$key1][$target] = [];
$exported[$key1][$target][] = $exported[$key2]['name'];
}
$exported[$key1][$target][] = $exported[$key2]['name'];
}
return array_values($exported);
}
return array_values($exported);
}
protected function afterLoad(Entity $tag)
{
$tag->setLazyLoader(
Tag::LAZY_LOADER_IMPLIED_TAGS,
function (Tag $tag)
{
return $this->findImpliedTags($tag);
});
protected function afterLoad(Entity $tag)
{
$tag->setLazyLoader(
Tag::LAZY_LOADER_IMPLIED_TAGS,
function (Tag $tag)
{
return $this->findImpliedTags($tag);
});
$tag->setLazyLoader(
Tag::LAZY_LOADER_SUGGESTED_TAGS,
function (Tag $tag)
{
return $this->findSuggested($tag);
});
}
$tag->setLazyLoader(
Tag::LAZY_LOADER_SUGGESTED_TAGS,
function (Tag $tag)
{
return $this->findSuggested($tag);
});
}
protected function afterSave(Entity $tag)
{
$this->syncImpliedTags($tag);
$this->syncSuggestedTags($tag);
}
protected function afterSave(Entity $tag)
{
$this->syncImpliedTags($tag);
$this->syncSuggestedTags($tag);
}
protected function decorateQueryFromRequirement($query, Requirement $requirement)
{
if ($requirement->getType() === TagFilter::REQUIREMENT_PARTIAL_TAG_NAME)
{
$sql = 'INSTR(LOWER(tags.name), LOWER(?)) > 0';
protected function decorateQueryFromRequirement($query, Requirement $requirement)
{
if ($requirement->getType() === TagFilter::REQUIREMENT_PARTIAL_TAG_NAME)
{
$sql = 'INSTR(LOWER(tags.name), LOWER(?)) > 0';
if ($requirement->isNegated())
$sql = 'NOT ' . $sql;
if ($requirement->isNegated())
$sql = 'NOT ' . $sql;
$query->where($sql, $requirement->getValue()->getValue());
return;
}
$query->where($sql, $requirement->getValue()->getValue());
return;
}
elseif ($requirement->getType() === TagFilter::REQUIREMENT_CATEGORY)
{
$sql = 'IFNULL(category, \'default\')';
$requirement->setType($sql);
return parent::decorateQueryFromRequirement($query, $requirement);
}
elseif ($requirement->getType() === TagFilter::REQUIREMENT_CATEGORY)
{
$sql = 'IFNULL(category, \'default\')';
$requirement->setType($sql);
return parent::decorateQueryFromRequirement($query, $requirement);
}
parent::decorateQueryFromRequirement($query, $requirement);
}
parent::decorateQueryFromRequirement($query, $requirement);
}
private function findImpliedTags(Tag $tag)
{
return $this->findRelatedTagsByType($tag, self::TAG_RELATION_IMPLICATION);
}
private function findImpliedTags(Tag $tag)
{
return $this->findRelatedTagsByType($tag, self::TAG_RELATION_IMPLICATION);
}
private function findSuggested(Tag $tag)
{
return $this->findRelatedTagsByType($tag, self::TAG_RELATION_SUGGESTION);
}
private function findSuggested(Tag $tag)
{
return $this->findRelatedTagsByType($tag, self::TAG_RELATION_SUGGESTION);
}
private function syncImpliedTags($tag)
{
$this->syncRelatedTagsByType($tag, $tag->getImpliedTags(), self::TAG_RELATION_IMPLICATION);
}
private function syncImpliedTags($tag)
{
$this->syncRelatedTagsByType($tag, $tag->getImpliedTags(), self::TAG_RELATION_IMPLICATION);
}
private function syncSuggestedTags($tag)
{
$this->syncRelatedTagsByType($tag, $tag->getSuggestedTags(), self::TAG_RELATION_SUGGESTION);
}
private function syncSuggestedTags($tag)
{
$this->syncRelatedTagsByType($tag, $tag->getSuggestedTags(), self::TAG_RELATION_SUGGESTION);
}
private function syncRelatedTagsByType(Tag $tag, array $relatedTags, $type)
{
$relatedTagIds = array_filter(array_unique(array_map(
function ($tag)
{
if (!$tag->getId())
throw new \RuntimeException('Unsaved entities found');
return $tag->getId();
},
$relatedTags)));
private function syncRelatedTagsByType(Tag $tag, array $relatedTags, $type)
{
$relatedTagIds = array_filter(array_unique(array_map(
function ($tag)
{
if (!$tag->getId())
throw new \RuntimeException('Unsaved entities found');
return $tag->getId();
},
$relatedTags)));
$this->pdo->deleteFrom('tagRelations')
->where('tag1id', $tag->getId())
->where('type', $type)
->execute();
$this->pdo->deleteFrom('tagRelations')
->where('tag1id', $tag->getId())
->where('type', $type)
->execute();
foreach ($relatedTagIds as $tagId)
{
$this->pdo
->insertInto('tagRelations')
->values([
'tag1id' => $tag->getId(),
'tag2id' => $tagId,
'type' => $type])
->execute();
}
}
foreach ($relatedTagIds as $tagId)
{
$this->pdo
->insertInto('tagRelations')
->values([
'tag1id' => $tag->getId(),
'tag2id' => $tagId,
'type' => $type])
->execute();
}
}
private function findRelatedTagsByType(Tag $tag, $type)
{
$tagId = $tag->getId();
$query = $this->pdo->from($this->tableName)
->innerJoin('tagRelations tr', 'tags.id = tr.tag2id')
->where('tr.type', $type)
->where('tr.tag1id', $tagId);
$arrayEntities = iterator_to_array($query);
return $this->arrayToEntities($arrayEntities);
}
private function findRelatedTagsByType(Tag $tag, $type)
{
$tagId = $tag->getId();
$query = $this->pdo->from($this->tableName)
->innerJoin('tagRelations tr', 'tags.id = tr.tag2id')
->where('tr.type', $type)
->where('tr.tag1id', $tagId);
$arrayEntities = iterator_to_array($query);
return $this->arrayToEntities($arrayEntities);
}
}

View file

@ -5,39 +5,39 @@ use Szurubooru\DatabaseConnection;
class TokenDao extends AbstractDao
{
public function __construct(DatabaseConnection $databaseConnection)
{
parent::__construct(
$databaseConnection,
'tokens',
new TokenEntityConverter());
}
public function __construct(DatabaseConnection $databaseConnection)
{
parent::__construct(
$databaseConnection,
'tokens',
new TokenEntityConverter());
}
public function findByName($tokenName)
{
return $this->findOneBy('name', $tokenName);
}
public function findByName($tokenName)
{
return $this->findOneBy('name', $tokenName);
}
public function findByAdditionalDataAndPurpose($additionalData, $purpose)
{
$query = $this->pdo->from($this->tableName)
->where('additionalData', $additionalData)
->where('purpose', $purpose);
$arrayEntities = iterator_to_array($query);
$entities = $this->arrayToEntities($arrayEntities);
if (!$entities || !count($entities))
return null;
$entity = array_shift($entities);
return $entity;
}
public function findByAdditionalDataAndPurpose($additionalData, $purpose)
{
$query = $this->pdo->from($this->tableName)
->where('additionalData', $additionalData)
->where('purpose', $purpose);
$arrayEntities = iterator_to_array($query);
$entities = $this->arrayToEntities($arrayEntities);
if (!$entities || !count($entities))
return null;
$entity = array_shift($entities);
return $entity;
}
public function deleteByName($tokenName)
{
return $this->deleteBy('name', $tokenName);
}
public function deleteByName($tokenName)
{
return $this->deleteBy('name', $tokenName);
}
public function deleteByAdditionalData($additionalData)
{
return $this->deleteBy('additionalData', $additionalData);
}
public function deleteByAdditionalData($additionalData)
{
return $this->deleteBy('additionalData', $additionalData);
}
}

View file

@ -4,40 +4,40 @@ use Szurubooru\DatabaseConnection;
class TransactionManager
{
private $databaseConnection;
private $databaseConnection;
public function __construct(DatabaseConnection $databaseConnection)
{
$this->databaseConnection = $databaseConnection;
}
public function __construct(DatabaseConnection $databaseConnection)
{
$this->databaseConnection = $databaseConnection;
}
public function commit($callback)
{
return $this->doInTransaction($callback, 'commit');
}
public function commit($callback)
{
return $this->doInTransaction($callback, 'commit');
}
public function rollback($callback)
{
return $this->doInTransaction($callback, 'rollBack');
}
public function rollback($callback)
{
return $this->doInTransaction($callback, 'rollBack');
}
public function doInTransaction($callback, $operation)
{
$pdo = $this->databaseConnection->getPDO();
if ($pdo->inTransaction())
return $callback();
public function doInTransaction($callback, $operation)
{
$pdo = $this->databaseConnection->getPDO();
if ($pdo->inTransaction())
return $callback();
$pdo->beginTransaction();
try
{
$ret = $callback();
$pdo->$operation();
return $ret;
}
catch (\Exception $e)
{
$pdo->rollBack();
throw $e;
}
}
$pdo->beginTransaction();
try
{
$ret = $callback();
$pdo->$operation();
return $ret;
}
catch (\Exception $e)
{
$pdo->rollBack();
throw $e;
}
}
}

View file

@ -9,78 +9,78 @@ use Szurubooru\Services\ThumbnailService;
class UserDao extends AbstractDao implements ICrudDao
{
const ORDER_NAME = 'name';
const ORDER_REGISTRATION_TIME = 'registrationTime';
const ORDER_NAME = 'name';
const ORDER_REGISTRATION_TIME = 'registrationTime';
private $fileDao;
private $thumbnailService;
private $fileDao;
private $thumbnailService;
public function __construct(
DatabaseConnection $databaseConnection,
PublicFileDao $fileDao,
ThumbnailService $thumbnailService)
{
parent::__construct(
$databaseConnection,
'users',
new UserEntityConverter());
public function __construct(
DatabaseConnection $databaseConnection,
PublicFileDao $fileDao,
ThumbnailService $thumbnailService)
{
parent::__construct(
$databaseConnection,
'users',
new UserEntityConverter());
$this->fileDao = $fileDao;
$this->thumbnailService = $thumbnailService;
}
$this->fileDao = $fileDao;
$this->thumbnailService = $thumbnailService;
}
public function findByName($userName)
{
return $this->findOneBy('name', $userName);
}
public function findByName($userName)
{
return $this->findOneBy('name', $userName);
}
public function findByEmail($userEmail, $allowUnconfirmed = false)
{
$result = $this->findOneBy('email', $userEmail);
if (!$result && $allowUnconfirmed)
{
$result = $this->findOneBy('emailUnconfirmed', $userEmail);
}
return $result;
}
public function findByEmail($userEmail, $allowUnconfirmed = false)
{
$result = $this->findOneBy('email', $userEmail);
if (!$result && $allowUnconfirmed)
{
$result = $this->findOneBy('emailUnconfirmed', $userEmail);
}
return $result;
}
public function hasAnyUsers()
{
return $this->hasAnyRecords();
}
public function hasAnyUsers()
{
return $this->hasAnyRecords();
}
public function deleteByName($userName)
{
$this->deleteBy('name', $userName);
$this->pdo->deleteFrom('tokens')->where('additionalData', $userName);
}
public function deleteByName($userName)
{
$this->deleteBy('name', $userName);
$this->pdo->deleteFrom('tokens')->where('additionalData', $userName);
}
protected function afterLoad(Entity $user)
{
$user->setLazyLoader(
User::LAZY_LOADER_CUSTOM_AVATAR_SOURCE_CONTENT,
function(User $user)
{
$avatarSource = $user->getCustomAvatarSourceContentPath();
return $this->fileDao->load($avatarSource);
});
}
protected function afterLoad(Entity $user)
{
$user->setLazyLoader(
User::LAZY_LOADER_CUSTOM_AVATAR_SOURCE_CONTENT,
function(User $user)
{
$avatarSource = $user->getCustomAvatarSourceContentPath();
return $this->fileDao->load($avatarSource);
});
}
protected function afterSave(Entity $user)
{
$targetPath = $user->getCustomAvatarSourceContentPath();
$content = $user->getCustomAvatarSourceContent();
if ($content)
$this->fileDao->save($targetPath, $content);
else
$this->fileDao->delete($targetPath);
$this->thumbnailService->deleteUsedThumbnails($targetPath);
}
protected function afterSave(Entity $user)
{
$targetPath = $user->getCustomAvatarSourceContentPath();
$content = $user->getCustomAvatarSourceContent();
if ($content)
$this->fileDao->save($targetPath, $content);
else
$this->fileDao->delete($targetPath);
$this->thumbnailService->deleteUsedThumbnails($targetPath);
}
protected function afterDelete(Entity $user)
{
$avatarSource = $user->getCustomAvatarSourceContentPath();
$this->fileDao->delete($avatarSource);
$this->thumbnailService->deleteUsedThumbnails($avatarSource);
}
protected function afterDelete(Entity $user)
{
$avatarSource = $user->getCustomAvatarSourceContentPath();
$this->fileDao->delete($avatarSource);
$this->thumbnailService->deleteUsedThumbnails($avatarSource);
}
}

View file

@ -5,45 +5,45 @@ use Szurubooru\PDOEx\PDOEx;
class DatabaseConnection
{
private $pdo;
private $config;
private $pdo;
private $config;
public function __construct(Config $config)
{
$this->config = $config;
}
public function __construct(Config $config)
{
$this->config = $config;
}
public function getPDO()
{
if (!$this->pdo)
{
$this->createPDO();
}
return $this->pdo;
}
public function getPDO()
{
if (!$this->pdo)
{
$this->createPDO();
}
return $this->pdo;
}
public function getDriver()
{
return $this->getPDO()->getAttribute(\PDO::ATTR_DRIVER_NAME);
}
public function getDriver()
{
return $this->getPDO()->getAttribute(\PDO::ATTR_DRIVER_NAME);
}
public function close()
{
$this->pdo = null;
}
public function close()
{
$this->pdo = null;
}
private function createPDO()
{
$cwd = getcwd();
if ($this->config->getDataDirectory())
chdir($this->config->getDataDirectory());
private function createPDO()
{
$cwd = getcwd();
if ($this->config->getDataDirectory())
chdir($this->config->getDataDirectory());
$this->pdo = new PDOEx(
$this->config->database->dsn,
$this->config->database->user,
$this->config->database->password);
$this->pdo = new PDOEx(
$this->config->database->dsn,
$this->config->database->user,
$this->config->database->password);
$this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
chdir($cwd);
}
$this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
chdir($cwd);
}
}

View file

@ -10,78 +10,78 @@ use Szurubooru\Services\TokenService;
final class Dispatcher
{
private $router;
private $config;
private $databaseConnection;
private $authService;
private $tokenService;
private $router;
private $config;
private $databaseConnection;
private $authService;
private $tokenService;
public function __construct(
Router $router,
Config $config,
DatabaseConnection $databaseConnection,
HttpHelper $httpHelper,
AuthService $authService,
TokenService $tokenService,
RouteRepository $routeRepository)
{
$this->router = $router;
$this->config = $config;
$this->databaseConnection = $databaseConnection;
$this->httpHelper = $httpHelper;
$this->authService = $authService;
$this->tokenService = $tokenService;
public function __construct(
Router $router,
Config $config,
DatabaseConnection $databaseConnection,
HttpHelper $httpHelper,
AuthService $authService,
TokenService $tokenService,
RouteRepository $routeRepository)
{
$this->router = $router;
$this->config = $config;
$this->databaseConnection = $databaseConnection;
$this->httpHelper = $httpHelper;
$this->authService = $authService;
$this->tokenService = $tokenService;
//if script fails prematurely, mark it as fail from advance
$this->httpHelper->setResponseCode(500);
//if script fails prematurely, mark it as fail from advance
$this->httpHelper->setResponseCode(500);
$routeRepository->injectRoutes($router);
}
$routeRepository->injectRoutes($router);
}
public function run($requestMethod, $requestUri)
{
try
{
$code = 200;
$this->authorizeFromRequestHeader();
$json = (array) $this->router->handle($requestMethod, $requestUri);
}
catch (\Exception $e)
{
$code = 400;
$trace = $e->getTrace();
foreach ($trace as &$item)
unset($item['args']);
$json = [
'error' => $e->getMessage(),
'trace' => $trace,
];
}
$end = microtime(true);
$json['__time'] = $end - Bootstrap::getStartTime();
if ($this->config->misc->dumpSqlIntoQueries)
{
$json['__queries'] = $this->databaseConnection->getPDO()->getQueryCount();
$json['__statements'] = $this->databaseConnection->getPDO()->getStatements();
}
public function run($requestMethod, $requestUri)
{
try
{
$code = 200;
$this->authorizeFromRequestHeader();
$json = (array) $this->router->handle($requestMethod, $requestUri);
}
catch (\Exception $e)
{
$code = 400;
$trace = $e->getTrace();
foreach ($trace as &$item)
unset($item['args']);
$json = [
'error' => $e->getMessage(),
'trace' => $trace,
];
}
$end = microtime(true);
$json['__time'] = $end - Bootstrap::getStartTime();
if ($this->config->misc->dumpSqlIntoQueries)
{
$json['__queries'] = $this->databaseConnection->getPDO()->getQueryCount();
$json['__statements'] = $this->databaseConnection->getPDO()->getStatements();
}
if (!$this->httpHelper->isRedirecting())
{
$this->httpHelper->setResponseCode($code);
$this->httpHelper->setHeader('Content-Type', 'application/json');
$this->httpHelper->outputJSON($json);
}
if (!$this->httpHelper->isRedirecting())
{
$this->httpHelper->setResponseCode($code);
$this->httpHelper->setHeader('Content-Type', 'application/json');
$this->httpHelper->outputJSON($json);
}
return $json;
}
return $json;
}
private function authorizeFromRequestHeader()
{
$loginTokenName = $this->httpHelper->getRequestHeader('X-Authorization-Token');
if ($loginTokenName)
{
$token = $this->tokenService->getByName($loginTokenName);
$this->authService->loginFromToken($token);
}
}
private function authorizeFromRequestHeader()
{
$loginTokenName = $this->httpHelper->getRequestHeader('X-Authorization-Token');
if ($loginTokenName)
{
$token = $this->tokenService->getByName($loginTokenName);
$this->authService->loginFromToken($token);
}
}
}

View file

@ -5,91 +5,91 @@ use Szurubooru\Entities\User;
final class Comment extends Entity
{
private $postId;
private $userId;
private $creationTime;
private $lastEditTime;
private $text;
private $postId;
private $userId;
private $creationTime;
private $lastEditTime;
private $text;
const LAZY_LOADER_USER = 'user';
const LAZY_LOADER_POST = 'post';
const LAZY_LOADER_USER = 'user';
const LAZY_LOADER_POST = 'post';
const META_SCORE = 'score';
const META_SCORE = 'score';
public function getUserId()
{
return $this->userId;
}
public function getUserId()
{
return $this->userId;
}
public function setUserId($userId)
{
$this->userId = $userId;
}
public function setUserId($userId)
{
$this->userId = $userId;
}
public function getPostId()
{
return $this->postId;
}
public function getPostId()
{
return $this->postId;
}
public function setPostId($postId)
{
$this->postId = $postId;
}
public function setPostId($postId)
{
$this->postId = $postId;
}
public function getCreationTime()
{
return $this->creationTime;
}
public function getCreationTime()
{
return $this->creationTime;
}
public function setCreationTime($creationTime)
{
$this->creationTime = $creationTime;
}
public function setCreationTime($creationTime)
{
$this->creationTime = $creationTime;
}
public function getLastEditTime()
{
return $this->lastEditTime;
}
public function getLastEditTime()
{
return $this->lastEditTime;
}
public function setLastEditTime($lastEditTime)
{
$this->lastEditTime = $lastEditTime;
}
public function setLastEditTime($lastEditTime)
{
$this->lastEditTime = $lastEditTime;
}
public function getText()
{
return $this->text;
}
public function getText()
{
return $this->text;
}
public function setText($text)
{
$this->text = $text;
}
public function setText($text)
{
$this->text = $text;
}
public function getUser()
{
return $this->lazyLoad(self::LAZY_LOADER_USER, null);
}
public function getUser()
{
return $this->lazyLoad(self::LAZY_LOADER_USER, null);
}
public function setUser(User $user = null)
{
$this->lazySave(self::LAZY_LOADER_USER, $user);
$this->userId = $user ? $user->getId() : null;
}
public function setUser(User $user = null)
{
$this->lazySave(self::LAZY_LOADER_USER, $user);
$this->userId = $user ? $user->getId() : null;
}
public function getPost()
{
return $this->lazyLoad(self::LAZY_LOADER_POST, null);
}
public function getPost()
{
return $this->lazyLoad(self::LAZY_LOADER_POST, null);
}
public function setPost(Post $post)
{
$this->lazySave(self::LAZY_LOADER_POST, $post);
$this->postId = $post->getId();
}
public function setPost(Post $post)
{
$this->lazySave(self::LAZY_LOADER_POST, $post);
$this->postId = $post->getId();
}
public function getScore()
{
return $this->getMeta(self::META_SCORE, 0);
}
public function getScore()
{
return $this->getMeta(self::META_SCORE, 0);
}
}

View file

@ -3,74 +3,74 @@ namespace Szurubooru\Entities;
abstract class Entity
{
protected $id = null;
private $lazyLoaders = [];
private $lazyContainers = [];
private $meta;
protected $id = null;
private $lazyLoaders = [];
private $lazyContainers = [];
private $meta;
public function __construct($id = null)
{
$this->id = $id === null ? null : intval($id);
}
public function __construct($id = null)
{
$this->id = $id === null ? null : intval($id);
}
public function getId()
{
return $this->id;
}
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $id;
}
public function setId($id)
{
$this->id = $id;
}
public function getMeta($metaName, $default = null)
{
if (!isset($this->meta[$metaName]))
return $default;
return $this->meta[$metaName];
}
public function getMeta($metaName, $default = null)
{
if (!isset($this->meta[$metaName]))
return $default;
return $this->meta[$metaName];
}
public function setMeta($metaName, $value)
{
$this->meta[$metaName] = $value;
}
public function setMeta($metaName, $value)
{
$this->meta[$metaName] = $value;
}
public function resetMeta()
{
$this->meta = [];
}
public function resetMeta()
{
$this->meta = [];
}
public function resetLazyLoaders()
{
$this->lazyLoaders = [];
$this->lazyContainers = [];
}
public function resetLazyLoaders()
{
$this->lazyLoaders = [];
$this->lazyContainers = [];
}
public function setLazyLoader($lazyContainerName, $getter)
{
$this->lazyLoaders[$lazyContainerName] = $getter;
}
public function setLazyLoader($lazyContainerName, $getter)
{
$this->lazyLoaders[$lazyContainerName] = $getter;
}
protected function lazyLoad($lazyContainerName, $defaultValue)
{
if (!isset($this->lazyContainers[$lazyContainerName]))
{
if (!isset($this->lazyLoaders[$lazyContainerName]))
{
return $defaultValue;
}
$result = $this->lazyLoaders[$lazyContainerName]($this);
$this->lazySave($lazyContainerName, $result);
}
else
{
$result = $this->lazyContainers[$lazyContainerName];
}
return $result;
}
protected function lazyLoad($lazyContainerName, $defaultValue)
{
if (!isset($this->lazyContainers[$lazyContainerName]))
{
if (!isset($this->lazyLoaders[$lazyContainerName]))
{
return $defaultValue;
}
$result = $this->lazyLoaders[$lazyContainerName]($this);
$this->lazySave($lazyContainerName, $result);
}
else
{
$result = $this->lazyContainers[$lazyContainerName];
}
return $result;
}
protected function lazySave($lazyContainerName, $value)
{
$this->lazyContainers[$lazyContainerName] = $value;
}
protected function lazySave($lazyContainerName, $value)
{
$this->lazyContainers[$lazyContainerName] = $value;
}
}

View file

@ -5,62 +5,62 @@ use Szurubooru\Entities\User;
final class Favorite extends Entity
{
private $postId;
private $userId;
private $time;
private $postId;
private $userId;
private $time;
const LAZY_LOADER_USER = 'user';
const LAZY_LOADER_POST = 'post';
const LAZY_LOADER_USER = 'user';
const LAZY_LOADER_POST = 'post';
public function getUserId()
{
return $this->userId;
}
public function getUserId()
{
return $this->userId;
}
public function setUserId($userId)
{
$this->userId = $userId;
}
public function setUserId($userId)
{
$this->userId = $userId;
}
public function getPostId()
{
return $this->postId;
}
public function getPostId()
{
return $this->postId;
}
public function setPostId($postId)
{
$this->postId = $postId;
}
public function setPostId($postId)
{
$this->postId = $postId;
}
public function getTime()
{
return $this->time;
}
public function getTime()
{
return $this->time;
}
public function setTime($time)
{
$this->time = $time;
}
public function setTime($time)
{
$this->time = $time;
}
public function getUser()
{
return $this->lazyLoad(self::LAZY_LOADER_USER, null);
}
public function getUser()
{
return $this->lazyLoad(self::LAZY_LOADER_USER, null);
}
public function setUser(User $user)
{
$this->lazySave(self::LAZY_LOADER_USER, $user);
$this->userId = $user->getId();
}
public function setUser(User $user)
{
$this->lazySave(self::LAZY_LOADER_USER, $user);
$this->userId = $user->getId();
}
public function getPost()
{
return $this->lazyLoad(self::LAZY_LOADER_POST, null);
}
public function getPost()
{
return $this->lazyLoad(self::LAZY_LOADER_POST, null);
}
public function setPost(Post $post)
{
$this->lazySave(self::LAZY_LOADER_POST, $post);
$this->postId = $post->getId();
}
public function setPost(Post $post)
{
$this->lazySave(self::LAZY_LOADER_POST, $post);
$this->postId = $post->getId();
}
}

View file

@ -3,31 +3,31 @@ namespace Szurubooru\Entities;
final class GlobalParam extends Entity
{
const KEY_FEATURED_POST_USER = 'featuredPostUser';
const KEY_FEATURED_POST = 'featuredPost';
const KEY_POST_SIZE = 'postSize';
const KEY_POST_COUNT = 'postCount';
const KEY_FEATURED_POST_USER = 'featuredPostUser';
const KEY_FEATURED_POST = 'featuredPost';
const KEY_POST_SIZE = 'postSize';
const KEY_POST_COUNT = 'postCount';
private $key;
private $value;
private $key;
private $value;
public function getKey()
{
return $this->key;
}
public function getKey()
{
return $this->key;
}
public function setKey($key)
{
$this->key = $key;
}
public function setKey($key)
{
$this->key = $key;
}
public function getValue()
{
return $this->value;
}
public function getValue()
{
return $this->value;
}
public function setValue($value)
{
$this->value = $value;
}
public function setValue($value)
{
$this->value = $value;
}
}

View file

@ -4,290 +4,290 @@ use Szurubooru\Entities\User;
final class Post extends Entity
{
const POST_SAFETY_SAFE = 1;
const POST_SAFETY_SKETCHY = 2;
const POST_SAFETY_UNSAFE = 3;
const POST_SAFETY_SAFE = 1;
const POST_SAFETY_SKETCHY = 2;
const POST_SAFETY_UNSAFE = 3;
const POST_TYPE_IMAGE = 1;
const POST_TYPE_FLASH = 2;
const POST_TYPE_VIDEO = 3;
const POST_TYPE_YOUTUBE = 4;
const POST_TYPE_ANIMATED_IMAGE = 5;
const POST_TYPE_IMAGE = 1;
const POST_TYPE_FLASH = 2;
const POST_TYPE_VIDEO = 3;
const POST_TYPE_YOUTUBE = 4;
const POST_TYPE_ANIMATED_IMAGE = 5;
const FLAG_LOOP = 1;
const FLAG_LOOP = 1;
const LAZY_LOADER_USER = 'user';
const LAZY_LOADER_TAGS = 'tags';
const LAZY_LOADER_CONTENT = 'content';
const LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT = 'thumbnailSourceContent';
const LAZY_LOADER_RELATED_POSTS = 'relatedPosts';
const LAZY_LOADER_USER = 'user';
const LAZY_LOADER_TAGS = 'tags';
const LAZY_LOADER_CONTENT = 'content';
const LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT = 'thumbnailSourceContent';
const LAZY_LOADER_RELATED_POSTS = 'relatedPosts';
const META_TAG_COUNT = 'tagCount';
const META_FAV_COUNT = 'favCount';
const META_COMMENT_COUNT = 'commentCount';
const META_SCORE = 'score';
const META_TAG_COUNT = 'tagCount';
const META_FAV_COUNT = 'favCount';
const META_COMMENT_COUNT = 'commentCount';
const META_SCORE = 'score';
private $name;
private $userId;
private $uploadTime;
private $lastEditTime;
private $safety;
private $contentType;
private $contentChecksum;
private $contentMimeType;
private $source;
private $imageWidth;
private $imageHeight;
private $originalFileSize;
private $originalFileName;
private $featureCount = 0;
private $lastFeatureTime;
private $flags = 0;
private $name;
private $userId;
private $uploadTime;
private $lastEditTime;
private $safety;
private $contentType;
private $contentChecksum;
private $contentMimeType;
private $source;
private $imageWidth;
private $imageHeight;
private $originalFileSize;
private $originalFileName;
private $featureCount = 0;
private $lastFeatureTime;
private $flags = 0;
public function getIdMarkdown()
{
return '@' . $this->id;
}
public function getIdMarkdown()
{
return '@' . $this->id;
}
public function getName()
{
return $this->name;
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
public function setName($name)
{
$this->name = $name;
}
public function getUserId()
{
return $this->userId;
}
public function getUserId()
{
return $this->userId;
}
public function setUserId($userId)
{
$this->userId = $userId;
}
public function setUserId($userId)
{
$this->userId = $userId;
}
public function getSafety()
{
return $this->safety;
}
public function getSafety()
{
return $this->safety;
}
public function setSafety($safety)
{
$this->safety = $safety;
}
public function setSafety($safety)
{
$this->safety = $safety;
}
public function getUploadTime()
{
return $this->uploadTime;
}
public function getUploadTime()
{
return $this->uploadTime;
}
public function setUploadTime($uploadTime)
{
$this->uploadTime = $uploadTime;
}
public function setUploadTime($uploadTime)
{
$this->uploadTime = $uploadTime;
}
public function getLastEditTime()
{
return $this->lastEditTime;
}
public function getLastEditTime()
{
return $this->lastEditTime;
}
public function setLastEditTime($lastEditTime)
{
$this->lastEditTime = $lastEditTime;
}
public function setLastEditTime($lastEditTime)
{
$this->lastEditTime = $lastEditTime;
}
public function getContentType()
{
return $this->contentType;
}
public function getContentType()
{
return $this->contentType;
}
public function setContentType($contentType)
{
$this->contentType = $contentType;
}
public function setContentType($contentType)
{
$this->contentType = $contentType;
}
public function getContentChecksum()
{
return $this->contentChecksum;
}
public function getContentChecksum()
{
return $this->contentChecksum;
}
public function setContentChecksum($contentChecksum)
{
$this->contentChecksum = $contentChecksum;
}
public function setContentChecksum($contentChecksum)
{
$this->contentChecksum = $contentChecksum;
}
public function getContentMimeType()
{
return $this->contentMimeType;
}
public function getContentMimeType()
{
return $this->contentMimeType;
}
public function setContentMimeType($contentMimeType)
{
$this->contentMimeType = $contentMimeType;
}
public function setContentMimeType($contentMimeType)
{
$this->contentMimeType = $contentMimeType;
}
public function getSource()
{
return $this->source;
}
public function getSource()
{
return $this->source;
}
public function setSource($source)
{
$this->source = $source;
}
public function setSource($source)
{
$this->source = $source;
}
public function getImageWidth()
{
return $this->imageWidth;
}
public function getImageWidth()
{
return $this->imageWidth;
}
public function setImageWidth($imageWidth)
{
$this->imageWidth = $imageWidth;
}
public function setImageWidth($imageWidth)
{
$this->imageWidth = $imageWidth;
}
public function getImageHeight()
{
return $this->imageHeight;
}
public function getImageHeight()
{
return $this->imageHeight;
}
public function setImageHeight($imageHeight)
{
$this->imageHeight = $imageHeight;
}
public function setImageHeight($imageHeight)
{
$this->imageHeight = $imageHeight;
}
public function getOriginalFileSize()
{
return $this->originalFileSize;
}
public function getOriginalFileSize()
{
return $this->originalFileSize;
}
public function setOriginalFileSize($originalFileSize)
{
$this->originalFileSize = $originalFileSize;
}
public function setOriginalFileSize($originalFileSize)
{
$this->originalFileSize = $originalFileSize;
}
public function getOriginalFileName()
{
return $this->originalFileName;
}
public function getOriginalFileName()
{
return $this->originalFileName;
}
public function setOriginalFileName($originalFileName)
{
$this->originalFileName = $originalFileName;
}
public function setOriginalFileName($originalFileName)
{
$this->originalFileName = $originalFileName;
}
public function getFeatureCount()
{
return $this->featureCount;
}
public function getFeatureCount()
{
return $this->featureCount;
}
public function setFeatureCount($featureCount)
{
$this->featureCount = $featureCount;
}
public function setFeatureCount($featureCount)
{
$this->featureCount = $featureCount;
}
public function getLastFeatureTime()
{
return $this->lastFeatureTime;
}
public function getLastFeatureTime()
{
return $this->lastFeatureTime;
}
public function setLastFeatureTime($lastFeatureTime)
{
$this->lastFeatureTime = $lastFeatureTime;
}
public function setLastFeatureTime($lastFeatureTime)
{
$this->lastFeatureTime = $lastFeatureTime;
}
public function getFlags()
{
return $this->flags;
}
public function getFlags()
{
return $this->flags;
}
public function setFlags($flags)
{
$this->flags = $flags;
}
public function setFlags($flags)
{
$this->flags = $flags;
}
public function getTags()
{
return $this->lazyLoad(self::LAZY_LOADER_TAGS, []);
}
public function getTags()
{
return $this->lazyLoad(self::LAZY_LOADER_TAGS, []);
}
public function setTags(array $tags)
{
$this->lazySave(self::LAZY_LOADER_TAGS, $tags);
$this->setMeta(self::META_TAG_COUNT, count($tags));
}
public function setTags(array $tags)
{
$this->lazySave(self::LAZY_LOADER_TAGS, $tags);
$this->setMeta(self::META_TAG_COUNT, count($tags));
}
public function getRelatedPosts()
{
return $this->lazyLoad(self::LAZY_LOADER_RELATED_POSTS, []);
}
public function getRelatedPosts()
{
return $this->lazyLoad(self::LAZY_LOADER_RELATED_POSTS, []);
}
public function setRelatedPosts(array $relatedPosts)
{
$this->lazySave(self::LAZY_LOADER_RELATED_POSTS, $relatedPosts);
}
public function setRelatedPosts(array $relatedPosts)
{
$this->lazySave(self::LAZY_LOADER_RELATED_POSTS, $relatedPosts);
}
public function getUser()
{
return $this->lazyLoad(self::LAZY_LOADER_USER, null);
}
public function getUser()
{
return $this->lazyLoad(self::LAZY_LOADER_USER, null);
}
public function setUser(User $user = null)
{
$this->lazySave(self::LAZY_LOADER_USER, $user);
$this->userId = $user ? $user->getId() : null;
}
public function setUser(User $user = null)
{
$this->lazySave(self::LAZY_LOADER_USER, $user);
$this->userId = $user ? $user->getId() : null;
}
public function getContent()
{
return $this->lazyLoad(self::LAZY_LOADER_CONTENT, null);
}
public function getContent()
{
return $this->lazyLoad(self::LAZY_LOADER_CONTENT, null);
}
public function setContent($content)
{
$this->lazySave(self::LAZY_LOADER_CONTENT, $content);
}
public function setContent($content)
{
$this->lazySave(self::LAZY_LOADER_CONTENT, $content);
}
public function getThumbnailSourceContent()
{
return $this->lazyLoad(self::LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT, null);
}
public function getThumbnailSourceContent()
{
return $this->lazyLoad(self::LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT, null);
}
public function setThumbnailSourceContent($content)
{
$this->lazySave(self::LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT, $content);
}
public function setThumbnailSourceContent($content)
{
$this->lazySave(self::LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT, $content);
}
public function getContentPath()
{
return 'posts' . DIRECTORY_SEPARATOR . $this->getName();
}
public function getContentPath()
{
return 'posts' . DIRECTORY_SEPARATOR . $this->getName();
}
public function getThumbnailSourceContentPath()
{
return 'posts' . DIRECTORY_SEPARATOR . $this->getName() . '-custom-thumb';
}
public function getThumbnailSourceContentPath()
{
return 'posts' . DIRECTORY_SEPARATOR . $this->getName() . '-custom-thumb';
}
public function getTagCount()
{
return $this->getMeta(self::META_TAG_COUNT, 0);
}
public function getTagCount()
{
return $this->getMeta(self::META_TAG_COUNT, 0);
}
public function getFavoriteCount()
{
return $this->getMeta(self::META_FAV_COUNT, 0);
}
public function getFavoriteCount()
{
return $this->getMeta(self::META_FAV_COUNT, 0);
}
public function getCommentCount()
{
return $this->getMeta(self::META_COMMENT_COUNT, 0);
}
public function getCommentCount()
{
return $this->getMeta(self::META_COMMENT_COUNT, 0);
}
public function getScore()
{
return $this->getMeta(self::META_SCORE, 0);
}
public function getScore()
{
return $this->getMeta(self::META_SCORE, 0);
}
}

View file

@ -3,83 +3,83 @@ namespace Szurubooru\Entities;
final class PostNote extends Entity
{
private $postId;
private $left;
private $top;
private $width;
private $height;
private $text;
private $postId;
private $left;
private $top;
private $width;
private $height;
private $text;
const LAZY_LOADER_POST = 'post';
const LAZY_LOADER_POST = 'post';
public function getPostId()
{
return $this->postId;
}
public function getPostId()
{
return $this->postId;
}
public function setPostId($postId)
{
$this->postId = $postId;
}
public function setPostId($postId)
{
$this->postId = $postId;
}
public function getLeft()
{
return $this->left;
}
public function getLeft()
{
return $this->left;
}
public function setLeft($left)
{
$this->left = $left;
}
public function setLeft($left)
{
$this->left = $left;
}
public function getTop()
{
return $this->top;
}
public function getTop()
{
return $this->top;
}
public function setTop($top)
{
$this->top = $top;
}
public function setTop($top)
{
$this->top = $top;
}
public function getWidth()
{
return $this->width;
}
public function getWidth()
{
return $this->width;
}
public function setWidth($width)
{
$this->width = $width;
}
public function setWidth($width)
{
$this->width = $width;
}
public function getHeight()
{
return $this->height;
}
public function getHeight()
{
return $this->height;
}
public function setHeight($height)
{
$this->height = $height;
}
public function setHeight($height)
{
$this->height = $height;
}
public function getText()
{
return $this->text;
}
public function getText()
{
return $this->text;
}
public function setText($text)
{
$this->text = $text;
}
public function setText($text)
{
$this->text = $text;
}
public function getPost()
{
return $this->lazyLoad(self::LAZY_LOADER_POST, null);
}
public function getPost()
{
return $this->lazyLoad(self::LAZY_LOADER_POST, null);
}
public function setPost(Post $post)
{
$this->lazySave(self::LAZY_LOADER_POST, $post);
$this->postId = $post->getId();
}
public function setPost(Post $post)
{
$this->lazySave(self::LAZY_LOADER_POST, $post);
$this->postId = $post->getId();
}
}

View file

@ -3,59 +3,59 @@ namespace Szurubooru\Entities;
final class Score extends Entity
{
private $postId;
private $commentId;
private $score;
private $time;
private $userId;
private $postId;
private $commentId;
private $score;
private $time;
private $userId;
public function getUserId()
{
return $this->userId;
}
public function getUserId()
{
return $this->userId;
}
public function setUserId($userId)
{
$this->userId = $userId;
}
public function setUserId($userId)
{
$this->userId = $userId;
}
public function getPostId()
{
return $this->postId;
}
public function getPostId()
{
return $this->postId;
}
public function setPostId($postId)
{
$this->postId = $postId;
}
public function setPostId($postId)
{
$this->postId = $postId;
}
public function getCommentId()
{
return $this->commentId;
}
public function getCommentId()
{
return $this->commentId;
}
public function setCommentId($commentId)
{
$this->commentId = $commentId;
}
public function setCommentId($commentId)
{
$this->commentId = $commentId;
}
public function getTime()
{
return $this->time;
}
public function getTime()
{
return $this->time;
}
public function setTime($time)
{
$this->time = $time;
}
public function setTime($time)
{
$this->time = $time;
}
public function getScore()
{
return $this->score;
}
public function getScore()
{
return $this->score;
}
public function setScore($score)
{
$this->score = $score;
}
public function setScore($score)
{
$this->score = $score;
}
}

View file

@ -4,101 +4,101 @@ use Szurubooru\Entities\User;
final class Snapshot extends Entity
{
const TYPE_POST = 0;
const TYPE_TAG = 1;
const TYPE_POST = 0;
const TYPE_TAG = 1;
const OPERATION_CREATION = 0;
const OPERATION_CHANGE = 1;
const OPERATION_DELETE = 2;
const OPERATION_CREATION = 0;
const OPERATION_CHANGE = 1;
const OPERATION_DELETE = 2;
const LAZY_LOADER_USER = 'user';
const LAZY_LOADER_USER = 'user';
private $time;
private $type;
private $primaryKey;
private $operation;
private $userId;
private $data;
private $dataDifference;
private $time;
private $type;
private $primaryKey;
private $operation;
private $userId;
private $data;
private $dataDifference;
public function getTime()
{
return $this->time;
}
public function getTime()
{
return $this->time;
}
public function setTime($time)
{
$this->time = $time;
}
public function setTime($time)
{
$this->time = $time;
}
public function getType()
{
return $this->type;
}
public function getType()
{
return $this->type;
}
public function setType($type)
{
$this->type = $type;
}
public function setType($type)
{
$this->type = $type;
}
public function getPrimaryKey()
{
return $this->primaryKey;
}
public function getPrimaryKey()
{
return $this->primaryKey;
}
public function setPrimaryKey($primaryKey)
{
$this->primaryKey = $primaryKey;
}
public function setPrimaryKey($primaryKey)
{
$this->primaryKey = $primaryKey;
}
public function getOperation()
{
return $this->operation;
}
public function getOperation()
{
return $this->operation;
}
public function setOperation($operation)
{
$this->operation = $operation;
}
public function setOperation($operation)
{
$this->operation = $operation;
}
public function getUserId()
{
return $this->userId;
}
public function getUserId()
{
return $this->userId;
}
public function setUserId($userId)
{
$this->userId = $userId;
}
public function setUserId($userId)
{
$this->userId = $userId;
}
public function getData()
{
return $this->data;
}
public function getData()
{
return $this->data;
}
public function setData($data)
{
$this->data = $data;
}
public function setData($data)
{
$this->data = $data;
}
public function getDataDifference()
{
return $this->dataDifference;
}
public function getDataDifference()
{
return $this->dataDifference;
}
public function setDataDifference($dataDifference)
{
$this->dataDifference = $dataDifference;
}
public function setDataDifference($dataDifference)
{
$this->dataDifference = $dataDifference;
}
public function getUser()
{
return $this->lazyLoad(self::LAZY_LOADER_USER, null);
}
public function getUser()
{
return $this->lazyLoad(self::LAZY_LOADER_USER, null);
}
public function setUser(User $user = null)
{
$this->lazySave(self::LAZY_LOADER_USER, $user);
$this->userId = $user ? $user->getId() : null;
}
public function setUser(User $user = null)
{
$this->lazySave(self::LAZY_LOADER_USER, $user);
$this->userId = $user ? $user->getId() : null;
}
}

View file

@ -3,78 +3,78 @@ namespace Szurubooru\Entities;
final class Tag extends Entity
{
private $name;
private $creationTime;
private $banned = false;
private $category = 'default';
private $name;
private $creationTime;
private $banned = false;
private $category = 'default';
const LAZY_LOADER_IMPLIED_TAGS = 'implications';
const LAZY_LOADER_SUGGESTED_TAGS = 'suggestions';
const LAZY_LOADER_IMPLIED_TAGS = 'implications';
const LAZY_LOADER_SUGGESTED_TAGS = 'suggestions';
const META_USAGES = 'usages';
const META_USAGES = 'usages';
public function getName()
{
return $this->name;
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
public function setName($name)
{
$this->name = $name;
}
public function getCreationTime()
{
return $this->creationTime;
}
public function getCreationTime()
{
return $this->creationTime;
}
public function setCreationTime($creationTime)
{
$this->creationTime = $creationTime;
}
public function setCreationTime($creationTime)
{
$this->creationTime = $creationTime;
}
public function isBanned()
{
return $this->banned;
}
public function isBanned()
{
return $this->banned;
}
public function setBanned($banned)
{
$this->banned = boolval($banned);
}
public function setBanned($banned)
{
$this->banned = boolval($banned);
}
public function getCategory()
{
return $this->category;
}
public function getCategory()
{
return $this->category;
}
public function setCategory($category)
{
$this->category = $category;
}
public function setCategory($category)
{
$this->category = $category;
}
public function getUsages()
{
return $this->getMeta(self::META_USAGES);
}
public function getUsages()
{
return $this->getMeta(self::META_USAGES);
}
public function getImpliedTags()
{
return $this->lazyLoad(self::LAZY_LOADER_IMPLIED_TAGS, []);
}
public function getImpliedTags()
{
return $this->lazyLoad(self::LAZY_LOADER_IMPLIED_TAGS, []);
}
public function setImpliedTags(array $impliedTags)
{
$this->lazySave(self::LAZY_LOADER_IMPLIED_TAGS, $impliedTags);
}
public function setImpliedTags(array $impliedTags)
{
$this->lazySave(self::LAZY_LOADER_IMPLIED_TAGS, $impliedTags);
}
public function getSuggestedTags()
{
return $this->lazyLoad(self::LAZY_LOADER_SUGGESTED_TAGS, []);
}
public function getSuggestedTags()
{
return $this->lazyLoad(self::LAZY_LOADER_SUGGESTED_TAGS, []);
}
public function setSuggestedTags(array $suggestedTags)
{
$this->lazySave(self::LAZY_LOADER_SUGGESTED_TAGS, $suggestedTags);
}
public function setSuggestedTags(array $suggestedTags)
{
$this->lazySave(self::LAZY_LOADER_SUGGESTED_TAGS, $suggestedTags);
}
}

View file

@ -3,41 +3,41 @@ namespace Szurubooru\Entities;
final class Token extends Entity
{
const PURPOSE_LOGIN = 1;
const PURPOSE_ACTIVATE = 2;
const PURPOSE_PASSWORD_RESET = 3;
const PURPOSE_LOGIN = 1;
const PURPOSE_ACTIVATE = 2;
const PURPOSE_PASSWORD_RESET = 3;
private $name;
private $purpose;
private $additionalData;
private $name;
private $purpose;
private $additionalData;
public function getName()
{
return $this->name;
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
public function setName($name)
{
$this->name = $name;
}
public function getPurpose()
{
return $this->purpose;
}
public function getPurpose()
{
return $this->purpose;
}
public function setPurpose($purpose)
{
$this->purpose = intval($purpose);
}
public function setPurpose($purpose)
{
$this->purpose = intval($purpose);
}
public function getAdditionalData()
{
return $this->additionalData;
}
public function getAdditionalData()
{
return $this->additionalData;
}
public function setAdditionalData($additionalData)
{
$this->additionalData = $additionalData;
}
public function setAdditionalData($additionalData)
{
$this->additionalData = $additionalData;
}
}

View file

@ -3,165 +3,165 @@ namespace Szurubooru\Entities;
final class User extends Entity
{
const ACCESS_RANK_NOBODY = 0;
const ACCESS_RANK_ANONYMOUS = 1;
const ACCESS_RANK_RESTRICTED_USER = 2;
const ACCESS_RANK_REGULAR_USER = 3;
const ACCESS_RANK_POWER_USER = 4;
const ACCESS_RANK_MODERATOR = 5;
const ACCESS_RANK_ADMINISTRATOR = 6;
const ACCESS_RANK_NOBODY = 0;
const ACCESS_RANK_ANONYMOUS = 1;
const ACCESS_RANK_RESTRICTED_USER = 2;
const ACCESS_RANK_REGULAR_USER = 3;
const ACCESS_RANK_POWER_USER = 4;
const ACCESS_RANK_MODERATOR = 5;
const ACCESS_RANK_ADMINISTRATOR = 6;
const AVATAR_STYLE_GRAVATAR = 1;
const AVATAR_STYLE_MANUAL = 2;
const AVATAR_STYLE_BLANK = 3;
const AVATAR_STYLE_GRAVATAR = 1;
const AVATAR_STYLE_MANUAL = 2;
const AVATAR_STYLE_BLANK = 3;
const LAZY_LOADER_CUSTOM_AVATAR_SOURCE_CONTENT = 'customAvatarContent';
const LAZY_LOADER_CUSTOM_AVATAR_SOURCE_CONTENT = 'customAvatarContent';
private $name;
private $email;
private $emailUnconfirmed;
private $passwordHash;
private $passwordSalt;
private $accessRank;
private $registrationTime;
private $lastLoginTime;
private $avatarStyle;
private $browsingSettings;
private $accountConfirmed = false;
private $banned = false;
private $name;
private $email;
private $emailUnconfirmed;
private $passwordHash;
private $passwordSalt;
private $accessRank;
private $registrationTime;
private $lastLoginTime;
private $avatarStyle;
private $browsingSettings;
private $accountConfirmed = false;
private $banned = false;
public function getName()
{
return $this->name;
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
public function setName($name)
{
$this->name = $name;
}
public function getEmail()
{
return $this->email;
}
public function getEmail()
{
return $this->email;
}
public function setEmail($email)
{
$this->email = $email;
}
public function setEmail($email)
{
$this->email = $email;
}
public function getEmailUnconfirmed()
{
return $this->emailUnconfirmed;
}
public function getEmailUnconfirmed()
{
return $this->emailUnconfirmed;
}
public function setEmailUnconfirmed($emailUnconfirmed)
{
$this->emailUnconfirmed = $emailUnconfirmed;
}
public function setEmailUnconfirmed($emailUnconfirmed)
{
$this->emailUnconfirmed = $emailUnconfirmed;
}
public function isBanned()
{
return $this->banned;
}
public function isBanned()
{
return $this->banned;
}
public function setBanned($banned)
{
$this->banned = boolval($banned);
}
public function setBanned($banned)
{
$this->banned = boolval($banned);
}
public function isAccountConfirmed()
{
return $this->accountConfirmed;
}
public function isAccountConfirmed()
{
return $this->accountConfirmed;
}
public function setAccountConfirmed($accountConfirmed)
{
$this->accountConfirmed = boolval($accountConfirmed);
}
public function setAccountConfirmed($accountConfirmed)
{
$this->accountConfirmed = boolval($accountConfirmed);
}
public function getPasswordHash()
{
return $this->passwordHash;
}
public function getPasswordHash()
{
return $this->passwordHash;
}
public function setPasswordHash($passwordHash)
{
$this->passwordHash = $passwordHash;
}
public function setPasswordHash($passwordHash)
{
$this->passwordHash = $passwordHash;
}
public function getPasswordSalt()
{
return $this->passwordSalt;
}
public function getPasswordSalt()
{
return $this->passwordSalt;
}
public function setPasswordSalt($passwordSalt)
{
$this->passwordSalt = $passwordSalt;
}
public function setPasswordSalt($passwordSalt)
{
$this->passwordSalt = $passwordSalt;
}
public function getAccessRank()
{
return $this->accessRank;
}
public function getAccessRank()
{
return $this->accessRank;
}
public function setAccessRank($accessRank)
{
$this->accessRank = $accessRank;
}
public function setAccessRank($accessRank)
{
$this->accessRank = $accessRank;
}
public function getRegistrationTime()
{
return $this->registrationTime;
}
public function getRegistrationTime()
{
return $this->registrationTime;
}
public function setRegistrationTime($registrationTime)
{
$this->registrationTime = $registrationTime;
}
public function setRegistrationTime($registrationTime)
{
$this->registrationTime = $registrationTime;
}
public function getLastLoginTime()
{
return $this->lastLoginTime;
}
public function getLastLoginTime()
{
return $this->lastLoginTime;
}
public function setLastLoginTime($lastLoginTime)
{
$this->lastLoginTime = $lastLoginTime;
}
public function setLastLoginTime($lastLoginTime)
{
$this->lastLoginTime = $lastLoginTime;
}
public function getAvatarStyle()
{
return $this->avatarStyle;
}
public function getAvatarStyle()
{
return $this->avatarStyle;
}
public function setAvatarStyle($avatarStyle)
{
$this->avatarStyle = $avatarStyle;
}
public function setAvatarStyle($avatarStyle)
{
$this->avatarStyle = $avatarStyle;
}
public function getBrowsingSettings()
{
return $this->browsingSettings;
}
public function getBrowsingSettings()
{
return $this->browsingSettings;
}
public function setBrowsingSettings($browsingSettings)
{
$this->browsingSettings = $browsingSettings;
}
public function setBrowsingSettings($browsingSettings)
{
$this->browsingSettings = $browsingSettings;
}
public function getCustomAvatarSourceContent()
{
return $this->lazyLoad(self::LAZY_LOADER_CUSTOM_AVATAR_SOURCE_CONTENT, null);
}
public function getCustomAvatarSourceContent()
{
return $this->lazyLoad(self::LAZY_LOADER_CUSTOM_AVATAR_SOURCE_CONTENT, null);
}
public function setCustomAvatarSourceContent($content)
{
$this->lazySave(self::LAZY_LOADER_CUSTOM_AVATAR_SOURCE_CONTENT, $content);
}
public function setCustomAvatarSourceContent($content)
{
$this->lazySave(self::LAZY_LOADER_CUSTOM_AVATAR_SOURCE_CONTENT, $content);
}
public function getCustomAvatarSourceContentPath()
{
return 'avatars' . DIRECTORY_SEPARATOR . $this->getId();
}
public function getCustomAvatarSourceContentPath()
{
return 'avatars' . DIRECTORY_SEPARATOR . $this->getId();
}
}

View file

@ -5,19 +5,19 @@ use Szurubooru\Validator;
class LoginFormData implements IValidatable
{
public $userNameOrEmail;
public $password;
public $userNameOrEmail;
public $password;
public function __construct($inputReader = null)
{
if ($inputReader !== null)
{
$this->userNameOrEmail = trim($inputReader->userNameOrEmail);
$this->password = $inputReader->password;
}
}
public function __construct($inputReader = null)
{
if ($inputReader !== null)
{
$this->userNameOrEmail = trim($inputReader->userNameOrEmail);
$this->password = $inputReader->password;
}
}
public function validate(Validator $validator)
{
}
public function validate(Validator $validator)
{
}
}

View file

@ -6,46 +6,46 @@ use Szurubooru\Validator;
class PostEditFormData implements IValidatable
{
public $content;
public $thumbnail;
public $safety;
public $source;
public $tags;
public $relations;
public $flags;
public $content;
public $thumbnail;
public $safety;
public $source;
public $tags;
public $relations;
public $flags;
public $seenEditTime;
public $seenEditTime;
public function __construct($inputReader = null)
{
if ($inputReader !== null)
{
$this->content = $inputReader->readFile('content');
$this->thumbnail = $inputReader->readFile('thumbnail');
if ($inputReader->safety)
$this->safety = EnumHelper::postSafetyFromString($inputReader->safety);
if ($inputReader->source !== null)
$this->source = $inputReader->source;
$this->tags = preg_split('/[\s+]/', $inputReader->tags);
if ($inputReader->relations !== null)
$this->relations = array_filter(preg_split('/[\s+]/', $inputReader->relations));
$this->seenEditTime = $inputReader->seenEditTime;
$this->flags = new \StdClass;
$this->flags->loop = !empty($inputReader->loop);
}
}
public function __construct($inputReader = null)
{
if ($inputReader !== null)
{
$this->content = $inputReader->readFile('content');
$this->thumbnail = $inputReader->readFile('thumbnail');
if ($inputReader->safety)
$this->safety = EnumHelper::postSafetyFromString($inputReader->safety);
if ($inputReader->source !== null)
$this->source = $inputReader->source;
$this->tags = preg_split('/[\s+]/', $inputReader->tags);
if ($inputReader->relations !== null)
$this->relations = array_filter(preg_split('/[\s+]/', $inputReader->relations));
$this->seenEditTime = $inputReader->seenEditTime;
$this->flags = new \StdClass;
$this->flags->loop = !empty($inputReader->loop);
}
}
public function validate(Validator $validator)
{
$validator->validatePostTags($this->tags);
public function validate(Validator $validator)
{
$validator->validatePostTags($this->tags);
if ($this->source !== null)
$validator->validatePostSource($this->source);
if ($this->source !== null)
$validator->validatePostSource($this->source);
if ($this->relations)
{
foreach ($this->relations as $relatedPostId)
$validator->validateNumber($relatedPostId);
}
}
if ($this->relations)
{
foreach ($this->relations as $relatedPostId)
$validator->validateNumber($relatedPostId);
}
}
}

View file

@ -5,26 +5,26 @@ use Szurubooru\Validator;
class PostNoteFormData implements IValidatable
{
public $left;
public $top;
public $width;
public $height;
public $text;
public $left;
public $top;
public $width;
public $height;
public $text;
public function __construct($inputReader = null)
{
if ($inputReader !== null)
{
$this->left = floatval($inputReader->left);
$this->top = floatval($inputReader->top);
$this->width = floatval($inputReader->width);
$this->height = floatval($inputReader->height);
$this->text = trim($inputReader->text);
}
}
public function __construct($inputReader = null)
{
if ($inputReader !== null)
{
$this->left = floatval($inputReader->left);
$this->top = floatval($inputReader->top);
$this->width = floatval($inputReader->width);
$this->height = floatval($inputReader->height);
$this->text = trim($inputReader->text);
}
}
public function validate(Validator $validator)
{
$validator->validateMinLength($this->text, 3, 'Post note content');
}
public function validate(Validator $validator)
{
$validator->validateMinLength($this->text, 3, 'Post note content');
}
}

View file

@ -5,24 +5,24 @@ use Szurubooru\Validator;
class RegistrationFormData implements IValidatable
{
public $userName;
public $password;
public $email;
public $userName;
public $password;
public $email;
public function __construct($inputReader = null)
{
if ($inputReader !== null)
{
$this->userName = trim($inputReader->userName);
$this->password = $inputReader->password;
$this->email = trim($inputReader->email);
}
}
public function __construct($inputReader = null)
{
if ($inputReader !== null)
{
$this->userName = trim($inputReader->userName);
$this->password = $inputReader->password;
$this->email = trim($inputReader->email);
}
}
public function validate(Validator $validator)
{
$validator->validateUserName($this->userName);
$validator->validatePassword($this->password);
$validator->validateEmail($this->email);
}
public function validate(Validator $validator)
{
$validator->validateUserName($this->userName);
$validator->validatePassword($this->password);
$validator->validateEmail($this->email);
}
}

View file

@ -5,40 +5,40 @@ use Szurubooru\Validator;
class TagEditFormData implements IValidatable
{
public $name;
public $banned;
public $category;
public $implications;
public $suggestions;
public $name;
public $banned;
public $category;
public $implications;
public $suggestions;
public function __construct($inputReader = null)
{
if ($inputReader !== null)
{
$this->name = trim($inputReader->name);
$this->category = strtolower(trim($inputReader->category));
public function __construct($inputReader = null)
{
if ($inputReader !== null)
{
$this->name = trim($inputReader->name);
$this->category = strtolower(trim($inputReader->category));
if ($inputReader->banned !== null)
$this->banned = boolval($inputReader->banned);
if ($inputReader->banned !== null)
$this->banned = boolval($inputReader->banned);
$this->implications = array_filter(array_unique(preg_split('/[\s+]/', $inputReader->implications)));
$this->suggestions = array_filter(array_unique(preg_split('/[\s+]/', $inputReader->suggestions)));
}
}
$this->implications = array_filter(array_unique(preg_split('/[\s+]/', $inputReader->implications)));
$this->suggestions = array_filter(array_unique(preg_split('/[\s+]/', $inputReader->suggestions)));
}
}
public function validate(Validator $validator)
{
if ($this->category !== null)
$validator->validateLength($this->category, 1, 25, 'Tag category');
public function validate(Validator $validator)
{
if ($this->category !== null)
$validator->validateLength($this->category, 1, 25, 'Tag category');
if ($this->name !== null)
$validator->validatePostTags([$this->name]);
if ($this->name !== null)
$validator->validatePostTags([$this->name]);
if (!empty($this->implications))
$validator->validatePostTags($this->implications);
if (!empty($this->implications))
$validator->validatePostTags($this->implications);
if (!empty($this->suggestions))
$validator->validatePostTags($this->suggestions);
}
if (!empty($this->suggestions))
$validator->validatePostTags($this->suggestions);
}
}

View file

@ -6,37 +6,37 @@ use Szurubooru\Validator;
class UploadFormData implements IValidatable
{
public $contentFileName;
public $content;
public $url;
public $anonymous;
public $safety;
public $source;
public $tags;
public $contentFileName;
public $content;
public $url;
public $anonymous;
public $safety;
public $source;
public $tags;
public function __construct($inputReader = null)
{
if ($inputReader !== null)
{
$this->contentFileName = $inputReader->contentFileName;
$this->content = $inputReader->readFile('content');
$this->url = $inputReader->url;
$this->anonymous = $inputReader->anonymous;
$this->safety = EnumHelper::postSafetyFromString($inputReader->safety);
$this->source = $inputReader->source;
$this->tags = preg_split('/[\s+]/', $inputReader->tags);
}
}
public function __construct($inputReader = null)
{
if ($inputReader !== null)
{
$this->contentFileName = $inputReader->contentFileName;
$this->content = $inputReader->readFile('content');
$this->url = $inputReader->url;
$this->anonymous = $inputReader->anonymous;
$this->safety = EnumHelper::postSafetyFromString($inputReader->safety);
$this->source = $inputReader->source;
$this->tags = preg_split('/[\s+]/', $inputReader->tags);
}
}
public function validate(Validator $validator)
{
if ($this->content === null && $this->url === null)
throw new \DomainException('Neither data or URL provided.');
public function validate(Validator $validator)
{
if ($this->content === null && $this->url === null)
throw new \DomainException('Neither data or URL provided.');
$validator->validatePostTags($this->tags);
$validator->validatePostTags($this->tags);
if ($this->source !== null)
$validator->validatePostSource($this->source);
}
if ($this->source !== null)
$validator->validatePostSource($this->source);
}
}

View file

@ -7,60 +7,60 @@ use Szurubooru\Validator;
class UserEditFormData implements IValidatable
{
public $userName;
public $email;
public $password;
public $accessRank;
public $avatarStyle;
public $avatarContent;
public $browsingSettings;
public $banned;
public $userName;
public $email;
public $password;
public $accessRank;
public $avatarStyle;
public $avatarContent;
public $browsingSettings;
public $banned;
public function __construct($inputReader = null)
{
if ($inputReader !== null)
{
$this->userName = $inputReader->userName;
$this->email = $inputReader->email;
$this->password = $inputReader->password;
if ($inputReader->accessRank !== null)
$this->accessRank = EnumHelper::accessRankFromString($inputReader->accessRank);
if ($inputReader->avatarStyle !== null)
$this->avatarStyle = EnumHelper::avatarStyleFromString($inputReader->avatarStyle);
$this->avatarContent = $inputReader->readFile('avatarContent');
$this->browsingSettings = json_decode($inputReader->browsingSettings);
if ($inputReader->banned !== null)
$this->banned = boolval($inputReader->banned);
}
}
public function __construct($inputReader = null)
{
if ($inputReader !== null)
{
$this->userName = $inputReader->userName;
$this->email = $inputReader->email;
$this->password = $inputReader->password;
if ($inputReader->accessRank !== null)
$this->accessRank = EnumHelper::accessRankFromString($inputReader->accessRank);
if ($inputReader->avatarStyle !== null)
$this->avatarStyle = EnumHelper::avatarStyleFromString($inputReader->avatarStyle);
$this->avatarContent = $inputReader->readFile('avatarContent');
$this->browsingSettings = json_decode($inputReader->browsingSettings);
if ($inputReader->banned !== null)
$this->banned = boolval($inputReader->banned);
}
}
public function validate(Validator $validator)
{
if ($this->userName !== null)
$validator->validateUserName($this->userName);
public function validate(Validator $validator)
{
if ($this->userName !== null)
$validator->validateUserName($this->userName);
if ($this->password !== null)
$validator->validatePassword($this->password);
if ($this->password !== null)
$validator->validatePassword($this->password);
if ($this->email !== null)
$validator->validateEmail($this->email);
if ($this->email !== null)
$validator->validateEmail($this->email);
if (strlen($this->avatarContent) > 1024 * 512)
throw new \DomainException('Avatar content must have at most 512 kilobytes.');
if (strlen($this->avatarContent) > 1024 * 512)
throw new \DomainException('Avatar content must have at most 512 kilobytes.');
if ($this->avatarContent)
{
$avatarContentMimeType = MimeHelper::getMimeTypeFromBuffer($this->avatarContent);
if (!MimeHelper::isImage($avatarContentMimeType))
throw new \DomainException('Avatar must be an image (detected: ' . $avatarContentMimeType . ').');
}
if ($this->avatarContent)
{
$avatarContentMimeType = MimeHelper::getMimeTypeFromBuffer($this->avatarContent);
if (!MimeHelper::isImage($avatarContentMimeType))
throw new \DomainException('Avatar must be an image (detected: ' . $avatarContentMimeType . ').');
}
if ($this->browsingSettings !== null)
{
if (!is_object($this->browsingSettings))
throw new \InvalidArgumentException('Browsing settings must be valid JSON.');
else if (strlen(json_encode($this->browsingSettings)) > 300)
throw new \InvalidArgumentException('Stringified browsing settings can have at most 300 characters.');
}
}
if ($this->browsingSettings !== null)
{
if (!is_object($this->browsingSettings))
throw new \InvalidArgumentException('Browsing settings must be valid JSON.');
else if (strlen(json_encode($this->browsingSettings)) > 300)
throw new \InvalidArgumentException('Stringified browsing settings can have at most 300 characters.');
}
}
}

View file

@ -6,111 +6,111 @@ use Szurubooru\Entities\User;
class EnumHelper
{
private static $accessRankMap =
[
'anonymous' => User::ACCESS_RANK_ANONYMOUS,
'restrictedUser' => User::ACCESS_RANK_RESTRICTED_USER,
'regularUser' => User::ACCESS_RANK_REGULAR_USER,
'powerUser' => User::ACCESS_RANK_POWER_USER,
'moderator' => User::ACCESS_RANK_MODERATOR,
'administrator' => User::ACCESS_RANK_ADMINISTRATOR,
];
private static $accessRankMap =
[
'anonymous' => User::ACCESS_RANK_ANONYMOUS,
'restrictedUser' => User::ACCESS_RANK_RESTRICTED_USER,
'regularUser' => User::ACCESS_RANK_REGULAR_USER,
'powerUser' => User::ACCESS_RANK_POWER_USER,
'moderator' => User::ACCESS_RANK_MODERATOR,
'administrator' => User::ACCESS_RANK_ADMINISTRATOR,
];
private static $avatarStyleMap =
[
'gravatar' => User::AVATAR_STYLE_GRAVATAR,
'manual' => User::AVATAR_STYLE_MANUAL,
'none' => User::AVATAR_STYLE_BLANK,
'blank' => User::AVATAR_STYLE_BLANK,
];
private static $avatarStyleMap =
[
'gravatar' => User::AVATAR_STYLE_GRAVATAR,
'manual' => User::AVATAR_STYLE_MANUAL,
'none' => User::AVATAR_STYLE_BLANK,
'blank' => User::AVATAR_STYLE_BLANK,
];
private static $postSafetyMap =
[
'safe' => Post::POST_SAFETY_SAFE,
'sketchy' => Post::POST_SAFETY_SKETCHY,
'unsafe' => Post::POST_SAFETY_UNSAFE,
];
private static $postSafetyMap =
[
'safe' => Post::POST_SAFETY_SAFE,
'sketchy' => Post::POST_SAFETY_SKETCHY,
'unsafe' => Post::POST_SAFETY_UNSAFE,
];
private static $postTypeMap =
[
'image' => Post::POST_TYPE_IMAGE,
'video' => Post::POST_TYPE_VIDEO,
'flash' => Post::POST_TYPE_FLASH,
'youtube' => Post::POST_TYPE_YOUTUBE,
'animation' => Post::POST_TYPE_ANIMATED_IMAGE,
];
private static $postTypeMap =
[
'image' => Post::POST_TYPE_IMAGE,
'video' => Post::POST_TYPE_VIDEO,
'flash' => Post::POST_TYPE_FLASH,
'youtube' => Post::POST_TYPE_YOUTUBE,
'animation' => Post::POST_TYPE_ANIMATED_IMAGE,
];
private static $snapshotTypeMap =
[
'post' => Snapshot::TYPE_POST,
];
private static $snapshotTypeMap =
[
'post' => Snapshot::TYPE_POST,
];
public static function accessRankToString($accessRank)
{
return self::enumToString(self::$accessRankMap, $accessRank);
}
public static function accessRankToString($accessRank)
{
return self::enumToString(self::$accessRankMap, $accessRank);
}
public static function accessRankFromString($accessRankString)
{
return self::stringToEnum(self::$accessRankMap, $accessRankString);
}
public static function accessRankFromString($accessRankString)
{
return self::stringToEnum(self::$accessRankMap, $accessRankString);
}
public static function avatarStyleToString($avatarStyle)
{
return self::enumToString(self::$avatarStyleMap, $avatarStyle);
}
public static function avatarStyleToString($avatarStyle)
{
return self::enumToString(self::$avatarStyleMap, $avatarStyle);
}
public static function avatarStyleFromString($avatarStyleString)
{
return self::stringToEnum(self::$avatarStyleMap, $avatarStyleString);
}
public static function avatarStyleFromString($avatarStyleString)
{
return self::stringToEnum(self::$avatarStyleMap, $avatarStyleString);
}
public static function postSafetyToString($postSafety)
{
return self::enumToString(self::$postSafetyMap, $postSafety);
}
public static function postSafetyToString($postSafety)
{
return self::enumToString(self::$postSafetyMap, $postSafety);
}
public static function postSafetyFromString($postSafetyString)
{
return self::stringToEnum(self::$postSafetyMap, $postSafetyString);
}
public static function postSafetyFromString($postSafetyString)
{
return self::stringToEnum(self::$postSafetyMap, $postSafetyString);
}
public static function postTypeToString($postType)
{
return self::enumToString(self::$postTypeMap, $postType);
}
public static function postTypeToString($postType)
{
return self::enumToString(self::$postTypeMap, $postType);
}
public static function postTypeFromString($postTypeString)
{
return self::stringToEnum(self::$postTypeMap, $postTypeString);
}
public static function postTypeFromString($postTypeString)
{
return self::stringToEnum(self::$postTypeMap, $postTypeString);
}
public static function snapshotTypeFromString($snapshotTypeString)
{
return self::stringToEnum(self::$snapshotTypeMap, $snapshotTypeString);
}
public static function snapshotTypeFromString($snapshotTypeString)
{
return self::stringToEnum(self::$snapshotTypeMap, $snapshotTypeString);
}
private static function enumToString($enumMap, $enumValue)
{
$reverseMap = array_flip($enumMap);
if (!isset($reverseMap[$enumValue]))
throw new \RuntimeException('Invalid value!');
private static function enumToString($enumMap, $enumValue)
{
$reverseMap = array_flip($enumMap);
if (!isset($reverseMap[$enumValue]))
throw new \RuntimeException('Invalid value!');
return $reverseMap[$enumValue];
}
return $reverseMap[$enumValue];
}
private static function stringToEnum($enumMap, $enumString)
{
$key = trim(strtolower($enumString));
$lowerEnumMap = array_change_key_case($enumMap, \CASE_LOWER);
if (!isset($lowerEnumMap[$key]))
{
throw new \DomainException(sprintf(
'Unrecognized value: %s.' . PHP_EOL . 'Possible values: %s',
$enumString,
join(', ', array_keys($lowerEnumMap))));
}
private static function stringToEnum($enumMap, $enumString)
{
$key = trim(strtolower($enumString));
$lowerEnumMap = array_change_key_case($enumMap, \CASE_LOWER);
if (!isset($lowerEnumMap[$key]))
{
throw new \DomainException(sprintf(
'Unrecognized value: %s.' . PHP_EOL . 'Possible values: %s',
$enumString,
join(', ', array_keys($lowerEnumMap))));
}
return $lowerEnumMap[$key];
}
return $lowerEnumMap[$key];
}
}

View file

@ -3,89 +3,89 @@ namespace Szurubooru\Helpers;
class HttpHelper
{
private $redirected = false;
private $redirected = false;
public function setResponseCode($code)
{
http_response_code($code);
}
public function setResponseCode($code)
{
http_response_code($code);
}
public function setHeader($key, $value)
{
header($key . ': ' . $value);
}
public function setHeader($key, $value)
{
header($key . ': ' . $value);
}
public function outputJSON($data)
{
$encodedJson = json_encode((array) $data);
$lastError = json_last_error();
if ($lastError !== JSON_ERROR_NONE)
$this->output('Fatal error while encoding JSON: ' . $lastError . PHP_EOL . PHP_EOL . print_r($data, true));
else
$this->output($encodedJson);
}
public function outputJSON($data)
{
$encodedJson = json_encode((array) $data);
$lastError = json_last_error();
if ($lastError !== JSON_ERROR_NONE)
$this->output('Fatal error while encoding JSON: ' . $lastError . PHP_EOL . PHP_EOL . print_r($data, true));
else
$this->output($encodedJson);
}
public function output($data)
{
echo $data;
}
public function output($data)
{
echo $data;
}
public function getRequestHeaders()
{
if (function_exists('getallheaders'))
{
return getallheaders();
}
$result = [];
foreach ($_SERVER as $key => $value)
{
if (substr($key, 0, 5) == "HTTP_")
{
$key = str_replace(" ", "-", ucwords(strtolower(str_replace("_", " ", substr($key, 5)))));
$result[$key] = $value;
}
else
{
$result[$key] = $value;
}
}
return $result;
}
public function getRequestHeaders()
{
if (function_exists('getallheaders'))
{
return getallheaders();
}
$result = [];
foreach ($_SERVER as $key => $value)
{
if (substr($key, 0, 5) == "HTTP_")
{
$key = str_replace(" ", "-", ucwords(strtolower(str_replace("_", " ", substr($key, 5)))));
$result[$key] = $value;
}
else
{
$result[$key] = $value;
}
}
return $result;
}
public function getRequestHeader($key)
{
$headers = $this->getRequestHeaders();
return isset($headers[$key]) ? $headers[$key] : null;
}
public function getRequestHeader($key)
{
$headers = $this->getRequestHeaders();
return isset($headers[$key]) ? $headers[$key] : null;
}
public function getRequestMethod()
{
return $_SERVER['REQUEST_METHOD'];
}
public function getRequestMethod()
{
return $_SERVER['REQUEST_METHOD'];
}
public function getRequestUri()
{
$requestUri = $_SERVER['REQUEST_URI'];
$requestUri = preg_replace('/\?.*$/', '', $requestUri);
return $requestUri;
}
public function getRequestUri()
{
$requestUri = $_SERVER['REQUEST_URI'];
$requestUri = preg_replace('/\?.*$/', '', $requestUri);
return $requestUri;
}
public function redirect($destination)
{
$this->setResponseCode(307);
$this->setHeader('Location', $destination);
$this->redirected = true;
}
public function redirect($destination)
{
$this->setResponseCode(307);
$this->setHeader('Location', $destination);
$this->redirected = true;
}
public function nonCachedRedirect($destination)
{
$this->setResponseCode(303);
$this->setHeader('Location', $destination);
$this->redirected = true;
}
public function nonCachedRedirect($destination)
{
$this->setResponseCode(303);
$this->setHeader('Location', $destination);
$this->redirected = true;
}
public function isRedirecting()
{
return $this->redirected;
}
public function isRedirecting()
{
return $this->redirected;
}
}

View file

@ -3,36 +3,36 @@ namespace Szurubooru\Helpers;
final class InputReader extends \ArrayObject
{
public function __construct()
{
parent::setFlags(parent::ARRAY_AS_PROPS | parent::STD_PROP_LIST);
public function __construct()
{
parent::setFlags(parent::ARRAY_AS_PROPS | parent::STD_PROP_LIST);
$_PUT = [];
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT')
parse_str(file_get_contents('php://input'), $_PUT);
$_PUT = [];
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT')
parse_str(file_get_contents('php://input'), $_PUT);
foreach ([$_GET, $_POST, $_PUT] as $source)
{
foreach ($source as $key => $value)
$this->offsetSet($key, $value);
}
}
foreach ([$_GET, $_POST, $_PUT] as $source)
{
foreach ($source as $key => $value)
$this->offsetSet($key, $value);
}
}
public function offsetGet($index)
{
if (!parent::offsetExists($index))
return null;
return parent::offsetGet($index);
}
public function offsetGet($index)
{
if (!parent::offsetExists($index))
return null;
return parent::offsetGet($index);
}
public function readFile($fileName)
{
if (!isset($_FILES[$fileName]))
return null;
public function readFile($fileName)
{
if (!isset($_FILES[$fileName]))
return null;
if (!$_FILES[$fileName]['tmp_name'])
throw new \Exception('File is probably too big.');
if (!$_FILES[$fileName]['tmp_name'])
throw new \Exception('File is probably too big.');
return file_get_contents($_FILES[$fileName]['tmp_name']);
}
return file_get_contents($_FILES[$fileName]['tmp_name']);
}
}

Some files were not shown because too many files have changed in this diff Show more